提交 e89b8681 authored 作者: 龙菲's avatar 龙菲

替换header和footer为自定义的

上级 cf079ab8
......@@ -3,11 +3,11 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<!-- <meta name="viewport" content="width=1050, user-scalable=no" /> -->
<meta
<meta name="viewport" content="width=1050, user-scalable=no" />
<!-- <meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
/> -->
<title>PDF阅读器</title>
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.5.3/modernizr.min.js"></script>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -21,10 +21,12 @@
"devDependencies": {
"@vant/auto-import-resolver": "^1.3.0",
"@vitejs/plugin-vue": "^5.2.3",
"fast-glob": "^3.3.3",
"sass-embedded": "^1.89.1",
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.7.0",
"vite": "^6.2.4",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-devtools": "^7.7.2"
}
}
This image diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715566062" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2831" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M897.707 989.867H126.293c-51.2 0-92.16-40.96-92.16-92.16V512c0-13.653 11.947-25.6 25.6-25.6s25.6 11.947 25.6 25.6v385.707c0 22.186 18.774 40.96 40.96 40.96H896c22.187 0 40.96-18.774 40.96-40.96V512c0-13.653 11.947-25.6 25.6-25.6s27.307 11.947 27.307 25.6v385.707c0 51.2-40.96 92.16-92.16 92.16z" p-id="2832"></path><path d="M512 738.987c-6.827 0-13.653-1.707-18.773-6.827l-225.28-226.987c-10.24-10.24-10.24-25.6 0-35.84s25.6-10.24 35.84 0L512 677.547l208.213-208.214c10.24-10.24 25.6-10.24 35.84 0s10.24 25.6 0 35.84l-225.28 225.28c-5.12 5.12-11.946 8.534-18.773 8.534z" p-id="2833"></path><path d="M512 738.987c-13.653 0-25.6-11.947-25.6-25.6V59.733c0-13.653 11.947-25.6 25.6-25.6s25.6 11.947 25.6 25.6v653.654c0 13.653-11.947 25.6-25.6 25.6z" p-id="2834"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715520044" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1538" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M368.896 192H224a32 32 0 0 0-32 32v137.888a32 32 0 0 0 64 0V256h112.896a32 32 0 0 0 0-64zM784.864 192H640a32 32 0 1 0 0 64h112.864v105.888a32 32 0 1 0 64 0V224a32 32 0 0 0-32-32zM368.896 777.92H256V672a32 32 0 1 0-64 0v137.92a32 32 0 0 0 32 32h144.896a32 32 0 1 0 0-64zM784.864 640a32 32 0 0 0-32 32v105.92H640a32 32 0 1 0 0 64h144.864a32 32 0 0 0 32-32V672a32 32 0 0 0-32-32z" p-id="1539"></path><path d="M912 48h-800c-35.296 0-64 28.704-64 64v800c0 35.296 28.704 64 64 64h800c35.296 0 64-28.704 64-64v-800c0-35.296-28.704-64-64-64z m-800 864v-800h800l0.064 800H112z" p-id="1540"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715523318" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1700" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M872.802928 755.99406 872.864326 755.99406 872.864326 755.624646Z" p-id="1701"></path><path d="M349.405343 154.62259 155.596266 154.62259c-29.150924 0-52.873208 23.724331-52.873208 52.845579l0 193.823404c0 29.150924 23.722284 52.844555 52.873208 52.844555l193.810101 0c29.136597 0 52.859905-23.693632 52.859905-52.844555L402.266271 207.467145C402.265248 178.345897 378.541941 154.62259 349.405343 154.62259M351.851045 207.467145l0 193.823404c0 1.339508-1.106194 2.474354-2.445702 2.474354L155.596266 403.764903c-1.338485 0-2.503007-1.134847-2.503007-2.474354L153.093259 207.467145c0-1.38351 1.134847-2.474354 2.503007-2.474354l193.810101 0C350.774527 204.992791 351.851045 206.084659 351.851045 207.467145" p-id="1702"></path><path d="M349.405343 569.837266 155.596266 569.837266c-29.150924 0-52.873208 23.75196-52.873208 52.856835L102.723058 816.519552c0 29.164227 23.722284 52.857858 52.873208 52.857858l193.810101 0c29.136597 0 52.859905-23.693632 52.859905-52.857858L402.266271 622.694101C402.265248 593.589227 378.541941 569.837266 349.405343 569.837266M351.851045 622.694101 351.851045 816.519552c0 1.36816-1.106194 2.472308-2.445702 2.472308L155.596266 818.99186c-1.338485 0-2.503007-1.104147-2.503007-2.472308L153.093259 622.694101c0-1.367137 1.134847-2.474354 2.503007-2.474354l193.810101 0C350.774527 620.219747 351.851045 621.326964 351.851045 622.694101" p-id="1703"></path><path d="M519.857457 224.930889c0.727571 0.480954 1.601474 0.801249 2.532683 0.801249l1.77646 0c0.434905 0.058328 0.900509 0.058328 1.36816 0l367.768061 0c0.233314 0.029676 0.493234 0.058328 0.697895 0.058328 0.233314 0 0.466628-0.028653 0.670266-0.058328l1.454118 0c0.787946 0 1.514493-0.261966 2.124384-0.626263 12.023848-2.081405 20.900006-12.341073 20.900006-24.464181 0-11.949146-8.586562-22.064528-20.345374-24.348548-0.756223-0.566912-1.687432-0.931209-2.679016-0.931209L522.389116 175.361937c-0.901533 0-1.775436 0.422625-2.501984 1.019213-11.614525 2.357697-20.200064 12.458753-20.200064 24.261567C499.687068 212.474183 508.272607 222.574215 519.857457 224.930889" p-id="1704"></path><path d="M519.507486 411.493935c0.756223 0.683569 1.77646 1.134847 2.88163 1.134847l373.73496 0c0.903579 0 1.719154-0.39295 2.446725-0.932232 11.818163-2.196015 20.550035-12.369725 20.550035-24.405853 0-12.123109-8.847505-22.354124-20.784372-24.434505-0.668219-0.39295-1.425466-0.596588-2.212388-0.596588l-0.697895 0.115634c-0.581238-0.145309-1.456165-0.203638-2.297322-0.115634l-366.867552 0.115634c-0.611937-0.145309-1.457188-0.203638-2.300392-0.115634l-1.571798 0c-0.814552 0-1.542122 0.233314-2.213411 0.714268-11.786441 2.241041-20.459984 12.398378-20.459984 24.317848C499.715721 398.976854 508.040317 408.990928 519.507486 411.493935" p-id="1705"></path><path d="M519.537162 660.680251c0.756223 0.667196 1.775436 1.075495 2.851954 1.075495l373.73496 0c0.408299 0 0.787946-0.058328 1.196245-0.174985 13.271258-0.608867 23.954575-11.641131 23.954575-25.118074 0-13.827937-11.294231-25.118074-25.15082-25.118074-0.202615 0-0.435928 0.027629-0.697895 0.058328L525.50406 611.402941c-0.437975-0.058328-0.873903-0.058328-1.36816 0l-1.746784 0c-0.842181 0-1.600451 0.25992-2.270716 0.725524-11.729136 2.270716-20.402679 12.428054-20.402679 24.334221C499.715721 648.166239 508.097622 658.176221 519.537162 660.680251" p-id="1706"></path><path d="M897.755226 777.807878c-0.493234-0.203638-1.077541-0.319272-1.63115-0.319272L522.389116 777.488607c-0.959861 0-1.893116 0.462534-2.589988 1.1328-11.583826 2.416026-20.083407 12.485359-20.083407 24.275893 0 11.904121 8.674567 22.064528 20.402679 24.334221 0.669242 0.405229 1.428535 0.60989 2.270716 0.60989l0.728594-0.115634c0.290619 0.057305 0.726547 0.202615 2.620687 0.115634l368.639918-0.115634c0.466628 0.115634 1.340531 0.290619 1.74576 0.290619 13.856589 0 25.15082-11.291161 25.15082-25.119097C921.274896 789.565666 910.883221 778.679735 897.755226 777.807878" p-id="1707"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715555298" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2509" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M376.832 474.112H130.048c-33.792 0-61.44-27.648-61.44-61.44V165.888c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c-0.512 33.792-27.648 60.928-61.952 60.928zM130.048 165.888v247.296h247.296V165.888H130.048zM739.84 525.312c-16.384 0-31.744-6.144-43.52-17.92L521.728 332.8c-11.776-11.776-17.92-27.136-17.92-43.52s6.144-31.744 17.92-43.52L696.32 71.168c11.776-11.776 27.136-17.92 43.52-17.92s31.744 6.144 43.52 17.92L957.952 245.76c11.776 11.776 17.92 27.136 17.92 43.52s-6.144 31.744-17.92 43.52L783.36 507.392c-11.776 11.776-27.136 17.92-43.52 17.92z m0-411.136l-174.592 174.592 174.592 174.592 174.592-174.592-174.592-174.592zM376.832 960.512H130.048c-33.792 0-61.44-27.648-61.44-61.44v-247.296c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c-0.512 34.304-27.648 61.44-61.952 61.44z m-246.784-308.224v247.296h247.296v-247.296H130.048zM863.232 960.512h-247.296c-33.792 0-61.44-27.648-61.44-61.44v-247.296c0-33.792 27.648-61.44 61.44-61.44h247.296c33.792 0 61.44 27.648 61.44 61.44v247.296c0 34.304-27.136 61.44-61.44 61.44z m-246.784-308.224v247.296h247.296v-247.296h-247.296z" p-id="2510"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715530928" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2028" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M238.506667 316.16L434.346667 512l-195.83999999999995 195.84000000000003L298.666667 768 554.6666670000001 512l-256.00000000000006-255.9999999999999zM768 768l-85.33333299999998 2.1316282072803006e-14-1.4210854715202004e-13-512 85.33333299999998-2.1316282072803006e-14z" p-id="2029"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715570577" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2990" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M734.73 769.42a31.91 31.91 0 0 0-9.41-22.67L490.13 512.46l235.19-234.29a32 32 0 0 0-45.17-45.34l-240.88 240a56 56 0 0 0 0 79.35l240.88 240a32 32 0 0 0 54.58-22.67z" p-id="2991"></path><path d="M289.27 256.64m32 0l0 0q32 0 32 32l0 447.65q0 32-32 32l0 0q-32 0-32-32l0-447.65q0-32 32-32Z" p-id="2992"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715575526" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3152" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M576.512 912.725333L223.232 561.493333h761.856V462.165333H223.232L576.512 110.933333H442.368L40.96 512.341333l401.408 400.384z" p-id="3153"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715526343" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1867" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M575.114968 127.655402 960.70186 513.00591 578.758961 894.948809 533.533944 849.723791 838.221318 545.037441 66.147024 545.038464 66.147024 481.081827 838.095451 481.081827 529.891997 172.879396Z" p-id="1868"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715558845" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2670" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M448 938.666667a21.333333 21.333333 0 0 1-15.093333-6.246667L225.833333 725.333333H53.333333a53.393333 53.393333 0 0 1-53.333333-53.333333V352a53.393333 53.393333 0 0 1 53.333333-53.333333h172.5l207.08-207.086667A21.333333 21.333333 0 0 1 469.333333 106.666667v810.666666a21.333333 21.333333 0 0 1-21.333333 21.333334zM53.333333 341.333333a10.666667 10.666667 0 0 0-10.666666 10.666667v320a10.666667 10.666667 0 0 0 10.666666 10.666667h181.333334a21.333333 21.333333 0 0 1 15.086666 6.246666L426.666667 865.833333V158.166667L249.753333 335.086667A21.333333 21.333333 0 0 1 234.666667 341.333333z m750.48 586.553334a21.333333 21.333333 0 0 1-12.726666-38.466667 474.853333 474.853333 0 0 0 52.78-45.553333c182.993333-182.993333 182.993333-480.74 0-663.733334a474.246667 474.246667 0 0 0-52.78-45.553333 21.333333 21.333333 0 0 1 25.42-34.273333 518.346667 518.346667 0 0 1 57.533333 49.653333 511.606667 511.606667 0 0 1 0 724.08 519.026667 519.026667 0 0 1-57.54 49.653333 21.22 21.22 0 0 1-12.686667 4.193334z m-86.213333-149.333334a21.333333 21.333333 0 0 1-13.733333-37.666666c6.666667-5.586667 13.146667-11.553333 19.333333-17.726667C779.6 666.78 810.666667 591.78 810.666667 512s-31.066667-154.78-87.48-211.186667c-6.173333-6.173333-12.666667-12.14-19.333334-17.726666a21.333333 21.333333 0 1 1 27.446667-32.666667 346.585333 346.585333 0 0 1 22.046667 20.213333 341.066667 341.066667 0 0 1 0 482.72 346.585333 346.585333 0 0 1-22.046667 20.213334 21.24 21.24 0 0 1-13.7 5.013333zM629.333333 625.72a21.333333 21.333333 0 0 1-16.733333-34.546667 127.366667 127.366667 0 0 0 0-158.346666 21.333333 21.333333 0 0 1 33.486667-26.433334 170.733333 170.733333 0 0 1 0 211.213334A21.333333 21.333333 0 0 1 629.333333 625.72z" p-id="2671"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715544776" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2185" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M919.264 905.984l-138.912-138.912C851.808 692.32 896 591.328 896 480c0-229.376-186.624-416-416-416S64 250.624 64 480s186.624 416 416 416c95.008 0 182.432-32.384 252.544-86.208l141.44 141.44a31.904 31.904 0 0 0 45.248 0 32 32 0 0 0 0.032-45.248zM128 480C128 285.92 285.92 128 480 128s352 157.92 352 352-157.92 352-352 352S128 674.08 128 480z" p-id="2186"></path><path d="M625.792 448H336a32 32 0 0 0 0 64h289.792a32 32 0 1 0 0-64z" p-id="2187"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1749715550975" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2347" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M640 456h-118.4V320a32 32 0 0 0-64 0v136H320a32 32 0 0 0 0 64h137.6V640a32 32 0 1 0 64 0v-120H640a32 32 0 1 0 0-64z" p-id="2348"></path><path d="M919.264 905.984l-138.912-138.912C851.808 692.32 896 591.328 896 480c0-229.376-186.624-416-416-416S64 250.624 64 480s186.624 416 416 416c95.008 0 182.432-32.384 252.544-86.208l141.44 141.44a31.904 31.904 0 0 0 45.248 0 32 32 0 0 0 0.032-45.248zM128 480C128 285.92 285.92 128 480 128s352 157.92 352 352-157.92 352-352 352S128 674.08 128 480z" p-id="2349"></path></svg>
\ No newline at end of file
......@@ -9,16 +9,16 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
BookMarks: typeof import('./components/BookMarks.vue')['default']
BookReader: typeof import('./components/BookReader.vue')['default']
BookReader: typeof import('./components/BookReader/index.vue')['default']
copy: typeof import('./components/Guide copy.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCol: typeof import('element-plus/es')['ElCol']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElFooter: typeof import('element-plus/es')['ElFooter']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElRow: typeof import('element-plus/es')['ElRow']
ElTree: typeof import('element-plus/es')['ElTree']
FileUpload: typeof import('./components/FileUpload.vue')['default']
Guide: typeof import('./components/Guide.vue')['default']
Guide: typeof import('./components/BookReader/guide.vue')['default']
'Guide copy': typeof import('./components/Guide copy.vue')['default']
IconCommunity: typeof import('./components/icons/IconCommunity.vue')['default']
IconDocumentation: typeof import('./components/icons/IconDocumentation.vue')['default']
......@@ -27,7 +27,8 @@ declare module 'vue' {
IconTooling: typeof import('./components/icons/IconTooling.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
SvgIcon: typeof import('./components/SvgIcon/index.vue')['default']
Test: typeof import('./components/test.vue')['default']
VanCell: typeof import('vant/es')['Cell']
VanCol: typeof import('vant/es')['Col']
VanIcon: typeof import('vant/es')['Icon']
......@@ -36,6 +37,5 @@ declare module 'vue' {
VanPopup: typeof import('vant/es')['Popup']
VanRow: typeof import('vant/es')['Row']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
}
}
<template>
<div class="book-reader" @touchstart="handleTouchStart" @touchend="handleTouchEnd">
<!-- <div v-if="loading" class="loading-overlay">
<div class="loader"></div>
<p>正在加载图片...</p>
</div> -->
<div
class="book-reader"
@touchstart="handleTouchStart"
@touchend="handleTouchEnd"
>
<div class="magazine-viewport">
<div ref="magazine" class="magazine">
<div v-for="(page, index) in processedPages" :key="index" :class="[
'page',
`p${index + 1}`,
{
hard: !page.isWide && index % 2 === 0,
odd: !page.isWide && index % 2 !== 0,
even: !page.isWide && index % 2 === 1,
mobile: isMobile,
},
]">
<img :data-page-index="index" :src="page.src" :alt="`第 ${page.page_num} 页`" @error="handleImageError(index)"
:class="['page-image', { 'wide-image': page.isWide }]" />
<div
v-for="(page, index) in processedPages"
:key="index"
:class="[
'page',
`p${index + 1}`,
{
hard: !page.isWide && index % 2 === 0,
odd: !page.isWide && index % 2 !== 0,
even: !page.isWide && index % 2 === 1,
mobile: isMobile,
},
]"
>
<img
:data-page-index="index"
:src="page.src"
:alt="`第 ${page.page_num} 页`"
@error="handleImageError(index)"
:class="['page-image', { 'wide-image': page.isWide }]"
/>
<!-- 添加小图叠加层 -->
<div v-if="page.images && page.images.length > 0" class="small-images-overlay">
<div v-for="(smallImage, imgIndex) in page.images" :key="imgIndex" class="small-image-container" :style="{
left: `${smallImage.position.x1 * 100}%`,
top: `${smallImage.position.y1 * 100}%`,
width: `${(smallImage.position.x2 - smallImage.position.x1) * 100
<div
v-if="page.images && page.images.length > 0"
class="small-images-overlay"
>
<div
v-for="(smallImage, imgIndex) in page.images"
:key="imgIndex"
class="small-image-container"
:style="{
left: `${smallImage.position.x1 * 100}%`,
top: `${smallImage.position.y1 * 100}%`,
width: `${
(smallImage.position.x2 - smallImage.position.x1) * 100
}%`,
height: `${(smallImage.position.y2 - smallImage.position.y1) * 100
height: `${
(smallImage.position.y2 - smallImage.position.y1) * 100
}%`,
}" @click="handleSmallImageClick(smallImage, page.page_num)">
}"
@click="handleSmallImageClick(smallImage, page.page_num)"
>
<!-- <img :src="smallImage.url" :alt="`小图 ${imgIndex + 1}`" class="small-image" /> -->
</div>
</div>
</div>
</div>
</div>
<van-tabbar class="tab-bar">
<div class="tab-bar-item" v-for="(item, index) in tabbars" :key="index" @click="clickTabBar(item.code)">
<!-- 目录 -->
<van-icon :name="item.icon" size="20" />
<!-- <van-tabbar class="tab-bar">
<div v-if="!isMobile" class="pc">
<div class="pc-left">
<div :key="index" @click="clickTabBar(item.code)">
<svg-icon name="back" color="red" size="14"></svg-icon>
</div>
</div>
<div class="pc-center">
</div>
<div class="pc-right">
</div>
</div>
<div v-else>
<div
class="tab-bar-item"
v-for="(item, index) in tabbars"
:key="index"
@click="clickTabBar(item.code)"
>
<van-icon :name="item.icon" size="20" />
</div>
</div>
</van-tabbar>
<!--
<div class="controls" :class="{ 'mobile-controls': isMobile }">
<el-button class="control-button" @click="previous" circle>
<el-icon>
<ArrowLeft />
</el-icon>
</el-button>
<el-button class="control-button" @click="next" circle>
<el-icon>
<ArrowRight />
</el-icon>
</el-button>
<el-button class="control-button" @click="zoomIn" circle>
<el-icon>
<ZoomIn />
</el-icon>
</el-button>
<el-button class="control-button" @click="zoomOut" circle>
<el-icon>
<ZoomOut />
</el-icon>
</el-button>
<el-button class="control-button" @click="showGuide" circle>
<el-icon>
<Menu />
</el-icon>
</el-button>
</div> -->
</van-tabbar> -->
<div v-if="showExitMessage" class="exit-message">按 ESC 键退出阅读</div>
<!-- 替换为 vue-easy-lightbox 预览组件 -->
<vue-easy-lightbox :visible="showViewer" :imgs="previewImages" :index="currentImageIndex"
@hide="showViewer = false" />
<vue-easy-lightbox
:visible="showViewer"
:imgs="previewImages"
:index="currentImageIndex"
@hide="showViewer = false"
/>
<div class="mobile-gesture-hint" v-if="isMobile">左右滑动切换页面</div>
<!-- Replace directory modal with Element Plus dialog -->
<Guide ref="guideRef" :bookmarks="bookmarks" @goToPage="goToPage"></Guide>
</div>
<div class="footer">
<el-row :gutter="10" class="tab-bar">
<el-col :class="['left', { isMobile }]" :span="isMobile ? 24 : 8">
<svg-icon name="menu" size="20" @click="showGuide"></svg-icon>
<!-- <svg-icon name="list" size="20" @click="showGuide"></svg-icon> -->
<svg-icon name="zoom-in" size="20" @click="zoomOut"></svg-icon>
<svg-icon name="zoom-out" size="20" @click="zoomIn"></svg-icon>
<svg-icon name="volumn" size="20"></svg-icon>
</el-col>
<el-col class="center" :span="8" v-if="!isMobile">
<svg-icon name="to-first" size="30" @click="toFirst"></svg-icon>
<svg-icon name="to-left" size="22" @click="previous"></svg-icon>
<div class="page-count">{{ currentPage }}</div>
<svg-icon name="to-right" size="22" @click="next"></svg-icon>
<svg-icon name="to-end" size="30" @clicl="toEnd"></svg-icon>
</el-col>
<el-col class="right" :span="8">
<!-- <svg-icon name="download" size="20"></svg-icon> -->
<!-- <svg-icon name="fullscreen" size="20"></svg-icon> -->
</el-col>
</el-row>
</div>
</template>
<script setup>
import $ from "jquery";
import "turn.js";
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from "vue";
import {
ArrowLeft,
ArrowRight,
ZoomIn,
ZoomOut,
Menu,
} from "@element-plus/icons-vue";
import VueEasyLightbox from "vue-easy-lightbox";
import Guide from "./Guide.vue";
import { showImagePreview } from 'vant';
import Guide from "./guide.vue";
import { showImagePreview } from "vant";
const props = defineProps({
pages: {
type: Array,
......@@ -110,33 +137,33 @@ const props = defineProps({
default: () => [],
},
});
const tabbars = ref([
{
label: '目录',
icon: 'apps-o',
code: 'menu'
},
{
label: '上一页',
icon: 'arrow-left',
code: 'previous'
},
{
label: '下一页',
icon: 'arrow',
code: 'next'
},
{
label: '放大',
icon: 'plus',
code: 'plus'
},
{
label: '缩小',
icon: 'minus',
code: 'minus'
}
])
// const tabbars = ref([
// {
// label: "目录",
// icon: "apps-o",
// code: "menu",
// },
// {
// label: "上一页",
// icon: "arrow-left",
// code: "previous",
// },
// {
// label: "下一页",
// icon: "arrow",
// code: "next",
// },
// {
// label: "放大",
// icon: "plus",
// code: "plus",
// },
// {
// label: "缩小",
// icon: "minus",
// code: "minus",
// },
// ]);
const magazine = ref(null);
const loading = ref(true);
const showExitMessage = ref(false);
......@@ -312,7 +339,7 @@ const initBook = async () => {
// 确保高度不超过视口高度
if (pageHeight > viewportHeight - 100) {
// 上下各留50px边距
pageHeight = viewportHeight - 100;
pageHeight = viewportHeight - 92;
// 重新计算宽度以保持比例
pageWidth = (pageHeight * 3) / 4;
}
......@@ -364,6 +391,7 @@ const initBook = async () => {
elevation: 50,
duration: 800,
autoCenter: true,
turnCorners: "bl,br",
page: 1,
when: {
turning: async (event, page, view) => {
......@@ -500,23 +528,23 @@ const handleImageError = async (index) => {
const clickTabBar = (code) => {
switch (code) {
case 'menu':
showGuide()
case "menu":
showGuide();
break;
case 'previous':
previous()
case "previous":
previous();
break;
case 'next':
next()
case "next":
next();
break;
case 'minus':
zoomOut()
case "minus":
zoomOut();
break;
case 'plus':
zoomIn()
case "plus":
zoomIn();
break;
}
}
};
const next = () => {
if (magazine.value && isInitialized.value) {
......@@ -552,6 +580,16 @@ const previous = () => {
}
};
const toFirst = () => {
const firstPage = props.pages[0].page;
$magazine.turn("page", firstPage);
};
const toEnd = () => {
const endPage = props.pages[props.pages.length - 1].page;
$magazine.turn("page", endPage);
};
const zoomIn = () => {
zoomLevel.value = Math.min(zoomLevel.value + 0.2, 2);
updateZoom();
......@@ -758,23 +796,20 @@ const handleSmallImageClick = (smallImage, pageNum) => {
currentImageIndex.value = currentPage.images.findIndex(
(img) => img.url === smallImage.url
);
const images = currentPage.images.map((img) => img.url)
showImagePreview({
images,
closeable: true,
startPosition: currentImageIndex.value,
});
// previewImages.value = currentPage.images.map((img) => ({
// src: img.url,
// title: `第 ${pageNum} 页`,
// }));
// // 显示预览组件
// showViewer.value = true;
// const images = currentPage.images.map((img) => img.url);
// showImagePreview({
// images,
// closeable: true,
// startPosition: currentImageIndex.value,
// });
previewImages.value = currentPage.images.map((img) => ({
src: img.url,
title: `第 ${pageNum} 页`,
}));
// 显示预览组件
showViewer.value = true;
}
};
......@@ -812,21 +847,22 @@ const showGuide = () => {
</script>
<style scoped lang="scss">
@import "./mobile.scss";
.book-reader {
width: 100vw;
height: 100vh;
height: calc(100vh - 92px);
display: flex;
justify-content: center;
align-items: center;
background-color: #333;
position: relative;
background-image: url("../assets/images/2.jpg");
background-image: url("@/assets/images/bg3.jpg");
background-size: 100% 100%;
touch-action: pan-y pinch-zoom;
}
.magazine-viewport {
width: 100%;
width: 100vw;
height: 100%;
display: flex;
justify-content: center;
......@@ -854,10 +890,12 @@ const showGuide = () => {
left: 50%;
width: 1px;
height: 100%;
background: linear-gradient(to bottom,
rgba(0, 0, 0, 0.1) 0%,
rgba(0, 0, 0, 0.2) 50%,
rgba(0, 0, 0, 0.1) 100%);
background: linear-gradient(
to bottom,
rgba(0, 0, 0, 0.1) 0%,
rgba(0, 0, 0, 0.2) 50%,
rgba(0, 0, 0, 0.1) 100%
);
z-index: 10;
pointer-events: none;
}
......@@ -1163,45 +1201,6 @@ const showGuide = () => {
opacity: 1;
}
@media (max-width: 768px) {
.controls {
bottom: 10px;
padding: 6px 14px;
gap: 10px;
}
.control-button {
width: 30px;
height: 30px;
}
.control-button svg {
width: 18px;
height: 18px;
}
.magazine {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
max-width: 100vw;
}
.page {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
}
.page-image {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
height: 100% !important;
object-fit: contain;
}
}
/* Update mobile controls styles */
.mobile-controls {
position: fixed;
......@@ -1276,30 +1275,43 @@ const showGuide = () => {
font-size: 14px;
}
/* Media query for mobile */
@media (max-width: 768px) {
.controls:not(.mobile-controls) {
display: none;
}
.mobile-controls {
display: flex;
}
.thumbnail-grid {
grid-template-columns: repeat(auto-fill, minmax(20vw, 1fr)) !important;
}
}
.tab-bar {
display: flex;
.tab-bar-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
.footer {
background-color: #444;
padding: 0 20px;
height: 46px;
.tab-bar {
background-color: #444;
color: #ccc;
width: 100%;
height: 100%;
.left,
.right,
.center {
display: flex;
align-items: center;
height: 100%;
}
.center {
justify-content: center;
.svg-icon {
margin: 20px;
}
}
.left {
justify-content: flex-start;
.svg-icon {
margin-right: 20px;
}
}
.isMobile {
justify-content: center;
}
.right {
justify-content: flex-end !important;
.svg-icon {
margin-right: 20px;
}
}
}
}
</style>
/* Media query for mobile */
@media (max-width: 768px) {
.magazine {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
max-width: 100vw;
}
.page {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
}
.page-image {
transform: translateZ(0);
-webkit-transform: translateZ(0);
width: 100% !important;
height: 100% !important;
object-fit: contain;
}
.controls:not(.mobile-controls) {
display: none;
}
.mobile-controls {
display: flex;
}
.thumbnail-grid {
grid-template-columns: repeat(auto-fill, minmax(20vw, 1fr)) !important;
}
}
\ No newline at end of file
<template>
<svg
:class="svgClass"
v-bind="$attrs"
:style="{ color: color, fontSize: size + 'px' }"
>
<use :href="iconName"></use>
</svg>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
name: {
type: String,
required: true,
},
color: {
type: String,
default: "",
},
size: {
type: Number,
},
});
const iconName = computed(() => `#icon-${props.name}`);
const svgClass = computed(() => {
if (props.name) return `svg-icon icon-${props.name}`;
return "svg-icon";
});
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
fill: currentColor;
vertical-align: middle;
}
</style>
......@@ -3,8 +3,11 @@ import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router';
import 'virtual:svg-icons-register'
import SvgIcon from './components/SvgIcon/index.vue'
const app = createApp(App)
app.use(ElementPlus)
app.use(router)
app.component('svg-icon', SvgIcon) // 全局挂载组件
app.mount('#app')
<template>
<div>
<van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft" />
<div class="header">
<el-button type="primary" link class="back">返回</el-button>
微方志
</div>
<BookReader :pages="pages" :bookmarks="bookmarks" />
</div>
</template>
<script setup>
import { getDocumentDetail } from "@/api";
import BookReader from "@/components/BookReader.vue";
import BookReader from "@/components/BookReader/index.vue";
const route = useRoute();
const router = useRouter();
/* props */
/* emit */
/* data */
const title = ref('')
const title = ref("");
const pages = ref([]);
const bookmarks = ref([]);
/* computed */
......@@ -33,14 +36,31 @@ async function loadData(id) {
});
}
function onClickLeft(){
router.go(-1)
function onClickLeft() {
router.go(-1);
}
onMounted(() => {
const { id } = route.params;
bookmarks.value = JSON.parse(localStorage.getItem(`bookmarks-${id}`));
title.value = route.query.title
title.value = route.query.title;
loadData(id);
});
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.header {
background-color: #444;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
position: relative;
height: 46px;
padding: 0 20px;
.back {
position: absolute;
left: 20px;
top: 50%;
transform: translateY(-50%);
}
}
</style>
<template>
<div class="book-list-container">
<van-nav-bar title="微方志">
<!-- <van-nav-bar title="微方志" class="nav-bar">
<template #right>
<van-icon name="search" size="20" />
</template>
</van-nav-bar>
</van-nav-bar> -->
<el-header class="header">微方志</el-header>
<van-row class="book-card-list">
<van-col span="8" v-for="(book, index) in books" :key="book.book_id + index">
<!-- <van-row class="book-card-list">
<van-col
span="8"
v-for="(book, index) in books"
:key="book.book_id + index"
>
<div class="book-card" shadow="hover" @click="openBook(book)">
<div class="book-cover">{{ book.name }}</div>
<div class="book-cover"></div>
<div class="book-name">{{ book.name }}</div>
</div>
</van-col>
</van-row>
<!-- <el-row :gutter="16" class="book-card-list">
</van-row> -->
<el-row :gutter="16" class="book-card-list">
<el-col
v-for="(book, index) in books"
:key="book.book_id + index"
:span="8"
:lg="4"
>
<div class="book-card" shadow="hover" @click="openBook(book)">
<div class="book-cover">{{ book.name }}</div>
<div class="book-cover"></div>
<div class="book-name">{{ book.name }}</div>
</div>
</el-col>
</el-row> -->
</el-row>
</div>
</template>
<script lang="ts" setup>
import {
ref,
computed
} from "vue";
import {
getDocList
} from "@/api/index";
import { ref, computed } from "vue";
import { getDocList } from "@/api/index";
import router from "@/router";
// 模拟接口返回数据类型
interface Book {
......@@ -57,10 +58,10 @@ async function loadData() {
function openBook(book) {
console.log(book);
const query = {
title:book.name
title: book.name,
};
const path = `/detail/${book.book_id}`;
localStorage.setItem(`bookmarks-${book.book_id}`, book.bookmarks)
localStorage.setItem(`bookmarks-${book.book_id}`, book.bookmarks);
router.push({
query,
path,
......@@ -72,23 +73,65 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.header {
background-color: #444;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.book-list-container {
height: 100vh;
.book-card-list{
padding: 30px;
background-image: url(@/assets/images/5.jpg);
background-size: cover;
.book-card-list {
padding: 50px 13%;
.book-card {
border-radius: 8px;
cursor: pointer;
transition: all ease 0.3s;
&:hover {
transform: translateY(-10px);
}
.book-cover {
background-image: url(@/assets/images/default2.jpg);
background-size: cover;
border-radius: 8px;
display: flex;
justify-content: center;
font-family: 楷体;
font-size: 20px;
margin-bottom: 10px;
width: 150px; /* 固定宽度 */
height: 200px; /* 高度按比例计算(2:3) */
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
padding: 10px;
}
}
}
.book-card {
border-radius: 8px;
}
.book-cover {
background-color: rgba(65, 184, 131, 0.4);
padding: 50px 10px;
@media (max-width: 768px) {
.book-card-list {
padding: 30px;
.book-card {
border-radius: 8px;
display: flex;
justify-content: center;
font-family: 楷体;
font-size: 18px;
margin-bottom: 10px;
.book-cover {
background-color: rgba(65, 184, 131, 0.4);
padding: 50px 10px;
border-radius: 8px;
display: flex;
justify-content: center;
font-family: 楷体;
font-size: 18px;
margin-bottom: 10px;
width: 150px; /* 固定宽度 */
height: 150px; /* 高度按比例计算(2:3) */
}
}
}
}
......
......@@ -6,8 +6,9 @@ import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver,VantResolver } from 'unplugin-vue-components/resolvers'
import { ElementPlusResolver, VantResolver } from 'unplugin-vue-components/resolvers'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [
......@@ -17,16 +18,20 @@ export default defineConfig({
// 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
imports: ['vue', 'vue-router', 'pinia'],
// 自动导入 Element Plus 相关函数
resolvers: [ElementPlusResolver(),VantResolver()],
resolvers: [ElementPlusResolver(), VantResolver()],
// 生成自动导入的TS声明文件
dts: 'src/auto-imports.d.ts',
}),
Components({
// 自动导入组件
resolvers: [ElementPlusResolver(),VantResolver()],
resolvers: [ElementPlusResolver(), VantResolver()],
// 生成自动导入的TS声明文件
dts: 'src/components.d.ts',
}),
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/assets/svg')], // SVG 存放路径
symbolId: 'icon-[name]'
})
],
resolve: {
alias: {
......@@ -41,7 +46,7 @@ export default defineConfig({
rewrite: (path) => path.replace(/^\/api/, '')
}
},
host:'0.0.0.0',
port:8089,
host: '0.0.0.0',
port: 8089,
}
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论