init commit
23
.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
60
README.md
Normal file
@ -0,0 +1,60 @@
|
||||
# 爱盼-网盘资源搜索Web
|
||||
爱盼-网盘资源搜索:是一个免费开源项目,感谢 [混合盘提供的API](https://docs.hunhepan.com/api-docs.html)
|
||||
👉 [爱盼-网盘资源搜索](https://so.aicompasspro.com)
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 在 Vercel 上部署
|
||||
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/unilei/aipan-netdisk-search.git&project-name=aipan-netdisk-search&repository-name=aipan-netdisk-search)
|
||||
|
||||
### 在 Vercel 上手动部署 操作方法
|
||||
|
||||
```
|
||||
1. fork 本项目
|
||||
2. 在 [Vercel] 官网点击 [New Project]
|
||||
3. 点击 [Import Git Repository] 并选择你 fork 的此项目并点击 [import]
|
||||
4. 然后直接点 [Deploy] 接着等部署完成即可
|
||||
```
|
||||
|
||||
### 1. 克隆项目
|
||||
|
||||
```bash
|
||||
git clone https://github.com/unilei/aipan-netdisk-search.git
|
||||
```
|
||||
|
||||
### 2. 安装依赖
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
```
|
||||
### 3. 运行到浏览器
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm run dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
```
|
||||
|
||||
### 4. 在浏览器打开 [http://localhost:3001](http://localhost:3001)
|
||||
![success_deploy.jpg](/assets/readme/screen-1.png)
|
||||
![success_deploy.jpg](/assets/readme/screen-2.png)
|
||||
|
||||
#### 如何部署到自己服务器? NUXT.JS 打包部署文档
|
||||
[部署文档](https://nuxt.com/docs/getting-started/deployment)
|
||||
|
||||
### 打赏
|
||||
<img src="/assets/donation/wechat_pay.jpg" width=200 />
|
||||
|
||||
### 交流
|
||||
<img src="/assets/readme/wechat.jpg" width=200 />
|
6
app.config.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export default defineAppConfig({
|
||||
foo:'bar',
|
||||
theme:{
|
||||
primaryColor:'#ababab'
|
||||
}
|
||||
})
|
28
app.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<NuxtLayout>
|
||||
<NuxtPage></NuxtPage>
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
for(const [key,component] of Object.entries(ElementPlusIconsVue)){
|
||||
nuxtApp.vueApp.component(key,component)
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
body{
|
||||
background-color: #fcfcfd;
|
||||
padding: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
BIN
assets/donation/alipay.png
Normal file
After Width: | Height: | Size: 32 KiB |
1
assets/donation/dashang.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715865726218" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4382" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M235.8 67.9C153 87.4 87.4 153 67.9 235.8L235.8 67.9z" fill="#FF6968" p-id="4383"></path><path d="M301.7 62H287C163.3 62 62 163.3 62 287v14.7L301.7 62z" fill="#FF6867" p-id="4384"></path><path d="M361.7 62H287C163.3 62 62 163.3 62 287v74.7L361.7 62z" fill="#FF6866" p-id="4385"></path><path d="M421.6 62H287C163.3 62 62 163.3 62 287v134.6L421.6 62z" fill="#FF6765" p-id="4386"></path><path d="M481.6 62H287c-19.4 0-38.3 2.5-56.3 7.2L69.2 230.7c-4.7 18-7.2 36.9-7.2 56.3v194.6L481.6 62z" fill="#FF6764" p-id="4387"></path><path d="M62 541.6L541.6 62H297.9L62 297.9z" fill="#FF6763" p-id="4388"></path><path d="M62 601.6L601.6 62H357.8L62 357.8z" fill="#FF6662" p-id="4389"></path><path d="M62 417.8v243.7L661.5 62H417.8z" fill="#FF6661" p-id="4390"></path><path d="M62 477.8v243.7L721.5 62H477.8z" fill="#FF6560" p-id="4391"></path><path d="M737 62H537.8L62 537.8V737c0 13.9 1.3 27.5 3.7 40.8l712-712C764.5 63.3 750.9 62 737 62z" fill="#FF655F" p-id="4392"></path><path d="M737 62H597.7L62 597.7V737c0 30.8 6.3 60.1 17.6 86.9L823.9 79.6C797.1 68.3 767.8 62 737 62z" fill="#FF655E" p-id="4393"></path><path d="M862.8 100.7C826.8 76.3 783.5 62 737 62h-79.3L62 657.7V737c0 46.5 14.3 89.8 38.7 125.8l762.1-762.1z" fill="#FF645D" p-id="4394"></path><path d="M895.6 127.8C854.9 87.2 798.7 62 737 62h-19.3L62 717.7V737c0 61.7 25.2 117.9 65.8 158.6l767.8-767.8z" fill="#FF645C" p-id="4395"></path><path d="M65.2 774.5C75.6 835.8 111 889 160.6 922.8l762.3-762.3c-33.9-49.5-87-85-148.3-95.4L65.2 774.5z" fill="#FF635B" p-id="4396"></path><path d="M78.5 821.2c22.4 55.1 66.2 99.6 120.8 122.9l744.8-744.8c-23.3-54.7-67.8-98.4-122.9-120.8L78.5 821.2z" fill="#FF635A" p-id="4397"></path><path d="M99.2 860.5c33 49.9 85.3 86.1 146.1 97.6l712.8-712.8c-11.5-60.8-47.7-113.1-97.6-146.1L99.2 860.5z" fill="#FF635A" p-id="4398"></path><path d="M962 287c0-63-26.2-120.1-68.3-161.1L125.9 893.7C166.9 935.8 224 962 287 962h14.3L962 301.3V287z" fill="#FF6259" p-id="4399"></path><path d="M962 287c0-47.8-15.1-92.2-40.7-128.7l-763 763C194.8 946.9 239.2 962 287 962h74.3L962 361.3V287z" fill="#FF6258" p-id="4400"></path><path d="M962 287c0-32.1-6.8-62.7-19.1-90.4L196.6 942.9c27.7 12.3 58.3 19.1 90.4 19.1h134.3L962 421.3V287z" fill="#FF6157" p-id="4401"></path><path d="M287 962h194.2L962 481.2V287c0-15.4-1.6-30.4-4.5-44.9L242.1 957.5c14.5 2.9 29.5 4.5 44.9 4.5z" fill="#FF6156" p-id="4402"></path><path d="M541.2 962L962 541.2V297.5L297.5 962z" fill="#FF6155" p-id="4403"></path><path d="M601.2 962L962 601.2V357.5L357.5 962z" fill="#FF6054" p-id="4404"></path><path d="M661.2 962L962 661.2V417.4L417.4 962z" fill="#FF6053" p-id="4405"></path><path d="M721.1 962L962 721.1V477.4L477.4 962z" fill="#FF5F52" p-id="4406"></path><path d="M962 737V537.4L537.4 962H737c17.1 0 33.7-1.9 49.7-5.6l169.7-169.7c3.7-16 5.6-32.6 5.6-49.7z" fill="#FF5F51" p-id="4407"></path><path d="M962 597.4L597.4 962H737c123.8 0 225-101.3 225-225V597.4z" fill="#FF5F50" p-id="4408"></path><path d="M962 657.3L657.3 962H737c123.8 0 225-101.3 225-225v-79.7z" fill="#FF5E4F" p-id="4409"></path><path d="M962 717.3L717.3 962H737c123.8 0 225-101.3 225-225v-19.7z" fill="#FF5E4E" p-id="4410"></path><path d="M957.5 781.8L781.8 957.5c88-18 157.7-87.7 175.7-175.7z" fill="#FF5D4D" p-id="4411"></path><path d="M512 512m-243 0a243 243 0 1 0 486 0 243 243 0 1 0-486 0Z" fill="#FFF3F3" p-id="4412"></path><path d="M512 512m-207 0a207 207 0 1 0 414 0 207 207 0 1 0-414 0Z" fill="#FFCDCB" p-id="4413"></path><path d="M500.4 402.8h23.4v26.4H547c4.8-8 9.1-16.3 12.9-25l21.5 7.5c-3.1 6.9-6.5 12.7-10.1 17.6h40.2v49.1h-22v-30H434.7v30.2h-22.2v-49.4h41.7c-3.3-5.8-7.2-11.4-11.7-16.8l21.1-7.7c5.2 6.7 9.8 14.9 14 24.6h22.9v-26.5z m24.1 142.5c-3.3 26.7-10.2 44.3-20.8 52.9-11.5 11.1-39 18.2-82.4 21.5l-8.9-20.1c36.3-1.4 60.3-6.3 71.8-14.7 10.1-7.8 16.1-21.6 18-41.4l22.3 1.8z m62.7-28.7v64.8h-22v-45.2h-106V584h-22v-67.4h150z m-136.4-56.2h122.6v46.1H450.8v-46.1z m100.9 30.4v-14.5h-79.1v14.5h79.1z m-24.4 87.5c31 6.4 59 14.2 84 23.4l-12.6 19.4c-26.8-11.2-54.4-19.9-82.6-26l11.2-16.8z" fill="#FFFFFF" p-id="4414"></path></svg>
|
After Width: | Height: | Size: 4.3 KiB |
BIN
assets/donation/wechat_pay.jpg
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
assets/donation/wechat_pay.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
assets/github.png
Normal file
After Width: | Height: | Size: 697 B |
3
assets/lang/en-US.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
3
assets/lang/zh-CN.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
BIN
assets/my-logo.png
Normal file
After Width: | Height: | Size: 140 KiB |
BIN
assets/netdisk/aliyun.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/netdisk/baidu.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/netdisk/quark.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/netdisk/xunlei.png
Normal file
After Width: | Height: | Size: 374 B |
BIN
assets/readme/screen-1.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
assets/readme/screen-2.png
Normal file
After Width: | Height: | Size: 322 KiB |
BIN
assets/readme/wechat.jpg
Normal file
After Width: | Height: | Size: 230 KiB |
85
components/customInput/inputForSearch.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<script setup>
|
||||
const searchSiteData = ref([
|
||||
{
|
||||
id:1,
|
||||
name:'谷歌',
|
||||
url:'https://www.google.com/search',
|
||||
s_key:'q'
|
||||
},
|
||||
{
|
||||
id:2,
|
||||
name:'必应[国际]',
|
||||
url:'https://www.bing.com/search',
|
||||
s_key:'q'
|
||||
},
|
||||
{
|
||||
id:3,
|
||||
name:'必应[国内]',
|
||||
url:'https://cn.bing.com/',
|
||||
s_key:'q'
|
||||
},
|
||||
{
|
||||
id:4,
|
||||
name:'百度',
|
||||
url:'https://www.baidu.com/s',
|
||||
s_key:'q'
|
||||
}
|
||||
|
||||
])
|
||||
const searchSite = ref({
|
||||
id:4,
|
||||
name:'百度',
|
||||
url:'https://www.baidu.com/s',
|
||||
s_key:'wd'
|
||||
})
|
||||
const searchKeyword = ref('')
|
||||
const search = ()=>{
|
||||
let str = searchSite.value.url + '?'+ searchSite.value.s_key+'=' + searchKeyword.value
|
||||
window.open(str, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-[100%] md:w-[800px] border border-slate-300 font-mono overflow-hidden rounded-[50px]">
|
||||
<client-only>
|
||||
<el-input class="h-[50px]" v-model="searchKeyword" placeholder="请输入关键词" @keydown.enter="search()" >
|
||||
<template #prepend>
|
||||
<el-select class="w-[40px] md:w-[100px] h-[50px]" placeholder="搜索引擎" value-key="id" v-model="searchSite">
|
||||
<el-option class="h-[50px]" v-for="(item,i) in searchSiteData" :key="i" :label="item.name" :value="item"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-button icon="search" @click="search()"></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</client-only>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-input__inner) {
|
||||
height: 48px;
|
||||
}
|
||||
:deep(.el-input__wrapper){
|
||||
box-shadow: none;
|
||||
}
|
||||
:deep(.el-input-group__prepend){
|
||||
box-shadow: none;
|
||||
}
|
||||
:deep(.el-input){
|
||||
--el-input-focus-border:transparent;
|
||||
--el-input-border-color:transparent;
|
||||
--el-input-focus-border-color:transparent;
|
||||
--el-input-hover-border-color:transparent;
|
||||
}
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input.is-focus .el-input__wrapper){
|
||||
box-shadow: none !important;
|
||||
}
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input .el-input__inner){
|
||||
text-align: center;
|
||||
}
|
||||
:deep(.el-select .el-input__wrapper.is-focus){
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
82
components/diskInfoList.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
sources: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['openLink'])
|
||||
|
||||
const handleOpenSourceLink = (link: string) => {
|
||||
emit('openLink', link)
|
||||
}
|
||||
|
||||
const formatDiskType = (type: string) => {
|
||||
switch (type) {
|
||||
case 'ALY':
|
||||
return '阿里云盘'
|
||||
case 'BDY':
|
||||
return '百度网盘'
|
||||
case 'QUARK':
|
||||
return '夸克网盘'
|
||||
case 'XUNLEI':
|
||||
return '迅雷网盘'
|
||||
default:
|
||||
return '未知类型'
|
||||
}
|
||||
}
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
return new Date(date).toLocaleDateString()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="bg-white shadow p-[14px] rounded-[6px] cursor-pointer
|
||||
hover:bg-[#f5f5f5] hover:shadow-lg transition duration-300 ease-in-out"
|
||||
v-for="(item,i) in sources?.list" :key="i"
|
||||
@click="handleOpenSourceLink(item.link)"
|
||||
>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'ALY'" src="@/assets/netdisk/aliyun.png" alt="aliyun">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'QUARK'" src="@/assets/netdisk/quark.png" alt="quark">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'BDY'" src="@/assets/netdisk/baidu.png" alt="baidu">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'XUNLEI'" src="@/assets/netdisk/xunlei.png" alt="xunlei">
|
||||
<p class="text-[14px] font-inter font-[600]" v-html="item.disk_name"></p>
|
||||
</div>
|
||||
<div class="py-[12px]">
|
||||
<p class="text-[12px] text-slate-400 truncate-3-lines" v-html="item.files"></p>
|
||||
</div>
|
||||
<div class="text-[12px] text-slate-600 flex flex-row items-center justify-between">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<span v-if="item.disk_type" class="bg-blue-500 text-white px-[6px] py-[2px] rounded">
|
||||
{{ formatDiskType(item.disk_type) }}
|
||||
</span>
|
||||
<span v-if="item.disk_pass" class=" bg-purple-500 text-white px-[6px] py-[2px] rounded">
|
||||
{{ item.disk_pass }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="item.update_time" class="text-slate-600 px-[6px] py-[2px] rounded">
|
||||
{{ formatDate(item.update_time) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
em {
|
||||
color: blue;
|
||||
margin: 0 2px;
|
||||
}
|
||||
</style>
|
||||
<style scoped>
|
||||
.truncate-3-lines {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
15
components/layout/Footer.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="flex flex-row items-center justify-center my-[20px]">
|
||||
<p class="font-mono text-[12px] text-center text-gray-400">
|
||||
爱盼-网盘资源搜索
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
24
components/layout/Header.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<el-affix>
|
||||
<div class="shadow px-[20px] py-[10px]">
|
||||
<div class="max-w-[1240px] mx-auto h-[40px] flex flex-row items-center justify-between">
|
||||
<div class="flex flex-row items-center justify-center gap-1">
|
||||
<img class="w-[40px] h-[40px] cursor-pointer" src="@/assets/my-logo.png" alt="logo" @click="goHome()">
|
||||
<h1 class="text-[14px] font-serif font-bold cursor-pointer" @click="goHome()">爱盼-网盘资源搜索</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-affix>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
const router = useRouter()
|
||||
const goHome = () => {
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
87
components/search/SearchHeader.vue
Normal file
@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
const router = useRouter()
|
||||
const goHome = () => {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
keyword: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
}
|
||||
})
|
||||
const searchKeyword = ref(props.keyword)
|
||||
const emit = defineEmits(['search'])
|
||||
const search = () => {
|
||||
emit('search',searchKeyword.value)
|
||||
}
|
||||
const goGithub = () => {
|
||||
window.open('https://github.com/unilei/aipan-netdisk-search.git')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-affix>
|
||||
<div class="bg-white shadow px-[20px] py-[10px]">
|
||||
<div class="max-w-[1240px] mx-auto h-[40px] flex flex-row items-center gap-6 relative">
|
||||
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
<img class="w-[30px] h-[30px] md:w-[40px] md:h-[40px] cursor-pointer" src="@/assets/my-logo.png" alt="logo" @click="goHome()">
|
||||
<h1 class="hidden md:block text-[14px] font-serif font-bold cursor-pointer" @click="goHome()" >爱盼-网盘资源搜索</h1>
|
||||
</div>
|
||||
|
||||
<div class="w-[220px] md:w-[400px] border border-slate-300 font-mono overflow-hidden rounded-[50px]">
|
||||
<client-only>
|
||||
<el-input class="h-[30px]"
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入关键词搜索"
|
||||
@keydown.enter="search()"
|
||||
prefix-icon="Search"
|
||||
>
|
||||
</el-input>
|
||||
</client-only>
|
||||
</div>
|
||||
|
||||
<div class="absolute right-[20px]">
|
||||
<el-button link @click="goGithub()">
|
||||
<img class="w-[20px] h-[20px]" src="@/assets/github.png" alt="github">
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</el-affix>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.el-input__inner) {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__prepend) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:deep(.el-input) {
|
||||
--el-input-focus-border: transparent;
|
||||
--el-input-border-color: transparent;
|
||||
--el-input-focus-border-color: transparent;
|
||||
--el-input-hover-border-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input.is-focus .el-input__wrapper) {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input .el-input__inner) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-select .el-input__wrapper.is-focus) {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
30
components/sources/tags.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
tagsData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
|
||||
const handleChange = (id) => {
|
||||
emit('change',id)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul class="grid grid-cols-5 gap-3">
|
||||
<li class="bg-white px-[14px] py-[6px]
|
||||
cursor-pointer hover:scale-105 rounded-[6px]
|
||||
transition duration-300 ease-in-out"
|
||||
v-for="(item,i) in tagsData" :key="i"
|
||||
@click="handleChange(item.id)"
|
||||
>
|
||||
<span class="text-[14px] font-inter font-[600]">{{ item.name }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
10
layouts/custom.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<slot></slot>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
15
layouts/default.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<Header></Header>
|
||||
<slot></slot>
|
||||
<Footer></Footer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Footer from "~/components/layout/Footer.vue";
|
||||
import Header from "~/components/layout/Header.vue";
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
103
nuxt.config.ts
Normal file
@ -0,0 +1,103 @@
|
||||
export default defineNuxtConfig({
|
||||
devtools: { enabled: false },
|
||||
app: {
|
||||
// head
|
||||
head: {
|
||||
title: '爱盼-网盘资源搜索',
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{
|
||||
name: 'referrer',
|
||||
content: 'no-referrer'
|
||||
},
|
||||
{
|
||||
name: 'referrer',
|
||||
content: 'always'
|
||||
},
|
||||
{
|
||||
name: 'referrer',
|
||||
content: 'strict-origin-when-cross-origin'
|
||||
}
|
||||
],
|
||||
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
|
||||
script: [
|
||||
{
|
||||
src: 'https://www.googletagmanager.com/gtag/js?id=G-7X3KPN3R02',
|
||||
async: true
|
||||
},
|
||||
{
|
||||
src: '/ga.js'
|
||||
},
|
||||
{
|
||||
src: '/qrcode.min.js'
|
||||
},
|
||||
{
|
||||
src: 'https://challenges.cloudflare.com/turnstile/v0/api.js'
|
||||
},
|
||||
{
|
||||
src: 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8210373406341452',
|
||||
async: true,
|
||||
crossorigin: 'anonymous'
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
},
|
||||
// build modules
|
||||
modules: [
|
||||
'@element-plus/nuxt',
|
||||
'@nuxtjs/tailwindcss',
|
||||
'@nuxtjs/device',
|
||||
'@nuxtjs/i18n',
|
||||
'@nuxtjs/google-fonts'
|
||||
|
||||
],
|
||||
tailwindcss: {
|
||||
configPath: 'tailwind.config.js'
|
||||
},
|
||||
googleFonts: {
|
||||
display: 'swap',
|
||||
prefetch: false,
|
||||
preconnect: false,
|
||||
preload: true,
|
||||
download: false,
|
||||
base64: false,
|
||||
families: {
|
||||
'Inter': [100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
'Poetsen One': [100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
'Sedan SC': [100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
'Briem Hand': [100, 200, 300, 400, 500, 600, 700, 800, 900],
|
||||
'Noto Sans Simplified Chinese': [100, 200, 300, 400, 500, 600, 700, 800, 900]
|
||||
}
|
||||
},
|
||||
i18n: {
|
||||
defaultLocale: 'cn',
|
||||
langDir: './assets/lang/',
|
||||
locales: [
|
||||
{
|
||||
code: 'en',
|
||||
name: 'English',
|
||||
iso: 'en-US',
|
||||
file: 'en-US.json'
|
||||
},
|
||||
{
|
||||
code: 'cn',
|
||||
name: '中文',
|
||||
iso: 'zh-CN',
|
||||
file: 'zh-CN.json'
|
||||
}
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
|
||||
],
|
||||
nitro: {
|
||||
devProxy: {
|
||||
|
||||
}
|
||||
},
|
||||
runtimeConfig: {
|
||||
openaiApiKey: '',
|
||||
proxyUrl: ''
|
||||
}
|
||||
})
|
14270
package-lock.json
generated
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev --port 3001",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@element-plus/nuxt": "^1.0.7",
|
||||
"@nuxt/config": "^2.17.1",
|
||||
"@nuxt/devtools": "latest",
|
||||
"@nuxt/types": "^2.17.1",
|
||||
"@nuxt/typescript-build": "^3.0.1",
|
||||
"@nuxtjs/device": "^3.1.1",
|
||||
"@nuxtjs/google-fonts": "^3.2.0",
|
||||
"@nuxtjs/i18n": "^8.0.0-rc.7",
|
||||
"@types/node": "^18.16.19",
|
||||
"nuxt": "^3.7.0",
|
||||
"sass": "^1.77.1",
|
||||
"typescript": "^5.1.6",
|
||||
"vue-tsc": "^1.8.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "^2.1.0",
|
||||
"@nuxtjs/tailwindcss": "^6.8.0",
|
||||
"axios": "^1.6.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"nuxt-icon": "^0.6.10",
|
||||
"nuxt-proxy": "^0.0.8"
|
||||
},
|
||||
"overrides": {
|
||||
"vue": "latest"
|
||||
}
|
||||
}
|
16
pages/donate.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-[20px]">
|
||||
<h1 class=" text-3xl font-bold text-center">打赏</h1>
|
||||
<div class="mt-10 flex justify-center">
|
||||
<img style="width: 300px;margin-top: 40px;" src="@/assets/donation/wechat_pay.jpg" alt="打赏">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
100
pages/index.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
layout: 'custom',
|
||||
})
|
||||
const searchKeyword = ref('')
|
||||
const router = useRouter()
|
||||
|
||||
const search = (keyword) => {
|
||||
router.push({path:'/search',query:{keyword:encodeURIComponent(keyword)}})
|
||||
}
|
||||
const donate = () => {
|
||||
router.push({path:'/donate'})
|
||||
}
|
||||
const hotKeywords = ref(['庆余年2','歌手2024','庆余年','我的阿勒泰','新生'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-[#ffffff] min-h-screen py-[60px]">
|
||||
|
||||
<div class="flex flex-row items-center justify-center gap-3 mt-[80px]">
|
||||
<img class="w-[40px] h-[40px] sm:w-[60px] sm:h-[60px]" src="@/assets/my-logo.png" alt="logo">
|
||||
<h1 class="text-[18px] sm:text-[24px] font-serif font-bold ">爱盼-网盘资源搜索</h1>
|
||||
</div>
|
||||
|
||||
<div class="max-w-[1240px] mx-auto mt-[20px]">
|
||||
<div class="w-[80%] md:w-[700px] mx-auto border border-slate-300 font-mono overflow-hidden rounded-[50px]">
|
||||
<client-only>
|
||||
<el-input class="h-[40px] sm:h-[50px]"
|
||||
v-model="searchKeyword"
|
||||
placeholder="请输入关键词搜索"
|
||||
@keydown.enter="search(searchKeyword)"
|
||||
prefix-icon="Search"
|
||||
>
|
||||
</el-input>
|
||||
</client-only>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-w-[1240px] mx-auto mt-[20px]">
|
||||
<div class="flex flex-row flex-wrap gap-1 justify-center">
|
||||
<el-tag class="mx-1 cursor-pointer"
|
||||
v-for="keyword in hotKeywords"
|
||||
:key="keyword"
|
||||
type="info"
|
||||
@click="search(keyword)"
|
||||
>
|
||||
{{ keyword }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="fixed bottom-0 left-0 right-0 bg-white p-3">
|
||||
<div class="flex flex-row items-center justify-center gap-3 my-3">
|
||||
<a class="" href="https://github.com/unilei/aipan-netdisk-search">
|
||||
<img class="w-[50px] h-[50px]" src="@/assets/github.png" alt="github">
|
||||
</a>
|
||||
<el-button color="#ffffff" @click="donate()">
|
||||
<img class="w-[50px] h-[50px]" src="@/assets/donation/dashang.svg" alt="打赏">
|
||||
</el-button>
|
||||
</div>
|
||||
<p class="text-center text-[8px] sm:text-[12px] text-slate-400">
|
||||
声明:本站不产生/存储任何数据,也从未参与录制、上传,所有资源均来自网络。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.el-input__inner) {
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:deep(.el-input-group__prepend) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
:deep(.el-input) {
|
||||
--el-input-focus-border: transparent;
|
||||
--el-input-border-color: transparent;
|
||||
--el-input-focus-border-color: transparent;
|
||||
--el-input-hover-border-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input.is-focus .el-input__wrapper) {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
:deep(.el-input-group--prepend .el-input-group__prepend .el-select .el-input .el-input__inner) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(.el-select .el-input__wrapper.is-focus) {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
</style>
|
110
pages/latest-sources.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<script setup>
|
||||
import Tags from "~/components/sources/tags.vue";
|
||||
import SearchHeader from "~/components/search/SearchHeader.vue";
|
||||
import DiskInfoList from "~/components/diskInfoList.vue";
|
||||
|
||||
definePageMeta({
|
||||
layout: 'custom',
|
||||
})
|
||||
|
||||
const tagsVisible = ref(false)
|
||||
|
||||
const tagsData = ref([])
|
||||
const getTabsData = async () => {
|
||||
let res = await $fetch('/api/sources/hh/tabs')
|
||||
if (res.code === 200) {
|
||||
tagsData.value = res.data
|
||||
await getSourcesDataByTag(res.data[0].id)
|
||||
}
|
||||
}
|
||||
|
||||
const sourcesData = ref([])
|
||||
const getSourcesDataByTag = async (id) => {
|
||||
let res = await $fetch('/api/sources/hh/tabs-id', {
|
||||
method: 'get',
|
||||
query: {
|
||||
id: id,
|
||||
page: 1,
|
||||
size: 20
|
||||
}
|
||||
})
|
||||
sourcesData.value = res.data
|
||||
}
|
||||
|
||||
const latestSourcesData = ref([])
|
||||
const latestPage = ref(1)
|
||||
const latestSize = ref(10)
|
||||
const getLatestSourcesData = async (page, size) => {
|
||||
const loading = ElLoading.service({
|
||||
text: '加载中...',
|
||||
background: 'transparent',
|
||||
target: '#latest-sources-all',
|
||||
})
|
||||
let res = await $fetch('/api/sources/hh/latest-sources', {
|
||||
method: 'get',
|
||||
query: {
|
||||
page: page,
|
||||
size: size
|
||||
}
|
||||
})
|
||||
if (res.code === 200) {
|
||||
latestSourcesData.value = res.data
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
|
||||
const handleLatestPageChange = (page) => {
|
||||
latestPage.value = page
|
||||
window.scroll(0, 0)
|
||||
getLatestSourcesData(latestPage.value, latestSize.value)
|
||||
}
|
||||
const handleOpenSourceLink = (url) => {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
// BDY, ALY, QUARK, XUNLEI
|
||||
|
||||
const keyword = ref('')
|
||||
const router = useRouter()
|
||||
const search = (keyword) => {
|
||||
router.push({path: '/search', query: {keyword: encodeURIComponent(keyword)}})
|
||||
}
|
||||
onMounted(() => {
|
||||
getTabsData()
|
||||
getLatestSourcesData(latestPage.value, latestSize.value)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen">
|
||||
<search-header :keyword="keyword" @search="search"></search-header>
|
||||
|
||||
<div class="max-w-[1240px] mx-auto p-[20px] sm:py-[20px]">
|
||||
|
||||
<tags v-if="tagsVisible" :tags-data="tagsData" @change="getSourcesDataByTag"></tags>
|
||||
|
||||
<div class="max-w-[1240px] mx-auto grid grid-cols-1 md:grid-cols-[1fr_400px] gap-8">
|
||||
|
||||
<div class="min-h-[calc(100vh-90px)]" id="latest-sources-all">
|
||||
<div class="text-xl font-bold">最新资源</div>
|
||||
<div class="grid grid-cols-1 gap-3 mt-3">
|
||||
<disk-info-list :sources="latestSourcesData" @open-link="handleOpenSourceLink"></disk-info-list>
|
||||
</div>
|
||||
<div class="mt-[20px] flex justify-center">
|
||||
<client-only>
|
||||
<el-pagination
|
||||
layout="prev, pager, next"
|
||||
@current-change="handleLatestPageChange"
|
||||
:total="latestSourcesData?.total"
|
||||
></el-pagination>
|
||||
</client-only>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
236
pages/search.vue
Normal file
@ -0,0 +1,236 @@
|
||||
<script setup>
|
||||
import SearchHeader from "~/components/search/SearchHeader.vue";
|
||||
import DiskInfoList from "~/components/diskInfoList.vue";
|
||||
import aliImg from '@/assets/netdisk/aliyun.png'
|
||||
import quarkImg from '@/assets/netdisk/quark.png'
|
||||
import xunleiImg from '@/assets/netdisk/xunlei.png'
|
||||
import bdyImg from '@/assets/netdisk/baidu.png'
|
||||
|
||||
definePageMeta({
|
||||
layout: 'custom',
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const handleOpenSourceLink = (url) => {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
const tabsOptions = [
|
||||
{
|
||||
label: '所有',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
label: '阿里',
|
||||
value: 'ALY',
|
||||
img: aliImg
|
||||
},
|
||||
{
|
||||
label: '百度',
|
||||
value: 'BDY',
|
||||
img: bdyImg
|
||||
},
|
||||
{
|
||||
label: '夸克',
|
||||
value: 'QUARK',
|
||||
img: quarkImg
|
||||
},
|
||||
{
|
||||
label: '迅雷',
|
||||
value: 'XUNLEI',
|
||||
img: xunleiImg
|
||||
}
|
||||
]
|
||||
|
||||
const route = useRoute()
|
||||
const keyword = ref(decodeURIComponent(route.query.keyword))
|
||||
const currentTabValue = ref('')
|
||||
const page = ref(1)
|
||||
const exact = ref(false)
|
||||
|
||||
const sources = ref([])
|
||||
const handleSearchByHunhe = async () => {
|
||||
let res = await $fetch('/api/sources/hh/search', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
'engine': currentEngine.value,
|
||||
"q": keyword.value,
|
||||
"page": page.value,
|
||||
"size": 10,
|
||||
"time": "",
|
||||
"type": currentTabValue.value,
|
||||
"exact": exact.value
|
||||
}
|
||||
})
|
||||
if (res.code === 200) {
|
||||
sources.value = res.data
|
||||
}
|
||||
}
|
||||
|
||||
const search = (e) => {
|
||||
keyword.value = e
|
||||
handleSearchByHunhe()
|
||||
}
|
||||
|
||||
const handleChangeTab = (e) => {
|
||||
currentTabValue.value = e
|
||||
handleSearchByHunhe()
|
||||
}
|
||||
|
||||
const handleCurrentPageChange = (e) => {
|
||||
page.value = e
|
||||
window.scroll(0, 0)
|
||||
handleSearchByHunhe()
|
||||
}
|
||||
|
||||
const handleChangeExact = (e) => {
|
||||
exact.value = !e
|
||||
handleSearchByHunhe()
|
||||
}
|
||||
const handleEngineChange = (e) => {
|
||||
currentEngine.value = e
|
||||
handleSearchByHunhe()
|
||||
}
|
||||
const latestSourcesData = ref([])
|
||||
const getLatestSourcesData = async (page, size) => {
|
||||
const loading = ElLoading.service({
|
||||
text: '加载中...',
|
||||
background: 'transparent',
|
||||
target: '#latest-sources',
|
||||
})
|
||||
let res = await $fetch('/api/sources/hh/latest-sources', {
|
||||
method: 'get',
|
||||
query: {
|
||||
page: page,
|
||||
size: size
|
||||
}
|
||||
})
|
||||
if (res.code === 200) {
|
||||
latestSourcesData.value = res.data
|
||||
loading.close()
|
||||
}
|
||||
}
|
||||
const handleGoToLatestSources = () => {
|
||||
router.push({path: '/latest-sources'})
|
||||
}
|
||||
const currentEngine = ref(1)
|
||||
const searchOptions = [
|
||||
{
|
||||
label: '默认引擎',
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: '搜索引擎一',
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
label: '搜索引擎二',
|
||||
value: 3
|
||||
},
|
||||
{
|
||||
label: '搜索引擎三',
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: '搜索引擎四',
|
||||
value: 5
|
||||
},
|
||||
{
|
||||
label: '搜索引擎五',
|
||||
value: 6
|
||||
}
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
handleSearchByHunhe()
|
||||
getLatestSourcesData(1, 10)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<search-header :keyword="keyword" @search="search"></search-header>
|
||||
|
||||
<div class="max-w-[1240px] mx-auto grid grid-cols-1 md:grid-cols-[1fr_400px] gap-8">
|
||||
<div class="grid grid-cols-1 gap-3 sm:mt-3 sm:pb-[60px] min-h-[500px] p-[20px] md:p-0">
|
||||
<div class="py-3">
|
||||
<ul class="flex flex-row gap-3 flex-wrap">
|
||||
<li v-for="(item,i) in tabsOptions" :key="i">
|
||||
<el-check-tag :checked="item.value === currentTabValue" @click="handleChangeTab(item.value)"
|
||||
type="success">
|
||||
<div class="flex flex-row items-center">
|
||||
<span class="text-[10px] md:text-[14px]">{{ item.label }}</span>
|
||||
</div>
|
||||
</el-check-tag>
|
||||
</li>
|
||||
<li>
|
||||
<el-check-tag :checked="exact" @click="handleChangeExact(exact)"
|
||||
type="success">
|
||||
<span class="text-[10px] md:text-[14px]">精确搜索</span>
|
||||
</el-check-tag>
|
||||
</li>
|
||||
<li>
|
||||
<el-select
|
||||
v-model="currentEngine"
|
||||
placeholder="Select"
|
||||
style="width: 140px"
|
||||
@change="handleEngineChange"
|
||||
>
|
||||
<el-option v-for="item in searchOptions" :key="item.value" :label="item.label" :value="item.value">
|
||||
|
||||
</el-option>
|
||||
</el-select>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<disk-info-list :sources="sources" @open-link="handleOpenSourceLink"></disk-info-list>
|
||||
|
||||
<div class="py-[40px] flex justify-center">
|
||||
<client-only>
|
||||
<el-pagination
|
||||
layout="prev, pager, next"
|
||||
@current-change="handleCurrentPageChange"
|
||||
:total="sources?.total"
|
||||
></el-pagination>
|
||||
</client-only>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-[20px] sm:py-[20px]">
|
||||
<div class="bg-white shadow p-[14px] rounded-[6px]">
|
||||
<div class="flex flex-row justify-between items-center">
|
||||
<span class="text-[14px] font-bold">最近更新</span>
|
||||
<div>
|
||||
<el-button link icon="refresh" @click="getLatestSourcesData(1, 10)"></el-button>
|
||||
<el-button link icon="more" @click="handleGoToLatestSources()"></el-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-3 mt-3 min-h-[500px]" id="latest-sources">
|
||||
<div
|
||||
class="bg-white shadow p-[14px] rounded-[6px] cursor-pointer
|
||||
hover:bg-[#f5f5f5] hover:shadow-lg transition duration-300 ease-in-out"
|
||||
v-for="(item,i) in latestSourcesData?.list" :key="i"
|
||||
@click="handleOpenSourceLink(item.link)"
|
||||
>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'ALY'" src="@/assets/netdisk/aliyun.png" alt="aliyun">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'QUARK'" src="@/assets/netdisk/quark.png" alt="quark">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'BDY'" src="@/assets/netdisk/baidu.png" alt="baidu">
|
||||
<img class="w-[20px]" v-if="item.disk_type === 'XUNLEI'" src="@/assets/netdisk/xunlei.png" alt="xunlei">
|
||||
<span class="text-[14px] font-inter">{{ item.disk_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
BIN
public/favicon-edu.ico
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 310 KiB |
5
public/ga.js
Normal file
@ -0,0 +1,5 @@
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-7X3KPN3R02');
|
BIN
public/icon/kkpans.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
public/icon/openai.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
public/logo.png
Normal file
After Width: | Height: | Size: 310 KiB |
1
public/qrcode.min.js
vendored
Normal file
23
server/api/sources/hh/latest-sources.ts
Normal file
@ -0,0 +1,23 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
||||
const query = await getQuery(event)
|
||||
|
||||
try{
|
||||
let res = await $fetch('https://api.hunhepan.com/v1/raw_disk/latest_with_extab',{
|
||||
method:'GET',
|
||||
query:{
|
||||
type: query.type,
|
||||
page: query.page,
|
||||
size: query.size
|
||||
}
|
||||
})
|
||||
return res
|
||||
|
||||
}catch (e) {
|
||||
console.log(e)
|
||||
return {
|
||||
code: 500,
|
||||
msg:'error',
|
||||
}
|
||||
}
|
||||
})
|
38
server/api/sources/hh/search-multi.ts
Normal file
@ -0,0 +1,38 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
||||
// 定义多个 API 的请求配置
|
||||
const apiEndpoints = [
|
||||
{ url: 'https://alipanx.com/v1/search/disk', method: 'POST' },
|
||||
{ url: 'https://xlpanso.com/v1/search/disk', method: 'POST' },
|
||||
{ url: 'https://hunhepan.com/open/search/disk', method: 'POST' },
|
||||
{ url: 'https://www.lzpanx.com/v1/search/disk', method: 'POST' },
|
||||
{ url: 'https://qkpanso.com/v1/search/disk', method: 'POST' },
|
||||
{ url: 'https://www.pansou.icu/v1/search/disk', method: 'POST' }
|
||||
];
|
||||
|
||||
try {
|
||||
const body = await readBody(event);
|
||||
|
||||
// 使用 Promise.all() 并行发起多个请求
|
||||
const requests = apiEndpoints.map(async (endpoint) => {
|
||||
const res = await $fetch(endpoint.url, {
|
||||
method: 'POST',
|
||||
body
|
||||
});
|
||||
return res;
|
||||
});
|
||||
|
||||
// 等待所有请求完成
|
||||
const results = await Promise.all(requests);
|
||||
|
||||
// 返回所有请求的结果数组
|
||||
return results;
|
||||
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return {
|
||||
code: 500,
|
||||
msg: 'error',
|
||||
};
|
||||
}
|
||||
});
|
32
server/api/sources/hh/search.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
||||
try{
|
||||
let body = await readBody(event)
|
||||
|
||||
let apiEndpoints = [
|
||||
{ url: 'https://alipanx.com/v1/search/disk', engine: 2 },
|
||||
{ url: 'https://xlpanso.com/v1/search/disk', engine: 3 },
|
||||
{ url: 'https://hunhepan.com/open/search/disk', engine: 1 },
|
||||
{ url: 'https://www.lzpanx.com/v1/search/disk', engine: 4 },
|
||||
{ url: 'https://qkpanso.com/v1/search/disk', engine: 5 },
|
||||
{ url: 'https://www.pansou.icu/v1/search/disk', engine: 6 }
|
||||
];
|
||||
let engineValue = body.engine
|
||||
let index = apiEndpoints.findIndex((item) => item.engine === engineValue)
|
||||
|
||||
let res = await $fetch( apiEndpoints[index].url ,{
|
||||
method:'POST',
|
||||
body
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
|
||||
}catch (e) {
|
||||
console.log(e)
|
||||
return {
|
||||
code: 500,
|
||||
msg:'error',
|
||||
}
|
||||
}
|
||||
})
|
22
server/api/sources/hh/tabs-id.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
||||
const query = await getQuery(event)
|
||||
|
||||
try{
|
||||
let res = await $fetch('https://api.hunhepan.com/v1/extab/raw_disks/'+query.id,{
|
||||
method:'GET',
|
||||
query:{
|
||||
page: query.page,
|
||||
size: query.size
|
||||
}
|
||||
})
|
||||
return res
|
||||
|
||||
}catch (e) {
|
||||
console.log(e)
|
||||
return {
|
||||
code: 500,
|
||||
msg:'error',
|
||||
}
|
||||
}
|
||||
})
|
16
server/api/sources/hh/tabs.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
|
||||
try{
|
||||
let res = await $fetch('https://api.hunhepan.com/v1/extab/list_all',{
|
||||
method:'GET'
|
||||
})
|
||||
return res
|
||||
|
||||
}catch (e) {
|
||||
console.log(e)
|
||||
return {
|
||||
code: 500,
|
||||
msg:'error',
|
||||
}
|
||||
}
|
||||
})
|
14
server/middleware/cors.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export default defineEventHandler((event) => {
|
||||
setResponseHeaders(event, {
|
||||
"Access-Control-Allow-Methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
'Access-Control-Allow-Credentials': 'true',
|
||||
"Access-Control-Allow-Headers": '*',
|
||||
"Access-Control-Expose-Headers": '*'
|
||||
})
|
||||
if(event.method === 'OPTIONS'){
|
||||
event.node.res.statusCode = 204
|
||||
event.node.res.statusMessage = "No Content."
|
||||
return 'OK'
|
||||
}
|
||||
})
|
2
server/routes/hello.ts
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
export default defineEventHandler(() => 'Hello World!')
|
11
tailwind.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
export const theme = {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
'inter': ['Inter', 'sans-serif'],
|
||||
'poetsen-one': ['Poetsen One', 'sans-serif'],
|
||||
'sedan-sc': ['Sedan SC', 'sans-serif'],
|
||||
'breiem-hand': ['Briem Hand', 'sans-serif'],
|
||||
'noto-sans-cn': ['Noto Sans Simplified Chinese', 'sans-serif']
|
||||
}
|
||||
}
|
||||
};
|
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
1180
utils/sensitiveWords.js
Normal file
13
vercel.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"headers": [
|
||||
{
|
||||
"source": "/api/(.*)",
|
||||
"headers": [
|
||||
{ "key": "Access-Control-Allow-Credentials", "value": "true" },
|
||||
{ "key": "Access-Control-Allow-Origin", "value": "*" },
|
||||
{ "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
|
||||
{ "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|