From ca793b4de71792f4168befcbffa5c4b76d4b002b Mon Sep 17 00:00:00 2001 From: Spasol Date: Sun, 5 Oct 2025 20:08:52 +0800 Subject: [PATCH] initial --- jm/src/findmaimaibotJM/__init__.py | 143 +- reijm-read/index.html | 18 +- .../src/components/layout/TheHeader.vue | 2 +- reijm-read/src/config/site.ts | 2 +- reijm-read/src/views/HomeView.vue | 568 +++++- reijm-read/src/views/Manga.vue | 126 +- reijm-read/src/views/User.vue | 9 +- reisa-admin/reisaAdminSpring/.gitattributes | 2 + reisa-admin/reisaAdminSpring/.gitignore | 33 + .../.mvn/wrapper/maven-wrapper.properties | 3 + reisa-admin/reisaAdminSpring/mvnw | 295 +++ reisa-admin/reisaAdminSpring/mvnw.cmd | 189 ++ reisa-admin/reisaAdminSpring/pom.xml | 77 + .../ReisaAdminSpringApplication.java | 15 + .../ast/reisaadminspring/api/ApiServerV1.java | 141 ++ .../org/ast/reisaadminspring/been/Server.java | 139 ++ .../org/ast/reisaadminspring/been/Status.java | 579 ++++++ .../ast/reisaadminspring/dao/ServerDao.java | 9 + .../ast/reisaadminspring/dao/StatusDao.java | 15 + .../service/SystemStatusService.java | 449 ++++ .../src/main/resources/application.properties | 6 + reisa-admin/src/App.vue | 1798 +++++++++++++++++ reisa-admin/src/assets/base.css | 86 + reisa-admin/src/assets/logo.svg | 1 + reisa-admin/src/assets/main.css | 35 + .../src/components/icons/IconCommunity.vue | 7 + .../components/icons/IconDocumentation.vue | 7 + .../src/components/icons/IconEcosystem.vue | 7 + .../src/components/icons/IconSupport.vue | 7 + .../src/components/icons/IconTooling.vue | 19 + reisa-admin/src/main.js | 8 + 31 files changed, 4714 insertions(+), 81 deletions(-) create mode 100644 reisa-admin/reisaAdminSpring/.gitattributes create mode 100644 reisa-admin/reisaAdminSpring/.gitignore create mode 100644 reisa-admin/reisaAdminSpring/.mvn/wrapper/maven-wrapper.properties create mode 100755 reisa-admin/reisaAdminSpring/mvnw create mode 100644 reisa-admin/reisaAdminSpring/mvnw.cmd create mode 100644 reisa-admin/reisaAdminSpring/pom.xml create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/ReisaAdminSpringApplication.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/api/ApiServerV1.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/been/Server.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/been/Status.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/dao/ServerDao.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/dao/StatusDao.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/java/org/ast/reisaadminspring/service/SystemStatusService.java create mode 100644 reisa-admin/reisaAdminSpring/src/main/resources/application.properties create mode 100644 reisa-admin/src/App.vue create mode 100644 reisa-admin/src/assets/base.css create mode 100644 reisa-admin/src/assets/logo.svg create mode 100644 reisa-admin/src/assets/main.css create mode 100644 reisa-admin/src/components/icons/IconCommunity.vue create mode 100644 reisa-admin/src/components/icons/IconDocumentation.vue create mode 100644 reisa-admin/src/components/icons/IconEcosystem.vue create mode 100644 reisa-admin/src/components/icons/IconSupport.vue create mode 100644 reisa-admin/src/components/icons/IconTooling.vue create mode 100644 reisa-admin/src/main.js diff --git a/jm/src/findmaimaibotJM/__init__.py b/jm/src/findmaimaibotJM/__init__.py index 6b66489..9bfcc24 100755 --- a/jm/src/findmaimaibotJM/__init__.py +++ b/jm/src/findmaimaibotJM/__init__.py @@ -58,17 +58,17 @@ from datetime import timedelta cache_time = timedelta(days=3) @app.get("/search/") -@cache_result(cache_time) +# @cache_result(cache_time) def search_site(search_query: str, page: int = 1): try: page = client.search_site(search_query=search_query, page=page) - results = [{"album_id": album_id, "title": title} for album_id, title in page] + results = [{"album_id": album_id, "name": title} for album_id, title in page] return results except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @app.get("/album/{album_id}/") -@cache_result(cache_time) +# @cache_result(cache_time) def get_album_details(album_id: int): try: page = client.search_site(search_query=str(album_id)) @@ -77,6 +77,92 @@ def get_album_details(album_id: int): image_urls = [] nums = [] # 遍历每个章节 + + + for photo in album: + # 章节实体类 + photo_detail = client.get_photo_detail(photo.photo_id, False) + + # 遍历每个图片 + for image in photo_detail: + # 图片实体类 + image_urls.append(image.img_url) + nums.append(JmImageTool.get_num_by_url(image.scramble_id, image.img_url)) + + return { + "album_id": album.album_id, + "scramble_id": album.scramble_id, + "name": album.name, + "page_count": album.page_count, + "pub_date": album.pub_date, + "update_date": album.update_date, + "likes": album.likes, + "views": album.views, + "comment_count": album.comment_count, + "works": album.works, + "actors": album.actors, + "authors": album.authors, + "tags": album.tags, + "related_list": album.related_list, + "episode_list": album.episode_list, + "image_urls": image_urls, + "nums": nums + } + except Exception as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@app.get("/album/{album_id}/debug") +# @cache_result(cache_time) +def get_album_details(album_id: int): + try: + page = client.search_site(search_query=str(album_id)) + album = page.single_album + + # 输出调试信息到控制台 + import json as json_module + + # 创建简单的序列化函数,避免复杂对象导致的问题 + def simple_serialize(obj): + if hasattr(obj, '__dict__'): + result = {} + for key, value in obj.__dict__.items(): + try: + # 尝试直接序列化 + json_module.dumps(value) + result[key] = value + except: + # 如果不能序列化,转换为字符串 + result[key] = str(value) + return result + else: + return str(obj) + + # 输出page和album的调试信息到控制台 + print("=" * 50) + print("DEBUG: Page object") + print("=" * 50) + try: + print(json_module.dumps(simple_serialize(page), indent=2, ensure_ascii=False)) + except Exception as e: + print(f"无法序列化page对象: {e}") + print(f"Page类型: {type(page)}") + print(f"Page属性: {[attr for attr in dir(page) if not attr.startswith('_')]}") + + print("\n" + "=" * 50) + print("DEBUG: Album object") + print("=" * 50) + try: + print(json_module.dumps(simple_serialize(album), indent=2, ensure_ascii=False)) + except Exception as e: + print(f"无法序列化album对象: {e}") + print(f"Album类型: {type(album)}") + print(f"Album属性: {[attr for attr in dir(album) if not attr.startswith('_')]}") + + # 存储所有图片的URL + image_urls = [] + nums = [] + # 遍历每个章节 for photo in album: # 章节实体类 photo_detail = client.get_photo_detail(photo.photo_id, False) @@ -110,57 +196,8 @@ def get_album_details(album_id: int): raise HTTPException(status_code=400, detail=str(e)) -@app.get("/album/{album_id}/chapters/") -@cache_result(cache_time) -def get_album_chapters_paginated(album_id: int, page: int = 1, per_page: int = 5): - """ - 分页获取专辑章节列表 - :param album_id: 专辑ID - :param page: 页码(从1开始) - :param per_page: 每页章节数 - """ - try: - page_result = client.search_site(search_query=str(album_id)) - album = page_result.single_album - - # 计算分页信息 - total_chapters = len(album.photos) - total_pages = (total_chapters + per_page - 1) // per_page # 向上取整 - - if page < 1 or page > total_pages: - raise HTTPException(status_code=404, detail="Page out of range") - - # 计算当前页的章节范围 - start_index = (page - 1) * per_page - end_index = min(start_index + per_page, total_chapters) - - # 获取当前页的章节信息 - chapters = [] - for i in range(start_index, end_index): - photo = album.photos[i] - chapters.append({ - "chapter_index": i, - "chapter_id": photo.photo_id, - "title": photo.name, - "page_count": photo.page_count, - "pub_date": photo.pub_date - }) - - return { - "album_id": album.album_id, - "album_name": album.name, - "current_page": page, - "per_page": per_page, - "total_chapters": total_chapters, - "total_pages": total_pages, - "chapters": chapters - } - except Exception as e: - raise HTTPException(status_code=400, detail=str(e)) - - @app.get("/fast/{album_id}/") -# @cache_result(cache_time) +@cache_result(cache_time) def get_album_details(album_id: int): try: page = client.search_site(search_query=str(album_id)) diff --git a/reijm-read/index.html b/reijm-read/index.html index 8446fa6..8bc58d8 100644 --- a/reijm-read/index.html +++ b/reijm-read/index.html @@ -7,24 +7,24 @@ Powered by Reisa - - + + - - + + - + - - - + + + @@ -35,7 +35,7 @@ { "@context": "https://schema.org", "@type": "Organization", - "name": " Powered by Reisa", + "name": " Powered by ReiJM", "url": "https://www.godserver.cn", "logo": "/src/assets/logo.png", "sameAs": ["https://github.com/Spaso1", "https://twitter.com/Spaso1"] diff --git a/reijm-read/src/components/layout/TheHeader.vue b/reijm-read/src/components/layout/TheHeader.vue index 07561c3..a8f441d 100644 --- a/reijm-read/src/components/layout/TheHeader.vue +++ b/reijm-read/src/components/layout/TheHeader.vue @@ -85,7 +85,7 @@ const toggleMenu = () => { - Union + ReiJM diff --git a/reijm-read/src/config/site.ts b/reijm-read/src/config/site.ts index fc250d7..1e0c1e1 100644 --- a/reijm-read/src/config/site.ts +++ b/reijm-read/src/config/site.ts @@ -1,6 +1,6 @@ export const siteConfig = { // 基本信息 - name: "Powered by Reisa", // 作者名称 + name: "Re", // 作者名称 title: "FindMaimaiDX开发者 学生", // 职位头衔 siteName: "ReisaSpasol | MaimaiDX", // 网站标题 siteDescription: diff --git a/reijm-read/src/views/HomeView.vue b/reijm-read/src/views/HomeView.vue index a658331..87bc8ed 100644 --- a/reijm-read/src/views/HomeView.vue +++ b/reijm-read/src/views/HomeView.vue @@ -1,17 +1,581 @@ - + diff --git a/reijm-read/src/views/Manga.vue b/reijm-read/src/views/Manga.vue index 765d3e1..ee8a588 100644 --- a/reijm-read/src/views/Manga.vue +++ b/reijm-read/src/views/Manga.vue @@ -3,8 +3,10 @@ import { ref, onMounted, onUnmounted, computed, watch } from 'vue' import { useRoute } from 'vue-router' import axios from 'axios' +import router from "@/router"; const route = useRoute() +const token = localStorage.getItem('token') // 漫画专辑数据 interface AlbumData { @@ -25,7 +27,7 @@ const albumInfo = ref | null>(null) const showMenu = ref(false) const isFullscreen = ref(false) const showDrawer = ref(false) -const currentImageIndex = ref(0) // 当前显示的图片索引 +let currentImageIndex = ref(0) // 当前显示的图片索引 const imageStates = ref>([]) const loading = ref(true) const canvasImages = ref([]) // 解码后的图片 @@ -35,6 +37,20 @@ const abortLoading = ref(false) // 取消加载标志 const shouldHideHeader = computed(() => { return route.meta?.hideHeader === true }) +// 在现有代码中添加新的函数 +const reportReadManga = async (mangaId: string, index: number) => { + try { + await axios.post('/api/manga/read', {}, { + headers: { + Token: token || '', + mangaId: mangaId, + index: index.toString() + } + }); + } catch (error) { + console.error('上报阅读进度失败:', error); + } +} // 计算当前页码信息 const currentPageInfo = computed(() => { @@ -51,10 +67,12 @@ const fetchAlbum = async (id: string) => { try { loading.value = true - console.log('发送请求到:', `/api/manga/read?mangaId=${id}`) const response = await axios.get(`/api/manga/read?mangaId=${id}`, { maxRedirects: 5, validateStatus: (status) => status < 500, + headers: { + Token: `${token}` + } }) console.log('收到响应:', response) @@ -96,6 +114,9 @@ const fetchAlbum = async (id: string) => { } else { loading.value = false } + scrollToImage(data.readIndex) + currentImageIndex.value = data.readIndex + console.log(currentImageIndex.value) } catch (error) { console.error('加载专辑失败', error) loading.value = false @@ -286,7 +307,7 @@ const handleTouchMove = (index: number, event: TouchEvent) => { } } -// 处理滚轮缩放(仅鼠标滚轮) +// 处理滚轮缩放(以鼠标位置为中心点缩放) const handleWheel = (index: number, event: WheelEvent) => { // 确保是鼠标滚轮事件而不是触摸板手势 if (Math.abs(event.deltaX) > Math.abs(event.deltaY) * 2) { @@ -297,15 +318,50 @@ const handleWheel = (index: number, event: WheelEvent) => { event.preventDefault() const currentState = imageStates.value[index] + // 获取图片元素 + const imgElement = document.getElementById(`image-${index}`)?.querySelector('.manga-image') + if (!imgElement) return + + // 计算鼠标在图片中的相对位置 + const rect = imgElement.getBoundingClientRect() + const mouseX = event.clientX - rect.left + const mouseY = event.clientY - rect.top + + // 计算当前鼠标位置相对于图片中心的偏移(减小移动幅度) + const centerX = rect.width / 2.7 + const centerY = rect.height / 2.5 + const offsetX = (mouseX - centerX) * 0.4 // 减少移动幅度 + const offsetY = (mouseY - centerY) * 0.4 // 减少移动幅度 + if (event.deltaY < 0) { // 向上滚动放大 if (currentState.scale < 3) { - currentState.scale *= 1.1 + const newScale = currentState.scale * 1.1 + const scaleRatio = newScale / currentState.scale + + // 以鼠标位置为中心进行缩放(减小位移) + const newTranslateX = currentState.translateX - offsetX * (scaleRatio - 1) + const newTranslateY = currentState.translateY - offsetY * (scaleRatio - 1) + + currentState.scale = newScale + currentState.translateX = newTranslateX + currentState.translateY = newTranslateY } } else { // 向下滚动缩小 if (currentState.scale > 1) { - currentState.scale /= 1.1 + const newScale = currentState.scale / 1.1 + const scaleRatio = newScale / currentState.scale + + // 以鼠标位置为中心进行缩放(减小位移) + const newTranslateX = currentState.translateX - offsetX * (scaleRatio - 1) + const newTranslateY = currentState.translateY - offsetY * (scaleRatio - 1) + + currentState.scale = newScale + currentState.translateX = newTranslateX + currentState.translateY = newTranslateY + + // 如果缩放到原始大小,重置位置 if (currentState.scale <= 1) { currentState.scale = 1 currentState.translateX = 0 @@ -381,6 +437,10 @@ const handleScroll = () => { } } +const back = () => { + router.push('/') +} + // 使用节流优化滚动处理 const throttledHandleScroll = throttle(handleScroll, 100) @@ -416,9 +476,31 @@ watch( }, { immediate: true } ) +let refreshInterval: number | null = null; +// 新增:刷新token的函数 +const refreshToken = async () => { + try { + const token = localStorage.getItem('token'); + if (!token) return; + + const response = await axios.post('/api/user/ref', { + data: token, + timestamp: Date.now() + }, { + headers: { + 'Token' : token, + 'Content-Type': 'application/json' + } + }); + } catch (error) { + console.error('Refresh token failed:', error); + } +}; // 组件挂载时添加事件监听器 onMounted(() => { + refreshInterval = window.setInterval(refreshToken, 30000); + window.addEventListener('keydown', handleKeydown) // 直接监听 manga-reader 元素的滚动事件,而不是 manga-content const mangaReader = document.querySelector('.manga-reader') @@ -429,6 +511,16 @@ onMounted(() => { // 初始化当前图片索引 handleScroll() }) +// 替换现有的 watch 监听器 +watch([currentImageIndex, loading, mangaImages], ([newIndex, isLoading, images]) => { + // 只有在非加载状态且索引有效时才发送请求 + if (albumInfo.value && !isLoading && newIndex >= 0 && + newIndex < images.length) { + reportReadManga(albumInfo.value.album_id, newIndex); + } +}); + + // 组件卸载时移除事件监听器 onUnmounted(() => { @@ -446,10 +538,10 @@ onUnmounted(() => { @click="toggleMenu" :class="{ 'no-header': shouldHideHeader }"> - - - - + + + +
{ >