Răsfoiți Sursa

fix: web书籍部分图片加载失败

Xwite 3 ani în urmă
părinte
comite
20fc74078e

+ 1 - 0
modules/web/.eslintrc-auto-import.json

@@ -4,6 +4,7 @@
     "ComponentPublicInstance": true,
     "ComputedRef": true,
     "EffectScope": true,
+    "ElLoading": true,
     "ElMessage": true,
     "InjectionKey": true,
     "PropType": true,

+ 1 - 0
modules/web/src/auto-imports.d.ts

@@ -5,6 +5,7 @@
 export {}
 declare global {
   const EffectScope: typeof import('vue')['EffectScope']
+  const ElLoading: typeof import('element-plus/es')['ElLoading']
   const ElMessage: typeof import('element-plus/es')['ElMessage']
   const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
   const computed: typeof import('vue')['computed']

+ 5 - 5
modules/web/src/components/BookItems.vue

@@ -3,7 +3,7 @@
     <div class="wrapper">
       <div
         class="book"
-        v-for="book in props.books"
+        v-for="book in books"
         :key="book.bookUrl"
         @click="handleClick(book)"
       >
@@ -22,7 +22,7 @@
             <div class="author">
               {{ book.author }}
             </div>
-            <div class="tags" v-show="props.isSearch">
+            <div class="tags" v-show="isSearch">
               <el-tag
                 v-for="tag in book.kind?.split(',').slice(0, 2)"
                 :key="tag"
@@ -30,16 +30,16 @@
                 {{ tag }}
               </el-tag>
             </div>
-            <div class="update-info" v-show="!props.isSearch">
+            <div class="update-info" v-show="!isSearch">
               <div class="dot">•</div>
               <div class="size">共{{ book.totalChapterNum }}章</div>
               <div class="dot">•</div>
               <div class="date">{{ dateFormat(book.lastCheckTime) }}</div>
             </div>
           </div>
-          <div class="intro" v-show="props.isSearch">{{ book.intro }}</div>
+          <div class="intro" v-show="isSearch">{{ book.intro }}</div>
 
-          <div class="dur-chapter" v-show="!props.isSearch">
+          <div class="dur-chapter" v-show="!isSearch">
             已读:{{ book.durChapterTitle }}
           </div>
           <div class="last-chapter">最新:{{ book.latestChapterTitle }}</div>

+ 13 - 5
modules/web/src/components/ChapterContent.vue

@@ -1,9 +1,10 @@
 <template>
-  <div v-for="(para, index) in props.carray" :key="index">
+  <div v-for="(para, index) in carray" :key="index">
     <img
       class="full"
       v-if="/^\s*<img[^>]*src[^>]+>$/.test(para)"
       :src="getImageSrc(para)"
+      @error.once="proxyImage"
       loading="lazy"
     />
     <p v-else :style="style" v-html="para" />
@@ -12,8 +13,10 @@
 
 <script setup>
 import config from "../plugins/config";
+import { getImageFromLegado, isLegadoUrl } from "../plugins/utils";
+
 const store = useBookStore();
-const props = defineProps(["carray"]);
+defineProps(["carray"]);
 
 const fontFamily = computed(() => {
   if (store.config.font >= 0) {
@@ -30,10 +33,15 @@ const style = computed(() => {
   return style;
 });
 
-function getImageSrc(content) {
+const getImageSrc = (content) => {
   const imgPattern = /<img[^>]*src="([^"]*(?:"[^>]+\})?)"[^>]*>/;
-  return content.match(imgPattern)[1];
-}
+  const src = content.match(imgPattern)[1];
+  if (isLegadoUrl(src)) return getImageFromLegado(src);
+  return src;
+};
+const proxyImage = (event) => {
+  event.target.src = getImageFromLegado(event.target.src);
+};
 
 watch(fontSize, () => {
   store.setShowContent(false);

+ 6 - 6
modules/web/src/components/SourceItem.vue

@@ -11,12 +11,12 @@
 </template>
 
 <script setup>
-const { source } = defineProps(['source'])
-const store = useSourceStore()
-const { errorPushSources } = storeToRefs(store)
-const handleSourceClick = source => {
-  store.changeCurrentSource(source)
-}
+defineProps(["source"]);
+const store = useSourceStore();
+const { errorPushSources } = storeToRefs(store);
+const handleSourceClick = (source) => {
+  store.changeCurrentSource(source);
+};
 </script>
 <style lang="scss" scoped>
 .error {

+ 6 - 4
modules/web/src/components/SourceList.vue

@@ -30,7 +30,7 @@
   </div>
   <el-checkbox-group id="source-list" v-model="sourceSelect">
     <virtual-list
-      style="height: 100%; overflow-y: auto; overflow-x: hidden;"
+      style="height: 100%; overflow-y: auto; overflow-x: hidden"
       :data-key="(source) => source.bookSourceUrl || source.sourceUrl"
       :data-sources="sourcesFiltered"
       :data-component="SourceItem"
@@ -42,7 +42,7 @@
 <script setup>
 import { Folder, Delete, Download, Search } from "@element-plus/icons-vue";
 import { isSourceContains } from "../utils/souce";
-import VirtualList from 'vue3-virtual-scroll-list';
+import VirtualList from "vue3-virtual-scroll-list";
 import SourceItem from "./SourceItem.vue";
 
 const store = useSourceStore();
@@ -98,7 +98,10 @@ const importSourceFile = () => {
 };
 const outExport = () => {
   const exportFile = document.createElement("a");
-  let sources = sourceSelect.value.length === 0 ? sourcesFiltered.value : sourceSelect.value,
+  let sources =
+      sourceSelect.value.length === 0
+        ? sourcesFiltered.value
+        : sourceSelect.value,
     sourceType = isBookSource.value ? "BookSource" : "RssSource";
 
   exportFile.download = `${sourceType}_${Date()
@@ -129,5 +132,4 @@ const outExport = () => {
     width: 100%;
   }
 }
-
 </style>

+ 2 - 6
modules/web/src/components/SourceTabForm.vue

@@ -1,7 +1,7 @@
 <template>
   <el-tabs id="source-edit">
     <el-tab-pane
-      v-for="{ name, children } in tabsData"
+      v-for="{ name, children } in Object.values(config)"
       :label="name"
       :key="name"
     >
@@ -59,11 +59,7 @@
 
 <script setup>
 const store = useSourceStore();
-
-const props = defineProps(["config"]);
-
-const tabsData = Object.values(props.config);
-
+defineProps(["config"]);
 const { currentSource } = storeToRefs(store);
 </script>
 

+ 20 - 18
modules/web/src/components/ToolBar.vue

@@ -73,25 +73,27 @@ import { isInvaildSource } from "../utils/souce";
 const store = useSourceStore();
 const pull = () => {
   const loadingMsg = ElMessage({
-    message: '加载中……',
+    message: "加载中……",
     showClose: true,
-    duration: 0
-  })
-  API.getSources().then(({ data }) => {
-    if (data.isSuccess) {
-      store.changeTabName("editList");
-      store.saveSources(data.data);
-      ElMessage({
-        message: `成功拉取${data.data.length}条源`,
-        type: "success",
-      });
-    } else {
-      ElMessage({
-        message: data.errorMsg ?? "后端错误",
-        type: "error",
-      });
-    }
-  }).finally(() => loadingMsg.close());
+    duration: 0,
+  });
+  API.getSources()
+    .then(({ data }) => {
+      if (data.isSuccess) {
+        store.changeTabName("editList");
+        store.saveSources(data.data);
+        ElMessage({
+          message: `成功拉取${data.data.length}条源`,
+          type: "success",
+        });
+      } else {
+        ElMessage({
+          message: data.errorMsg ?? "后端错误",
+          type: "error",
+        });
+      }
+    })
+    .finally(() => loadingMsg.close());
 };
 
 const push = () => {

+ 1 - 5
modules/web/src/plugins/utils.js

@@ -1,7 +1,7 @@
 import { formatDate } from "@vueuse/shared";
 
 export const isLegadoUrl = (/** @type {string} */ url) =>
-  /,\s*\s*\{/.test(url) ||
+  /,\s*\{/.test(url) ||
   !(
     url.startsWith("http") ||
     url.startsWith("data:") ||
@@ -11,10 +11,6 @@ export const isLegadoUrl = (/** @type {string} */ url) =>
  * @param {string} src
  */
 export function getImageFromLegado(src) {
-  //返回阅读代理的图片链接 已经代理的或者dataurl返回传入值
-  if (!isLegadoUrl(src)) {
-    return src;
-  }
   return (
     (import.meta.env.VITE_API || location.origin) +
     "/image?path=" +

+ 4 - 7
modules/web/src/views/BookChapter.vue

@@ -85,7 +85,7 @@
           <div class="title" :index="data.index" v-if="showContent">
             {{ data.title }}
           </div>
-          <chapter-content :carray="data.content" v-if="showContent"/>
+          <chapter-content :carray="data.content" v-if="showContent" />
         </div>
         <div class="loading" ref="loading"></div>
         <div class="bottom-bar" ref="bottom"></div>
@@ -105,7 +105,7 @@ const loadingSerive = ref(null);
 const content = ref();
 
 watch(showLoading, (loading) => {
- if (!loading) return loadingSerive.value?.close();
+  if (!loading) return loadingSerive.value?.close();
   loadingSerive.value = ElLoading.service({
     target: content.value,
     spinner: loadingSvg,
@@ -139,15 +139,13 @@ const {
   showContent,
 } = storeToRefs(store);
 
-const { chapterPos, index: chapterIndex} = toRefs(store.readingBook);
+const { chapterPos, index: chapterIndex } = toRefs(store.readingBook);
 
 const { theme, infiniteLoading } = toRefs(store.config);
 
 // 主题部分
 const bodyColor = computed(() => settings.themes[theme.value].body);
-const chapterColor = computed(
-  () => settings.themes[theme.value].content
-);
+const chapterColor = computed(() => settings.themes[theme.value].content);
 const popupColor = computed(() => settings.themes[theme.value].popup);
 
 const readWidth = computed(() => {
@@ -215,7 +213,6 @@ watch(popupColor, (color) => {
   rightBarTheme.value.background = color;
 });
 
-
 watchEffect(() => {
   if (chapterData.value.length > 0) {
     store.setContentLoading(false);

+ 2 - 2
modules/web/src/views/BookShelf.vue

@@ -147,7 +147,7 @@ const searchBook = () => {
     () => {
       showLoading.value = false;
       if (books.value.length == 0) {
-        ElMessage.info("搜索结果为空")
+        ElMessage.info("搜索结果为空");
       }
     }
   );
@@ -224,7 +224,7 @@ const fetchBookShelfData = () => {
       showLoading.value = false;
       store.setConnectType("danger");
       store.setConnectStatus("连接失败");
-      ElMessage.error("后端连接失败")
+      ElMessage.error("后端连接失败");
       store.setNewConnect(false);
       throw error;
     });

+ 0 - 5
modules/web/src/views/SourceEditor.vue

@@ -34,10 +34,5 @@ if (/bookSource/i.test(location.href)) {
     width: 360px;
     margin-right: 20px;
   }
-  #loading {
-    position: fixed;
-    top: 100px;
-    left: 90vw;
-  }
 }
 </style>