This commit is contained in:
Lan
2024-11-23 21:50:46 +08:00
parent 9693f3d329
commit a247dd163d
7 changed files with 166 additions and 140 deletions
+21 -13
View File
@@ -45,10 +45,11 @@
id="code"
v-model="code"
type="text"
class="w-full px-4 py-3 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-300 pr-10"
class="w-full px-4 py-3 rounded-lg placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 transition duration-300 pr-10"
:class="[
isDarkMode ? 'bg-gray-700 bg-opacity-50' : 'bg-gray-100',
{ 'ring-2 ring-red-500': error }
{ 'ring-2 ring-red-500': error },
isDarkMode ? 'text-gray-300' : 'text-gray-800'
]"
placeholder="请输入5位取件码"
required
@@ -592,19 +593,26 @@ const showContentPreview = () => {
/* 添加 Markdown 样式 */
:deep(.prose) {
@apply text-left;
text-align: left;
}
:deep(.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6) {
@apply text-indigo-600 dark:text-indigo-400;
:deep(.prose h1),
:deep(.prose h2),
:deep(.prose h3),
:deep(.prose h4),
:deep(.prose h5),
:deep(.prose h6) {
color: rgb(79, 70, 229); /* text-indigo-600 */
}
:deep(.prose a) {
@apply text-blue-600 dark:text-blue-400;
}
:deep(.prose code) {
@apply bg-gray-100 dark:bg-gray-700 rounded px-1;
}
:deep(.prose pre) {
@apply bg-gray-100 dark:bg-gray-700 rounded p-4 overflow-x-auto;
@media (prefers-color-scheme: dark) {
:deep(.prose h1),
:deep(.prose h2),
:deep(.prose h3),
:deep(.prose h4),
:deep(.prose h5),
:deep(.prose h6) {
color: rgb(129, 140, 248); /* text-indigo-400 */
}
}
/* 添加新的宽度类 */
+1 -1
View File
@@ -424,7 +424,7 @@ const selectedFile = ref<File | null>(null)
const textContent = ref('')
const fileInput = ref<HTMLInputElement | null>(null)
const expirationMethod = ref('day')
const expirationValue = ref('')
const expirationValue = ref('1')
const uploadProgress = ref(0)
const showDrawer = ref(false)
const selectedRecord = ref<any>(null)
+136 -120
View File
@@ -11,7 +11,7 @@
<div class="relative flex-1">
<input
type="text"
v-model="fileSearchQuery"
v-model="params.keyword"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white placeholder-gray-400'
@@ -25,53 +25,20 @@
:class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']"
/>
</div>
<select
v-model="fileTypeFilter"
:class="[
isDarkMode
? 'bg-gray-700 border-gray-600 text-white'
: 'bg-white border-gray-300 text-gray-900'
]"
class="border rounded-lg px-4 py-2 focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
>
<option value="">所有类型</option>
<option value="PDF">PDF</option>
<option value="Image">图片</option>
<option value="Video">视频</option>
<option value="Document">文档</option>
</select>
</div>
<!-- 上传按钮 -->
<!-- 搜索按钮 -->
<div class="flex gap-4">
<button
@click="$refs.fileInput.click()"
@click="handleSearch"
class="flex items-center px-4 py-2 rounded-lg bg-indigo-600 text-white hover:bg-indigo-700 transition-colors duration-200"
>
<UploadIcon class="w-5 h-5 mr-2" />
上传文件
<SearchIcon class="w-5 h-5 mr-2" />
搜索
</button>
<input ref="fileInput" type="file" multiple class="hidden" @change="handleFileUpload" />
</div>
</div>
<!-- 拖拽上传区域 -->
<div
v-if="showDropZone"
class="mb-6 border-2 border-dashed rounded-lg p-8 text-center"
:class="[isDarkMode ? 'border-gray-600 bg-gray-800/50' : 'border-gray-300 bg-gray-50']"
@drop.prevent="handleFileDrop"
@dragover.prevent="showDropZone = true"
@dragleave.prevent="showDropZone = false"
>
<UploadCloudIcon
class="mx-auto w-12 h-12 mb-4"
:class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']"
/>
<p :class="[isDarkMode ? 'text-gray-300' : 'text-gray-700']">拖拽文件到此处上传</p>
</div>
<!-- File List -->
<div
class="rounded-lg shadow-md overflow-hidden transition-colors duration-300"
@@ -106,7 +73,14 @@
: 'bg-white divide-y divide-gray-200'
]"
>
<tr v-for="file in files" :key="file.id">
<tr v-for="file in tableData" :key="file.id">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<span class="font-medium" :class="[isDarkMode ? 'text-white' : 'text-gray-900']">
{{ file.code }}
</span>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<FileIcon
@@ -114,28 +88,29 @@
:class="[isDarkMode ? 'text-indigo-400' : 'text-indigo-500']"
/>
<span class="font-medium" :class="[isDarkMode ? 'text-white' : 'text-gray-900']">
{{ file.name }}
{{ file.prefix }}
</span>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span :class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']">
{{ file.size }}
{{ Math.round((file.size / 1024 / 1024) * 100) / 100 }}MB
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span :class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']">
{{ file.type }}
{{ file.text }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span :class="[isDarkMode ? 'text-gray-400' : 'text-gray-500']">
{{ file.lastModified }}
{{ file.expired_at ? formatTimestamp(file.expired_at) : '永久' }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
@click="downloadFile(file)"
<!-- <button
v-if="file.file_path"
@click="downloadFile(file.id)"
class="mr-3 transition-colors duration-200"
:class="[
isDarkMode
@@ -144,9 +119,9 @@
]"
>
下载
</button>
</button> -->
<button
@click="deleteFile(file)"
@click="deleteFile(file.id)"
class="transition-colors duration-200"
:class="[
isDarkMode
@@ -244,75 +219,128 @@
<script setup lang="ts">
import { inject, ref, computed } from 'vue'
import api from '@/utils/api'
import { FileIcon, SearchIcon } from 'lucide-vue-next'
import { useAlertStore } from '@/stores/alertStore'
const alertStore = useAlertStore()
function formatTimestamp(timestamp: string): string {
const date = new Date(timestamp)
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
const seconds = date.getSeconds().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
const isDarkMode = inject('isDarkMode')
const tableData: any = ref([])
// 新增的响应式变量
const fileSearchQuery = ref('')
const fileTypeFilter = ref('')
const showDropZone = ref(false)
const handleFileUpload = (event: Event) => {
const files = (event.target as HTMLInputElement).files
if (files && files.length > 0) {
console.log('Uploading files:', files)
}
}
interface File {
id: number
name: string
size: string
type: string
lastModified: string
}
const fileTableHeaders = ['名称', '大小', '类型', '最后修改', '操作']
const files: File[] = [
{ id: 1, name: 'document.pdf', size: '2.5 MB', type: 'PDF', lastModified: '2024-01-15' },
{ id: 2, name: 'image.jpg', size: '1.8 MB', type: 'Image', lastModified: '2024-01-14' },
{
id: 3,
name: 'spreadsheet.xlsx',
size: '3.2 MB',
type: 'Spreadsheet',
lastModified: '2024-01-13'
},
{
id: 4,
name: 'presentation.pptx',
size: '5.1 MB',
type: 'Presentation',
lastModified: '2024-01-12'
},
{ id: 5, name: 'video.mp4', size: '15.7 MB', type: 'Video', lastModified: '2024-01-11' }
]
const handleFileDrop = (event: any) => {
const files = (event.dataTransfer as DataTransfer).files
if (files && files.length > 0) {
console.log('Dropped files:', files)
}
}
// 修改文件表头
const fileTableHeaders = ['取件码', '名称', '大小', '描述', '过期时间', '操作']
// 分页参数
const params = ref({
page: 1,
size: 10,
total: 0
total: 0,
keyword: ''
})
// 下载文件处理
const downloadFile = async (id: number) => {
try {
const response = await api({
url: '/admin/file/download',
method: 'get',
params: { id },
responseType: 'blob'
})
const contentDisposition = response.headers['content-disposition']
let filename = 'file'
const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
if (filenameMatch != null && filenameMatch[1]) {
filename = filenameMatch[1].replace(/['"]/g, '')
}
// @ts-ignore
if (window.showSaveFilePicker) {
await saveFileByWebApi(response.data, filename)
} else {
await saveFileByElementA(response.data, filename)
}
} catch (error) {
console.error('下载失败:', error)
}
}
// 删除文件处理
const deleteFile = async (id: number) => {
try {
await api({
url: '/admin/file/delete',
method: 'delete',
data: { id }
})
await loadFiles()
} catch (error) {
console.error('删除失败:', error)
}
}
// 文件保存辅助函数
async function saveFileByElementA(fileBlob: Blob, filename: string) {
const downloadUrl = window.URL.createObjectURL(fileBlob)
const link = document.createElement('a')
link.href = downloadUrl
link.download = filename
document.body.appendChild(link)
link.click()
window.URL.revokeObjectURL(downloadUrl)
document.body.removeChild(link)
}
async function saveFileByWebApi(fileBlob: Blob, filename: string) {
// @ts-ignore
const newHandle = await window.showSaveFilePicker({
suggestedName: filename
})
const writableStream = await newHandle.createWritable()
await writableStream.write(fileBlob)
await writableStream.close()
}
// 加载文件列表
const loadFiles = async () => {
try {
const res: any = await api({
url: '/admin/file/list',
method: 'get',
params: params.value
})
tableData.value = res.detail.data
params.value.total = res.detail.total
alertStore.showAlert('加载成功', 'success')
} catch (error) {
console.error('加载文件列表失败:', error)
}
}
// 页码改变处理函数
const handlePageChange = async (page: any) => {
if (page < 1 || page > totalPages.value) return
params.value.page = page
await loadFiles()
}
// 初始加载
loadFiles()
// 计算总页数
const totalPages = computed(() => Math.ceil(params.value.total / params.value.size))
const downloadFile = (file: File) => {
console.log('Downloading file:', file.name)
}
const deleteFile = (file: File) => {
console.log('Deleting file:', file.name)
}
// 计算要显示的页码
const displayedPages = computed(() => {
const current = params.value.page
@@ -349,21 +377,9 @@ const displayedPages = computed(() => {
return pages
})
// 页码改变处理函数
const handlePageChange = async (page: any) => {
if (page < 1 || page > totalPages.value) return
params.value.page = page
await loadFiles() // 重新加载文件列表
}
// 加载文件列表
const loadFiles = async () => {
try {
params.value.total = 85
// 更新文件列表数据...
} catch (error) {
console.error('加载文件列表失败:', error)
// 处理错误...
}
// 添加搜索处理函数
const handleSearch = async () => {
params.value.page = 1 // 重置页码到第一页
await loadFiles()
}
</script>
+4 -2
View File
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { inject, ref } from 'vue'
import api from '@/utils/api'
import { useAlertStore } from '@/stores/alertStore'
const isDarkMode = inject('isDarkMode')
interface ConfigState {
@@ -124,6 +125,7 @@ const refreshData = () => {
}
})
}
const alertStore = useAlertStore()
// 转换文件大小为字节
const convertToBytes = (size: number, unit: string): number => {
const units = {
@@ -151,9 +153,9 @@ const submitSave = () => {
data: formData
}).then((res: any) => {
if (res.code == 200) {
alert('保存成功')
alertStore.showAlert('保存成功', 'success')
} else {
alert(res.message)
alertStore.showAlert(res.message, 'error')
}
})
}