first commit

This commit is contained in:
2025-04-17 00:03:17 +08:00
commit 349a4538b1
19 changed files with 4730 additions and 0 deletions

51
src/App.vue Normal file
View File

@@ -0,0 +1,51 @@
<template>
<div class="min-h-screen flex flex-col">
<header class="bg-white shadow-sm dark:bg-gray-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center">
<h1 class="text-2xl font-bold text-primary-600">{{ siteName }}</h1>
</div>
<div class="flex items-center space-x-4">
<button @click="toggleDarkMode" class="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700">
<svg v-if="isDark" class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
<svg v-else class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
</svg>
</button>
</div>
</div>
</div>
</header>
<main class="flex-grow">
<router-view />
</main>
<footer class="bg-white dark:bg-gray-800">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<p class="text-center text-gray-500 dark:text-gray-400">
&copy; {{ new Date().getFullYear() }} {{ siteName }}. All rights reserved.
</p>
</div>
</footer>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useDark, useToggle } from '@vueuse/core'
const siteName = '绝绝子网盘搜索'
const isDark = useDark()
const toggleDarkMode = useToggle(isDark)
onMounted(() => {
// 初始化主题
if (localStorage.getItem('darkMode') === 'true') {
document.documentElement.classList.add('dark')
}
})
</script>

35
src/assets/main.css Normal file
View File

@@ -0,0 +1,35 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
html {
@apply antialiased;
}
body {
@apply bg-gray-50 text-gray-900 dark:bg-gray-900 dark:text-gray-100;
}
}
@layer components {
.btn {
@apply px-4 py-2 rounded-md font-medium transition-colors duration-200;
}
.btn-primary {
@apply bg-primary-600 text-white hover:bg-primary-700;
}
.btn-secondary {
@apply bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600;
}
.input {
@apply w-full px-4 py-2 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent dark:bg-gray-800 dark:border-gray-700;
}
.card {
@apply bg-white rounded-lg shadow-md p-6 dark:bg-gray-800;
}
}

13
src/config/index.js Normal file
View File

@@ -0,0 +1,13 @@
export const config = {
// 网站配置
siteName: '绝绝子网盘搜索',
siteDescription: '专注于收录全网云盘资源,支持七大网盘搜索',
siteKeywords: '网盘搜索,百度网盘搜索,阿里云盘搜索,夸克网盘搜索,资源搜索',
// API配置
api: {
search: '/opensearch.php',
data: '/opendata.php',
dataEntry: '/opendataentry.php'
}
}

12
src/main.js Normal file
View File

@@ -0,0 +1,12 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import './assets/main.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

41
src/router/index.js Normal file
View File

@@ -0,0 +1,41 @@
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
title: '绝绝子网盘搜索 - 专注网盘资源搜索'
}
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue'),
meta: {
title: '关于我们 - 绝绝子网盘搜索'
}
}
]
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
}
})
// 设置页面标题
router.beforeEach((to, from, next) => {
document.title = to.meta.title || '绝绝子网盘搜索'
next()
})
export default router

44
src/utils/axios.js Normal file
View File

@@ -0,0 +1,44 @@
import axios from 'axios'
import { config } from '../config'
// 创建 axios 实例
const instance = axios.create({
baseURL: '/api',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
})
// 请求拦截器
instance.interceptors.request.use(
config => {
// 添加时间戳防止缓存
if (config.method === 'get') {
config.params = {
...config.params,
_t: new Date().getTime()
}
}
return config
},
error => {
console.error('Request error:', error)
return Promise.reject(error)
}
)
// 响应拦截器
instance.interceptors.response.use(
response => {
return response
},
error => {
console.error('Response error:', error)
return Promise.reject(error)
}
)
export default instance

55
src/views/About.vue Normal file
View File

@@ -0,0 +1,55 @@
<template>
<div class="container mx-auto px-4 py-8">
<div class="max-w-3xl mx-auto">
<div class="card">
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-6">关于我们</h1>
<div class="prose dark:prose-invert max-w-none">
<p class="mb-4">
绝绝子网盘搜索是一个专注于网盘资源搜索的平台致力于为用户提供快速准确的网盘资源搜索服务
</p>
<h2 class="text-xl font-semibold mt-8 mb-4">支持网盘</h2>
<ul class="list-disc pl-6 mb-6">
<li>阿里云盘</li>
<li>夸克网盘</li>
<li>百度网盘</li>
<li>迅雷网盘</li>
<li>天翼云盘</li>
<li>蓝奏云</li>
<li>其他主流网盘</li>
</ul>
<h2 class="text-xl font-semibold mt-8 mb-4">使用说明</h2>
<ol class="list-decimal pl-6 mb-6">
<li>在搜索框输入关键词</li>
<li>点击搜索按钮或按回车键</li>
<li>查看搜索结果</li>
<li>点击"查看资源"按钮访问网盘链接</li>
</ol>
<h2 class="text-xl font-semibold mt-8 mb-4">注意事项</h2>
<ul class="list-disc pl-6 mb-6">
<li>请遵守相关法律法规合理使用搜索服务</li>
<li>部分资源可能需要提取码请仔细查看</li>
<li>资源链接有效性由资源提供者负责</li>
<li>如发现违规内容请联系我们处理</li>
</ul>
<h2 class="text-xl font-semibold mt-8 mb-4">联系我们</h2>
<p class="mb-4">
如果您有任何问题或建议欢迎通过以下方式联系我们
</p>
<ul class="list-disc pl-6">
<li>邮箱support@juejuezi.cc</li>
<li>反馈通过网站底部的反馈按钮</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup>
// 页面逻辑
</script>

228
src/views/Home.vue Normal file
View File

@@ -0,0 +1,228 @@
<template>
<div class="container mx-auto px-4 py-8">
<div class="max-w-4xl mx-auto">
<!-- Logo 和标题区域 -->
<div class="text-center mb-12">
<div class="flex items-center justify-center mb-6">
<svg class="w-12 h-12 text-primary-600 mr-4" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 6.5C4 5.67157 4.67157 5 5.5 5H18.5C19.3284 5 20 5.67157 20 6.5V17.5C20 18.3284 19.3284 19 18.5 19H5.5C4.67157 19 4 18.3284 4 17.5V6.5Z" stroke="currentColor" stroke-width="2"/>
<path d="M8 12H16M8 15H13" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M8 9H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>
<h1 class="text-4xl md:text-5xl font-bold bg-gradient-to-r from-primary-600 to-primary-400 bg-clip-text text-transparent">
{{ config.siteName }}
</h1>
</div>
<p class="text-lg text-gray-600 mb-2">
{{ config.siteDescription }}
</p>
<p class="text-sm text-gray-500">
已收录 10000000+ 网盘资源免费分享
</p>
</div>
<!-- 搜索框区域 -->
<div class="card mb-8 border-2 border-primary-100">
<div class="relative">
<input
v-model="searchQuery"
type="text"
class="input pr-24 text-lg h-14"
placeholder="输入关键词搜索资源..."
@keyup.enter="handleSearch"
/>
<button
@click="handleSearch"
class="absolute right-2 top-1/2 transform -translate-y-1/2 btn btn-primary h-10 flex items-center"
:disabled="loading"
>
<svg v-if="loading" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>{{ loading ? '搜索中' : '搜索' }}</span>
</button>
</div>
</div>
<!-- 快捷分类标签 -->
<div class="mb-8">
<div class="flex flex-wrap gap-2 justify-center">
<button
v-for="tag in quickTags"
:key="tag"
@click="quickSearch(tag)"
class="px-3 py-1 rounded-full text-sm bg-gray-100 hover:bg-primary-100 text-gray-600 hover:text-primary-600 transition-colors duration-200"
>
{{ tag }}
</button>
</div>
</div>
<!-- 错误提示 -->
<div v-if="error" class="card mb-8 bg-red-50">
<div class="text-red-600">
{{ error }}
</div>
</div>
<!-- 加载动画 -->
<div v-if="loading" class="text-center py-12">
<div class="inline-flex items-center px-4 py-2 font-semibold leading-6 text-primary-600 transition ease-in-out duration-150 cursor-not-allowed">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-primary-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
正在搜索中...
</div>
</div>
<!-- 搜索结果 -->
<div v-else-if="searchResults.length > 0" class="space-y-4">
<div
v-for="(result, index) in searchResults"
:key="index"
class="card hover:shadow-lg transition-shadow duration-200 border border-gray-100"
>
<div class="cursor-pointer" @click="toggleExpand(index)">
<h3 class="text-base md:text-lg font-semibold text-gray-900"
:class="{ 'line-clamp-2': !expandedItems[index] }">
{{ removeEmoji(result.ScrName) }}
</h3>
<div v-if="!expandedItems[index] && isLongText(removeEmoji(result.ScrName))"
class="text-primary-600 text-sm mt-1 hover:text-primary-700">
点击展开全文
</div>
</div>
<div class="flex flex-wrap items-center gap-2 md:gap-4 text-sm text-gray-500 my-4">
<span class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{{ formatTime(result.addtime) }}
</span>
<span class="flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
</svg>
{{ result.Scrurlname }}
</span>
</div>
<div class="flex flex-wrap items-center gap-3 md:gap-4">
<a
:href="result.Scrurl"
target="_blank"
class="btn btn-primary flex items-center text-sm md:text-base"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
查看资源
</a>
<span v-if="result.Scrpass" class="flex items-center text-sm text-gray-500">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z" />
</svg>
提取码: {{ result.Scrpass }}
</span>
</div>
</div>
</div>
<!-- 无搜索结果 -->
<div v-else-if="searched" class="text-center py-12">
<div class="inline-block">
<svg class="w-16 h-16 text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-gray-500 text-lg">未找到相关资源换个关键词试试</p>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import http from '../utils/axios'
import { config } from '../config'
const searchQuery = ref('')
const searchResults = ref([])
const loading = ref(false)
const searched = ref(false)
const error = ref('')
const expandedItems = reactive({})
// 快捷搜索标签
const quickTags = [
'电影', '音乐', '小说', '动漫',
'软件', '教程', '设计', '游戏'
]
// 移除 emoji 标签
const removeEmoji = (text) => {
if (!text) return ''
// 使用正则表达式移除所有 [@emoji=xxx] 格式的内容
return text.replace(/\[@emoji=[^\]]*\]/g, '')
}
const handleSearch = async () => {
if (!searchQuery.value.trim()) return
loading.value = true
searched.value = true
searchResults.value = []
error.value = ''
// 重置展开状态
Object.keys(expandedItems).forEach(key => delete expandedItems[key])
try {
const response = await http.get(config.api.search, {
params: {
wd: searchQuery.value
}
})
if (response.data.code === 0) {
searchResults.value = response.data.Data || []
} else {
error.value = response.data.msg || '搜索失败,请稍后重试'
}
} catch (err) {
console.error('搜索出错:', err)
error.value = err.response?.data?.message || '搜索出错,请稍后重试'
} finally {
loading.value = false
}
}
const quickSearch = (tag) => {
searchQuery.value = tag
handleSearch()
}
const formatTime = (timestamp) => {
const date = new Date(parseInt(timestamp))
return date.toLocaleString()
}
const toggleExpand = (index) => {
expandedItems[index] = !expandedItems[index]
}
const isLongText = (text) => {
return text && text.length > 50
}
</script>
<style>
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>