2025-07-10 13:58:28 +08:00
|
|
|
|
<template>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-100 p-3 sm:p-5">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<div class="max-w-7xl mx-auto">
|
|
|
|
|
|
<!-- 头部 -->
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div class="bg-slate-800 dark:bg-gray-800 text-white dark:text-gray-100 rounded-lg shadow-lg p-4 sm:p-8 mb-4 sm:mb-8 text-center">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<h1 class="text-2xl sm:text-3xl font-bold mb-4">
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<NuxtLink to="/" class="text-white hover:text-gray-200 dark:hover:text-gray-300 no-underline">网盘资源管理系统</NuxtLink>
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</h1>
|
|
|
|
|
|
<nav class="mt-4 flex flex-col sm:flex-row justify-center gap-2 sm:gap-4">
|
|
|
|
|
|
<NuxtLink
|
2025-07-11 00:49:41 +08:00
|
|
|
|
to="/admin"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
class="w-full sm:w-auto px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-md transition-colors text-center flex items-center justify-center gap-2"
|
|
|
|
|
|
>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<i class="fas fa-arrow-left"></i> 返回
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</NuxtLink>
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="showAddModal = true"
|
|
|
|
|
|
class="w-full sm:w-auto px-4 py-2 bg-green-600 hover:bg-green-700 rounded-md transition-colors text-center flex items-center justify-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<i class="fas fa-plus"></i> 批量添加
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 批量添加模态框 -->
|
|
|
|
|
|
<div v-if="showAddModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div class="bg-white dark:bg-gray-900 rounded-lg shadow-xl p-6 max-w-4xl w-full mx-4 max-h-[90vh] overflow-y-auto text-gray-900 dark:text-gray-100">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<div class="flex justify-between items-center mb-4">
|
|
|
|
|
|
<h3 class="text-lg font-bold">批量添加待处理资源</h3>
|
|
|
|
|
|
<button @click="closeModal" class="text-gray-500 hover:text-gray-800">
|
|
|
|
|
|
<i class="fas fa-times"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">输入格式说明:</label>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded text-sm text-gray-600 dark:text-gray-300 mb-4">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<p class="mb-2"><strong>格式1:</strong>标题和URL两行一组</p>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<pre class="bg-white dark:bg-gray-800 p-2 rounded border text-xs">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
电影标题1
|
|
|
|
|
|
https://pan.baidu.com/s/123456
|
|
|
|
|
|
电影标题2
|
|
|
|
|
|
https://pan.baidu.com/s/789012</pre>
|
|
|
|
|
|
<p class="mt-2 mb-2"><strong>格式2:</strong>只有URL,系统自动判断</p>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<pre class="bg-white dark:bg-gray-800 p-2 rounded border text-xs">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
https://pan.baidu.com/s/123456
|
|
|
|
|
|
https://pan.baidu.com/s/789012
|
|
|
|
|
|
https://pan.baidu.com/s/345678</pre>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-4">
|
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">资源内容:</label>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
v-model="resourceText"
|
|
|
|
|
|
rows="15"
|
2025-07-11 00:49:41 +08:00
|
|
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-900 dark:text-gray-100 dark:placeholder-gray-500"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
placeholder="请输入资源内容,支持两种格式..."
|
|
|
|
|
|
></textarea>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="flex justify-end gap-2">
|
|
|
|
|
|
<button @click="closeModal" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
|
|
|
|
|
|
取消
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button @click="handleBatchAdd" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
|
|
|
|
|
|
批量添加
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 操作按钮 -->
|
|
|
|
|
|
<div class="flex justify-between items-center mb-4">
|
|
|
|
|
|
<h2 class="text-xl font-semibold text-gray-900">待处理资源管理</h2>
|
|
|
|
|
|
<div class="flex gap-2">
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="refreshData"
|
|
|
|
|
|
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<i class="fas fa-refresh"></i> 刷新
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="clearAll"
|
|
|
|
|
|
class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 flex items-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<i class="fas fa-trash"></i> 清空全部
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 资源列表 -->
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow overflow-hidden">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
|
<table class="w-full">
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<thead class="bg-slate-800 dark:bg-gray-700 text-white dark:text-gray-100 sticky top-0 z-10">
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">ID</th>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">标题</th>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">URL</th>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">创建时间</th>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">IP地址</th>
|
|
|
|
|
|
<th class="px-4 py-3 text-left text-sm font-medium">操作</th>
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<tbody class="divide-y divide-gray-200 dark:divide-gray-700 max-h-96 overflow-y-auto">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<tr v-if="loading" class="text-center py-8">
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<td colspan="6" class="text-gray-500 dark:text-gray-400">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<i class="fas fa-spinner fa-spin mr-2"></i>加载中...
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<tr v-else-if="readyResources.length === 0">
|
|
|
|
|
|
<td colspan="6">
|
|
|
|
|
|
<div class="flex flex-col items-center justify-center py-12">
|
|
|
|
|
|
<svg class="w-16 h-16 text-gray-300 dark:text-gray-600 mb-4" fill="none" stroke="currentColor" viewBox="0 0 48 48">
|
|
|
|
|
|
<circle cx="24" cy="24" r="20" stroke-width="3" stroke-dasharray="6 6" />
|
|
|
|
|
|
<path d="M16 24h16M24 16v16" stroke-width="3" stroke-linecap="round" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="text-lg font-semibold text-gray-400 dark:text-gray-500 mb-2">暂无待处理资源</div>
|
|
|
|
|
|
<div class="text-sm text-gray-400 dark:text-gray-600">你可以点击上方"批量添加"按钮快速导入资源</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</td>
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</tr>
|
|
|
|
|
|
<tr
|
|
|
|
|
|
v-for="resource in readyResources"
|
|
|
|
|
|
:key="resource.id"
|
2025-07-11 00:49:41 +08:00
|
|
|
|
class="hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<td class="px-4 py-3 text-sm text-gray-900 dark:text-gray-100 font-medium">{{ resource.id }}</td>
|
|
|
|
|
|
<td class="px-4 py-3 text-sm text-gray-900 dark:text-gray-100">
|
|
|
|
|
|
<span v-if="resource.title" :title="resource.title">{{ escapeHtml(resource.title) }}</span>
|
|
|
|
|
|
<span v-else class="text-gray-400 dark:text-gray-500 italic">未设置</span>
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</td>
|
|
|
|
|
|
<td class="px-4 py-3 text-sm">
|
|
|
|
|
|
<a
|
2025-07-11 00:49:41 +08:00
|
|
|
|
:href="checkUrlSafety(resource.url)"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
target="_blank"
|
2025-07-11 00:49:41 +08:00
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
|
|
class="text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:underline break-all"
|
|
|
|
|
|
:title="resource.url"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
{{ escapeHtml(resource.url) }}
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</a>
|
|
|
|
|
|
</td>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
2025-07-10 13:58:28 +08:00
|
|
|
|
{{ formatTime(resource.create_time) }}
|
|
|
|
|
|
</td>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
|
|
|
|
|
{{ escapeHtml(resource.ip || '-') }}
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</td>
|
|
|
|
|
|
<td class="px-4 py-3 text-sm">
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="deleteResource(resource.id)"
|
2025-07-11 00:49:41 +08:00
|
|
|
|
class="text-red-600 hover:text-red-800 dark:text-red-400 dark:hover:text-red-300 transition-colors"
|
|
|
|
|
|
title="删除此资源"
|
2025-07-10 13:58:28 +08:00
|
|
|
|
>
|
|
|
|
|
|
<i class="fas fa-trash"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<!-- 分页组件 -->
|
|
|
|
|
|
<div v-if="totalPages > 1" class="mt-6 flex justify-center">
|
|
|
|
|
|
<div class="flex items-center space-x-4 bg-white dark:bg-gray-800 rounded-lg shadow-lg p-4">
|
|
|
|
|
|
<!-- 总资源数 -->
|
|
|
|
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
|
|
|
|
共 <span class="font-semibold text-gray-900 dark:text-gray-100">{{ totalCount }}</span> 个待处理资源
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="w-px h-6 bg-gray-300 dark:bg-gray-600"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 上一页 -->
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="goToPage(currentPage - 1)"
|
|
|
|
|
|
:disabled="currentPage <= 1"
|
|
|
|
|
|
class="px-4 py-2 text-sm font-medium text-gray-500 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 flex items-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<i class="fas fa-chevron-left"></i>
|
|
|
|
|
|
<span>上一页</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 页码 -->
|
|
|
|
|
|
<template v-for="page in visiblePages" :key="page">
|
|
|
|
|
|
<button
|
|
|
|
|
|
v-if="typeof page === 'number'"
|
|
|
|
|
|
@click="goToPage(page)"
|
|
|
|
|
|
:class="[
|
|
|
|
|
|
'px-4 py-2 text-sm font-medium rounded-md transition-all duration-200 min-w-[40px]',
|
|
|
|
|
|
page === currentPage
|
|
|
|
|
|
? 'bg-blue-600 text-white shadow-md'
|
|
|
|
|
|
: 'text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 hover:bg-gray-200 dark:hover:bg-gray-600'
|
|
|
|
|
|
]"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ page }}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<span v-else class="px-3 py-2 text-sm text-gray-500">...</span>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 下一页 -->
|
|
|
|
|
|
<button
|
|
|
|
|
|
@click="goToPage(currentPage + 1)"
|
|
|
|
|
|
:disabled="currentPage >= totalPages"
|
|
|
|
|
|
class="px-4 py-2 text-sm font-medium text-gray-500 bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-md hover:bg-gray-200 dark:hover:bg-gray-600 disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-200 flex items-center gap-2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<span>下一页</span>
|
|
|
|
|
|
<i class="fas fa-chevron-right"></i>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-07-10 13:58:28 +08:00
|
|
|
|
<!-- 统计信息 -->
|
2025-07-11 00:49:41 +08:00
|
|
|
|
<div v-if="totalPages <= 1" class="mt-4 text-center">
|
|
|
|
|
|
<div class="inline-flex items-center bg-white dark:bg-gray-800 rounded-lg shadow px-6 py-3">
|
|
|
|
|
|
<div class="text-sm text-gray-600 dark:text-gray-400">
|
|
|
|
|
|
共 <span class="font-semibold text-gray-900 dark:text-gray-100">{{ totalCount }}</span> 个待处理资源
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
interface ReadyResource {
|
|
|
|
|
|
id: number
|
|
|
|
|
|
title?: string
|
|
|
|
|
|
url: string
|
|
|
|
|
|
create_time: string
|
|
|
|
|
|
ip?: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const readyResources = ref<ReadyResource[]>([])
|
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
|
const showAddModal = ref(false)
|
|
|
|
|
|
const resourceText = ref('')
|
|
|
|
|
|
|
2025-07-11 00:49:41 +08:00
|
|
|
|
// 分页相关状态
|
|
|
|
|
|
const currentPage = ref(1)
|
|
|
|
|
|
const pageSize = ref(100)
|
|
|
|
|
|
const totalCount = ref(0)
|
|
|
|
|
|
const totalPages = ref(0)
|
|
|
|
|
|
|
2025-07-10 13:58:28 +08:00
|
|
|
|
// 获取待处理资源API
|
|
|
|
|
|
const { useReadyResourceApi } = await import('~/composables/useApi')
|
|
|
|
|
|
const readyResourceApi = useReadyResourceApi()
|
|
|
|
|
|
|
|
|
|
|
|
// 获取数据
|
|
|
|
|
|
const fetchData = async () => {
|
|
|
|
|
|
loading.value = true
|
|
|
|
|
|
try {
|
2025-07-11 00:49:41 +08:00
|
|
|
|
const response = await readyResourceApi.getReadyResources({
|
|
|
|
|
|
page: currentPage.value,
|
|
|
|
|
|
page_size: pageSize.value
|
|
|
|
|
|
}) as any
|
|
|
|
|
|
|
|
|
|
|
|
// 使用标准化的接口返回格式
|
|
|
|
|
|
readyResources.value = response.data
|
|
|
|
|
|
totalCount.value = response.pagination.total
|
|
|
|
|
|
totalPages.value = response.pagination.total_pages
|
2025-07-10 13:58:28 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('获取待处理资源失败:', error)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-11 00:49:41 +08:00
|
|
|
|
// 跳转到指定页面
|
|
|
|
|
|
const goToPage = (page: number) => {
|
|
|
|
|
|
if (page >= 1 && page <= totalPages.value) {
|
|
|
|
|
|
currentPage.value = page
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算可见的页码
|
|
|
|
|
|
const visiblePages = computed(() => {
|
|
|
|
|
|
const pages: (number | string)[] = []
|
|
|
|
|
|
const maxVisible = 5
|
|
|
|
|
|
|
|
|
|
|
|
if (totalPages.value <= maxVisible) {
|
|
|
|
|
|
// 如果总页数不多,显示所有页码
|
|
|
|
|
|
for (let i = 1; i <= totalPages.value; i++) {
|
|
|
|
|
|
pages.push(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果总页数很多,显示部分页码
|
|
|
|
|
|
if (currentPage.value <= 3) {
|
|
|
|
|
|
// 当前页在前几页
|
|
|
|
|
|
for (let i = 1; i <= 4; i++) {
|
|
|
|
|
|
pages.push(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
pages.push('...')
|
|
|
|
|
|
pages.push(totalPages.value)
|
|
|
|
|
|
} else if (currentPage.value >= totalPages.value - 2) {
|
|
|
|
|
|
// 当前页在后几页
|
|
|
|
|
|
pages.push(1)
|
|
|
|
|
|
pages.push('...')
|
|
|
|
|
|
for (let i = totalPages.value - 3; i <= totalPages.value; i++) {
|
|
|
|
|
|
pages.push(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 当前页在中间
|
|
|
|
|
|
pages.push(1)
|
|
|
|
|
|
pages.push('...')
|
|
|
|
|
|
for (let i = currentPage.value - 1; i <= currentPage.value + 1; i++) {
|
|
|
|
|
|
pages.push(i)
|
|
|
|
|
|
}
|
|
|
|
|
|
pages.push('...')
|
|
|
|
|
|
pages.push(totalPages.value)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return pages
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-07-10 13:58:28 +08:00
|
|
|
|
// 刷新数据
|
|
|
|
|
|
const refreshData = () => {
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭模态框
|
|
|
|
|
|
const closeModal = () => {
|
|
|
|
|
|
showAddModal.value = false
|
|
|
|
|
|
resourceText.value = ''
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 批量添加
|
|
|
|
|
|
const handleBatchAdd = async () => {
|
|
|
|
|
|
if (!resourceText.value.trim()) {
|
|
|
|
|
|
alert('请输入资源内容')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await readyResourceApi.createReadyResourcesFromText(resourceText.value) as any
|
|
|
|
|
|
console.log('批量添加成功:', response)
|
|
|
|
|
|
closeModal()
|
|
|
|
|
|
fetchData()
|
2025-07-11 00:49:41 +08:00
|
|
|
|
alert(`成功添加 ${response.data.count} 个资源`)
|
2025-07-10 13:58:28 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('批量添加失败:', error)
|
|
|
|
|
|
alert('批量添加失败,请检查输入格式')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除资源
|
|
|
|
|
|
const deleteResource = async (id: number) => {
|
|
|
|
|
|
if (!confirm('确定要删除这个待处理资源吗?')) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
await readyResourceApi.deleteReadyResource(id)
|
2025-07-11 00:49:41 +08:00
|
|
|
|
// 如果当前页没有数据了,回到上一页
|
|
|
|
|
|
if (readyResources.value.length === 1 && currentPage.value > 1) {
|
|
|
|
|
|
currentPage.value--
|
|
|
|
|
|
}
|
2025-07-10 13:58:28 +08:00
|
|
|
|
fetchData()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('删除失败:', error)
|
|
|
|
|
|
alert('删除失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清空全部
|
|
|
|
|
|
const clearAll = async () => {
|
|
|
|
|
|
if (!confirm('确定要清空所有待处理资源吗?此操作不可恢复!')) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await readyResourceApi.clearReadyResources() as any
|
|
|
|
|
|
console.log('清空成功:', response)
|
2025-07-11 00:49:41 +08:00
|
|
|
|
currentPage.value = 1 // 清空后回到第一页
|
2025-07-10 13:58:28 +08:00
|
|
|
|
fetchData()
|
2025-07-11 00:49:41 +08:00
|
|
|
|
alert(`成功清空 ${response.data.deleted_count} 个资源`)
|
2025-07-10 13:58:28 +08:00
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('清空失败:', error)
|
|
|
|
|
|
alert('清空失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化时间
|
|
|
|
|
|
const formatTime = (timeString: string) => {
|
|
|
|
|
|
const date = new Date(timeString)
|
|
|
|
|
|
return date.toLocaleString('zh-CN')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-11 00:49:41 +08:00
|
|
|
|
// 转义HTML防止XSS
|
|
|
|
|
|
const escapeHtml = (text: string) => {
|
|
|
|
|
|
if (!text) return text
|
|
|
|
|
|
const div = document.createElement('div')
|
|
|
|
|
|
div.textContent = text
|
|
|
|
|
|
return div.innerHTML
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证URL安全性
|
|
|
|
|
|
const checkUrlSafety = (url: string) => {
|
|
|
|
|
|
if (!url) return '#'
|
|
|
|
|
|
try {
|
|
|
|
|
|
const urlObj = new URL(url)
|
|
|
|
|
|
// 只允许http和https协议
|
|
|
|
|
|
if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:') {
|
|
|
|
|
|
return '#'
|
|
|
|
|
|
}
|
|
|
|
|
|
return url
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
return '#'
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-10 13:58:28 +08:00
|
|
|
|
// 页面加载时获取数据
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
fetchData()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2025-07-11 00:49:41 +08:00
|
|
|
|
/* 表格滚动样式 */
|
|
|
|
|
|
.overflow-x-auto {
|
|
|
|
|
|
max-height: 500px;
|
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表格头部固定 */
|
|
|
|
|
|
thead {
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 分页按钮悬停效果 */
|
|
|
|
|
|
.pagination-button:hover {
|
|
|
|
|
|
transform: translateY(-1px);
|
|
|
|
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 当前页码按钮效果 */
|
|
|
|
|
|
.current-page {
|
|
|
|
|
|
box-shadow: 0 4px 6px -1px rgba(59, 130, 246, 0.3), 0 2px 4px -1px rgba(59, 130, 246, 0.2);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 表格行悬停效果 */
|
|
|
|
|
|
tbody tr:hover {
|
|
|
|
|
|
background-color: rgba(59, 130, 246, 0.05);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 暗黑模式下的表格行悬停 */
|
|
|
|
|
|
.dark tbody tr:hover {
|
|
|
|
|
|
background-color: rgba(59, 130, 246, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 统计信息卡片效果 */
|
|
|
|
|
|
.stats-card {
|
|
|
|
|
|
backdrop-filter: blur(10px);
|
|
|
|
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.dark .stats-card {
|
|
|
|
|
|
background-color: rgba(31, 41, 55, 0.9);
|
|
|
|
|
|
}
|
2025-07-10 13:58:28 +08:00
|
|
|
|
</style>
|