first commit
This commit is contained in:
commit
349a4538b1
24
.eslintrc.js
Normal file
24
.eslintrc.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
browser: true,
|
||||||
|
es2021: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'plugin:vue/vue3-recommended',
|
||||||
|
'eslint:recommended',
|
||||||
|
'@vue/eslint-config-prettier',
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2021,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||||
|
'vue/multi-word-component-names': 'off',
|
||||||
|
'vue/no-v-html': 'off',
|
||||||
|
'vue/require-default-prop': 'off',
|
||||||
|
'vue/no-unused-components': 'warn',
|
||||||
|
},
|
||||||
|
}
|
9
.prettierrc
Normal file
9
.prettierrc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 100,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"endOfLine": "auto"
|
||||||
|
}
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Pan Search
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# 绝绝子网盘搜索
|
||||||
|
|
||||||
|
一个简洁的网盘资源搜索工具,支持多平台资源搜索,提供现代化的用户界面和流畅的搜索体验。
|
||||||
|
|
||||||
|
## 功能特点
|
||||||
|
|
||||||
|
- 🔍 快速搜索:支持多平台网盘资源搜索
|
||||||
|
- 🎨 现代化界面:采用 Material Design 设计风格
|
||||||
|
- 🌙 深色模式:支持自动切换深色/浅色主题
|
||||||
|
- 📱 响应式设计:完美适配各种设备尺寸
|
||||||
|
- ⚡ 性能优化:快速加载,流畅体验
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- Vue 3 - 前端框架
|
||||||
|
- Vite - 构建工具
|
||||||
|
- TailwindCSS - 样式框架
|
||||||
|
- Axios - HTTP 客户端
|
||||||
|
- Vue Router - 路由管理
|
||||||
|
- Pinia - 状态管理
|
||||||
|
|
||||||
|
## 开发指南
|
||||||
|
|
||||||
|
### 环境要求
|
||||||
|
|
||||||
|
- Node.js >= 16.0.0
|
||||||
|
- npm >= 7.0.0
|
||||||
|
|
||||||
|
### 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 开发环境
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### 构建生产版本
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## 部署说明
|
||||||
|
|
||||||
|
### 1. 构建项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
构建完成后,文件将生成在 `dist` 目录中。
|
||||||
|
|
||||||
|
### 2. 配置 Nginx
|
||||||
|
|
||||||
|
项目提供了一个 `nginx.conf.template` 配置模板文件,使用时需要:
|
||||||
|
|
||||||
|
1. 复制 `nginx.conf.template` 文件并重命名为 `nginx.conf`
|
||||||
|
2. 替换文件中的以下占位符:
|
||||||
|
- `[你的域名]`: 网站域名,如 `pan.example.com`
|
||||||
|
- `[你的网站根目录]`: 网站文件存放目录,如 `/www/wwwroot/pan.example.com`
|
||||||
|
- `[日志目录]`: 日志文件存放目录,如 `/www/wwwlogs/pan.example.com`
|
||||||
|
- `[目标API地址]`: API 服务器地址,如 `https://api.example.com/`
|
||||||
|
- `[允许的域名]`: 允许跨域访问的域名,如 `https://pan.example.com`
|
||||||
|
|
||||||
|
示例配置:
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name pan.example.com;
|
||||||
|
root /www/wwwroot/pan.example.com;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
access_log /www/wwwlogs/pan.example.com/access.log;
|
||||||
|
error_log /www/wwwlogs/pan.example.com/error.log;
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass https://api.example.com/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
|
||||||
|
add_header 'Access-Control-Allow-Origin' 'https://pan.example.com' always;
|
||||||
|
# ... 其他配置 ...
|
||||||
|
}
|
||||||
|
|
||||||
|
# ... 其他配置 ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 上传文件
|
||||||
|
|
||||||
|
将 `dist` 目录中的所有文件上传到服务器的网站根目录。
|
||||||
|
|
||||||
|
### 4. 配置域名
|
||||||
|
|
||||||
|
确保域名已正确解析到服务器IP,并在服务器上配置好SSL证书(如果需要)。
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 在部署到生产环境之前,请确保所有占位符都已正确替换
|
||||||
|
- 建议启用 HTTPS 以提升安全性
|
||||||
|
- 定期备份网站数据和日志文件
|
||||||
|
- 监控服务器资源使用情况,及时优化配置
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT License
|
15
index.html
Normal file
15
index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>绝绝子网盘搜索</title>
|
||||||
|
<meta name="description" content="专注于收录全网云盘资源,支持七大网盘搜索">
|
||||||
|
<meta name="keywords" content="网盘搜索,百度网盘搜索,阿里云盘搜索,夸克网盘搜索,资源搜索">
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
58
nginx.conf.template
Normal file
58
nginx.conf.template
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name [你的域名];
|
||||||
|
root [你的网站根目录];
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
access_log [日志目录]/access.log;
|
||||||
|
error_log [日志目录]/error.log;
|
||||||
|
|
||||||
|
# API 反向代理
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass https://www.yunso.net/api/;
|
||||||
|
proxy_set_header Host www.yunso.net;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# CORS 设置
|
||||||
|
add_header 'Access-Control-Allow-Origin' '[允许的域名]' always;
|
||||||
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||||
|
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always;
|
||||||
|
add_header 'Access-Control-Max-Age' 1728000 always;
|
||||||
|
add_header 'Content-Type' 'application/json charset=UTF-8' always;
|
||||||
|
|
||||||
|
# 处理 OPTIONS 请求
|
||||||
|
if ($request_method = 'OPTIONS') {
|
||||||
|
return 204;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 静态文件缓存
|
||||||
|
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
|
||||||
|
expires 7d;
|
||||||
|
add_header Cache-Control "public, no-transform";
|
||||||
|
}
|
||||||
|
|
||||||
|
# 前端路由
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 禁止访问敏感文件
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /package\.json$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gzip 压缩
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1000;
|
||||||
|
gzip_proxied expired no-cache no-store private auth;
|
||||||
|
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
|
}
|
3897
package-lock.json
generated
Normal file
3897
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "juejuezi-new",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
|
||||||
|
"format": "prettier --write src/"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@vueuse/core": "^10.3.0",
|
||||||
|
"autoprefixer": "^10.4.14",
|
||||||
|
"axios": "^1.4.0",
|
||||||
|
"pinia": "^2.1.6",
|
||||||
|
"postcss": "^8.4.27",
|
||||||
|
"tailwindcss": "^3.3.3",
|
||||||
|
"vue": "^3.3.4",
|
||||||
|
"vue-router": "^4.2.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
|
"@vue/eslint-config-prettier": "^8.0.0",
|
||||||
|
"eslint": "^8.45.0",
|
||||||
|
"eslint-plugin-vue": "^9.15.1",
|
||||||
|
"prettier": "^3.0.0",
|
||||||
|
"terser": "^5.39.0",
|
||||||
|
"vite": "^4.4.5"
|
||||||
|
}
|
||||||
|
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
51
src/App.vue
Normal file
51
src/App.vue
Normal 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">
|
||||||
|
© {{ 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
35
src/assets/main.css
Normal 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
13
src/config/index.js
Normal 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
12
src/main.js
Normal 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
41
src/router/index.js
Normal 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
44
src/utils/axios.js
Normal 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
55
src/views/About.vue
Normal 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
228
src/views/Home.vue
Normal 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>
|
29
tailwind.config.js
Normal file
29
tailwind.config.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
"./index.html",
|
||||||
|
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: {
|
||||||
|
50: '#f0f9ff',
|
||||||
|
100: '#e0f2fe',
|
||||||
|
200: '#bae6fd',
|
||||||
|
300: '#7dd3fc',
|
||||||
|
400: '#38bdf8',
|
||||||
|
500: '#0ea5e9',
|
||||||
|
600: '#0284c7',
|
||||||
|
700: '#0369a1',
|
||||||
|
800: '#075985',
|
||||||
|
900: '#0c4a6e',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter var', 'sans-serif'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
49
vite.config.js
Normal file
49
vite.config.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
port: 3000,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'https://www.yunso.net',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, '')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
assetsDir: 'assets',
|
||||||
|
sourcemap: false,
|
||||||
|
minify: 'terser',
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
drop_console: true,
|
||||||
|
drop_debugger: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: path.resolve(__dirname, 'index.html'),
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
manualChunks: {
|
||||||
|
'vue': ['vue', 'vue-router', 'pinia'],
|
||||||
|
'vendor': ['axios', '@vueuse/core'],
|
||||||
|
},
|
||||||
|
chunkFileNames: 'assets/js/[name]-[hash].js',
|
||||||
|
entryFileNames: 'assets/js/[name]-[hash].js',
|
||||||
|
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
base: '/',
|
||||||
|
})
|
Reference in New Issue
Block a user