fix:some bug

This commit is contained in:
Lan
2024-11-25 18:30:14 +08:00
parent a247dd163d
commit 007291a2d9
10 changed files with 239 additions and 87 deletions
-8
View File
@@ -100,14 +100,6 @@ provide('isLoading', isLoading)
transition: background-color 0.5s ease;
}
.light {
@apply bg-gradient-to-br from-blue-50 via-indigo-50 to-white;
}
.dark {
@apply bg-gradient-to-br from-gray-900 via-indigo-900 to-black;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
+2 -9
View File
@@ -98,7 +98,7 @@
<script setup>
import { FileIcon, CalendarIcon, ClockIcon, KeyIcon, XIcon } from 'lucide-vue-next'
import QRCode from 'qrcode.vue'
import { useAlertStore } from '@/stores/alertStore'
import { copyToClipboard } from '@/utils/clipboard'
const props = defineProps({
record: Object,
@@ -106,17 +106,10 @@ const props = defineProps({
baseUrl: String
})
const alertStore = useAlertStore()
defineEmits(['close', 'show-preview'])
const copyShareLink = async () => {
try {
await navigator.clipboard.writeText(`${props.baseUrl}/retrieve/${props.record.code}`)
alertStore.showAlert('链接已复制到剪贴板', 'success')
} catch (err) {
alertStore.showAlert('复制失败,请手动复制', 'error')
}
copyToClipboard(`${props.baseUrl}/retrieve/${props.record.code}`)
}
</script>
+33
View File
@@ -236,4 +236,37 @@ input:checked + .slider {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 300ms;
}
.custom-scrollbar {
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: #cbd5e0;
border-radius: 4px;
&:hover {
background-color: #a0aec0;
}
}
/* 适配暗黑模式 */
:deep(.dark &::-webkit-scrollbar-thumb) {
background-color: #4a5568;
&:hover {
background-color: #2d3748;
}
}
}
/* 确保内容区域不会被截断 */
.space-y-6 {
margin-bottom: 5rem;
}
</style>
+1 -2
View File
@@ -1,5 +1,4 @@
import axios from 'axios'
import { useRouter } from 'vue-router'
// 从环境变量中获取 API 基础 URL
const baseURL =
@@ -13,7 +12,7 @@ const sanitizedBaseURL = typeof baseURL === 'string' ? baseURL : ''
// 创建 axios 实例
const api = axios.create({
baseURL: sanitizedBaseURL,
timeout: 10000, // 请求超时时间
timeout: 1000000000000000, // 请求超时时间
headers: {
'Content-Type': 'application/json'
}
+81
View File
@@ -0,0 +1,81 @@
/**
* 剪贴板工具函数
*/
import { useAlertStore } from '@/stores/alertStore'
interface CopyOptions {
successMsg?: string
errorMsg?: string
showMsg?: boolean
}
/**
* 复制文本到剪贴板
* @param text 要复制的文本
* @param options 配置选项
* @returns Promise<boolean> 是否复制成功
*/
export const copyToClipboard = async (
text: string,
options: CopyOptions = {}
): Promise<boolean> => {
const { successMsg = '复制成功', errorMsg = '复制失败,请手动复制', showMsg = true } = options
const alertStore = useAlertStore()
try {
// 优先使用 Clipboard API
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(text)
if (showMsg) alertStore.showAlert(successMsg, 'success')
return true
}
// 后备方案:使用传统的复制方法
const textarea = document.createElement('textarea')
textarea.value = text
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
const success = document.execCommand('copy')
document.body.removeChild(textarea)
if (success) {
if (showMsg) alertStore.showAlert(successMsg, 'success')
return true
} else {
throw new Error('execCommand copy failed')
}
} catch (err) {
console.error('复制失败:', err)
if (showMsg) alertStore.showAlert(errorMsg, 'error')
return false
}
}
/**
* 生成并复制取件链接
* @param code 取件码
* @returns Promise<boolean> 是否复制成功
*/
export const copyRetrieveLink = async (code: string): Promise<boolean> => {
const link = `${window.location.origin}/#/?code=${code}`
return copyToClipboard(link, {
successMsg: '取件链接已复制到剪贴板',
errorMsg: '复制失败,请手动复制取件链接'
})
}
/**
* 复制取件码
* @param code 取件码
* @returns Promise<boolean> 是否复制成功
*/
export const copyRetrieveCode = async (code: string): Promise<boolean> => {
return copyToClipboard(code, {
successMsg: '取件码已复制到剪贴板',
errorMsg: '复制失败,请手动复制取件码'
})
}
+10
View File
@@ -0,0 +1,10 @@
// 存储单位转换
export const getStorageUnit = (value: number) => {
if (value >= 1024 * 1024 * 1024) {
return Math.round(value / (1024 * 1024 * 1024)) + 'GB'
} else if (value >= 1024 * 1024) {
return Math.round(value / (1024 * 1024)) + 'MB'
} else {
return Math.round(value / 1024) + 'KB'
}
}
+13 -31
View File
@@ -92,7 +92,7 @@
</span>
</p>
<p :class="['mt-2 text-xs', isDarkMode ? 'text-gray-500' : 'text-gray-400']">
支持各种常见格式最大20MB
支持各种常见格式最大{{ getStorageUnit(config.uploadSize) }}
</p>
</div>
</div>
@@ -128,11 +128,9 @@
: 'bg-white text-gray-900 border border-gray-300'
]"
>
<option value="day">按天数</option>
<option value="hour">按小时</option>
<option value="minute">按分钟</option>
<option value="count">按查看次数</option>
<option value="forever">永久</option>
<option v-for="item in config.expireStyle" :value="item" :key="item">
{{ getUnit(item) }}
</option>
</select>
<div v-if="expirationMethod !== 'forever'" class="flex items-center space-x-2">
<div class="relative flex-grow">
@@ -414,6 +412,11 @@ import QRCode from 'qrcode.vue'
import SparkMD5 from 'spark-md5'
import { useFileDataStore } from '../stores/fileData'
import api from '@/utils/api'
import { copyRetrieveLink, copyRetrieveCode } from '@/utils/clipboard'
import { getStorageUnit } from '@/utils/convert'
const config: any = JSON.parse(localStorage.getItem('config') || '{}')
console.log(config)
const router = useRouter()
const isDarkMode = inject('isDarkMode')
@@ -549,8 +552,8 @@ const mergeChunks = async (fileHash: string, totalChunks: number) => {
console.log(`请求合并文件切片, fileHash: ${fileHash}, totalChunks: ${totalChunks}`)
}
const getPlaceholder = () => {
switch (expirationMethod.value) {
const getPlaceholder = (value: string = expirationMethod.value) => {
switch (value) {
case 'day':
return '输入天数'
case 'hour':
@@ -566,8 +569,8 @@ const getPlaceholder = () => {
}
}
const getUnit = () => {
switch (expirationMethod.value) {
const getUnit = (value: string = expirationMethod.value) => {
switch (value) {
case 'day':
return '天'
case 'hour':
@@ -703,27 +706,6 @@ const getQRCodeValue = (record: any) => {
return `${baseUrl}/?code=${record.retrieveCode}`
}
const copyRetrieveCode = async (code: string) => {
try {
await navigator.clipboard.writeText(code)
alertStore.showAlert('取件码已复制到剪贴板', 'success')
} catch (err) {
console.error('无法复制取件码: ', err)
alertStore.showAlert('复制失败,请手动复制取件码', 'error')
}
}
const copyRetrieveLink = async (code: string) => {
const link = `${baseUrl}/?code=${code}`
try {
await navigator.clipboard.writeText(link)
alertStore.showAlert('取件链接已复制到剪贴板', 'success')
} catch (err) {
console.error('无法复制取件链接: ', err)
alertStore.showAlert('复制失败,请动复制取件链接', 'error')
}
}
// 使用 onMounted 钩子延迟加载一些非关键资源或初始化
onMounted(() => {
// 这里可以放置一些非立即需要的初始化代码
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div>
<div class="p-6 h-screen overflow-y-auto custom-scrollbar">
<h2 class="text-2xl font-bold mb-6" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
仪表盘
</h2>
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div>
<div class="p-6 h-screen overflow-y-auto custom-scrollbar">
<h2 class="text-2xl font-bold mb-6" :class="[isDarkMode ? 'text-white' : 'text-gray-800']">
文件管理
</h2>
+97 -35
View File
@@ -33,6 +33,7 @@ interface ConfigState {
uploadCount: number
errorMinute: number
errorCount: number
s3_proxy: number
}
const config = ref<ConfigState>({
@@ -63,7 +64,8 @@ const config = ref<ConfigState>({
s3_hostname: '',
uploadCount: 1,
errorMinute: 1,
errorCount: 1
errorCount: 1,
s3_proxy: 0
})
const fileSize = ref(1)
@@ -439,6 +441,99 @@ refreshData()
]"
/>
</div>
<div class="space-y-2">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
S3 Region Name
</label>
<input
type="text"
v-model="config.s3_region_name"
placeholder="auto"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]"
/>
</div>
<div class="space-y-2">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
S3 Signature Version
</label>
<select
v-model="config.s3_signature_version"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400'
]"
>
<option value="s3v2">S3v2</option>
<option value="s3v4">S3v4</option>
</select>
</div>
<div class="space-y-2">
<label
class="block text-sm font-medium"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
S3 Hostname
</label>
<input
type="text"
v-model="config.s3_hostname"
class="w-full rounded-md shadow-sm px-4 py-2.5 transition-all duration-200 ease-in-out border focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400 hover:border-gray-500'
: 'border-gray-300 hover:border-gray-400 placeholder-gray-500'
]"
/>
</div>
<div class="space-y-2">
<label
class="block text-sm font-medium mb-2"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
启用代理
</label>
<div class="flex items-center">
<button
type="button"
@click="config.s3_proxy = config.s3_proxy === 1 ? 0 : 1"
class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
:class="[config.s3_proxy === 1 ? 'bg-indigo-600' : 'bg-gray-200']"
role="switch"
:aria-checked="config.s3_proxy === 1"
>
<span
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
:class="[
config.s3_proxy === 1 ? 'translate-x-5' : 'translate-x-0',
isDarkMode && config.s3_proxy !== 1 ? 'bg-gray-100' : 'bg-white'
]"
/>
</button>
<span
class="ml-3 text-sm"
:class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']"
>
{{ config.s3_proxy === 1 ? '已开启' : '已关闭' }}
</span>
</div>
</div>
</div>
</div>
</div>
@@ -716,37 +811,4 @@ refreshData()
</div>
</div>
</template>
<style scoped>
.custom-scrollbar {
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: #cbd5e0;
border-radius: 4px;
&:hover {
background-color: #a0aec0;
}
}
/* 适配暗黑模式 */
:deep(.dark &::-webkit-scrollbar-thumb) {
background-color: #4a5568;
&:hover {
background-color: #2d3748;
}
}
}
/* 确保内容区域不会被截断 */
.space-y-6 {
margin-bottom: 5rem;
}
</style>
<style scoped></style>