+
+ mdi-calendar-blank
-
- 暂无考试科目,点击"添加科目"按钮开始添加
-
-
- 添加科目
+ 暂无考试科目安排
+
+ 点击上方"添加科目"按钮开始配置
+
+
+ 立即添加科目
@@ -575,6 +750,9 @@ export default {
success: "",
isEditMode: false, // 新增:编辑模式状态
showJsonPreview: false, // 新增:JSON预览显示状态
+ availableSubjects: [], // 可用的科目列表
+ customSubjectInput: "", // 自定义科目输入
+ enableCustomAlertTime: false, // 是否启用自定义提醒时间
defaultExamTips: [
"请保持卷面整洁,字迹清晰,诚信应考。在听到终考铃时立刻起立,停止作答。",
"沉着 冷静 细心 守记",
@@ -584,7 +762,7 @@ export default {
},
computed: {
/**
- * 格式化的JSON字符串
+ * 格式化的JSON字符串(旧版,完整数据)
*/
formattedJson() {
try {
@@ -595,6 +773,29 @@ export default {
}
},
+ /**
+ * 格式化的存储格式JSON字符串(只包含核心字段)
+ */
+ formattedStorageJson() {
+ try {
+ const storageConfig = {
+ examName: this.localConfig.examName,
+ message: this.localConfig.message,
+ room: this.localConfig.room,
+ examInfos: this.localConfig.examInfos.map((info) => ({
+ name: info.name,
+ start: this.formatDisplayDateTime(info.start),
+ end: this.formatDisplayDateTime(info.end),
+ alertTime: parseInt(info.alertTime) || 15,
+ })),
+ };
+ return JSON.stringify(storageConfig, null, 2);
+ } catch (err) {
+ console.error("格式化存储JSON时出错:", err);
+ return "无效的JSON格式";
+ }
+ },
+
/**
* 检查配置是否有效
*/
@@ -723,10 +924,317 @@ export default {
},
},
},
+ created() {
+ this.loadSubjects();
+ },
methods: {
/**
- * 加载配置数据
+ * 加载可用的科目列表
*/
+ async loadSubjects() {
+ try {
+ const response = await dataProvider.loadData("classworks-config-subject");
+ if (response && Array.isArray(response)) {
+ this.availableSubjects = response
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
+ .map(subject => ({
+ name: subject.name,
+ order: subject.order ?? 0
+ }));
+ } else {
+ // 使用默认科目列表
+ this.availableSubjects = [
+ { 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 },
+ ];
+ }
+ } catch (error) {
+ console.warn('加载科目列表失败,使用默认列表:', error);
+ // 使用默认科目列表
+ this.availableSubjects = [
+ { 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 },
+ ];
+ }
+ },
+
+ /**
+ * 自动填充剩余科目的时间(基于最后一个科目,每个科目间隔10分钟)
+ */
+ autoFillRemaining() {
+ if (this.localConfig.examInfos.length === 0) return;
+
+ let lastEndTime = null;
+
+ // 找到最后已设置的时间
+ for (let i = this.localConfig.examInfos.length - 1; i >= 0; i--) {
+ if (this.localConfig.examInfos[i].end) {
+ lastEndTime = new Date(this.localConfig.examInfos[i].end);
+ break;
+ }
+ }
+
+ // 如果没有任何已设置的时间,使用当前时间
+ if (!lastEndTime) {
+ lastEndTime = new Date();
+ }
+
+ // 从前往后填充
+ for (let i = 0; i < this.localConfig.examInfos.length; i++) {
+ const examInfo = this.localConfig.examInfos[i];
+
+ // 如果已经有时间,跳过但更新 lastEndTime
+ if (examInfo.end) {
+ lastEndTime = new Date(examInfo.end);
+ continue;
+ }
+
+ // 计算新的开始和结束时间
+ const startTime = new Date(lastEndTime.getTime() + 10 * 60 * 1000); // 前一个结束时间 + 10分钟
+ const endTime = new Date(startTime.getTime() + 2 * 60 * 60 * 1000); // 考试时长2小时
+
+ // 更新科目时间
+ examInfo.start = this.formatDateTimeLocal(startTime);
+ examInfo.startDate = startTime;
+ examInfo.startTime = this.formatTimeOnly(startTime);
+ examInfo.startFormatted = this.formatDisplayDateTime(startTime);
+
+ examInfo.end = this.formatDateTimeLocal(endTime);
+ examInfo.endDate = endTime;
+ examInfo.endTime = this.formatTimeOnly(endTime);
+ examInfo.endFormatted = this.formatDisplayDateTime(endTime);
+
+ lastEndTime = endTime;
+ }
+
+ this.success = '已自动填充所有科目的时间(间隔10分钟)';
+ },
+
+ /**
+ * 验证时间格式
+ */
+ validateTimeFormat(value, fieldName) {
+ if (!value) return true; // 空值由必填验证处理
+
+ // 匹配格式: YYYY/MM/DD HH:mm 或 YYYY-MM-DD HH:mm
+ const match = value.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})\s+(\d{1,2}):(\d{1,2})/);
+ if (!match) {
+ return `${fieldName}格式不正确,请使用格式:2025/01/01 09:00`;
+ }
+
+ const [, year, month, day, hour, minute] = match;
+ const y = parseInt(year);
+ const m = parseInt(month);
+ const d = parseInt(day);
+ const h = parseInt(hour);
+ const min = parseInt(minute);
+
+ // 验证日期范围
+ if (m < 1 || m > 12) return `${fieldName}月份不合法(1-12)`;
+ if (d < 1 || d > 31) return `${fieldName}日期不合法(1-31)`;
+ if (h < 0 || h > 23) return `${fieldName}小时不合法(0-23)`;
+ if (min < 0 || min > 59) return `${fieldName}分钟不合法(0-59)`;
+
+ // 验证日期是否真实存在
+ const date = new Date(y, m - 1, d, h, min);
+ if (isNaN(date.getTime())) {
+ return `${fieldName}日期不存在`;
+ }
+
+ // 验证月份和日期是否匹配(防止2月30日等情况)
+ if (date.getMonth() !== m - 1 || date.getDate() !== d) {
+ return `${fieldName}日期不存在`;
+ }
+
+ return true;
+ },
+
+ /**
+ * 验证结束时间晚于开始时间
+ */
+ validateEndAfterStart(examInfo) {
+ if (!examInfo.startFormatted || !examInfo.endFormatted) return true;
+
+ try {
+ const start = new Date(examInfo.start || examInfo.startFormatted.replace(/\//g, '-'));
+ const end = new Date(examInfo.end || examInfo.endFormatted.replace(/\//g, '-'));
+
+ if (isNaN(start.getTime()) || isNaN(end.getTime())) {
+ return true; // 格式错误由其他验证处理
+ }
+
+ if (end <= start) {
+ return '结束时间必须晚于开始时间';
+ }
+
+ // 检查时长是否合理(不超过24小时)
+ const duration = (end.getTime() - start.getTime()) / (1000 * 60 * 60);
+ if (duration > 24) {
+ return '考试时长不能超过24小时';
+ }
+
+ return true;
+ } catch (error) {
+ return true;
+ }
+ },
+
+ /**
+ * 验证科目时间不重叠
+ */
+ validateNoTimeOverlap(currentExamInfo, currentIndex) {
+ if (!currentExamInfo.startFormatted || !currentExamInfo.endFormatted) {
+ return true; // 时间未设置时不验证重叠
+ }
+
+ try {
+ const currentStart = new Date(currentExamInfo.start || currentExamInfo.startFormatted.replace(/\//g, '-'));
+ const currentEnd = new Date(currentExamInfo.end || currentExamInfo.endFormatted.replace(/\//g, '-'));
+
+ if (isNaN(currentStart.getTime()) || isNaN(currentEnd.getTime())) {
+ return true; // 格式错误由其他验证处理
+ }
+
+ // 检查与其他科目的时间重叠
+ for (let i = 0; i < this.localConfig.examInfos.length; i++) {
+ if (i === currentIndex) continue; // 跳过当前科目
+
+ const otherExamInfo = this.localConfig.examInfos[i];
+ if (!otherExamInfo.start || !otherExamInfo.end) continue;
+
+ const otherStart = new Date(otherExamInfo.start);
+ const otherEnd = new Date(otherExamInfo.end);
+
+ if (isNaN(otherStart.getTime()) || isNaN(otherEnd.getTime())) continue;
+
+ // 检查时间重叠:当前开始时间在其他时间段内 或 当前结束时间在其他时间段内 或 当前时间段完全包含其他时间段
+ const isOverlap = (
+ (currentStart >= otherStart && currentStart < otherEnd) || // 当前开始时间在其他时间段内
+ (currentEnd > otherStart && currentEnd <= otherEnd) || // 当前结束时间在其他时间段内
+ (currentStart <= otherStart && currentEnd >= otherEnd) // 当前时间段完全包含其他时间段
+ );
+
+ if (isOverlap) {
+ const otherSubjectName = otherExamInfo.name || `第${i + 1}个科目`;
+ return `时间与"${otherSubjectName}"重叠`;
+ }
+ }
+
+ return true;
+ } catch (error) {
+ return true;
+ }
+ },
+
+ /**
+ * 切换提醒时间模式
+ */
+ toggleAlertTimeMode() {
+ if (!this.enableCustomAlertTime) {
+ // 关闭自定义时,将所有提醒时间设为15分钟
+ this.localConfig.examInfos.forEach(info => {
+ info.alertTime = 15;
+ });
+ }
+ },
+
+ /**
+ * 计算考试时长
+ */
+ getExamDuration(examInfo) {
+ if (!examInfo.start || !examInfo.end) return '';
+
+ try {
+ const startTime = new Date(examInfo.start);
+ const endTime = new Date(examInfo.end);
+
+ if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
+ return '';
+ }
+
+ const durationMs = endTime.getTime() - startTime.getTime();
+ const durationMinutes = Math.round(durationMs / (1000 * 60));
+
+ if (durationMinutes < 60) {
+ return `${durationMinutes}分钟`;
+ }
+
+ const hours = Math.floor(durationMinutes / 60);
+ const minutes = durationMinutes % 60;
+
+ if (minutes === 0) {
+ return `${hours}小时`;
+ } else {
+ return `${hours}小时${minutes}分钟`;
+ }
+ } catch (error) {
+ return '';
+ }
+ },
+
+ /**
+ * 从输入框更新开始时间
+ */
+ updateStartDateTimeFromInput(index) {
+ if (index === undefined || !this.localConfig.examInfos[index]) return;
+
+ const examInfo = this.localConfig.examInfos[index];
+ const formatted = examInfo.startFormatted;
+ if (!formatted) return;
+
+ // 尝试解析输入格式: 2025/01/01 09:00 或 2025-01-01 09:00
+ const match = formatted.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})\s+(\d{1,2}):(\d{1,2})/);
+ if (!match) return;
+
+ const [, year, month, day, hour, minute] = match;
+ const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute));
+
+ if (isNaN(date.getTime())) return;
+
+ examInfo.startDate = date;
+ examInfo.startTime = this.formatTimeOnly(date);
+ examInfo.start = this.formatDateTimeLocal(date);
+ this.updateStartDateTime(index);
+ },
+
+ /**
+ * 从输入框更新结束时间
+ */
+ updateEndDateTimeFromInput(index) {
+ if (index === undefined || !this.localConfig.examInfos[index]) return;
+
+ const examInfo = this.localConfig.examInfos[index];
+ const formatted = examInfo.endFormatted;
+ if (!formatted) return;
+
+ // 尝试解析输入格式: 2025/01/01 11:00 或 2025-01-01 11:00
+ const match = formatted.match(/(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})\s+(\d{1,2}):(\d{1,2})/);
+ if (!match) return;
+
+ const [, year, month, day, hour, minute] = match;
+ const date = new Date(parseInt(year), parseInt(month) - 1, parseInt(day), parseInt(hour), parseInt(minute));
+
+ if (isNaN(date.getTime())) return;
+
+ examInfo.endDate = date;
+ examInfo.endTime = this.formatTimeOnly(date);
+ examInfo.end = this.formatDateTimeLocal(date);
+ this.updateEndDateTime(index);
+ },
async loadConfig() {
this.loading = true;
this.error = "";
@@ -766,7 +1274,38 @@ export default {
info.endFormatted = this.formatDisplayDateTime(endDate);
info.endDateMenu = false;
}
+
+ // 初始化时长(分钟)- 前端计算
+ try {
+ if (info.start && info.end) {
+ const s = new Date(info.start);
+ const e = new Date(info.end);
+ const diff = Math.round((e.getTime() - s.getTime()) / (1000 * 60));
+ if (diff > 0 && diff <= 24 * 60) {
+ info.durationMinutes = diff;
+ } else {
+ info.durationMinutes = 120;
+ }
+ } else {
+ info.durationMinutes = 120;
+ }
+ } catch (_) {
+ info.durationMinutes = 120;
+ }
+
+ // 初始化提醒时间 - 处理数据迁移
+ if (info.alertTime === undefined || info.alertTime === null) {
+ info.alertTime = 15; // 旧数据默认15分钟
+ } else {
+ info.alertTime = parseInt(info.alertTime) || 15;
+ }
});
+
+ // 检测是否有自定义提醒时间
+ const hasCustomAlertTime = this.localConfig.examInfos.some(
+ info => info.alertTime !== 15
+ );
+ this.enableCustomAlertTime = hasCustomAlertTime;
} else {
console.error("加载配置失败:", response);
this.error =
@@ -801,13 +1340,16 @@ export default {
this.error = "";
try {
- // 创建保存用的配置副本,转换时间格式
+ // 创建保存用的配置副本,只保存核心字段
const configToSave = {
- ...this.localConfig,
+ examName: this.localConfig.examName,
+ message: this.localConfig.message,
+ room: this.localConfig.room,
examInfos: this.localConfig.examInfos.map((info) => ({
- ...info,
+ name: info.name,
start: this.formatDisplayDateTime(info.start),
end: this.formatDisplayDateTime(info.end),
+ alertTime: parseInt(info.alertTime) || 15, // 默认15分钟
})),
};
@@ -839,14 +1381,27 @@ export default {
* 添加考试科目
*/
addExamInfo() {
- const now = new Date();
- const startTime = new Date(now.getTime() + 60 * 60 * 1000); // 1小时后
- const endTime = new Date(startTime.getTime() + 2 * 60 * 60 * 1000); // 2小时后
+ // 获取最后一个科目的结束时间,或使用当前时间
+ let baseTime = new Date();
+
+ if (this.localConfig.examInfos.length > 0) {
+ const lastExamInfo = this.localConfig.examInfos[this.localConfig.examInfos.length - 1];
+ if (lastExamInfo.end) {
+ baseTime = new Date(lastExamInfo.end);
+ }
+ }
+
+ // 新科目开始时间 = 上一个科目结束时间 + 10分钟
+ const startTime = new Date(baseTime.getTime() + 10 * 60 * 1000);
+ // 新科目结束时间 = 开始时间 + 2小时
+ const endTime = new Date(startTime.getTime() + 2 * 60 * 60 * 1000);
const examInfo = {
- name: "新科目",
+ name: "",
start: this.formatDateTimeLocal(startTime),
end: this.formatDateTimeLocal(endTime),
+ durationMinutes: 120,
+ alertTime: 15, // 默认提醒时间15分钟
// 日期选择器相关数据
startDate: startTime,
startTime: this.formatTimeOnly(startTime),
@@ -880,17 +1435,82 @@ export default {
},
/**
- * 复制JSON到剪贴板
+ * 复制JSON到剪贴板(存储格式)
*/
async copyToClipboard() {
try {
- await navigator.clipboard.writeText(this.formattedJson);
- this.success = "JSON已复制到剪贴板";
- } catch (err) {
+ await navigator.clipboard.writeText(this.formattedStorageJson);
+ this.$message.success('配置已复制到剪贴板');
+ } catch (err) {
this.error = "复制失败: " + err.message;
}
},
+ /**
+ * 下载为JSON文件
+ */
+ downloadAsJson() {
+ try {
+ const blob = new Blob([this.formattedStorageJson], { type: 'application/json' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `${this.localConfig.examName || 'exam-config'}.json`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ this.$message?.success('已下载 JSON 文件');
+ } catch (err) {
+ this.error = '下载失败: ' + err.message;
+ }
+ },
+
+ /**
+ * 下载为EA2文件(ExamAware2格式)
+ */
+ downloadAsEa2() {
+ try {
+ const blob = new Blob([this.formattedStorageJson], { type: 'application/json' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = `${this.localConfig.examName || 'exam-config'}.ea2`;
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ this.$message?.success('已下载 ExamAware2 知试 (.ea2)文件');
+
+
+ } catch (err) {
+ this.error = '下载失败: ' + err.message;
+ }
+ },
+
+ /**
+ * 复制配置链接(用于ExamSchedule)
+ */
+ async copyConfigUrl() {
+ try {
+ // 获取配置的云端访问地址
+ const result = await dataProvider.getKeyCloudUrl(`es_${this.configId}`, {
+ autoMigrate: true,
+ autoConfig: true
+ });
+
+ if (result.success && result.url) {
+ // 直接复制KV地址
+ await navigator.clipboard.writeText(result.url);
+ this.$message.success('云端地址已复制到剪贴板');
+ } else {
+ throw new Error(result.error || '获取云端地址失败');
+ }
+ } catch (err) {
+ this.error = '复制链接失败: ' + err.message;
+ }
+ },
+
/**
* 切换编辑模式
*/
@@ -923,6 +1543,52 @@ export default {
}
},
+ /**
+ * 时长提示(人性化显示)
+ */
+ durationHint(examInfo) {
+ const m = parseInt(examInfo?.durationMinutes);
+ if (isNaN(m) || m <= 0) return "";
+ if (m < 60) return `${m} 分钟`;
+ const h = Math.floor(m / 60);
+ const mm = m % 60;
+ return mm === 0 ? `${h} 小时` : `${h} 小时 ${mm} 分钟`;
+ },
+
+ /**
+ * 从时长输入更新结束时间
+ */
+ updateDurationFromInput(index) {
+ const examInfo = this.localConfig.examInfos[index];
+ let m = parseInt(examInfo.durationMinutes);
+ if (isNaN(m) || m <= 0) m = 120;
+ if (m > 24 * 60) m = 24 * 60;
+ examInfo.durationMinutes = m;
+
+ // 需要有开始时间作为基准
+ if (!examInfo.startDate || !examInfo.startTime) {
+ // 如果尚未拆分,尝试从 start 解析
+ if (examInfo.start) {
+ const s = new Date(examInfo.start);
+ if (!isNaN(s.getTime())) {
+ examInfo.startDate = s;
+ examInfo.startTime = this.formatTimeOnly(s);
+ }
+ }
+ }
+
+ if (examInfo.startDate && examInfo.startTime) {
+ const s = new Date(examInfo.startDate);
+ const [sh, sm] = String(examInfo.startTime).split(":");
+ s.setHours(parseInt(sh), parseInt(sm), 0, 0);
+ const e = new Date(s.getTime() + m * 60 * 1000);
+ examInfo.endDate = e;
+ examInfo.endTime = this.formatTimeOnly(e);
+ examInfo.end = this.formatDateTimeLocal(e);
+ examInfo.endFormatted = this.formatDisplayDateTime(e);
+ }
+ },
+
/**
* 格式化日期时间为datetime-local输入格式
*/
@@ -1027,6 +1693,38 @@ export default {
// 更新相关字段
examInfo.start = this.formatDateTimeLocal(date);
examInfo.startFormatted = this.formatDisplayDateTime(date);
+
+ // 根据已有时长或默认2小时自动更新结束时间
+ let durationMinutes = parseInt(examInfo.durationMinutes);
+ if (isNaN(durationMinutes) || durationMinutes <= 0 || durationMinutes > 24 * 60) {
+ // 若未设定有效时长,则尝试根据已设结束时间计算
+ try {
+ let existingEndDate = null;
+ if (examInfo.endDate && examInfo.endTime) {
+ existingEndDate = new Date(examInfo.endDate);
+ const [eh, em] = String(examInfo.endTime).split(":");
+ existingEndDate.setHours(parseInt(eh), parseInt(em), 0, 0);
+ } else if (examInfo.end) {
+ existingEndDate = new Date(examInfo.end);
+ }
+ if (existingEndDate && !isNaN(existingEndDate.getTime())) {
+ const diff = Math.round((existingEndDate.getTime() - date.getTime()) / (1000 * 60));
+ if (diff > 0 && diff <= 24 * 60) {
+ durationMinutes = diff;
+ }
+ }
+ } catch (_) {}
+ }
+ if (isNaN(durationMinutes) || durationMinutes <= 0 || durationMinutes > 24 * 60) {
+ durationMinutes = 120;
+ }
+
+ const newEnd = new Date(date.getTime() + durationMinutes * 60 * 1000);
+ examInfo.endDate = newEnd;
+ examInfo.endTime = this.formatTimeOnly(newEnd);
+ examInfo.end = this.formatDateTimeLocal(newEnd);
+ examInfo.endFormatted = this.formatDisplayDateTime(newEnd);
+ examInfo.durationMinutes = durationMinutes;
},
/**
@@ -1044,6 +1742,19 @@ export default {
// 更新相关字段
examInfo.end = this.formatDateTimeLocal(date);
examInfo.endFormatted = this.formatDisplayDateTime(date);
+
+ // 同步考试时长
+ try {
+ if (examInfo.startDate && examInfo.startTime) {
+ const s = new Date(examInfo.startDate);
+ const [sh, sm] = String(examInfo.startTime).split(":");
+ s.setHours(parseInt(sh), parseInt(sm), 0, 0);
+ const diff = Math.round((date.getTime() - s.getTime()) / (1000 * 60));
+ if (diff > 0 && diff <= 24 * 60) {
+ examInfo.durationMinutes = diff;
+ }
+ }
+ } catch (_) {}
},
/**
@@ -1194,6 +1905,23 @@ export default {
background-color: rgba(var(--v-theme-primary), 0.08) !important;
}
+.bg-success-lighten-5 {
+ background-color: rgba(var(--v-theme-success), 0.08) !important;
+}
+
+.bg-error-lighten-5 {
+ background-color: rgba(var(--v-theme-error), 0.08) !important;
+}
+
+/* 科目编辑项悬停效果 */
+.hover-highlight {
+ transition: background-color 0.2s ease;
+}
+
+.hover-highlight:hover {
+ background-color: rgba(var(--v-theme-primary), 0.05);
+}
+
.v-btn-toggle .v-btn:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
diff --git a/src/components/HitokotoCard.vue b/src/components/HitokotoCard.vue
index ea0a00d..82f457a 100644
--- a/src/components/HitokotoCard.vue
+++ b/src/components/HitokotoCard.vue
@@ -24,6 +24,19 @@
import { SettingsManager, watchSettings } from '@/utils/settings'
import dataProvider from '@/utils/dataProvider'
import axios from 'axios'
+import { Base64 } from 'js-base64'
+
+// 全局敏感词列表,强制生效。
+const GLOBAL_SENSITIVE_WORDS_ENCODED = [
+ '6IO4',
+ '5Lmz',
+ '6JCd6I6J',
+ '5rer',
+ '5aW4',
+]
+
+// 解码敏感词列表
+const GLOBAL_SENSITIVE_WORDS = GLOBAL_SENSITIVE_WORDS_ENCODED.map(word => Base64.decode(word))
export default {
name: 'HitokotoCard',
@@ -123,10 +136,7 @@ export default {
}
} else if (source === 'jinrishici') {
if (this.kvConfig.jinrishiciToken) {
- const res = await axios.get('https://v2.jinrishici.com/sentence', {
- headers: {
- 'X-User-Token': this.kvConfig.jinrishiciToken
- }
+ const res = await axios.get('https://v2.jinrishici.com/one.json?client=npm-sdk/1.0&X-User-Token='+encodeURIComponent(this.kvConfig.jinrishiciToken), {
})
if (res.data.status === 'success') {
data = res.data.data
@@ -145,8 +155,9 @@ export default {
}
if (content) {
- // Sensitive word check
- const hasSensitiveWord = this.kvConfig.sensitiveWords.some(word => content.includes(word))
+ // Sensitive word check (global + KV)
+ const combinedWords = [...GLOBAL_SENSITIVE_WORDS, ...this.kvConfig.sensitiveWords]
+ const hasSensitiveWord = combinedWords.some(word => word && content.includes(word))
if (hasSensitiveWord) {
// Retry
this.loading = false
diff --git a/src/components/HitokotoSettings.vue b/src/components/HitokotoSettings.vue
index c6da0c8..26555e7 100644
--- a/src/components/HitokotoSettings.vue
+++ b/src/components/HitokotoSettings.vue
@@ -61,6 +61,29 @@
/>
+