在线文档支持
This commit is contained in:
parent
ce7ee34666
commit
4e17ee281c
1286
reading-platform-frontend/package-lock.json
generated
1286
reading-platform-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -39,10 +39,10 @@
|
|||||||
"@types/node": "^20.11.28",
|
"@types/node": "^20.11.28",
|
||||||
"@vitejs/plugin-vue": "^5.0.4",
|
"@vitejs/plugin-vue": "^5.0.4",
|
||||||
"@vue/tsconfig": "^0.5.1",
|
"@vue/tsconfig": "^0.5.1",
|
||||||
"@playwright/test": "^1.58.2",
|
|
||||||
"orval": "^8.5.3",
|
"orval": "^8.5.3",
|
||||||
"sass-embedded": "^1.97.3",
|
"sass-embedded": "^1.97.3",
|
||||||
"typescript": "~5.4.0",
|
"typescript": "~5.4.0",
|
||||||
|
"unocss": "^66.6.6",
|
||||||
"unplugin-auto-import": "^0.17.5",
|
"unplugin-auto-import": "^0.17.5",
|
||||||
"unplugin-vue-components": "^0.26.0",
|
"unplugin-vue-components": "^0.26.0",
|
||||||
"unplugin-vue-router": "^0.19.2",
|
"unplugin-vue-router": "^0.19.2",
|
||||||
|
|||||||
@ -1,20 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-modal
|
<a-modal v-model:open="visible" :title="title" :width="modalWidth" :footer="null" centered @cancel="handleClose">
|
||||||
v-model:open="visible"
|
|
||||||
:title="title"
|
|
||||||
:width="modalWidth"
|
|
||||||
:footer="null"
|
|
||||||
centered
|
|
||||||
@cancel="handleClose"
|
|
||||||
>
|
|
||||||
<!-- PDF 预览 -->
|
<!-- PDF 预览 -->
|
||||||
<div v-if="fileType === 'pdf'" class="preview-container pdf-container">
|
<div v-if="fileType === 'pdf'" class="preview-container pdf-container">
|
||||||
<iframe
|
<iframe v-if="previewUrl" :src="previewUrl" class="pdf-iframe" frameborder="0"></iframe>
|
||||||
v-if="previewUrl"
|
|
||||||
:src="previewUrl"
|
|
||||||
class="pdf-iframe"
|
|
||||||
frameborder="0"
|
|
||||||
></iframe>
|
|
||||||
<div v-else class="preview-error">
|
<div v-else class="preview-error">
|
||||||
<FileTextOutlined style="font-size: 48px; color: #999;" />
|
<FileTextOutlined style="font-size: 48px; color: #999;" />
|
||||||
<p>无法预览此PDF文件</p>
|
<p>无法预览此PDF文件</p>
|
||||||
@ -31,13 +19,7 @@
|
|||||||
<div class="audio-info">
|
<div class="audio-info">
|
||||||
<h3>{{ fileName }}</h3>
|
<h3>{{ fileName }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<audio
|
<audio ref="audioRef" :src="previewUrl" controls class="audio-element" @error="handleMediaError">
|
||||||
ref="audioRef"
|
|
||||||
:src="previewUrl"
|
|
||||||
controls
|
|
||||||
class="audio-element"
|
|
||||||
@error="handleMediaError"
|
|
||||||
>
|
|
||||||
您的浏览器不支持音频播放
|
您的浏览器不支持音频播放
|
||||||
</audio>
|
</audio>
|
||||||
</div>
|
</div>
|
||||||
@ -45,39 +27,53 @@
|
|||||||
|
|
||||||
<!-- 视频播放器 -->
|
<!-- 视频播放器 -->
|
||||||
<div v-else-if="fileType === 'video'" class="preview-container video-container">
|
<div v-else-if="fileType === 'video'" class="preview-container video-container">
|
||||||
<video
|
<video ref="videoRef" :src="previewUrl" controls class="video-element" @error="handleMediaError">
|
||||||
ref="videoRef"
|
|
||||||
:src="previewUrl"
|
|
||||||
controls
|
|
||||||
class="video-element"
|
|
||||||
@error="handleMediaError"
|
|
||||||
>
|
|
||||||
您的浏览器不支持视频播放
|
您的浏览器不支持视频播放
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 图片预览 -->
|
<!-- 图片预览 -->
|
||||||
<div v-else-if="fileType === 'image'" class="preview-container image-container">
|
<div v-else-if="fileType === 'image'" class="preview-container image-container">
|
||||||
<a-image
|
<a-image :src="previewUrl" :preview="true" class="preview-image" @error="handleImageError" />
|
||||||
:src="previewUrl"
|
|
||||||
:preview="true"
|
|
||||||
class="preview-image"
|
|
||||||
@error="handleImageError"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- PPT 预览(使用 Office Online 或 Google Docs 预览) -->
|
<!-- PPT 预览 -->
|
||||||
<div v-else-if="fileType === 'ppt'" class="preview-container ppt-container">
|
<div v-else-if="fileType === 'ppt'" class="preview-container ppt-container">
|
||||||
<div class="ppt-notice">
|
<div class="ppt-notice">
|
||||||
<FilePptOutlined style="font-size: 48px; color: #ff7a45;" />
|
<FilePptOutlined style="font-size: 48px; color: #ff7a45;" />
|
||||||
<h3>PPT 文件预览</h3>
|
<h3>PPT 文件预览</h3>
|
||||||
<p>PPT 文件建议下载后使用 PowerPoint 或 WPS 查看</p>
|
<p>使用 WebOffice 在新页面中预览</p>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click="downloadFile">
|
<a-button type="primary" @click="openInWebOffice">
|
||||||
<DownloadOutlined /> 下载文件
|
<EyeOutlined /> WebOffice 预览
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="openInOfficeOnline">
|
</a-space>
|
||||||
<EyeOutlined /> 在线预览
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Word 预览 -->
|
||||||
|
<div v-else-if="fileType === 'doc'" class="preview-container ppt-container">
|
||||||
|
<div class="ppt-notice">
|
||||||
|
<FileTextOutlined style="font-size: 48px; color: #1890ff;" />
|
||||||
|
<h3>Word 文件预览</h3>
|
||||||
|
<p>使用 WebOffice 在新页面中预览</p>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="openInWebOffice">
|
||||||
|
<EyeOutlined /> WebOffice 预览
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Excel 预览 -->
|
||||||
|
<div v-else-if="fileType === 'excel'" class="preview-container ppt-container">
|
||||||
|
<div class="ppt-notice">
|
||||||
|
<FileOutlined style="font-size: 48px; color: #52c41a;" />
|
||||||
|
<h3>Excel 文件预览</h3>
|
||||||
|
<p>使用 WebOffice 在新页面中预览</p>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="openInWebOffice">
|
||||||
|
<EyeOutlined /> WebOffice 预览
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
</div>
|
</div>
|
||||||
@ -95,17 +91,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
|
||||||
<div class="preview-footer" v-if="fileType !== 'other'">
|
|
||||||
<a-space>
|
|
||||||
<a-button @click="downloadFile">
|
|
||||||
<DownloadOutlined /> 下载
|
|
||||||
</a-button>
|
|
||||||
<a-button type="link" @click="openInNewTab">
|
|
||||||
<ExportOutlined /> 新窗口打开
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -121,11 +106,14 @@ import {
|
|||||||
ExportOutlined,
|
ExportOutlined,
|
||||||
} from '@ant-design/icons-vue';
|
} from '@ant-design/icons-vue';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
import { openWebOffice } from '@/views/office/webOffice';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
open: boolean;
|
open: boolean;
|
||||||
fileUrl: string;
|
fileUrl: string;
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
/** 可选,用于 WebOffice 预览时的文件标识 */
|
||||||
|
fileId?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@ -150,6 +138,8 @@ const fileType = computed(() => {
|
|||||||
|
|
||||||
if (checkStr.endsWith('.pdf')) return 'pdf';
|
if (checkStr.endsWith('.pdf')) return 'pdf';
|
||||||
if (checkStr.endsWith('.ppt') || checkStr.endsWith('.pptx')) return 'ppt';
|
if (checkStr.endsWith('.ppt') || checkStr.endsWith('.pptx')) return 'ppt';
|
||||||
|
if (checkStr.match(/\.(doc|docx)$/)) return 'doc';
|
||||||
|
if (checkStr.match(/\.(xls|xlsx)$/)) return 'excel';
|
||||||
if (checkStr.match(/\.(mp3|wav|ogg|aac|flac|m4a)$/)) return 'audio';
|
if (checkStr.match(/\.(mp3|wav|ogg|aac|flac|m4a)$/)) return 'audio';
|
||||||
if (checkStr.match(/\.(mp4|webm|ogg|mov|avi|mkv)$/)) return 'video';
|
if (checkStr.match(/\.(mp4|webm|ogg|mov|avi|mkv)$/)) return 'video';
|
||||||
if (checkStr.match(/\.(jpg|jpeg|png|gif|webp|bmp|svg)$/)) return 'image';
|
if (checkStr.match(/\.(jpg|jpeg|png|gif|webp|bmp|svg)$/)) return 'image';
|
||||||
@ -223,18 +213,39 @@ const openInNewTab = () => {
|
|||||||
window.open(previewUrl.value, '_blank');
|
window.open(previewUrl.value, '_blank');
|
||||||
};
|
};
|
||||||
|
|
||||||
// 使用 Office Online 预览 PPT
|
// 是否支持 WebOffice 预览(PPT、Word、Excel)
|
||||||
const openInOfficeOnline = () => {
|
const isOfficeFile = computed(
|
||||||
// 需要 Office Online 服务支持,这里使用完整的 URL
|
() => ['ppt', 'doc', 'excel'].includes(fileType.value)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 解析文件名得到 name 和 type
|
||||||
|
const parseFileName = (name: string) => {
|
||||||
|
const lastDot = name.lastIndexOf('.');
|
||||||
|
if (lastDot === -1) return { name: name, type: '' };
|
||||||
|
return {
|
||||||
|
name: name.slice(0, lastDot),
|
||||||
|
type: name.slice(lastDot + 1).toLowerCase(),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用 WebOffice 在新页面预览(阿里云 IMM)
|
||||||
|
const openInWebOffice = () => {
|
||||||
const fullUrl = previewUrl.value;
|
const fullUrl = previewUrl.value;
|
||||||
if (!fullUrl.startsWith('http')) {
|
if (!fullUrl.startsWith('http')) {
|
||||||
message.warning('PPT 在线预览需要完整的文件 URL');
|
message.warning('WebOffice 预览需要完整的文件 URL');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const { name, type } = parseFileName(props.fileName);
|
||||||
// 使用微软 Office Online 预览服务
|
if (!type) {
|
||||||
const officeUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(fullUrl)}`;
|
message.warning('无法识别文件类型');
|
||||||
window.open(officeUrl, '_blank');
|
return;
|
||||||
|
}
|
||||||
|
openWebOffice({
|
||||||
|
id: props.fileId || '',
|
||||||
|
url: fullUrl,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 媒体加载错误处理
|
// 媒体加载错误处理
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { createApp } from 'vue';
|
|||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import Antd from 'ant-design-vue';
|
import Antd from 'ant-design-vue';
|
||||||
import 'ant-design-vue/dist/reset.css';
|
import 'ant-design-vue/dist/reset.css';
|
||||||
|
import 'virtual:uno.css';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
|
|
||||||
|
|||||||
@ -455,6 +455,16 @@ const routes: RouteRecordRaw[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/office/WebOffice',
|
||||||
|
name: 'WebOffice',
|
||||||
|
component: () => import('@/views/office/WebOffice.vue'),
|
||||||
|
meta: { requiresAuth: true, title: '在线预览' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/weboffice',
|
||||||
|
redirect: '/office/WebOffice',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: '/404',
|
||||||
name: 'NotFound',
|
name: 'NotFound',
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!expire" ref="containerRef" class="w-full h-full"></div>
|
|
||||||
|
<div v-if="!expire" ref="containerRef" class="!w-full !h-full pos-fixed top-0 left-0 z-999"></div>
|
||||||
<div v-else class="flex justify-center">
|
<div v-else class="flex justify-center">
|
||||||
<div class="my-60px">
|
<div class="my-60px">
|
||||||
链接已失效!<span class=" cursor-pointer color-#0085FF ml-10px" @click="home">返回首页</span>
|
链接已失效!<span class=" cursor-pointer color-#0085FF ml-10px" @click="home">返回首页</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <Modal ref="modalRef" class="max-w-80%" width="1340px" v-model:open="open" :footer="null" title="在线资源">
|
<!-- <Modal ref="modalRef" class="max-w-80%" width="1340px" v-model:open="open" :footer="null" title="在线资源">
|
||||||
|
|
||||||
<div class="flex min-h-600px bg-#f5f5f5 flex-col ">
|
<div class="flex min-h-600px bg-#f5f5f5 flex-col ">
|
||||||
@ -40,22 +40,16 @@
|
|||||||
<script lang="ts" name="WebOffice" setup>
|
<script lang="ts" name="WebOffice" setup>
|
||||||
import { onMounted, ref, nextTick, reactive, watch, onUnmounted, onBeforeUnmount } from 'vue';
|
import { onMounted, ref, nextTick, reactive, watch, onUnmounted, onBeforeUnmount } from 'vue';
|
||||||
|
|
||||||
import request from '/@/apis/fetch';
|
|
||||||
// import { Modal, Pagination } from 'ant-design-vue';
|
|
||||||
import {
|
import {
|
||||||
generateWebofficeToken,
|
generateWebofficeToken,
|
||||||
generateWebofficeTokenReadOnly,
|
generateWebofficeTokenReadOnly,
|
||||||
refreshWebofficeToken,
|
refreshWebofficeToken,
|
||||||
} from '@/api/imm.api';
|
} from '@/api/imm.api';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
// import { usePermission } from '@/hooks/web/usePermission';
|
|
||||||
// import { insertPPTImage, insertWordImage } from './webOffice';
|
|
||||||
import { getTemItem, TemObj } from './temObjs';
|
import { getTemItem, TemObj } from './temObjs';
|
||||||
import { createImgPreview } from '/@/components/Preview/index';
|
|
||||||
|
|
||||||
const containerRef = ref(null);
|
const containerRef = ref<HTMLElement | null>(null);
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const open = ref(false);
|
|
||||||
const expire = ref(false);
|
const expire = ref(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
let updateSizeInterval: any;
|
let updateSizeInterval: any;
|
||||||
@ -64,15 +58,9 @@ onMounted(() => {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
init(containerRef.value);
|
init(containerRef.value);
|
||||||
})
|
})
|
||||||
updateSizeInterval = setInterval(() => {
|
|
||||||
if (baseInstance.value) {
|
|
||||||
updateSize();
|
|
||||||
}
|
|
||||||
}, 1000 * 60 * 5)
|
|
||||||
});
|
});
|
||||||
const _temObj = ref<TemObj>({
|
const _temObj = ref<TemObj>({
|
||||||
id: '',
|
id: '',
|
||||||
type: '',
|
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
name: '',
|
name: '',
|
||||||
url: '',
|
url: '',
|
||||||
@ -82,12 +70,6 @@ const updateSize = async () => {
|
|||||||
if (!onUnmountedUpdateSize.value) {
|
if (!onUnmountedUpdateSize.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!expire.value && _temObj.value.isEdit) {
|
|
||||||
var formData = new FormData();
|
|
||||||
formData.append('id', _temObj.value.id);
|
|
||||||
formData.append('type', _temObj.value.type);
|
|
||||||
navigator.sendBeacon('/activity/cms/cmsFilePublic/updateSize', formData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
updateSize();
|
updateSize();
|
||||||
@ -113,7 +95,7 @@ function home() {
|
|||||||
router.replace("/datas");
|
router.replace("/datas");
|
||||||
}
|
}
|
||||||
const baseInstance = ref<any>(null);
|
const baseInstance = ref<any>(null);
|
||||||
async function init(mount, timeout = 10 * 60 * 1000) {
|
async function init(mount: HTMLElement | null) {
|
||||||
if (!mount) {
|
if (!mount) {
|
||||||
console.error('确保挂载节点元素存在。 一般在 onMounted 钩子中调用。');
|
console.error('确保挂载节点元素存在。 一般在 onMounted 钩子中调用。');
|
||||||
}
|
}
|
||||||
@ -129,7 +111,7 @@ async function init(mount, timeout = 10 * 60 * 1000) {
|
|||||||
|
|
||||||
_temObj.value = temObj;
|
_temObj.value = temObj;
|
||||||
|
|
||||||
const url = decodeURIComponent(`oss://lesingle-activity${new URL(decodeURIComponent(temObj.url)).pathname}`);
|
const url = decodeURIComponent(`oss://lesingle-kid-course${new URL(decodeURIComponent(temObj.url)).pathname}`);
|
||||||
let tokenInfo = await getTokenFun(url, temObj);
|
let tokenInfo = await getTokenFun(url, temObj);
|
||||||
const instance = (window as any).aliyun.config({
|
const instance = (window as any).aliyun.config({
|
||||||
mount,
|
mount,
|
||||||
@ -141,7 +123,7 @@ async function init(mount, timeout = 10 * 60 * 1000) {
|
|||||||
Object.assign(tokenInfo, data);
|
Object.assign(tokenInfo, data);
|
||||||
return {
|
return {
|
||||||
token: tokenInfo.accessToken,
|
token: tokenInfo.accessToken,
|
||||||
timeout,
|
timeout: 10 * 60 * 1000,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -149,7 +131,7 @@ async function init(mount, timeout = 10 * 60 * 1000) {
|
|||||||
baseInstance.value = instance;
|
baseInstance.value = instance;
|
||||||
instance.setToken({
|
instance.setToken({
|
||||||
token: tokenInfo.accessToken,
|
token: tokenInfo.accessToken,
|
||||||
timeout,
|
timeout: 10 * 60 * 1000,
|
||||||
});
|
});
|
||||||
await instance.ready();
|
await instance.ready();
|
||||||
// const imgurl = 'http://image.activity.lesingle.com/activitymaterial/poster/%E5%8A%A8%E7%89%A9%E7%BB%98%E6%9C%AC_1736908271102.jpg';
|
// const imgurl = 'http://image.activity.lesingle.com/activitymaterial/poster/%E5%8A%A8%E7%89%A9%E7%BB%98%E6%9C%AC_1736908271102.jpg';
|
||||||
@ -207,36 +189,4 @@ async function refreshTokenFun(tokenInfo: any) {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped></style>
|
||||||
.activity {
|
|
||||||
font-weight: bold;
|
|
||||||
background: rgba(24, 144, 255, 0.08);
|
|
||||||
color: #1890FF;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.cardView {
|
|
||||||
margin-left: 12px;
|
|
||||||
padding-left: 12px;
|
|
||||||
margin-top: 12px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
&>div {
|
|
||||||
margin-right: 12px;
|
|
||||||
margin-top: 6px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 6px;
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
img {
|
|
||||||
width: 200px;
|
|
||||||
height: 200px;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -1,69 +1,73 @@
|
|||||||
|
import { ref, watch } from "vue";
|
||||||
import { ref, watch, } from 'vue';
|
|
||||||
/**
|
/**
|
||||||
* 临时localStorage缓存,使用后立即删除,适合跨页面使用
|
* 临时localStorage缓存,使用后立即删除,适合跨页面使用
|
||||||
*/
|
*/
|
||||||
const TemKel = '_t'
|
const TemKel = "_t";
|
||||||
/**
|
/**
|
||||||
* 设置缓存超时
|
* 设置缓存超时
|
||||||
*/
|
*/
|
||||||
const base_time = 1000 * 60 * 60 * 8;
|
const base_time = 1000 * 60 * 60 * 8;
|
||||||
type Tem = {
|
type Tem = {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
time: number,
|
time: number;
|
||||||
val: TemObj
|
val: TemObj;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
export function initilTemItem() {
|
export function initilTemItem() {
|
||||||
const tem: Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
const tem: Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
||||||
const _time = Date.now();
|
const _time = Date.now();
|
||||||
const _tem: Tem = {};
|
const _tem: Tem = {};
|
||||||
for (let key in tem) {
|
for (let key in tem) {
|
||||||
const val = tem[key];
|
const val = tem[key];
|
||||||
if (_time - val.time < base_time) {
|
if (_time - val.time < base_time) {
|
||||||
_tem[key] = val
|
_tem[key] = val;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
localStorage.setItem(TemKel, JSON.stringify(_tem));
|
localStorage.setItem(TemKel, JSON.stringify(_tem));
|
||||||
}
|
}
|
||||||
export type TemObj = {
|
export type TemObj = {
|
||||||
id: string;
|
id: string;
|
||||||
url: string;
|
url: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
isEdit: boolean;
|
||||||
isEdit: boolean;
|
};
|
||||||
}
|
export function setTemItem(
|
||||||
export function setTemItem(val: TemObj, time: Number = Date.now() + base_time): string {
|
val: TemObj,
|
||||||
const key = `_t${Date.now()}${Math.floor(Math.random() * 100000)}`;
|
time: Number = Date.now() + base_time,
|
||||||
let Tem: Tem = {};
|
): string {
|
||||||
try {
|
const key = `_t${Date.now()}${Math.floor(Math.random() * 100000)}`;
|
||||||
Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
let Tem: Tem = {};
|
||||||
} catch (error) { }
|
try {
|
||||||
Tem[key] = {
|
Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
||||||
time: Date.now(),
|
} catch (error) {}
|
||||||
val: val
|
Tem[key] = {
|
||||||
}
|
time: Date.now(),
|
||||||
localStorage.setItem(TemKel, JSON.stringify(Tem));
|
val: val,
|
||||||
|
};
|
||||||
|
localStorage.setItem(TemKel, JSON.stringify(Tem));
|
||||||
|
|
||||||
return key
|
return key;
|
||||||
}
|
}
|
||||||
export function getTemItem(key: string): TemObj | null {
|
export function getTemItem(key: string): TemObj | null {
|
||||||
let Tem: Tem = {};
|
let Tem: Tem = {};
|
||||||
try {
|
try {
|
||||||
Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
Tem = JSON.parse(localStorage.getItem(TemKel) || "{}");
|
||||||
return Tem[key].val
|
return Tem[key].val;
|
||||||
} catch (error) { }
|
} catch (error) {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param val 默认值
|
* @param val 默认值
|
||||||
*/
|
*/
|
||||||
export function getCacheVal(key: string, defaultVal: any) {
|
export function getCacheVal(key: string, defaultVal: any) {
|
||||||
const _val = ref(Number(localStorage.getItem(key) || defaultVal));
|
const _val = ref(Number(localStorage.getItem(key) || defaultVal));
|
||||||
watch(() => _val.value, () => {
|
watch(
|
||||||
localStorage.setItem(key, `${_val.value}`)
|
() => _val.value,
|
||||||
})
|
() => {
|
||||||
return _val
|
localStorage.setItem(key, `${_val.value}`);
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
9
reading-platform-frontend/uno.config.ts
Normal file
9
reading-platform-frontend/uno.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'unocss';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
shortcuts: {
|
||||||
|
'flex-center': 'flex items-center justify-center',
|
||||||
|
'flex-between': 'flex items-center justify-between',
|
||||||
|
'flex-col-center': 'flex flex-col items-center justify-center',
|
||||||
|
},
|
||||||
|
});
|
||||||
@ -6,10 +6,12 @@ import Components from 'unplugin-vue-components/vite';
|
|||||||
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
||||||
import viteCompression from 'vite-plugin-compression';
|
import viteCompression from 'vite-plugin-compression';
|
||||||
import fileRouter from 'unplugin-vue-router/vite';
|
import fileRouter from 'unplugin-vue-router/vite';
|
||||||
|
import UnoCSS from 'unocss/vite';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
|
UnoCSS(),
|
||||||
fileRouter({
|
fileRouter({
|
||||||
routesFolder: 'src/views',
|
routesFolder: 'src/views',
|
||||||
extensions: ['.vue'],
|
extensions: ['.vue'],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user