feat: background image cache indexdb

This commit is contained in:
KUN1007 2023-10-19 18:19:34 +08:00
parent 64ad8215ac
commit b5e222855e
12 changed files with 185 additions and 69 deletions

16
.vscode/settings.json vendored
View file

@ -2,12 +2,14 @@
"cSpell.words": [
"ACGNGAME",
"Akai",
"Amayui",
"arpa",
"axios",
"azkhx",
"bangumi",
"Bilibili",
"Bishoujo",
"Chuudoku",
"Codepen",
"cout",
"dompurify",
@ -16,11 +18,15 @@
"Galgame",
"Galworld",
"gsap",
"Hana",
"Hikari",
"Hitomi",
"Hokenshitsu",
"iconify",
"INTLIFY",
"Irotoridori",
"Joshu",
"Karenai",
"kfmax",
"Koori",
"kungal",
@ -28,10 +34,12 @@
"kungalgamer",
"ldquo",
"Licence",
"localforage",
"loli",
"majesticons",
"Mangekyou",
"Maniwa",
"Meister",
"mingcute",
"Mirai",
"mockjs",
@ -40,22 +48,29 @@
"Murasame",
"Nanami",
"nawa",
"NEKOPARA",
"non-moe",
"nprogress",
"okaidia",
"Otome",
"Owaru",
"persistedstate",
"Pinia",
"prismjs",
"rdquo",
"Roka",
"Sahou",
"Sakura",
"Sekai",
"Senren",
"Sensei",
"Shabondama",
"shinnku",
"Shugaten",
"signin",
"sina",
"SMEE",
"Somnium",
"tachi",
"tada",
"tdesign",
@ -75,6 +90,7 @@
"Vite",
"VNDB",
"vueup",
"Wataridori",
"weixin",
"Wenders",
"ymgal",

View file

@ -22,6 +22,7 @@
"animate.css": "^4.1.1",
"dayjs": "^1.11.10",
"dompurify": "^3.0.6",
"localforage": "^1.10.0",
"nprogress": "^0.2.0",
"pinia": "^2.1.6",
"pinia-plugin-persistedstate": "^3.2.0",

View file

@ -17,6 +17,9 @@ dependencies:
dompurify:
specifier: ^3.0.6
version: 3.0.6
localforage:
specifier: ^1.10.0
version: 1.10.0
nprogress:
specifier: ^0.2.0
version: 0.2.0
@ -1475,6 +1478,10 @@ packages:
engines: {node: '>=8'}
dev: true
/immediate@3.0.6:
resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
dev: false
/immutable@4.3.4:
resolution: {integrity: sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==}
dev: true
@ -1569,6 +1576,18 @@ packages:
hasBin: true
dev: true
/lie@3.1.1:
resolution: {integrity: sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==}
dependencies:
immediate: 3.0.6
dev: false
/localforage@1.10.0:
resolution: {integrity: sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==}
dependencies:
lie: 3.1.1
dev: false
/lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
dev: false

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
// vue
import { ref } from 'vue'
import { onMounted, ref } from 'vue'
// store
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
@ -9,46 +9,44 @@ import { storeToRefs } from 'pinia'
//
import Message from '@/components/alert/Message'
import backgroundImages from './background'
import { backgroundImages } from './background'
import { getBackgroundURL } from '@/hooks/useBackgroundPicture'
import { restoreBackground } from '@/hooks/useBackgroundPicture'
const imageArray = ref<string[]>([])
// 使 store
const settingsStore = useKUNGalgameSettingsStore()
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
storeToRefs(settingsStore)
storeToRefs(useKUNGalgameSettingsStore())
//
const getBackground = async (imageNumber: number) => {
return await getBackgroundURL(`bg${imageNumber}-m`)
}
//
const handelChangeImage = (index: number) => {
showKUNGalgameBackground.value = index.toString()
showKUNGalgameBackground.value = `bg${index}`
}
/* :
https://s3.bmp.ovh/imgs/2023/05/30/1ee99996d0eb2646.png
https://s3.bmp.ovh/imgs/2023/05/30/87d94be5e004547a.png
https://s3.bmp.ovh/imgs/2023/05/30/2a639bd15113b570.png
https://s3.bmp.ovh/imgs/2023/05/30/b7c73a1643bdc55b.png
https://s3.bmp.ovh/imgs/2023/05/30/ee67fdadd4104bbd.png
https://s3.bmp.ovh/imgs/2023/05/30/30aacd3045496498.png
https://s3.bmp.ovh/imgs/2023/05/30/ab2da01971cc1629.png
https://s3.bmp.ovh/imgs/2023/05/30/ed196495796482e4.png
https://s3.bmp.ovh/imgs/2023/05/30/a6dcdae0afe118f0.png
https://s3.bmp.ovh/imgs/2023/05/30/7aa57120cc6977a1.png
*/
//
const url = ref('')
const handleCustomBackground = () => {
if (url.value) {
showKUNGalgameCustomBackground.value = url.value
showKUNGalgameBackground.value = '1007'
showKUNGalgameBackground.value = 'bg1007'
url.value = ''
} else {
Message('Please input valid image url', '请输入合法的图片链接', 'warn')
}
}
//
onMounted(async () => {
for (const background of backgroundImages) {
const backgroundURL = await getBackground(background.index)
imageArray.value.push(backgroundURL)
}
})
</script>
<template>
@ -61,7 +59,7 @@ const handleCustomBackground = () => {
<ul class="kungalgame-restore-bg">
<li v-for="kun in backgroundImages" :key="kun.index">
<img
:src="kun.image"
:src="imageArray[kun.index - 1]"
:alt="kun.alt"
@click="handelChangeImage(kun.index)"
/>

View file

@ -1,56 +1,57 @@
/* :
https://s3.bmp.ovh/imgs/2023/05/30/1ee99996d0eb2646.png
https://s3.bmp.ovh/imgs/2023/05/30/87d94be5e004547a.png
https://s3.bmp.ovh/imgs/2023/05/30/2a639bd15113b570.png
https://s3.bmp.ovh/imgs/2023/05/30/b7c73a1643bdc55b.png
https://s3.bmp.ovh/imgs/2023/05/30/ee67fdadd4104bbd.png
https://s3.bmp.ovh/imgs/2023/05/30/30aacd3045496498.png
https://s3.bmp.ovh/imgs/2023/05/30/ab2da01971cc1629.png
https://s3.bmp.ovh/imgs/2023/05/30/ed196495796482e4.png
https://s3.bmp.ovh/imgs/2023/05/30/a6dcdae0afe118f0.png
https://s3.bmp.ovh/imgs/2023/05/30/7aa57120cc6977a1.png
*/
interface background {
index: number
image: string
alt: string
}
// 定义背景图片列表
const backgroundImages: background[] = [
export const backgroundImages: background[] = [
{
index: 1,
image: '/src/assets/images/bg/bg1-m.png',
alt: 'azkhx',
alt: 'Akai Hitomi ni Utsuru Sekai 紅い瞳に映るセカイ 红瞳映入的世界',
},
{
index: 2,
image: '/src/assets/images/bg/bg2-m.png',
alt: 'azkhx',
alt: 'Shugaten! しゅがてん! 糖调',
},
{
index: 3,
image: '/src/assets/images/bg/bg3-m.png',
alt: 'azkhx',
alt: 'Amayui Castle Meister 天結いキャッスルマイスター 天结神缘',
},
{
index: 4,
image: '/src/assets/images/bg/bg4-m.png',
alt: 'azkhx',
alt: 'Pieces Wataridori no Somnium 渡り鳥のソムニウム 渡鸟的梦',
},
{
index: 5,
image: '/src/assets/images/bg/bg5-m.png',
alt: 'azkhx',
alt: 'Karenai Sekai to Owaru Hana 枯れない世界と終わる花 不败世界与终焉之花',
},
{
index: 6,
image: '/src/assets/images/bg/bg6-m.png',
alt: 'azkhx',
alt: 'NEKOPARA ネコぱら 猫娘乐园',
},
{
index: 7,
image: '/src/assets/images/bg/bg7-m.png',
alt: 'azkhx',
alt: 'Sakura no Uta サクラノ詩 樱之诗',
},
{
index: 8,
image: '/src/assets/images/bg/bg8-m.png',
alt: 'azkhx',
alt: 'Hokenshitsu no Sensei to Shabondama Chuudoku no Joshu 保健室のセンセーとシャボン玉中毒の助手 保健室的老师与肥皂泡中毒的助手',
},
{
index: 9,
image: '/src/assets/images/bg/bg9-m.png',
alt: 'azkhx',
alt: 'Senren * Banka 千恋*万花 千恋*万花',
},
]
export default backgroundImages

View file

@ -1,28 +1,76 @@
// 导入设置面板 store
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
import { useKUNGalgameUserStore } from '@/store/modules/kungalgamer'
import { saveImage, getImage } from './useLocalforage'
import { storeToRefs } from 'pinia'
import { computed } from 'vue'
// 使用设置面板的 store
const settingsStore = useKUNGalgameSettingsStore()
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
storeToRefs(settingsStore)
// 恢复空白背景
export const restoreBackground = () => {
showKUNGalgameBackground.value = '0'
// 从后端获取背景图片数据
const fetchGetBackground = async (imageName: string): Promise<Blob> => {
const baseUrl = import.meta.env.VITE_API_BASE_URL
const url = `/uploads/image/bg/${imageName}.webp`
const fullUrl = `${baseUrl}${url}`
const response = await fetch(fullUrl, {
method: 'GET',
headers: {
Authorization: `Bearer ${useKUNGalgameUserStore().getToken()}`,
},
})
return await response.blob()
}
export const currBackground = computed(() => {
// 根据图片的序号获取图片链接
const getBackgroundURL = async (imageName: string) => {
// 本地保存的图片 blob 数据
const backgroundImageBlobData = await getImage(imageName)
// 有数据则从本地创建 blob 链接
if (backgroundImageBlobData) {
return URL.createObjectURL(backgroundImageBlobData)
} else {
// 本地数据没有图片 blob 数据则从后端获取图片 blob 数据并存储在本地
const imageBlob = await fetchGetBackground(`${imageName}`)
console.log('调用 fetch get blob')
await saveImage(imageBlob, imageName)
return URL.createObjectURL(imageBlob)
}
}
// 这里的图片名后端定义的是 bg1.webp大图, bg1-m.webp预览图
const getCurrentBackground = async () => {
if (
showKUNGalgameBackground.value === '0' ||
showKUNGalgameBackground.value === 'bg0' ||
showKUNGalgameBackground.value === 'none'
) {
return 'none'
} else if (showKUNGalgameBackground.value === '1007') {
return `url(${showKUNGalgameCustomBackground.value})`
} else {
// TODO: 替换为后端接口
return `url(/src/assets/images/bg/bg${showKUNGalgameBackground.value}.png)`
}
})
if (showKUNGalgameBackground.value === 'bg1007') {
return `${showKUNGalgameCustomBackground.value}`
}
// 获取图片的 blob url
const url = await getBackgroundURL(showKUNGalgameBackground.value)
return url
}
// 获取所有图片的预览图好像。。。min 比 thumbnail 萌一点
// const getCurrentBackgroundMin = async () => {
// let imageArray: string[] = []
// for (let i = 0; i < 9; i++) {
// const url = await getBackgroundURL(`bg${i}-m`)
// imageArray.push(url)
// }
// return imageArray
// }
// 恢复空白背景
const restoreBackground = () => {
showKUNGalgameBackground.value = 'bg0'
}
export { getBackgroundURL, getCurrentBackground, restoreBackground }

View file

@ -0,0 +1,16 @@
import localforage from 'localforage'
// 保存图片
const saveImage = async (imageData: Blob, imageName: string): Promise<void> => {
await localforage.setItem(imageName, imageData)
}
// 获取图片
const getImage = async (imageName: string): Promise<Blob | null> => {
return await localforage.getItem(imageName)
}
// 删除图片
const deleteImage = async (imageName: string): Promise<void> => {
await localforage.removeItem(imageName)
}
export { saveImage, getImage, deleteImage }

View file

@ -1,16 +1,34 @@
<!-- 先放一个 Layout 在这里后面应该用得到 -->
<script setup lang="ts">
import { onMounted, watch, ref } from 'vue'
//
import 'animate.css'
import { currBackground } from '@/hooks/useBackgroundPicture'
import { getCurrentBackground } from '@/hooks/useBackgroundPicture'
import KUNGalgameTopBar from '@/components/top-bar/KUNGalgameTopBar.vue'
import { useKUNGalgameSettingsStore } from '@/store/modules/settings'
import { storeToRefs } from 'pinia'
const { showKUNGalgameBackground, showKUNGalgameCustomBackground } =
storeToRefs(useKUNGalgameSettingsStore())
const imageURL = ref('')
onMounted(async () => {
imageURL.value = await getCurrentBackground()
})
watch(
() => [showKUNGalgameBackground.value, showKUNGalgameCustomBackground.value],
async () => {
imageURL.value = await getCurrentBackground()
}
)
</script>
<template>
<!-- #default v-slot 的简写route 就是路由Component 是一个 v-node -->
<div class="app" :style="{ backgroundImage: currBackground }">
<div class="app" :style="{ backgroundImage: `url(${imageURL})` }">
<div class="top-bar">
<KUNGalgameTopBar />
</div>

View file

@ -81,7 +81,7 @@ export const constantRoutes: RouteRecordRaw[] = [
},
},
// KUNGalgame 403 TODO:
// KUNGalgame 403
{
name: '403',
path: '/kungalgame403',

View file

@ -70,15 +70,14 @@ onBeforeRouteLeave(async (to, from, next) => {
<!-- 版权 -->
<KUNGalgameFooter style="margin: 0 auto; padding-top: 10px" />
<span style="margin: 0 auto; color: var(--kungalgame-font-color-3)"
>Editor powered by quill</span
>
<span style="margin: 0 auto; color: var(--kungalgame-font-color-3)">
Editor powered by quill
</span>
</div>
</template>
<style lang="scss" scoped>
.root {
margin-top: 20px;
height: calc(100vh - 65px);
min-height: 1000px;
display: flex;

View file

@ -2,8 +2,6 @@
import { Icon } from '@iconify/vue'
const props = defineProps(['data'])
// TODO:
</script>
<template>

View file

@ -118,8 +118,10 @@ const handleClickComment = (
<!-- 顶部左侧名字 -->
<div class="name">
{{ `${comment.c_user.name} ${$tm('topic.content.comment')}` }}
<!-- 跳转到用户主页 TODO: -->
<a href="#">{{ comment.to_user.name }}</a>
<!-- 跳转到用户主页 -->
<RouterLink :to="`/kungalgamer/${comment.to_user.uid}/info`">
{{ comment.to_user.name }}
</RouterLink>
</div>
<!-- 顶部右侧点赞 -->
<div class="operate">