Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.

Commit ade6809

Browse files
committed
📝 docs(README): update FAQ section and refine explanations
- add note about increased difficulty in fetching textbook data - clarify response for 403 errors in the FAQ section ✨ feat(api): implement caching for textbook material tags - add static cache using Lazy<Mutex> for textbook material tags - use cached data if available to reduce redundant API calls - add API command to clear textbook material tags cache ✨ feat(settings): add UI for clearing textbook material tags cache - include a new button in settings to clear cache - display confirmation dialog before clearing cache - show success or error messages based on cache clearing result 💄 style(vue): reformat templates and improve readability - adjust template formatting for better code alignment - improve readability of long attribute bindings - add padding to separate sections ♻️ refactor(settings): optimize imports and maintain consistency - streamline import statements for element-plus components - ensure consistent formatting in script setup section
1 parent 667cf52 commit ade6809

File tree

5 files changed

+107
-44
lines changed

5 files changed

+107
-44
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ https://github.com/alterem/tauri-react-template
7979

8080
## 常见问题 (FAQ)
8181

82+
**由于对端网站改版,现在获取教材的方法难度上升,可能需要更多的时间去分析网站数据**
83+
8284
**Q: 在 macOS 上下载的应用无法直接打开,提示“无法验证开发者”或类似错误怎么办?**
8385

8486
A: 这是 macOS 的 Gatekeeper 安全机制导致的。应用未经过 Apple 的开发者认证,首次打开可能会被阻止。可以在终端执行以下命令来允许应用运行:
@@ -91,7 +93,7 @@ xattr -rd com.apple.quarantine /Applications/KnowledgeGrab.app
9193

9294
**Q: 下载时出现 403 错误怎么办?**
9395

94-
A: 出现 403 错误通常是对端服务器的访问限制导致的。目前暂时没有有效的解决办法
96+
A: 出现 403 通常是由于对端服务器禁止了这个资源的访问
9597

9698
## 参与贡献
9799

src-tauri/src/api.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::models::{DataVersion, DropdownOption, TagApiResponse, TagChild, Textbook};
22
use base64::{Engine, engine::general_purpose::STANDARD};
3+
use once_cell::sync::Lazy;
34
use reqwest;
45
use std::collections::HashMap;
6+
use std::sync::Mutex;
57
use tauri::command;
68

79
const DATA_VERSION_URL: &str =
@@ -16,6 +18,9 @@ const DOWNLOAD_URL_FORMAT: &str =
1618
const SPECIAL_EDUCATION: &str = "特殊教育";
1719
const HIGH_SCHOOL: &str = "高中";
1820

21+
static TCH_MATERIAL_TAG_CACHE: Lazy<Mutex<Option<HashMap<String, TagChild>>>> =
22+
Lazy::new(|| Mutex::new(None));
23+
1924
struct HierarchyNavigator<'a> {
2025
tag_hierarchy: &'a HashMap<String, TagChild>,
2126
}
@@ -503,6 +508,14 @@ pub async fn fetch_data_version() -> Result<serde_json::Value, String> {
503508

504509
#[command]
505510
pub async fn fetch_tch_material_tag() -> Result<HashMap<String, TagChild>, String> {
511+
{
512+
let cache = TCH_MATERIAL_TAG_CACHE.lock().unwrap();
513+
if let Some(cached_data) = cache.as_ref() {
514+
println!("Using cached textbook material tags data");
515+
return Ok(cached_data.clone());
516+
}
517+
}
518+
506519
println!(
507520
"Fetching and parsing textbook material tags from: {}",
508521
TCH_MATERIAL_TAG_URL
@@ -536,9 +549,23 @@ pub async fn fetch_tch_material_tag() -> Result<HashMap<String, TagChild>, Strin
536549

537550
let parsed_hierarchy = crate::models::parse_hierarchies_recursive(Some(hierarchies_to_parse));
538551

552+
{
553+
let mut cache = TCH_MATERIAL_TAG_CACHE.lock().unwrap();
554+
*cache = Some(parsed_hierarchy.clone());
555+
println!("Cached textbook material tags data for future use");
556+
}
557+
539558
Ok(parsed_hierarchy)
540559
}
541560

561+
#[command]
562+
pub async fn clear_tch_material_tag_cache() -> Result<(), String> {
563+
let mut cache = TCH_MATERIAL_TAG_CACHE.lock().unwrap();
564+
*cache = None;
565+
println!("Cleared textbook material tags cache");
566+
Ok(())
567+
}
568+
542569
pub async fn fetch_and_parse_data_version() -> Result<DataVersion, String> {
543570
let json_value = fetch_data_version().await?;
544571

src-tauri/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ fn main() {
309309
app_lib::api::fetch_filter_options,
310310
app_lib::api::fetch_textbook_categories,
311311
app_lib::api::fetch_image,
312+
app_lib::api::clear_tch_material_tag_cache,
312313
open_download_folder_prompt,
313314
open_url
314315
])

src/pages/HelpPage.vue

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
<template>
2-
<div class="max-h-[calc(100vh-100px)] text-left" :style="{ backgroundColor: 'var(--bg-color)', color: 'var(--text-color)' }">
2+
<div class="max-h-[calc(100vh-100px)] text-left"
3+
:style="{ backgroundColor: 'var(--bg-color)', color: 'var(--text-color)' }">
34
<div class="text-3xl font-bold mb-6">使用帮助</div>
4-
5+
56
<div class="mb-8">
67
<div class="text-2xl font-semibold mb-3">项目概述</div>
7-
<p class="mb-4">国家中小学智慧教育平台资源下载工具是一款专为教育工作者、学生和家长设计的桌面应用程序,旨在简化国家中小学智慧教育平台上教育资源的获取和管理过程。该工具提供了直观的用户界面,支持按学科、版本和年级筛选教材,并提供单本下载和批量下载功能,让用户能够轻松获取所需的教育资源。</p>
8+
<p class="mb-4">
9+
国家中小学智慧教育平台资源下载工具是一款专为教育工作者、学生和家长设计的桌面应用程序,旨在简化国家中小学智慧教育平台上教育资源的获取和管理过程。该工具提供了直观的用户界面,支持按学科、版本和年级筛选教材,并提供单本下载和批量下载功能,让用户能够轻松获取所需的教育资源。
10+
</p>
811
</div>
9-
12+
1013
<div class="mb-8">
1114
<div class="text-2xl font-semibold mb-3">主要功能</div>
12-
15+
1316
<div class="mb-4">
1417
<div class="text-lg font-medium mb-2">1. 教材资源浏览与筛选</div>
1518
<ul class="list-none pl-6 mb-3">
@@ -18,7 +21,7 @@
1821
<li>搜索功能:支持关键词搜索,快速定位特定教材</li>
1922
</ul>
2023
</div>
21-
24+
2225
<div class="mb-4">
2326
<div class="text-lg font-medium mb-2">2. 下载管理</div>
2427
<ul class="list-none pl-6 mb-3">
@@ -28,7 +31,7 @@
2831
<li>下载状态追踪:清晰显示每本教材的下载状态</li>
2932
</ul>
3033
</div>
31-
34+
3235
<div class="mb-4">
3336
<div class="text-lg font-medium mb-2">3. 系统设置</div>
3437
<ul class="list-none pl-6 mb-3">
@@ -39,10 +42,10 @@
3942
</ul>
4043
</div>
4144
</div>
42-
45+
4346
<div class="mb-8">
4447
<div class="text-2xl font-semibold mb-3">使用指南</div>
45-
48+
4649
<div class="mb-4">
4750
<div class="text-lg font-medium mb-2">第一步:设置应用</div>
4851
<p class="mb-2">首次使用前,请先进入"设置"页面:</p>
@@ -52,7 +55,7 @@
5255
<li>输入 API 令牌:如需访问特定资源,请输入有效的 API 令牌</li>
5356
</ol>
5457
</div>
55-
58+
5659
<div class="mb-4">
5760
<div class="text-lg font-medium mb-2">第二步:浏览和筛选教材</div>
5861
<ol class="list-decimal pl-6 mb-3">
@@ -61,7 +64,7 @@
6164
<li>浏览教材列表,查看封面和详细信息</li>
6265
</ol>
6366
</div>
64-
67+
6568
<div class="mb-4">
6669
<div class="text-lg font-medium mb-2">第三步:下载教材</div>
6770
<ol class="list-decimal pl-6 mb-3">
@@ -72,10 +75,10 @@
7275
</ol>
7376
</div>
7477
</div>
75-
78+
7679
<div class="mb-8">
7780
<div class="text-2xl font-semibold mb-3">常见问题</div>
78-
81+
7982
<div class="mb-3">
8083
<div class="text-lg font-medium mb-2">下载速度慢怎么办?</div>
8184
<p>可以尝试以下方法:</p>
@@ -85,7 +88,7 @@
8588
<li>选择网络较好的时间段下载</li>
8689
</ul>
8790
</div>
88-
91+
8992
<div class="mb-3">
9093
<div class="text-lg font-medium mb-2">下载失败如何处理?</div>
9194
<p>下载失败时,可以:</p>
@@ -95,7 +98,7 @@
9598
<li>重新点击下载按钮尝试下载</li>
9699
</ul>
97100
</div>
98-
101+
99102
<div class="mb-3">
100103
<div class="text-lg font-medium mb-2">找不到特定教材怎么办?</div>
101104
<p>可以尝试:</p>
@@ -106,7 +109,7 @@
106109
</ul>
107110
</div>
108111
</div>
109-
112+
110113
<div class="mb-8">
111114
<div class="text-2xl font-semibold mb-3">免责声明</div>
112115
<div>
@@ -117,7 +120,7 @@
117120
<p>使用本应用即表示您同意本免责声明的所有条款和条件。</p>
118121
</div>
119122
</div>
120-
123+
121124
<div>
122125
<div class="text-2xl font-semibold mb-3">联系与支持</div>
123126
<p class="mb-4">如果您在使用过程中遇到任何问题,或有任何建议和反馈,请通过以下方式联系我们:</p>
@@ -128,11 +131,10 @@
128131
</ul>
129132
<p class="mt-4">我们将持续改进应用,为您提供更好的教育资源获取体验。</p>
130133
</div>
134+
<div class="pt-4"></div>
131135
</div>
132136
</template>
133137

134-
<style scoped>
135-
136-
</style>
138+
<style scoped></style>
137139
<script setup lang="ts">
138140
</script>

src/pages/SettingsPage.vue

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
11
<template>
2-
<div class="max-h-[calc(100vh-100px)] text-left" :style="{ backgroundColor: 'var(--bg-color)', color: 'var(--text-color)' }">
2+
<div class="max-h-[calc(100vh-100px)] text-left"
3+
:style="{ backgroundColor: 'var(--bg-color)', color: 'var(--text-color)' }">
34
<div class="text-3xl font-bold mb-6">设置</div>
45

56
<div class="p-6 rounded-lg shadow mb-6">
67
<div class="text-xl font-semibold mb-4">下载设置</div>
78
<el-form label-position="left" label-width="120px">
89
<el-form-item label="API Token">
9-
<el-input
10-
v-model="apiToken"
11-
placeholder="请输入 API Token"
12-
></el-input>
10+
<el-input v-model="apiToken" placeholder="请输入 API Token"></el-input>
1311
</el-form-item>
1412
<el-form-item label="下载路径">
1513
<div class="flex items-center w-full space-x-2">
16-
<el-input
17-
v-model="downloadPath"
18-
placeholder="请选择下载路径"
19-
:readonly="true"
20-
class="flex-1"
21-
></el-input>
14+
<el-input v-model="downloadPath" placeholder="请选择下载路径" :readonly="true" class="flex-1"></el-input>
2215
<el-button @click="selectDownloadPath">选择目录</el-button>
2316
</div>
2417
</el-form-item>
2518
<el-form-item label="多线程下载数">
26-
<el-slider v-model="threadCount" show-input :min="1" :max="16"/>
19+
<el-slider v-model="threadCount" show-input :min="1" :max="16" />
2720
</el-form-item>
2821
<el-form-item label="按分类保存">
2922
<el-switch v-model="saveByCategory" />
@@ -34,26 +27,37 @@
3427
<div class="text-xl font-semibold mb-4">主题设置</div>
3528
<el-form label-position="left" label-width="120px">
3629
<el-form-item label="主题模式">
37-
<el-switch
38-
:model-value="isDarkMode"
39-
active-text="暗色模式"
40-
inactive-text="亮色模式"
41-
@change="toggleTheme"
42-
/>
30+
<el-switch :model-value="isDarkMode" active-text="暗色模式" inactive-text="亮色模式" @change="toggleTheme" />
31+
</el-form-item>
32+
</el-form>
33+
</div>
34+
35+
<div class="p-6 rounded-lg shadow mb-6">
36+
<div class="text-xl font-semibold mb-4">系统设置</div>
37+
<el-form label-position="left" label-width="120px">
38+
<el-form-item label="缓存管理">
39+
<div class="flex items-center space-x-2">
40+
<el-button type="warning" @click="clearCache" :loading="clearingCache">
41+
清理标签缓存
42+
</el-button>
43+
<span class="text-sm text-gray-500">清理教材标签缓存,下次请求时将重新获取</span>
44+
</div>
4345
</el-form-item>
4446
</el-form>
4547
</div>
4648

4749
<div class="mt-6 flex justify-center">
4850
<el-button type="primary" @click="saveSettings">保存设置</el-button>
4951
</div>
52+
<div class="pt-4"></div>
5053
</div>
5154
</template>
5255

5356
<script setup lang="ts">
54-
import {ref, onMounted, inject, type Ref} from 'vue';
55-
import {ElInput, ElButton, ElMessage, ElForm, ElFormItem, ElSwitch} from 'element-plus';
56-
import {open} from '@tauri-apps/plugin-dialog';
57+
import { ref, onMounted, inject, type Ref } from 'vue';
58+
import { ElInput, ElButton, ElMessage, ElForm, ElFormItem, ElSwitch, ElSlider, ElMessageBox } from 'element-plus';
59+
import { open } from '@tauri-apps/plugin-dialog';
60+
import { invoke } from '@tauri-apps/api/core';
5761
5862
const isDarkMode = inject('isDarkMode') as Ref<boolean>;
5963
const toggleTheme = inject('toggleTheme') as () => void;
@@ -62,6 +66,7 @@ const apiToken = ref('');
6266
const downloadPath = ref('');
6367
const threadCount = ref(4);
6468
const saveByCategory = ref(false);
69+
const clearingCache = ref(false);
6570
6671
const LOCAL_STORAGE_TOKEN_KEY = 'api_token';
6772
const LOCAL_STORAGE_DOWNLOAD_PATH_KEY = 'download_path';
@@ -102,6 +107,33 @@ const selectDownloadPath = async () => {
102107
}
103108
};
104109
110+
const clearCache = async () => {
111+
try {
112+
await ElMessageBox.confirm(
113+
'清理缓存后,下次获取教材标签数据时将重新从服务器加载。确定要清理缓存吗?',
114+
'确认清理缓存',
115+
{
116+
confirmButtonText: '确定',
117+
cancelButtonText: '取消',
118+
type: 'warning',
119+
}
120+
);
121+
122+
clearingCache.value = true;
123+
await invoke('clear_tch_material_tag_cache');
124+
ElMessage.success('标签缓存已清理');
125+
} catch (error) {
126+
if (error === 'cancel') {
127+
// 用户取消操作,不显示错误信息
128+
return;
129+
}
130+
console.error('清理缓存失败:', error);
131+
ElMessage.error('清理缓存失败: ' + error);
132+
} finally {
133+
clearingCache.value = false;
134+
}
135+
};
136+
105137
const saveSettings = () => {
106138
localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, apiToken.value);
107139
localStorage.setItem(LOCAL_STORAGE_THREAD_COUNT_KEY, threadCount.value.toString());
@@ -116,5 +148,4 @@ const saveSettings = () => {
116148
};
117149
</script>
118150

119-
<style scoped>
120-
</style>
151+
<style scoped></style>

0 commit comments

Comments
 (0)