Merge branch 'dev' of https://github.com/huangge1199/home into dev
# Conflicts: # .env # index.html # src/assets/socialLinks.json # src/components/Message.vue # yarn.lock
15
.dockerignore
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*
|
||||||
|
.dockerignore
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
.gitignore
|
||||||
|
README.md
|
||||||
|
LICENSE
|
||||||
|
.vscode
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
images
|
||||||
|
script
|
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.gitignore
|
35
.eslintrc.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": ["eslint:recommended", "plugin:vue/vue3-essential"],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["vue"],
|
||||||
|
"rules": {
|
||||||
|
"vue/multi-word-component-names": "off"
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"defineProps": true,
|
||||||
|
"defineEmits": true,
|
||||||
|
"withDefaults": true,
|
||||||
|
"h": true,
|
||||||
|
"vue": true,
|
||||||
|
"ref": true,
|
||||||
|
"reactive": true,
|
||||||
|
"computed": true,
|
||||||
|
"watch": true,
|
||||||
|
"provide": true,
|
||||||
|
"inject": true,
|
||||||
|
"defineComponent": true,
|
||||||
|
"onBeforeMount": true,
|
||||||
|
"onMounted": true,
|
||||||
|
"onBeforeUnmount": true,
|
||||||
|
"nextTick": true,
|
||||||
|
"ElMessage": true,
|
||||||
|
"$openList": true
|
||||||
|
}
|
||||||
|
}
|
38
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Dev 分支推送部署预览
|
||||||
|
## 仅部署 Win 端
|
||||||
|
name: Build Dev
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Build Website
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# 检出 Git 仓库
|
||||||
|
- name: Check out git repository
|
||||||
|
uses: actions/checkout@v4.1.1
|
||||||
|
# 安装 Node.js
|
||||||
|
- name: Install Node.js
|
||||||
|
uses: actions/setup-node@v4.0.0
|
||||||
|
with:
|
||||||
|
node-version: "18.x"
|
||||||
|
# 安装项目依赖
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm install
|
||||||
|
# 构建程序
|
||||||
|
- name: Build Website
|
||||||
|
run: npm run build
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
# 上传构建产物
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v3.1.3
|
||||||
|
with:
|
||||||
|
name: Home
|
||||||
|
path: dist
|
8
.prettierrc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/prettierrc",
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": true,
|
||||||
|
"printWidth": 100
|
||||||
|
}
|
128
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
one@imsyy.top.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
16
Dockerfile
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# 构建应用
|
||||||
|
FROM node:18 AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# 最小化镜像
|
||||||
|
FROM node:18-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
RUN npm install -g http-server
|
||||||
|
|
||||||
|
EXPOSE 12445
|
||||||
|
CMD ["http-server", "dist", "-p", "12445"]
|
107
README.md
@ -5,16 +5,17 @@
|
|||||||
简单的小主页,原来的看够了,重新弄了一个
|
简单的小主页,原来的看够了,重新弄了一个
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
![無名の主页](https://s2.loli.net/2022/07/14/K5JigfvDoNewtuS.webp)
|
![無名の主页](/screenshots/main.jpg)
|
||||||
|
|
||||||
>主页的 Logo 字体已经过压缩,若用本站 Logo 以外的字母会变回默认字体,这里是 [完整字体](https://file.4everland.app/font/Other/Pacifico-Regular.ttf)
|
>主页的 Logo 字体已经过压缩,若用本站 Logo 以外的字母会变回默认字体,这里是 [完整字体](https://file.imsyy.top/font/Other/Pacifico-Regular.ttf),若无法下载,可将字体目录下的 `Pacifico-Regular-all.ttf` 进行替换
|
||||||
|
|
||||||
### Demo
|
### Demo
|
||||||
|
|
||||||
>由于 CDN 缓存原因,查看最新效果可能需要 `Ctrl` + `F5` 强制刷新浏览器缓存
|
>由于 CDN 缓存原因,查看最新效果可能需要 `Ctrl` + `F5` 强制刷新浏览器缓存
|
||||||
|
|
||||||
- [無名の主页](https://www.imsyy.top)
|
- [無名の主页](https://www.imsyy.top)
|
||||||
- [無名の主页 - 备用线路](https://home-imsyy.vercel.app/)
|
- [無名の主页 - Dev](https://home-imsyy.vercel.app)
|
||||||
|
- [無名の主页 - 备用线路](https://home-5iw.pages.dev)
|
||||||
|
|
||||||
### 功能
|
### 功能
|
||||||
|
|
||||||
@ -27,7 +28,19 @@
|
|||||||
- [x] 音乐播放器
|
- [x] 音乐播放器
|
||||||
- [x] 移动端适配
|
- [x] 移动端适配
|
||||||
|
|
||||||
### 部署
|
### 自动部署
|
||||||
|
|
||||||
|
如果遇到构建环境或者打包过程出现错误,则可以采用 `Github Actions` 来进行自动构建
|
||||||
|
|
||||||
|
- 在成功 `fork` 仓库后,前往 `Actions` 页面,若您是首次开启,则会出现下面的提示,点击开启
|
||||||
|
|
||||||
|
![步骤1](/screenshots/step1.jpg)
|
||||||
|
|
||||||
|
- 然后在仓库中进行任意修改后均会触发工作流的运行,在工作流完成后,会在下方生成一个可供下载的压缩包,这就是构建出的静态文件,可自行上传至服务器
|
||||||
|
|
||||||
|
![步骤2](/screenshots/step2.jpg)
|
||||||
|
|
||||||
|
### 手动部署
|
||||||
|
|
||||||
* **安装** [node.js](https://nodejs.org/zh-cn/) **环境**
|
* **安装** [node.js](https://nodejs.org/zh-cn/) **环境**
|
||||||
|
|
||||||
@ -52,6 +65,63 @@ pnpm build
|
|||||||
```
|
```
|
||||||
> 构建完成后,静态资源会在 **`dist` 目录** 中生成,可将 **`dist` 文件夹下的文件**上传至服务器,也可使用 `Vercel` 等托管平台一键导入并自动部署
|
> 构建完成后,静态资源会在 **`dist` 目录** 中生成,可将 **`dist` 文件夹下的文件**上传至服务器,也可使用 `Vercel` 等托管平台一键导入并自动部署
|
||||||
|
|
||||||
|
### Docker 部署
|
||||||
|
|
||||||
|
> 安装及配置 Docker 将不在此处说明,请自行解决
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 构建
|
||||||
|
docker build -t home .
|
||||||
|
# 运行
|
||||||
|
docker run -p 12445:12445 -d home
|
||||||
|
```
|
||||||
|
|
||||||
|
### 网站链接
|
||||||
|
|
||||||
|
在 `src/assets/siteLinks.json` 中可以自定义网站链接(以指向自己的网站):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"icon": "Blog",
|
||||||
|
"name": "博客",
|
||||||
|
"link": "https://blog.imsyy.top/"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
其中 `icon` 网站链接的图标可以在 `src/components/Links/index.vue` 中添加:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
||||||
|
// 此处引入的是 fa 类型
|
||||||
|
import {
|
||||||
|
Link,
|
||||||
|
Blog,
|
||||||
|
CompactDisc,
|
||||||
|
Cloud,
|
||||||
|
Compass,
|
||||||
|
Book,
|
||||||
|
Fire,
|
||||||
|
LaptopCode,
|
||||||
|
} from "@vicons/fa";
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// 网站链接图标
|
||||||
|
const siteIcon = {
|
||||||
|
Blog,
|
||||||
|
Cloud,
|
||||||
|
CompactDisc,
|
||||||
|
Compass,
|
||||||
|
Book,
|
||||||
|
Fire,
|
||||||
|
LaptopCode,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 社交链接
|
||||||
|
|
||||||
|
在 `src/assets/socialLinks.json` 中可以自定义社交链接。
|
||||||
|
|
||||||
### 天气
|
### 天气
|
||||||
|
|
||||||
天气及地区获取需要 `高德开放平台` 相关 API
|
天气及地区获取需要 `高德开放平台` 相关 API
|
||||||
@ -122,6 +192,28 @@ make clean all
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### 网站图标及网站背景
|
||||||
|
|
||||||
|
#### 网站背景
|
||||||
|
|
||||||
|
可以在 `public/images` 中修改网站背景
|
||||||
|
|
||||||
|
如果想要添加更多的本地图片作为网站背景,可以将图片重命名 `background+数字` 的形式,并在 `src/components/Background/index.vue` 中进行修改:
|
||||||
|
|
||||||
|
```js
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
// 修改此处 Math.random() 后面的第一个数字为图片的数量
|
||||||
|
bgUrl.value = `/images/background${Math.floor(
|
||||||
|
Math.random() * 10 + 1
|
||||||
|
)}.webp`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 网站图标
|
||||||
|
|
||||||
|
可以在 `public/images/icon` 中修改网站图标。
|
||||||
|
|
||||||
### 技术栈
|
### 技术栈
|
||||||
|
|
||||||
* [Vue](https://cn.vuejs.org/)
|
* [Vue](https://cn.vuejs.org/)
|
||||||
@ -133,9 +225,14 @@ make clean all
|
|||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
||||||
* [MetingAPI By 武恩赐](https://api.wuenci.com/meting/api/)
|
* [小歪 API](https://api.aixiaowai.cn)
|
||||||
* [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
* [搏天 API](https://api.btstu.cn/doc/sjbz.php)
|
||||||
|
* [教书先生 API](https://api.oioweb.cn/doc/weather/GetWeather)
|
||||||
* [高德开放平台](https://lbs.amap.com/)
|
* [高德开放平台](https://lbs.amap.com/)
|
||||||
* [Hitokoto 一言](https://hitokoto.cn/)
|
* [Hitokoto 一言](https://hitokoto.cn/)
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[![Star History Chart](https://api.star-history.com/svg?repos=imsyy/home&type=Date)](https://star-history.com/#imsyy/home&Date)
|
||||||
|
|
||||||
<a title="SSL" target="_blank" href="https://myssl.com/seal/detail?domain=blog.imsyy.top"><img src="https://img.shields.io/badge/MySSL-安全认证-brightgreen"></a> <a title="CDN" target="_blank" href="https://cdnjs.com/"><img src="https://img.shields.io/badge/CDN-Cloudflare-blue"></a> <a title="Copyright" target="_blank" href="https://imsyy.top/"><img src="https://img.shields.io/badge/Copyright%20%C2%A9%202020--2023-%E7%84%A1%E5%90%8D-red"></a>
|
<a title="SSL" target="_blank" href="https://myssl.com/seal/detail?domain=blog.imsyy.top"><img src="https://img.shields.io/badge/MySSL-安全认证-brightgreen"></a> <a title="CDN" target="_blank" href="https://cdnjs.com/"><img src="https://img.shields.io/badge/CDN-Cloudflare-blue"></a> <a title="Copyright" target="_blank" href="https://imsyy.top/"><img src="https://img.shields.io/badge/Copyright%20%C2%A9%202020--2023-%E7%84%A1%E5%90%8D-red"></a>
|
||||||
|
@ -14,7 +14,8 @@ Simple little homepage, had enough of the original one and made a new one
|
|||||||
>Due to CDN caching, you may need `Ctrl` + `F5` to force a browser cache refresh to see the latest results
|
>Due to CDN caching, you may need `Ctrl` + `F5` to force a browser cache refresh to see the latest results
|
||||||
|
|
||||||
- [無名の主页](https://www.imsyy.top)
|
- [無名の主页](https://www.imsyy.top)
|
||||||
- [無名の主页 - 备用线路](https://home-imsyy.vercel.app/)
|
- [無名の主页 - Dev](https://home-imsyy.vercel.app)
|
||||||
|
- [無名の主页 - Standby](https://home-5iw.pages.dev)
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
|
9
docker-compose.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "12445:12445"
|
44
package.json
@ -4,36 +4,40 @@
|
|||||||
"github": "https://github.com/imsyy/home",
|
"github": "https://github.com/imsyy/home",
|
||||||
"home": "https://imsyy.top",
|
"home": "https://imsyy.top",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "4.0.5",
|
"version": "4.1.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"format": "prettier --write src/",
|
||||||
|
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.vue --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@icon-park/vue-next": "^1.4.2",
|
"@worstone/vue-aplayer": "^1.0.6",
|
||||||
"aplayer": "^1.10.1",
|
"aplayer": "^1.10.1",
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.6.3",
|
||||||
"element-plus": "^2.2.18",
|
"element-plus": "^2.4.4",
|
||||||
"fetch-jsonp": "^1.2.3",
|
"fetch-jsonp": "^1.3.0",
|
||||||
"pinia": "^2.0.23",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.0.0",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
"swiper": "^9.3.2",
|
"swiper": "^9.4.1",
|
||||||
"terser": "^5.16.1",
|
"vue": "^3.4.3"
|
||||||
"vue": "^3.2.37",
|
|
||||||
"vue3-aplayer": "^1.7.3"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@icon-park/vue-next": "^1.4.2",
|
||||||
"@vicons/fa": "^0.12.0",
|
"@vicons/fa": "^0.12.0",
|
||||||
"@vicons/material": "^0.12.0",
|
|
||||||
"@vicons/utils": "^0.1.4",
|
"@vicons/utils": "^0.1.4",
|
||||||
"@vitejs/plugin-vue": "^3.1.0",
|
"@vitejs/plugin-vue": "^4.6.2",
|
||||||
"sass": "^1.55.0",
|
"eslint": "^8.56.0",
|
||||||
"unplugin-auto-import": "^0.11.2",
|
"eslint-plugin-vue": "^9.19.2",
|
||||||
"unplugin-vue-components": "^0.22.8",
|
"prettier": "^3.1.1",
|
||||||
"vite": "^3.1.0",
|
"sass": "^1.69.6",
|
||||||
"vite-plugin-html": "^3.2.0",
|
"terser": "^5.26.0",
|
||||||
"vite-plugin-pwa": "^0.14.1"
|
"unplugin-auto-import": "^0.11.5",
|
||||||
|
"unplugin-vue-components": "^0.22.12",
|
||||||
|
"vite": "^4.5.1",
|
||||||
|
"vite-plugin-compression": "^0.5.1",
|
||||||
|
"vite-plugin-pwa": "^0.14.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3619
pnpm-lock.yaml
BIN
public/font/Pacifico-Regular-all.ttf
Normal file
3
public/font/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
## Logo 字体替换
|
||||||
|
|
||||||
|
可将该文件夹下的 `Pacifico-Regular-all.ttf` 替换原来的 `Pacifico-Regular.ttf`
|
BIN
public/images/background1.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 58 KiB |
BIN
public/images/background10.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 46 KiB |
BIN
public/images/background2.jpg
Normal file
After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 96 KiB |
BIN
public/images/background3.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 26 KiB |
BIN
public/images/background4.jpg
Normal file
After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 109 KiB |
BIN
public/images/background5.jpg
Normal file
After Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 147 KiB |
BIN
public/images/background6.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 36 KiB |
BIN
public/images/background7.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 46 KiB |
BIN
public/images/background8.jpg
Normal file
After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 116 KiB |
BIN
public/images/background9.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 80 KiB |
@ -1,141 +0,0 @@
|
|||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-box .loading-left-bg,
|
|
||||||
#loading-box .loading-right-bg {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 999;
|
|
||||||
width: 50%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #515151e0;
|
|
||||||
transition: all 0.75s cubic-bezier(0.42, 0, 0, 1.01);
|
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-box .loading-right-bg {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-box > .spinner-box {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 999999;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-box .spinner-box .loading-word {
|
|
||||||
position: absolute;
|
|
||||||
color: #ffffff;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
transform: translateY(64px);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-title {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
margin: 20px 10px 4px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-box .spinner-box .configure-core {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #37474f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 加载完成 */
|
|
||||||
.loaded .loading-left-bg {
|
|
||||||
transform: translate(-100%, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loaded .loading-right-bg {
|
|
||||||
transform: translate(100%, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
.loaded .spinner-box {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
position: absolute;
|
|
||||||
top: calc(50% - 32px);
|
|
||||||
left: calc(50% - 32px);
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: 50%;
|
|
||||||
perspective: 800px;
|
|
||||||
transition: all 0.7s cubic-bezier(0.42, 0, 0, 1.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner {
|
|
||||||
position: absolute;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner.one {
|
|
||||||
left: 0%;
|
|
||||||
top: 0%;
|
|
||||||
animation: rotate-one 1s linear infinite;
|
|
||||||
border-bottom: 3px solid #efeffa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner.two {
|
|
||||||
right: 0%;
|
|
||||||
top: 0%;
|
|
||||||
animation: rotate-two 1s linear infinite;
|
|
||||||
border-right: 3px solid #efeffa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner.three {
|
|
||||||
right: 0%;
|
|
||||||
bottom: 0%;
|
|
||||||
animation: rotate-three 1s linear infinite;
|
|
||||||
border-top: 3px solid #efeffa;
|
|
||||||
}
|
|
||||||
|
|
||||||
noscript {
|
|
||||||
z-index: 1000;
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 26px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate-one {
|
|
||||||
0% {
|
|
||||||
transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate-two {
|
|
||||||
0% {
|
|
||||||
transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate-three {
|
|
||||||
0% {
|
|
||||||
transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
1
public/loading/loading.min.css
vendored
@ -1 +0,0 @@
|
|||||||
*{margin:0;padding:0}#loading-box .loading-left-bg,#loading-box .loading-right-bg{position:fixed;z-index:999;width:50%;height:100%;background-color:#515151e0;transition:all .75s cubic-bezier(.42,0,0,1.01);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}#loading-box .loading-right-bg{right:0}#loading-box>.spinner-box{position:fixed;z-index:999999;display:flex;justify-content:center;align-items:center;width:100%;height:100vh}#loading-box .spinner-box .loading-word{position:absolute;color:#fff;font-size:.95rem;transform:translateY(64px);text-align:center}.loading-title{font-size:1.25rem;margin:20px 10px 4px 10px}#loading-box .spinner-box .configure-core{width:100%;height:100%;background-color:#37474f}.loaded .loading-left-bg{transform:translate(-100%,0)}.loaded .loading-right-bg{transform:translate(100%,0)}.loaded .spinner-box{display:none!important}.loader{position:absolute;top:calc(50% - 32px);left:calc(50% - 32px);width:64px;height:64px;border-radius:50%;perspective:800px;transition:all .7s cubic-bezier(.42,0,0,1.01)}.inner{position:absolute;box-sizing:border-box;width:100%;height:100%;border-radius:50%}.inner.one{left:0;top:0;animation:rotate-one 1s linear infinite;border-bottom:3px solid #efeffa}.inner.two{right:0;top:0;animation:rotate-two 1s linear infinite;border-right:3px solid #efeffa}.inner.three{right:0;bottom:0;animation:rotate-three 1s linear infinite;border-top:3px solid #efeffa}noscript{z-index:1000;position:absolute;display:flex;justify-content:center;width:100%;margin-top:26px}@keyframes rotate-one{0%{transform:rotateX(35deg) rotateY(-45deg) rotateZ(0)}100%{transform:rotateX(35deg) rotateY(-45deg) rotateZ(360deg)}}@keyframes rotate-two{0%{transform:rotateX(50deg) rotateY(10deg) rotateZ(0)}100%{transform:rotateX(50deg) rotateY(10deg) rotateZ(360deg)}}@keyframes rotate-three{0%{transform:rotateX(35deg) rotateY(55deg) rotateZ(0)}100%{transform:rotateX(35deg) rotateY(55deg) rotateZ(360deg)}}
|
|
BIN
screenshots/main.jpg
Normal file
After Width: | Height: | Size: 245 KiB |
BIN
screenshots/step1.jpg
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
screenshots/step2.jpg
Normal file
After Width: | Height: | Size: 67 KiB |
133
src/App.vue
@ -1,18 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="animate">
|
<!-- 加载 -->
|
||||||
<Background />
|
<Loading />
|
||||||
<main>
|
<!-- 壁纸 -->
|
||||||
|
<Background @loadComplete="loadComplete" />
|
||||||
|
<!-- 主界面 -->
|
||||||
|
<Transition name="fade" mode="out-in">
|
||||||
|
<main id="main" v-if="store.imgLoadStatus">
|
||||||
<div class="container" v-show="!store.backgroundShow">
|
<div class="container" v-show="!store.backgroundShow">
|
||||||
<section class="main" v-show="!store.setOpenState">
|
<section class="all" v-show="!store.setOpenState">
|
||||||
<MainLeft />
|
<MainLeft />
|
||||||
<MainRight v-show="!store.boxOpenState" />
|
<MainRight v-show="!store.boxOpenState" />
|
||||||
<Box v-show="store.boxOpenState" />
|
<Box v-show="store.boxOpenState" />
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section class="more" v-show="store.setOpenState" @click="store.setOpenState = false">
|
||||||
class="more"
|
|
||||||
v-show="store.setOpenState"
|
|
||||||
@click="store.setOpenState = false"
|
|
||||||
>
|
|
||||||
<MoreSet />
|
<MoreSet />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -20,30 +20,32 @@
|
|||||||
<Icon
|
<Icon
|
||||||
class="menu"
|
class="menu"
|
||||||
size="24"
|
size="24"
|
||||||
|
v-show="!store.backgroundShow"
|
||||||
@click="store.mobileOpenState = !store.mobileOpenState"
|
@click="store.mobileOpenState = !store.mobileOpenState"
|
||||||
>
|
>
|
||||||
<component :is="store.mobileOpenState ? CloseSmall : HamburgerButton" />
|
<component :is="store.mobileOpenState ? CloseSmall : HamburgerButton" />
|
||||||
</Icon>
|
</Icon>
|
||||||
</main>
|
<!-- 页脚 -->
|
||||||
|
<Transition name="fade" mode="out-in">
|
||||||
<Footer v-show="!store.backgroundShow && !store.setOpenState" />
|
<Footer v-show="!store.backgroundShow && !store.setOpenState" />
|
||||||
</div>
|
</Transition>
|
||||||
|
</main>
|
||||||
|
</Transition>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onBeforeUnmount, watch } from "vue";
|
|
||||||
import { helloInit, checkDays } from "@/utils/getTime.js";
|
import { helloInit, checkDays } from "@/utils/getTime.js";
|
||||||
|
import { HamburgerButton, CloseSmall } from "@icon-park/vue-next";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import { Icon } from "@vicons/utils";
|
import { Icon } from "@vicons/utils";
|
||||||
import { HamburgerButton, CloseSmall } from "@icon-park/vue-next";
|
import Loading from "@/components/Loading.vue";
|
||||||
import MainLeft from "@/views/Main/Left.vue";
|
import MainLeft from "@/views/Main/Left.vue";
|
||||||
import MainRight from "@/views/Main/Right.vue";
|
import MainRight from "@/views/Main/Right.vue";
|
||||||
import Background from "@/components/Background/index.vue";
|
import Background from "@/components/Background.vue";
|
||||||
import Footer from "@/components/Footer/index.vue";
|
import Footer from "@/components/Footer.vue";
|
||||||
import Box from "@/views/Box/index.vue";
|
import Box from "@/views/Box/index.vue";
|
||||||
import MoreSet from "@/views/MoreSet/index.vue";
|
import MoreSet from "@/views/MoreSet/index.vue";
|
||||||
import cursorInit from "@/utils/cursor.js";
|
import cursorInit from "@/utils/cursor.js";
|
||||||
import config from "@/../package.json";
|
import config from "@/../package.json";
|
||||||
// 新春灯笼
|
|
||||||
// import "@/utils/lantern.js";
|
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
@ -52,22 +54,29 @@ const getWidth = () => {
|
|||||||
store.setInnerWidth(window.innerWidth);
|
store.setInnerWidth(window.innerWidth);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
// 加载完成事件
|
||||||
// 自定义鼠标
|
const loadComplete = () => {
|
||||||
cursorInit();
|
nextTick(() => {
|
||||||
// 加载完成事件
|
|
||||||
window.addEventListener("load", () => {
|
|
||||||
console.log("加载完成");
|
|
||||||
// 去除加载标记
|
|
||||||
document.getElementsByTagName("body")[0].className = "";
|
|
||||||
// 给加载动画添加结束标记
|
|
||||||
const loadingBox = document.getElementById("loading-box");
|
|
||||||
loadingBox.classList.add("loaded");
|
|
||||||
// 欢迎提示
|
// 欢迎提示
|
||||||
helloInit();
|
helloInit();
|
||||||
// 默哀模式
|
// 默哀模式
|
||||||
checkDays();
|
checkDays();
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听宽度变化
|
||||||
|
watch(
|
||||||
|
() => store.innerWidth,
|
||||||
|
(value) => {
|
||||||
|
if (value < 990) {
|
||||||
|
store.boxOpenState = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 自定义鼠标
|
||||||
|
cursorInit();
|
||||||
|
|
||||||
// 屏蔽右键
|
// 屏蔽右键
|
||||||
document.oncontextmenu = () => {
|
document.oncontextmenu = () => {
|
||||||
@ -95,8 +104,7 @@ onMounted(() => {
|
|||||||
window.addEventListener("resize", getWidth);
|
window.addEventListener("resize", getWidth);
|
||||||
|
|
||||||
// 控制台输出
|
// 控制台输出
|
||||||
const styleTitle1 =
|
const styleTitle1 = "font-size: 20px;font-weight: 600;color: rgb(244,167,89);";
|
||||||
"font-size: 20px;font-weight: 600;color: rgb(244,167,89);";
|
|
||||||
const styleTitle2 = "font-size:12px;color: rgb(244,167,89);";
|
const styleTitle2 = "font-size:12px;color: rgb(244,167,89);";
|
||||||
const styleContent = "color: rgb(30,152,255);";
|
const styleContent = "color: rgb(30,152,255);";
|
||||||
const title1 = "無名の主页";
|
const title1 = "無名の主页";
|
||||||
@ -108,39 +116,30 @@ onMounted(() => {
|
|||||||
_| |_| | | |____) | | | | |
|
_| |_| | | |____) | | | | |
|
||||||
|_____|_| |_|_____/ |_| |_|`;
|
|_____|_| |_|_____/ |_| |_|`;
|
||||||
const content = `\n\n版本: ${config.version}\n主页: ${config.home}\nGithub: ${config.github}`;
|
const content = `\n\n版本: ${config.version}\n主页: ${config.home}\nGithub: ${config.github}`;
|
||||||
console.info(
|
console.info(`%c${title1} %c${title2} %c${content}`, styleTitle1, styleTitle2, styleContent);
|
||||||
`%c${title1} %c${title2} %c${content}`,
|
|
||||||
styleTitle1,
|
|
||||||
styleTitle2,
|
|
||||||
styleContent
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 监听宽度变化
|
|
||||||
watch(
|
|
||||||
() => store.innerWidth,
|
|
||||||
(value) => {
|
|
||||||
if (value < 990) {
|
|
||||||
store.boxOpenState = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("resize", getWidth);
|
window.removeEventListener("resize", getWidth);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
main {
|
#main {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: scale(1.2);
|
||||||
|
transition: transform 0.3s;
|
||||||
|
animation: fade-blur-main-in 0.65s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||||
|
animation-delay: 0.5s;
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@media (max-width: 1200px) {
|
.all {
|
||||||
padding: 0 2vw;
|
|
||||||
}
|
|
||||||
.main {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0 0.75rem;
|
padding: 0 0.75rem;
|
||||||
@ -158,8 +157,10 @@ main {
|
|||||||
background-color: #00000080;
|
background-color: #00000080;
|
||||||
backdrop-filter: blur(20px);
|
backdrop-filter: blur(20px);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
}
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
padding: 0 2vw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.menu {
|
.menu {
|
||||||
@ -174,37 +175,17 @@ main {
|
|||||||
background: rgb(0 0 0 / 20%);
|
background: rgb(0 0 0 / 20%);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
transition: all 0.3s;
|
transition: transform 0.3s;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
.i-icon {
|
.i-icon {
|
||||||
transform: translateY(2px);
|
transform: translateY(2px);
|
||||||
}
|
}
|
||||||
@media (min-width: 720px) {
|
@media (min-width: 721px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 加载动画层
|
|
||||||
.animate {
|
|
||||||
transform: scale(1);
|
|
||||||
transition: all ease 1.25s;
|
|
||||||
opacity: 1;
|
|
||||||
filter: blur(0);
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
.animate {
|
|
||||||
transform: scale(1.2);
|
|
||||||
transition: all ease 1.25s;
|
|
||||||
opacity: 0;
|
|
||||||
filter: blur(10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -8,14 +8,13 @@ import fetchJsonp from "fetch-jsonp";
|
|||||||
// 获取音乐播放列表
|
// 获取音乐播放列表
|
||||||
export const getPlayerList = async (server, type, id) => {
|
export const getPlayerList = async (server, type, id) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`${import.meta.env.VITE_SONG_API}?server=${server}&type=${type}&id=${id}`
|
`${import.meta.env.VITE_SONG_API}?server=${server}&type=${type}&id=${id}`,
|
||||||
);
|
);
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data[0].url.startsWith("@")) {
|
if (data[0].url.startsWith("@")) {
|
||||||
const [handle, jsonpCallback, jsonpCallbackFunction, url] = data[0].url
|
// eslint-disable-next-line no-unused-vars
|
||||||
.split("@")
|
const [handle, jsonpCallback, jsonpCallbackFunction, url] = data[0].url.split("@").slice(1);
|
||||||
.slice(1);
|
|
||||||
const jsonpData = await fetchJsonp(url).then((res) => res.json());
|
const jsonpData = await fetchJsonp(url).then((res) => res.json());
|
||||||
const domain = (
|
const domain = (
|
||||||
jsonpData.req_0.data.sip.find((i) => !i.startsWith("http://ws")) ||
|
jsonpData.req_0.data.sip.find((i) => !i.startsWith("http://ws")) ||
|
||||||
@ -23,18 +22,18 @@ export const getPlayerList = async (server, type, id) => {
|
|||||||
).replace("http://", "https://");
|
).replace("http://", "https://");
|
||||||
|
|
||||||
return data.map((v, i) => ({
|
return data.map((v, i) => ({
|
||||||
title: v.name || v.title,
|
name: v.name || v.title,
|
||||||
artist: v.artist || v.author,
|
artist: v.artist || v.author,
|
||||||
src: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
url: domain + jsonpData.req_0.data.midurlinfo[i].purl,
|
||||||
pic: v.pic,
|
cover: v.cover || v.pic,
|
||||||
lrc: v.lrc,
|
lrc: v.lrc,
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
return data.map((v) => ({
|
return data.map((v) => ({
|
||||||
title: v.name || v.title,
|
name: v.name || v.title,
|
||||||
artist: v.artist || v.author,
|
artist: v.artist || v.author,
|
||||||
src: v.url,
|
url: v.url,
|
||||||
pic: v.pic,
|
cover: v.cover || v.pic,
|
||||||
lrc: v.lrc,
|
lrc: v.lrc,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -63,7 +62,7 @@ export const getAdcode = async (key) => {
|
|||||||
// 获取高德地理天气信息
|
// 获取高德地理天气信息
|
||||||
export const getWeather = async (key, city) => {
|
export const getWeather = async (key, city) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`
|
`https://restapi.amap.com/v3/weather/weatherInfo?key=${key}&city=${city}`,
|
||||||
);
|
);
|
||||||
return await res.json();
|
return await res.json();
|
||||||
};
|
};
|
||||||
|
163
src/components/Background.vue
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="store.backgroundShow ? 'cover show' : 'cover'">
|
||||||
|
<img
|
||||||
|
v-show="store.imgLoadStatus"
|
||||||
|
class="bg"
|
||||||
|
alt="cover"
|
||||||
|
:src="bgUrl"
|
||||||
|
@load="imgLoadComplete"
|
||||||
|
@error.once="imgLoadError"
|
||||||
|
@animationend="imgAnimationEnd"
|
||||||
|
/>
|
||||||
|
<div :class="store.backgroundShow ? 'gray hidden' : 'gray'" />
|
||||||
|
<Transition name="fade" mode="out-in">
|
||||||
|
<a
|
||||||
|
v-if="store.backgroundShow && store.coverType != '3'"
|
||||||
|
class="down"
|
||||||
|
:href="bgUrl"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
下载壁纸
|
||||||
|
</a>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { mainStore } from "@/store";
|
||||||
|
import { Error } from "@icon-park/vue-next";
|
||||||
|
|
||||||
|
const store = mainStore();
|
||||||
|
const bgUrl = ref(null);
|
||||||
|
const imgTimeout = ref(null);
|
||||||
|
const emit = defineEmits(["loadComplete"]);
|
||||||
|
|
||||||
|
// 壁纸随机数
|
||||||
|
// 请依据文件夹内的图片个数修改 Math.random() 后面的第一个数字
|
||||||
|
const bgRandom = Math.floor(Math.random() * 10 + 1);
|
||||||
|
|
||||||
|
// 更换壁纸链接
|
||||||
|
const changeBg = (type) => {
|
||||||
|
if (type == 0) {
|
||||||
|
bgUrl.value = `/images/background${bgRandom}.jpg`;
|
||||||
|
} else if (type == 1) {
|
||||||
|
bgUrl.value = "https://api.dujin.org/bing/1920.php";
|
||||||
|
} else if (type == 2) {
|
||||||
|
bgUrl.value = "https://api.aixiaowai.cn/gqapi/gqapi.php";
|
||||||
|
} else if (type == 3) {
|
||||||
|
bgUrl.value = "https://api.aixiaowai.cn/api/api.php";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 图片加载完成
|
||||||
|
const imgLoadComplete = () => {
|
||||||
|
imgTimeout.value = setTimeout(
|
||||||
|
() => {
|
||||||
|
store.setImgLoadStatus(true);
|
||||||
|
},
|
||||||
|
Math.floor(Math.random() * (600 - 300 + 1)) + 300,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 图片动画完成
|
||||||
|
const imgAnimationEnd = () => {
|
||||||
|
console.log("壁纸加载且动画完成");
|
||||||
|
// 加载完成事件
|
||||||
|
emit("loadComplete");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 图片显示失败
|
||||||
|
const imgLoadError = () => {
|
||||||
|
console.error("壁纸加载失败:", bgUrl.value);
|
||||||
|
ElMessage({
|
||||||
|
message: "壁纸加载失败,已临时切换回默认",
|
||||||
|
icon: h(Error, {
|
||||||
|
theme: "filled",
|
||||||
|
fill: "#efefef",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
bgUrl.value = `/images/background${bgRandom}.jpg`;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 加载壁纸
|
||||||
|
changeBg(store.coverType);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearTimeout(imgTimeout.value);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cover {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transition: 0.25s;
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
&.show {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
filter: blur(20px) brightness(0.3);
|
||||||
|
transition:
|
||||||
|
filter 0.3s,
|
||||||
|
transform 0.3s;
|
||||||
|
animation: fade-blur-in 1s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
|
||||||
|
animation-delay: 0.45s;
|
||||||
|
}
|
||||||
|
.gray {
|
||||||
|
opacity: 1;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-image: radial-gradient(rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0.5) 100%),
|
||||||
|
radial-gradient(rgba(0, 0, 0, 0) 33%, rgba(0, 0, 0, 0.3) 166%);
|
||||||
|
|
||||||
|
transition: 1.5s;
|
||||||
|
&.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
transition: 1.5s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.down {
|
||||||
|
font-size: 16px;
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: block;
|
||||||
|
padding: 20px 26px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #00000030;
|
||||||
|
width: 120px;
|
||||||
|
height: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
background-color: #00000060;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,144 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="cover">
|
|
||||||
<img class="bg" :src="bgUrl" alt="cover" />
|
|
||||||
<div :class="store.backgroundShow ? 'gray sm' : 'gray'" />
|
|
||||||
<transition name="el-fade-in-linear">
|
|
||||||
<a
|
|
||||||
class="down"
|
|
||||||
:href="bgUrl"
|
|
||||||
target="_blank"
|
|
||||||
v-show="store.backgroundShow && store.coverType != '3'"
|
|
||||||
>下载壁纸</a
|
|
||||||
>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { onMounted, ref, watch, h } from "vue";
|
|
||||||
import { SuccessPicture } from "@icon-park/vue-next";
|
|
||||||
import { mainStore } from "@/store";
|
|
||||||
|
|
||||||
const store = mainStore();
|
|
||||||
const bgUrl = ref(null); // 壁纸链接
|
|
||||||
|
|
||||||
// 更换壁纸链接
|
|
||||||
const changeBg = (type) => {
|
|
||||||
if (type == 0) {
|
|
||||||
bgUrl.value = `/images/background${Math.floor(
|
|
||||||
Math.random() * 10 + 1
|
|
||||||
)}.webp`;
|
|
||||||
} else if (type == 1) {
|
|
||||||
bgUrl.value = "https://api.dujin.org/bing/1920.php";
|
|
||||||
} else if (type == 2) {
|
|
||||||
bgUrl.value = "https://api.btstu.cn/sjbz/api.php?lx=fengjing&format=images";
|
|
||||||
} else if (type == 3) {
|
|
||||||
bgUrl.value = "https://api.btstu.cn/sjbz/api.php?lx=dongman&format=images";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 加载壁纸
|
|
||||||
changeBg(store.coverType);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听壁纸种类变化
|
|
||||||
watch(
|
|
||||||
() => store.coverType,
|
|
||||||
(value) => {
|
|
||||||
changeBg(value);
|
|
||||||
ElMessage({
|
|
||||||
message: "壁纸设置成功",
|
|
||||||
icon: h(SuccessPicture, {
|
|
||||||
theme: "filled",
|
|
||||||
fill: "#efefef",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.cover {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
transition: 0.25s;
|
|
||||||
z-index: -1;
|
|
||||||
|
|
||||||
.bg {
|
|
||||||
transform: scale(1);
|
|
||||||
filter: blur(0);
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
transition: all 1.5s ease 0s;
|
|
||||||
backface-visibility: hidden;
|
|
||||||
}
|
|
||||||
.gray {
|
|
||||||
opacity: 1;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-image: radial-gradient(
|
|
||||||
rgba(0, 0, 0, 0) 0,
|
|
||||||
rgba(0, 0, 0, 0.5) 100%
|
|
||||||
),
|
|
||||||
radial-gradient(rgba(0, 0, 0, 0) 33%, rgba(0, 0, 0, 0.3) 166%);
|
|
||||||
|
|
||||||
transition: 1.5s;
|
|
||||||
&.sm {
|
|
||||||
opacity: 0;
|
|
||||||
transition: 1.5s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.down {
|
|
||||||
font-size: 16px;
|
|
||||||
color: white;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: 0 auto;
|
|
||||||
display: block;
|
|
||||||
padding: 20px 26px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background-color: #00000030;
|
|
||||||
width: 120px;
|
|
||||||
height: 30px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
&:hover {
|
|
||||||
transform: scale(1.05);
|
|
||||||
background-color: #00000060;
|
|
||||||
}
|
|
||||||
&:active {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载时动画
|
|
||||||
.loading {
|
|
||||||
.cover {
|
|
||||||
.bg {
|
|
||||||
transition: 1.5s;
|
|
||||||
transform: scale(1.1);
|
|
||||||
filter: blur(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gray {
|
|
||||||
transition: 1.5s;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
120
src/components/Footer.vue
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<footer id="footer" :class="store.footerBlur ? 'blur' : null">
|
||||||
|
<Transition name="fade" mode="out-in">
|
||||||
|
<div v-if="!store.playerState || !store.playerLrcShow" class="power">
|
||||||
|
<span>
|
||||||
|
Copyright ©
|
||||||
|
<span v-if="siteStartDate?.length >= 4" class="site-start">
|
||||||
|
{{ siteStartDate.substring(0, 4) }}
|
||||||
|
-
|
||||||
|
</span>
|
||||||
|
{{ fullYear }}
|
||||||
|
<a :href="siteUrl">{{ siteAnthor }}</a>
|
||||||
|
</span>
|
||||||
|
<!-- 以下信息请不要修改哦 -->
|
||||||
|
<span class="hidden">
|
||||||
|
& Made by
|
||||||
|
<a :href="config.github" target="_blank">
|
||||||
|
{{ config.author }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<!-- 站点备案 -->
|
||||||
|
<a v-if="siteIcp" href="https://beian.miit.gov.cn" target="_blank">
|
||||||
|
&
|
||||||
|
{{ siteIcp }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div v-else class="lrc">
|
||||||
|
<Transition name="fade" mode="out-in">
|
||||||
|
<div class="lrc-all" :key="store.getPlayerLrc">
|
||||||
|
<music-one theme="filled" size="18" fill="#efefef" />
|
||||||
|
<span class="lrc-text text-hidden" v-html="store.getPlayerLrc" />
|
||||||
|
<music-one theme="filled" size="18" fill="#efefef" />
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { MusicOne } from "@icon-park/vue-next";
|
||||||
|
import { mainStore } from "@/store";
|
||||||
|
import config from "@/../package.json";
|
||||||
|
|
||||||
|
const store = mainStore();
|
||||||
|
const fullYear = new Date().getFullYear();
|
||||||
|
|
||||||
|
// 加载配置数据
|
||||||
|
const siteStartDate = ref(import.meta.env.VITE_SITE_START);
|
||||||
|
const siteIcp = ref(import.meta.env.VITE_SITE_ICP);
|
||||||
|
const siteAnthor = ref(import.meta.env.VITE_SITE_ANTHOR);
|
||||||
|
const siteUrl = computed(() => {
|
||||||
|
const url = import.meta.env.VITE_SITE_URL;
|
||||||
|
if (!url) return "https://www.imsyy.top";
|
||||||
|
// 判断协议前缀
|
||||||
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||||
|
return "//" + url;
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#footer {
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
text-align: center;
|
||||||
|
z-index: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
.power {
|
||||||
|
animation: fade 0.3s;
|
||||||
|
}
|
||||||
|
.lrc {
|
||||||
|
padding: 0 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.lrc-all {
|
||||||
|
width: 98%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.lrc-text {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
.i-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.blur {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
background: rgb(0 0 0 / 25%);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
&.blur {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,101 +0,0 @@
|
|||||||
<template>
|
|
||||||
<footer>
|
|
||||||
<div class="power" v-show="!store.playerState">
|
|
||||||
<span>
|
|
||||||
Copyright ©
|
|
||||||
<span v-if="siteStartDate?.length >= 4" class="site-start">
|
|
||||||
{{ siteStartDate.substring(0, 4) }}
|
|
||||||
-
|
|
||||||
</span>
|
|
||||||
{{ fullYear }}
|
|
||||||
<a :href="SiteUrl">{{ SiteAnthor }}</a>
|
|
||||||
</span>
|
|
||||||
<!-- 以下信息请不要修改哦 -->
|
|
||||||
<span class="hidden">
|
|
||||||
& Made by
|
|
||||||
<a :href="config.github" target="_blank">
|
|
||||||
{{ config.author }}
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<!-- 站点备案 -->
|
|
||||||
<a v-if="siteIcp" href="https://beian.miit.gov.cn" target="_blank">
|
|
||||||
&
|
|
||||||
{{ siteIcp }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="lrc" v-show="store.playerState">
|
|
||||||
<music-one theme="filled" size="18" fill="#efefef" />
|
|
||||||
<span class="lrc-text">
|
|
||||||
{{ store.getPlayerLrc ? store.getPlayerLrc : "这句没有歌词" }}
|
|
||||||
</span>
|
|
||||||
<music-one theme="filled" size="18" fill="#efefef" />
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { MusicOne } from "@icon-park/vue-next";
|
|
||||||
import { mainStore } from "@/store";
|
|
||||||
import config from "@/../package.json";
|
|
||||||
|
|
||||||
const store = mainStore();
|
|
||||||
const fullYear = new Date().getFullYear();
|
|
||||||
|
|
||||||
// 加载配置数据
|
|
||||||
const siteStartDate = ref(import.meta.env.VITE_SITE_START);
|
|
||||||
const siteIcp = ref(import.meta.env.VITE_SITE_ICP);
|
|
||||||
const SiteAnthor = ref(import.meta.env.VITE_SITE_ANTHOR);
|
|
||||||
const SiteUrl = ref(import.meta.env.VITE_SITE_URL);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
footer {
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 46px;
|
|
||||||
line-height: 46px;
|
|
||||||
text-align: center;
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
background: rgb(0 0 0 / 25%);
|
|
||||||
z-index: 0;
|
|
||||||
animation: fade;
|
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
@media (max-width: 720px) {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.power {
|
|
||||||
animation: fade;
|
|
||||||
-webkit-animation: fade 0.3s;
|
|
||||||
}
|
|
||||||
.lrc {
|
|
||||||
padding: 0 20px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
animation: fade;
|
|
||||||
-webkit-animation: fade 0.3s;
|
|
||||||
.lrc-text {
|
|
||||||
margin: 0 8px;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
.i-icon {
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
display: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
169
src/components/GithubProject.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<div class="github-project">
|
||||||
|
<div class="title">
|
||||||
|
<github-one theme="two-tone" size="24" :fill="['#efefef', '#00000020']" />
|
||||||
|
<span>Github</span>
|
||||||
|
</div>
|
||||||
|
<Swiper
|
||||||
|
:modules="[Pagination, Mousewheel]"
|
||||||
|
:slides-per-view="1"
|
||||||
|
:space-between="40"
|
||||||
|
:pagination="{
|
||||||
|
el: '.swiper-pagination',
|
||||||
|
clickable: true,
|
||||||
|
bulletElement: 'div',
|
||||||
|
}"
|
||||||
|
:mousewheel="true"
|
||||||
|
>
|
||||||
|
<SwiperSlide v-for="list in projectList" :key="list">
|
||||||
|
<el-row class="all-project" :gutter="20">
|
||||||
|
<el-col v-for="(item, index) in list" :span="12" :key="index">
|
||||||
|
<div class="project cards" @click="toGithub(item)">
|
||||||
|
<div class="name">
|
||||||
|
<bookmark theme="outline" size="22" fill="#efefef" />
|
||||||
|
<div class="name-text">
|
||||||
|
<span class="author">{{ item.author }}</span>
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="desc">{{ item.desc }}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</SwiperSlide>
|
||||||
|
<div class="swiper-pagination" />
|
||||||
|
</Swiper>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { GithubOne, Bookmark } from "@icon-park/vue-next";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
|
import { Pagination, Mousewheel } from "swiper";
|
||||||
|
|
||||||
|
// 仓库数据
|
||||||
|
const projectData = [
|
||||||
|
{
|
||||||
|
name: "home",
|
||||||
|
author: "imsyy",
|
||||||
|
desc: "个人主页,我的个人主页,个人主页源码,主页模板,homepage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SPlayer",
|
||||||
|
author: "imsyy",
|
||||||
|
desc: "🎉 一个简约的音乐播放器,支持网易云音乐账号登录,逐字歌词,下载歌曲,展示评论区,音乐云盘及歌单管理,音乐频谱,移动端基础适配 | A minimalist music player",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Snavigation",
|
||||||
|
author: "imsyy",
|
||||||
|
desc: "Snavigation 一个简约的起始页 | 支持自定义搜索引擎,自定义快捷方式,自定义壁纸以及数据备份",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DailyHotApi",
|
||||||
|
author: "imsyy",
|
||||||
|
desc: "今日热榜 API,一个聚合热门数据的 API 接口,支持 Vercel 部署 | 前端页面:https://github.com/imsyy/DailyHot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "site-status",
|
||||||
|
author: "imsyy",
|
||||||
|
desc: "📺 一个基于 UptimeRobot API 的在线状态面板 | 站点监测 | 状态检测 | An online status panel based on the UptimeRobot API | UptimeRobot, status, site",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 计算网站链接
|
||||||
|
const projectList = computed(() => {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < projectData.length; i += 4) {
|
||||||
|
const subArr = projectData.slice(i, i + 4);
|
||||||
|
result.push(subArr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 跳转至 Github
|
||||||
|
const toGithub = (data) => {
|
||||||
|
window.open(`https://github.com/${data.author}/${data.name}`);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.github-project {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0.2rem 0 1.5rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
.i-icon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.swiper {
|
||||||
|
left: -10px;
|
||||||
|
width: calc(100% + 20px);
|
||||||
|
padding: 5px 10px 0;
|
||||||
|
z-index: 0;
|
||||||
|
.swiper-slide {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.swiper-pagination {
|
||||||
|
position: static;
|
||||||
|
margin-top: -8px;
|
||||||
|
:deep(.swiper-pagination-bullet) {
|
||||||
|
background-color: #fff;
|
||||||
|
width: 18px;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.all-project {
|
||||||
|
width: calc(100% + 20px);
|
||||||
|
.project {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 12px;
|
||||||
|
height: 100px;
|
||||||
|
background-color: transparent;
|
||||||
|
.name {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
.i-icon {
|
||||||
|
display: flex;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
.author {
|
||||||
|
opacity: 0.8;
|
||||||
|
&::after {
|
||||||
|
content: "/";
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
word-break: break-all;
|
||||||
|
font-size: 13px;
|
||||||
|
opacity: 0.8;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -18,19 +18,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<!-- 一言内容 -->
|
<!-- 一言内容 -->
|
||||||
<div class="content" @click="updateHitokoto">
|
<Transition name="el-fade-in-linear" mode="out-in">
|
||||||
|
<div :key="hitokotoData.text" class="content" @click="updateHitokoto">
|
||||||
<span class="text">{{ hitokotoData.text }}</span>
|
<span class="text">{{ hitokotoData.text }}</span>
|
||||||
<span class="from">-「 {{ hitokotoData.from }} 」</span>
|
<span class="from">-「 {{ hitokotoData.from }} 」</span>
|
||||||
</div>
|
</div>
|
||||||
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, onMounted, h } from "vue";
|
|
||||||
import { MusicMenu, Error } from "@icon-park/vue-next";
|
import { MusicMenu, Error } from "@icon-park/vue-next";
|
||||||
import { getHitokoto } from "@/api";
|
import { getHitokoto } from "@/api";
|
||||||
import debounce from "@/utils/debounce.js";
|
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
|
import debounce from "@/utils/debounce.js";
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
// 开启音乐面板按钮显隐
|
// 开启音乐面板按钮显隐
|
||||||
@ -43,13 +45,12 @@ const hitokotoData = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 获取一言数据
|
// 获取一言数据
|
||||||
const getHitokotoData = () => {
|
const getHitokotoData = async () => {
|
||||||
getHitokoto()
|
try {
|
||||||
.then((res) => {
|
const result = await getHitokoto();
|
||||||
hitokotoData.text = res.hitokoto;
|
hitokotoData.text = result.hitokoto;
|
||||||
hitokotoData.from = res.from;
|
hitokotoData.from = result.from;
|
||||||
})
|
} catch (error) {
|
||||||
.catch(() => {
|
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: "一言获取失败",
|
message: "一言获取失败",
|
||||||
icon: h(Error, {
|
icon: h(Error, {
|
||||||
@ -57,13 +58,13 @@ const getHitokotoData = () => {
|
|||||||
fill: "#efefef",
|
fill: "#efefef",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
});
|
hitokotoData.text = "这里应该显示一句话";
|
||||||
|
hitokotoData.from = "無名";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新一言数据
|
// 更新一言数据
|
||||||
const updateHitokoto = () => {
|
const updateHitokoto = () => {
|
||||||
hitokotoData.text = "新的一言正在赶来的路上";
|
|
||||||
hitokotoData.from = "来源加载中";
|
|
||||||
// 防抖
|
// 防抖
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
getHitokotoData();
|
getHitokotoData();
|
||||||
@ -80,8 +81,7 @@ onMounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
.open-music {
|
.open-music {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
@ -21,20 +21,16 @@
|
|||||||
>
|
>
|
||||||
<SwiperSlide v-for="site in siteLinksList" :key="site">
|
<SwiperSlide v-for="site in siteLinksList" :key="site">
|
||||||
<el-row class="link-all" :gutter="20">
|
<el-row class="link-all" :gutter="20">
|
||||||
<el-col
|
<el-col v-for="(item, index) in site" :span="8" :key="item">
|
||||||
v-for="(item, index) in site"
|
|
||||||
:span="8"
|
|
||||||
:key="item"
|
|
||||||
@click="jumpLink(item)"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="item cards"
|
class="item cards"
|
||||||
:style="index < 3 ? 'margin-bottom: 20px' : null"
|
:style="index < 3 ? 'margin-bottom: 20px' : null"
|
||||||
|
@click="jumpLink(item)"
|
||||||
>
|
>
|
||||||
<Icon size="26">
|
<Icon size="26">
|
||||||
<component :is="siteIcon[item.icon]" />
|
<component :is="siteIcon[item.icon]" />
|
||||||
</Icon>
|
</Icon>
|
||||||
<span class="name">{{ item.name }}</span>
|
<span class="name text-hidden">{{ item.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -45,25 +41,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, computed } from "vue";
|
|
||||||
import { Icon } from "@vicons/utils";
|
import { Icon } from "@vicons/utils";
|
||||||
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
// 可前往 https://www.xicons.org 自行挑选并在此处引入
|
||||||
import {
|
import { Link, Blog, CompactDisc, Cloud, Compass, Book, Fire, LaptopCode } from "@vicons/fa"; // 注意使用正确的类别
|
||||||
Link,
|
|
||||||
Blog,
|
|
||||||
CompactDisc,
|
|
||||||
Cloud,
|
|
||||||
Compass,
|
|
||||||
Book,
|
|
||||||
Fire,
|
|
||||||
LaptopCode,
|
|
||||||
} from "@vicons/fa";
|
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
import { Pagination, Mousewheel } from "swiper";
|
import { Pagination, Mousewheel } from "swiper";
|
||||||
import siteLinks from "@/assets/siteLinks.json";
|
import siteLinks from "@/assets/siteLinks.json";
|
||||||
import "swiper/scss";
|
|
||||||
import "swiper/scss/pagination";
|
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
@ -109,8 +93,7 @@ onMounted(() => {
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
.title {
|
.title {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
@ -149,8 +132,8 @@ onMounted(() => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
animation: fade;
|
padding: 0 10px;
|
||||||
-webkit-animation: fade 0.5s;
|
animation: fade 0.5s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.02);
|
transform: scale(1.02);
|
||||||
@ -183,6 +166,9 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
152
src/components/Loading.vue
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div id="loader-wrapper" :class="store.imgLoadStatus ? 'loaded' : null">
|
||||||
|
<div class="loader">
|
||||||
|
<div class="loader-circle" />
|
||||||
|
<div class="loader-text">
|
||||||
|
<span class="name">
|
||||||
|
{{ siteName }}
|
||||||
|
</span>
|
||||||
|
<span class="tip"> 加载中 </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="loader-section section-left" />
|
||||||
|
<div class="loader-section section-right" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { mainStore } from "@/store";
|
||||||
|
|
||||||
|
const store = mainStore();
|
||||||
|
|
||||||
|
// 配置
|
||||||
|
const siteName = import.meta.env.VITE_SITE_NAME;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#loader-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
overflow: hidden;
|
||||||
|
.loader {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.loader-circle {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #fff;
|
||||||
|
animation: spin 1.8s linear infinite;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 5px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #a4a4a4;
|
||||||
|
animation: spin-reverse 0.6s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
bottom: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 3px solid transparent;
|
||||||
|
border-top-color: #d3d3d3;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loader-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
color: #fff;
|
||||||
|
z-index: 2;
|
||||||
|
margin-top: 40px;
|
||||||
|
font-size: 24px;
|
||||||
|
.tip {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 18px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loader-section {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: 51%;
|
||||||
|
height: 100%;
|
||||||
|
background: #333;
|
||||||
|
z-index: 1;
|
||||||
|
&.section-left {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
&.section-right {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.loaded {
|
||||||
|
visibility: hidden;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
transition:
|
||||||
|
transform 0.3s 1s ease-out,
|
||||||
|
visibility 0.3s 1s ease-out;
|
||||||
|
.loader {
|
||||||
|
.loader-circle,
|
||||||
|
.loader-text {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loader-section {
|
||||||
|
&.section-left {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: transform 0.5s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
&.section-right {
|
||||||
|
transform: translateX(100%);
|
||||||
|
transition: transform 0.5s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin-reverse {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(-360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -73,7 +73,7 @@ watch(
|
|||||||
descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
|
descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
|
||||||
descriptionText.text = import.meta.env.VITE_DESC_TEXT;
|
descriptionText.text = import.meta.env.VITE_DESC_TEXT;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -83,8 +83,8 @@ watch(
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
max-width: 460px;
|
||||||
.logo-img {
|
.logo-img {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
@ -98,7 +98,7 @@ watch(
|
|||||||
font-family: "Pacifico-Regular";
|
font-family: "Pacifico-Regular";
|
||||||
|
|
||||||
.bg {
|
.bg {
|
||||||
font-size: 4rem;
|
font-size: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sm {
|
.sm {
|
||||||
@ -120,14 +120,17 @@ watch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.description {
|
.description {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-top: 3.5rem;
|
margin-top: 3.5rem;
|
||||||
max-width: 460px;
|
max-width: 460px;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
@ -11,32 +11,12 @@
|
|||||||
<span @click="store.musicOpenState = false">回到一言</span>
|
<span @click="store.musicOpenState = false">回到一言</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<go-start
|
<go-start theme="filled" size="30" fill="#efefef" @click="changeMusicIndex(0)" />
|
||||||
theme="filled"
|
|
||||||
size="30"
|
|
||||||
fill="#efefef"
|
|
||||||
@click="changeMusicIndex(0)"
|
|
||||||
/>
|
|
||||||
<div class="state" @click="changePlayState">
|
<div class="state" @click="changePlayState">
|
||||||
<play-one
|
<play-one theme="filled" size="50" fill="#efefef" v-show="!store.playerState" />
|
||||||
theme="filled"
|
<pause theme="filled" size="50" fill="#efefef" v-show="store.playerState" />
|
||||||
size="50"
|
|
||||||
fill="#efefef"
|
|
||||||
v-show="!store.playerState"
|
|
||||||
/>
|
|
||||||
<pause
|
|
||||||
theme="filled"
|
|
||||||
size="50"
|
|
||||||
fill="#efefef"
|
|
||||||
v-show="store.playerState"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<go-end
|
<go-end theme="filled" size="30" fill="#efefef" @click="changeMusicIndex(1)" />
|
||||||
theme="filled"
|
|
||||||
size="30"
|
|
||||||
fill="#efefef"
|
|
||||||
@click="changeMusicIndex(1)"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="name" v-show="!volumeShow">
|
<div class="name" v-show="!volumeShow">
|
||||||
@ -48,12 +28,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="volume" v-show="volumeShow">
|
<div class="volume" v-show="volumeShow">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<volume-mute
|
<volume-mute theme="filled" size="24" fill="#efefef" v-if="volumeNum == 0" />
|
||||||
theme="filled"
|
|
||||||
size="24"
|
|
||||||
fill="#efefef"
|
|
||||||
v-if="volumeNum == 0"
|
|
||||||
/>
|
|
||||||
<volume-small
|
<volume-small
|
||||||
theme="filled"
|
theme="filled"
|
||||||
size="24"
|
size="24"
|
||||||
@ -62,23 +37,13 @@
|
|||||||
/>
|
/>
|
||||||
<volume-notice theme="filled" size="24" fill="#efefef" v-else />
|
<volume-notice theme="filled" size="24" fill="#efefef" v-else />
|
||||||
</div>
|
</div>
|
||||||
<el-slider
|
<el-slider v-model="volumeNum" :show-tooltip="false" :min="0" :max="1" :step="0.01" />
|
||||||
v-model="volumeNum"
|
|
||||||
:show-tooltip="false"
|
|
||||||
:min="0"
|
|
||||||
:max="1"
|
|
||||||
:step="0.01"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 音乐列表弹窗 -->
|
<!-- 音乐列表弹窗 -->
|
||||||
<Transition name="fade">
|
<Transition name="fade" mode="out-in">
|
||||||
<div
|
<div class="music-list" v-show="musicListShow" @click="closeMusicList()">
|
||||||
class="music-list"
|
|
||||||
v-show="musicListShow"
|
|
||||||
@click="musicListShow = false"
|
|
||||||
>
|
|
||||||
<Transition name="zoom">
|
<Transition name="zoom">
|
||||||
<div class="list" v-show="musicListShow" @click.stop>
|
<div class="list" v-show="musicListShow" @click.stop>
|
||||||
<close-one
|
<close-one
|
||||||
@ -86,15 +51,14 @@
|
|||||||
theme="filled"
|
theme="filled"
|
||||||
size="28"
|
size="28"
|
||||||
fill="#ffffff60"
|
fill="#ffffff60"
|
||||||
@click="musicListShow = false"
|
@click="closeMusicList()"
|
||||||
/>
|
/>
|
||||||
<Player
|
<Player
|
||||||
|
ref="playerRef"
|
||||||
:songServer="playerData.server"
|
:songServer="playerData.server"
|
||||||
:songType="playerData.type"
|
:songType="playerData.type"
|
||||||
:songId="playerData.id"
|
:songId="playerData.id"
|
||||||
:volume="volumeNum"
|
:volume="volumeNum"
|
||||||
:shuffle="true"
|
|
||||||
ref="playerRef"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
@ -103,7 +67,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, watch, onMounted } from "vue";
|
|
||||||
import {
|
import {
|
||||||
GoStart,
|
GoStart,
|
||||||
PlayOne,
|
PlayOne,
|
||||||
@ -114,7 +77,7 @@ import {
|
|||||||
VolumeSmall,
|
VolumeSmall,
|
||||||
VolumeNotice,
|
VolumeNotice,
|
||||||
} from "@icon-park/vue-next";
|
} from "@icon-park/vue-next";
|
||||||
import Player from "@/components/Player/index.vue";
|
import Player from "@/components/Player.vue";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
@ -134,6 +97,13 @@ const playerData = reactive({
|
|||||||
// 开启播放列表
|
// 开启播放列表
|
||||||
const openMusicList = () => {
|
const openMusicList = () => {
|
||||||
musicListShow.value = true;
|
musicListShow.value = true;
|
||||||
|
playerRef.value.toggleList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭播放列表
|
||||||
|
const closeMusicList = () => {
|
||||||
|
musicListShow.value = false;
|
||||||
|
playerRef.value.toggleList();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 音乐播放暂停
|
// 音乐播放暂停
|
||||||
@ -149,6 +119,9 @@ const changeMusicIndex = (type) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 空格键事件
|
// 空格键事件
|
||||||
window.addEventListener("keydown", (e) => {
|
window.addEventListener("keydown", (e) => {
|
||||||
|
if (!store.musicIsOk) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
if (e.code == "Space") {
|
if (e.code == "Space") {
|
||||||
changePlayState();
|
changePlayState();
|
||||||
}
|
}
|
||||||
@ -163,7 +136,7 @@ watch(
|
|||||||
(value) => {
|
(value) => {
|
||||||
store.musicVolume = value;
|
store.musicVolume = value;
|
||||||
playerRef.value.changeVolume(store.musicVolume);
|
playerRef.value.changeVolume(store.musicVolume);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -179,8 +152,7 @@ watch(
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
.btns {
|
.btns {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -242,8 +214,7 @@ watch(
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
animation: fade;
|
animation: fade 0.3s;
|
||||||
-webkit-animation: fade 0.3s;
|
|
||||||
}
|
}
|
||||||
.volume {
|
.volume {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -251,8 +222,7 @@ watch(
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
animation: fade;
|
animation: fade 0.3s;
|
||||||
-webkit-animation: fade 0.3s;
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
span {
|
span {
|
||||||
@ -320,12 +290,6 @@ watch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 弹窗动画
|
// 弹窗动画
|
||||||
.fade-enter-active {
|
|
||||||
animation: fade 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
.fade-leave-active {
|
|
||||||
animation: fade 0.3s ease-in-out reverse;
|
|
||||||
}
|
|
||||||
.zoom-enter-active {
|
.zoom-enter-active {
|
||||||
animation: zoom 0.4s ease-in-out;
|
animation: zoom 0.4s ease-in-out;
|
||||||
}
|
}
|
@ -1,31 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<aplayer
|
<APlayer
|
||||||
showLrc
|
|
||||||
ref="player"
|
|
||||||
v-if="playList[0]"
|
v-if="playList[0]"
|
||||||
:music="playList[playIndex]"
|
ref="player"
|
||||||
:list="playList"
|
:audio="playList"
|
||||||
:autoplay="autoplay"
|
:autoplay="store.playerAutoplay"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
:repeat="repeat"
|
:autoSwitch="false"
|
||||||
:shuffle="shuffle"
|
:loop="store.playerLoop"
|
||||||
:listMaxHeight="listMaxHeight"
|
:order="store.playerOrder"
|
||||||
:listFolded="listFolded"
|
|
||||||
:volume="volume"
|
:volume="volume"
|
||||||
|
:showLrc="true"
|
||||||
|
:listFolded="listFolded"
|
||||||
|
:listMaxHeight="listMaxHeight"
|
||||||
|
:noticeSwitch="false"
|
||||||
@play="onPlay"
|
@play="onPlay"
|
||||||
@pause="onPause"
|
@pause="onPause"
|
||||||
@timeupdate="onTimeUp"
|
@timeupdate="onTimeUp"
|
||||||
@onSelectSong="onSelectSong"
|
@error="loadMusicError"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import aplayer from "vue3-aplayer";
|
|
||||||
import fetchJsonp from "fetch-jsonp";
|
|
||||||
import { h, ref, nextTick, onMounted } from "vue";
|
|
||||||
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
import { MusicOne, PlayWrong } from "@icon-park/vue-next";
|
||||||
import { getPlayerList } from "@/api";
|
import { getPlayerList } from "@/api";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
|
import APlayer from "@worstone/vue-aplayer";
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
@ -34,34 +33,17 @@ const player = ref(null);
|
|||||||
|
|
||||||
// 歌曲播放列表
|
// 歌曲播放列表
|
||||||
const playList = ref([]);
|
const playList = ref([]);
|
||||||
const playerLrc = ref("");
|
|
||||||
|
|
||||||
// 歌曲播放项
|
// 歌曲播放项
|
||||||
const playIndex = ref(0);
|
const playIndex = ref(0);
|
||||||
const playListCount = ref(0);
|
|
||||||
|
|
||||||
// 配置项
|
// 配置项
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// 音频自动播放
|
|
||||||
autoplay: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
// 主题色
|
// 主题色
|
||||||
theme: {
|
theme: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "#efefef",
|
default: "#efefef",
|
||||||
},
|
},
|
||||||
// 音频循环播放
|
|
||||||
repeat: {
|
|
||||||
type: String,
|
|
||||||
default: "list", //'list' | 'music' | 'none'
|
|
||||||
},
|
|
||||||
// 随机播放
|
|
||||||
shuffle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
// 默认音量
|
// 默认音量
|
||||||
volume: {
|
volume: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -70,10 +52,10 @@ const props = defineProps({
|
|||||||
return value >= 0 && value <= 1;
|
return value >= 0 && value <= 1;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 歌曲服务器 ( netease-网易云, tencent-qq音乐, kugou-酷狗, xiami-小米音乐, baidu-百度音乐 )
|
// 歌曲服务器 ( netease-网易云, tencent-qq音乐 )
|
||||||
songServer: {
|
songServer: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "netease", //'netease' | 'tencent' | 'kugou' | 'xiami' | 'baidu'
|
default: "netease", //'netease' | 'tencent'
|
||||||
},
|
},
|
||||||
// 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
// 播放类型 ( song-歌曲, playlist-播放列表, album-专辑, search-搜索, artist-艺术家 )
|
||||||
songType: {
|
songType: {
|
||||||
@ -92,42 +74,29 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
// 列表最大高度
|
// 列表最大高度
|
||||||
listMaxHeight: {
|
listMaxHeight: {
|
||||||
type: String,
|
type: Number,
|
||||||
default: "420px",
|
default: 420,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const listHeight = computed(() => {
|
||||||
|
return props.listMaxHeight + "px";
|
||||||
|
});
|
||||||
|
|
||||||
// 初始化播放器
|
// 初始化播放器
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
try {
|
try {
|
||||||
getPlayerList(props.songServer, props.songType, props.songId).then(
|
getPlayerList(props.songServer, props.songType, props.songId).then((res) => {
|
||||||
(res) => {
|
|
||||||
console.log(res);
|
console.log(res);
|
||||||
// 生成歌单信息
|
|
||||||
playIndex.value = Math.floor(Math.random() * res.length);
|
|
||||||
playListCount.value = res.length;
|
|
||||||
// 更改播放器加载状态
|
// 更改播放器加载状态
|
||||||
store.musicIsOk = true;
|
store.musicIsOk = true;
|
||||||
// 生成歌单
|
// 生成歌单
|
||||||
res.forEach((v) => {
|
playList.value = res;
|
||||||
playList.value.push({
|
console.log("音乐加载完成");
|
||||||
title: v.name || v.title,
|
console.log(playList.value);
|
||||||
artist: v.artist || v.author,
|
console.log(playIndex.value, playList.value.length, props.volume);
|
||||||
src: v.url || v.src,
|
|
||||||
pic: v.pic,
|
|
||||||
lrc: v.lrc,
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
console.log(
|
|
||||||
"音乐加载完成",
|
|
||||||
playList.value,
|
|
||||||
playIndex.value,
|
|
||||||
playListCount.value,
|
|
||||||
props.volume
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
store.musicIsOk = false;
|
store.musicIsOk = false;
|
||||||
@ -143,16 +112,14 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 播放暂停事件
|
// 播放
|
||||||
const onPlay = () => {
|
const onPlay = () => {
|
||||||
console.log("播放");
|
console.log("播放");
|
||||||
|
playIndex.value = player.value.aplayer.index;
|
||||||
// 播放状态
|
// 播放状态
|
||||||
store.setPlayerState(player.value.audio.paused);
|
store.setPlayerState(player.value.audioRef.paused);
|
||||||
// 储存播放器信息
|
// 储存播放器信息
|
||||||
store.setPlayerData(
|
store.setPlayerData(playList.value[playIndex.value].name, playList.value[playIndex.value].artist);
|
||||||
player.value.currentMusic.title,
|
|
||||||
player.value.currentMusic.artist
|
|
||||||
);
|
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
message: store.getPlayerData.name + " - " + store.getPlayerData.artist,
|
||||||
grouping: true,
|
grouping: true,
|
||||||
@ -162,19 +129,26 @@ const onPlay = () => {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 暂停
|
||||||
const onPause = () => {
|
const onPause = () => {
|
||||||
store.setPlayerState(player.value.audio.paused);
|
store.setPlayerState(player.value.audioRef.paused);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 音频时间更新事件
|
// 音频时间更新事件
|
||||||
const onTimeUp = () => {
|
const onTimeUp = () => {
|
||||||
let playerRef = player.value.$.vnode.el;
|
let lyrics = player.value.aplayer.lyrics[playIndex.value];
|
||||||
if (playerRef) {
|
let lyricIndex = player.value.aplayer.lyricIndex;
|
||||||
playerLrc.value = playerRef.getElementsByClassName(
|
if (!lyrics || !lyrics[lyricIndex]) {
|
||||||
"aplayer-lrc-current"
|
return;
|
||||||
)[0].innerHTML;
|
|
||||||
store.setPlayerLrc(playerLrc.value);
|
|
||||||
}
|
}
|
||||||
|
let lrc = lyrics[lyricIndex][1];
|
||||||
|
if (lrc === "Loading") {
|
||||||
|
lrc = "歌词加载中";
|
||||||
|
} else if (lrc === "Not available") {
|
||||||
|
lrc = "歌词加载失败";
|
||||||
|
}
|
||||||
|
store.setPlayerLrc(lrc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 切换播放暂停事件
|
// 切换播放暂停事件
|
||||||
@ -184,40 +158,55 @@ const playToggle = () => {
|
|||||||
|
|
||||||
// 切换音量事件
|
// 切换音量事件
|
||||||
const changeVolume = (value) => {
|
const changeVolume = (value) => {
|
||||||
player.value.audio.volume = value;
|
player.value.setVolume(value, false);
|
||||||
};
|
|
||||||
|
|
||||||
const onSelectSong = (val) => {
|
|
||||||
console.log(val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 切换上下曲
|
// 切换上下曲
|
||||||
const changeSong = (type) => {
|
const changeSong = (type) => {
|
||||||
playIndex.value = player.value.playIndex;
|
type === 0 ? player.value.skipBack() : player.value.skipForward();
|
||||||
playIndex.value += type ? 1 : -1;
|
|
||||||
// 判断是否处于最后/第一首
|
|
||||||
if (playIndex.value < 0) {
|
|
||||||
playIndex.value = playListCount.value - 1;
|
|
||||||
} else if (playIndex.value >= playListCount.value) {
|
|
||||||
playIndex.value = 0;
|
|
||||||
}
|
|
||||||
// console.log(playIndex.value, playList.value[playIndex.value]);
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
player.value.play();
|
player.value.play();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 切换歌曲列表状态
|
||||||
|
const toggleList = () => {
|
||||||
|
player.value.toggleList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载音频错误
|
||||||
|
const loadMusicError = () => {
|
||||||
|
let notice = "";
|
||||||
|
if (playList.value.length > 1) {
|
||||||
|
notice = "播放歌曲出现错误,播放器将在 2s 后进行下一首";
|
||||||
|
} else {
|
||||||
|
notice = "播放歌曲出现错误";
|
||||||
|
}
|
||||||
|
ElMessage({
|
||||||
|
message: notice,
|
||||||
|
grouping: true,
|
||||||
|
icon: h(PlayWrong, {
|
||||||
|
theme: "filled",
|
||||||
|
fill: "#EFEFEF",
|
||||||
|
duration: 2000,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
console.error(
|
||||||
|
"播放歌曲: " + player.value.aplayer.audio[player.value.aplayer.index].name + " 出现错误",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// 暴露子组件方法
|
// 暴露子组件方法
|
||||||
defineExpose({ playToggle, changeVolume, changeSong });
|
defineExpose({ playToggle, changeVolume, changeSong, toggleList });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.aplayer {
|
.aplayer {
|
||||||
width: 80%;
|
width: 80%;
|
||||||
background: transparent;
|
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-family: "HarmonyOS_Regular", sans-serif !important;
|
font-family: "HarmonyOS_Regular", sans-serif !important;
|
||||||
:deep(.aplayer-body) {
|
:deep(.aplayer-body) {
|
||||||
|
background-color: transparent;
|
||||||
.aplayer-pic {
|
.aplayer-pic {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -239,8 +228,8 @@ defineExpose({ playToggle, changeVolume, changeSong });
|
|||||||
}
|
}
|
||||||
.aplayer-lrc {
|
.aplayer-lrc {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 4px 0 6px 6px;
|
margin: 7px 0 6px 6px;
|
||||||
height: 100%;
|
height: 44px;
|
||||||
mask: linear-gradient(
|
mask: linear-gradient(
|
||||||
#fff 15%,
|
#fff 15%,
|
||||||
#fff 85%,
|
#fff 85%,
|
||||||
@ -272,6 +261,8 @@ defineExpose({ playToggle, changeVolume, changeSong });
|
|||||||
}
|
}
|
||||||
:deep(.aplayer-list) {
|
:deep(.aplayer-list) {
|
||||||
margin-top: 6px;
|
margin-top: 6px;
|
||||||
|
height: v-bind(listHeight);
|
||||||
|
background-color: transparent;
|
||||||
ol {
|
ol {
|
||||||
&::-webkit-scrollbar-track {
|
&::-webkit-scrollbar-track {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
202
src/components/Set.vue
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<div class="setting">
|
||||||
|
<el-collapse class="collapse" v-model="activeName" accordion>
|
||||||
|
<el-collapse-item title="个性壁纸" name="1">
|
||||||
|
<div class="bg-set">
|
||||||
|
<el-radio-group v-model="coverType" text-color="#ffffff" @change="radioChange">
|
||||||
|
<el-radio label="0" size="large" border>默认壁纸</el-radio>
|
||||||
|
<el-radio label="1" size="large" border>每日一图</el-radio>
|
||||||
|
<el-radio label="2" size="large" border>随机风景</el-radio>
|
||||||
|
<el-radio label="3" size="large" border>随机动漫</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="个性化调整" name="2">
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">建站日期显示</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="siteStartShow"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">音乐点击是否打开面板</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="musicClick"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">底栏歌词显示</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="playerLrcShow"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">底栏背景模糊</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="footerBlur"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="播放器配置" name="3">
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">自动播放</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="playerAutoplay"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">随机播放</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="playerOrder"
|
||||||
|
inline-prompt
|
||||||
|
:active-icon="CheckSmall"
|
||||||
|
:inactive-icon="CloseSmall"
|
||||||
|
active-value="random"
|
||||||
|
inactive-value="list"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<span class="text">循环模式</span>
|
||||||
|
<el-radio-group v-model="playerLoop" size="small" text-color="#FFFFFF">
|
||||||
|
<el-radio label="all" border>列表</el-radio>
|
||||||
|
<el-radio label="one" border>单曲</el-radio>
|
||||||
|
<el-radio label="none" border>不循环</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="其他设置" name="4">
|
||||||
|
<div>设置内容待增加</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { CheckSmall, CloseSmall, SuccessPicture } from "@icon-park/vue-next";
|
||||||
|
import { mainStore } from "@/store";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
|
||||||
|
const store = mainStore();
|
||||||
|
const {
|
||||||
|
coverType,
|
||||||
|
siteStartShow,
|
||||||
|
musicClick,
|
||||||
|
playerLrcShow,
|
||||||
|
footerBlur,
|
||||||
|
playerAutoplay,
|
||||||
|
playerOrder,
|
||||||
|
playerLoop,
|
||||||
|
} = storeToRefs(store);
|
||||||
|
|
||||||
|
// 默认选中项
|
||||||
|
const activeName = ref("1");
|
||||||
|
|
||||||
|
// 壁纸切换
|
||||||
|
const radioChange = () => {
|
||||||
|
ElMessage({
|
||||||
|
message: "壁纸设置成功,刷新后生效",
|
||||||
|
icon: h(SuccessPicture, {
|
||||||
|
theme: "filled",
|
||||||
|
fill: "#efefef",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.setting {
|
||||||
|
.collapse {
|
||||||
|
border-radius: 8px;
|
||||||
|
--el-collapse-content-bg-color: #ffffff10;
|
||||||
|
border-color: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.el-collapse-item__header) {
|
||||||
|
background-color: #ffffff30;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 15px;
|
||||||
|
padding-left: 18px;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-collapse-item__wrap) {
|
||||||
|
border-color: transparent;
|
||||||
|
|
||||||
|
.el-collapse-item__content {
|
||||||
|
padding: 20px;
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 14px;
|
||||||
|
.el-switch__core {
|
||||||
|
border-color: transparent;
|
||||||
|
background-color: #ffffff30;
|
||||||
|
}
|
||||||
|
.el-radio-group {
|
||||||
|
.el-radio {
|
||||||
|
margin: 2px 10px 2px 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.el-radio-group {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.el-radio {
|
||||||
|
margin: 10px 16px;
|
||||||
|
background: #ffffff26;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.el-radio__label {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-radio__inner {
|
||||||
|
background: #ffffff06 !important;
|
||||||
|
border: 2px solid #eeeeee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked {
|
||||||
|
background: #ffffff06 !important;
|
||||||
|
border: 2px solid #eeeeee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-checked {
|
||||||
|
.el-radio__inner {
|
||||||
|
background-color: #ffffff30 !important;
|
||||||
|
border-color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
& + .el-radio__label {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,142 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="setting">
|
|
||||||
<el-collapse class="collapse" v-model="activeName" accordion>
|
|
||||||
<el-collapse-item title="壁纸设置" name="1">
|
|
||||||
<div class="bg-set">
|
|
||||||
<el-radio-group v-model="bgSet" text-color="#ffffff">
|
|
||||||
<el-radio label="0" size="large" border>默认壁纸</el-radio>
|
|
||||||
<el-radio label="1" size="large" border>每日一图</el-radio>
|
|
||||||
<el-radio label="2" size="large" border>随机风景</el-radio>
|
|
||||||
<el-radio label="3" size="large" border>随机动漫</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
<el-collapse-item title="其他设置" name="2">
|
|
||||||
<div class="item">
|
|
||||||
<span class="text">建站日期显示</span>
|
|
||||||
<el-switch
|
|
||||||
v-model="siteStartShow"
|
|
||||||
inline-prompt
|
|
||||||
:active-icon="CheckSmall"
|
|
||||||
:inactive-icon="CloseSmall"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
|
||||||
<span class="text">音乐点击是否打开面板</span>
|
|
||||||
<el-switch
|
|
||||||
v-model="musicClick"
|
|
||||||
inline-prompt
|
|
||||||
:active-icon="CheckSmall"
|
|
||||||
:inactive-icon="CloseSmall"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
<el-collapse-item title="其他设置" name="3">
|
|
||||||
<div>设置内容待增加</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
<el-collapse-item title="其他设置" name="4">
|
|
||||||
<div>设置内容待增加</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted, watch } from "vue";
|
|
||||||
import { mainStore } from "@/store";
|
|
||||||
import { CheckSmall, CloseSmall } from "@icon-park/vue-next";
|
|
||||||
import { storeToRefs } from "pinia";
|
|
||||||
|
|
||||||
const store = mainStore();
|
|
||||||
const { siteStartShow, musicClick } = storeToRefs(store);
|
|
||||||
|
|
||||||
// 默认选中项
|
|
||||||
const activeName = ref("1");
|
|
||||||
const bgSet = ref("0");
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
bgSet.value = store.coverType.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 壁纸选中项
|
|
||||||
watch(
|
|
||||||
() => bgSet.value,
|
|
||||||
(value) => {
|
|
||||||
store.coverType = value;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.setting {
|
|
||||||
.collapse {
|
|
||||||
border-radius: 8px;
|
|
||||||
--el-collapse-content-bg-color: #ffffff10;
|
|
||||||
border-color: transparent;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
:deep(.el-collapse-item__header) {
|
|
||||||
background-color: #ffffff30;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 15px;
|
|
||||||
padding-left: 18px;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-collapse-item__wrap) {
|
|
||||||
border-color: transparent;
|
|
||||||
|
|
||||||
.el-collapse-item__content {
|
|
||||||
padding: 20px;
|
|
||||||
.item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 14px;
|
|
||||||
.el-switch__core {
|
|
||||||
border-color: transparent;
|
|
||||||
background-color: #ffffff30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.bg-set {
|
|
||||||
.el-radio-group {
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.el-radio {
|
|
||||||
margin: 10px 16px;
|
|
||||||
background: #ffffff26;
|
|
||||||
border: 2px solid transparent;
|
|
||||||
border-radius: 8px;
|
|
||||||
|
|
||||||
.el-radio__label {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-radio__inner {
|
|
||||||
background: #ffffff06 !important;
|
|
||||||
border: 2px solid #eeeeee !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-checked {
|
|
||||||
background: #ffffff06 !important;
|
|
||||||
border: 2px solid #eeeeee !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-checked {
|
|
||||||
.el-radio__inner {
|
|
||||||
background-color: #ffffff30 !important;
|
|
||||||
border-color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
& + .el-radio__label {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -18,7 +18,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
|
||||||
import socialLinks from "@/assets/socialLinks.json";
|
import socialLinks from "@/assets/socialLinks.json";
|
||||||
|
|
||||||
// 社交链接提示
|
// 社交链接提示
|
||||||
@ -37,9 +36,10 @@ const socialTip = ref("通过这里联系我吧");
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
backdrop-filter: blur(0);
|
backdrop-filter: blur(0);
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
transition:
|
||||||
transition: all 0.5s;
|
background-color 0.3s,
|
||||||
|
backdrop-filter 0.3s;
|
||||||
@media (max-width: 840px) {
|
@media (max-width: 840px) {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -60,9 +60,12 @@ const socialTip = ref("通过这里联系我吧");
|
|||||||
display: inherit;
|
display: inherit;
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0 12px;
|
margin: 0 12px;
|
||||||
transition: all 0.3s;
|
transition: transform 0.3s;
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
&:active {
|
&:active {
|
||||||
transform: scale(0.9);
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,8 +73,7 @@ const socialTip = ref("通过这里联系我吧");
|
|||||||
.tip {
|
.tip {
|
||||||
display: none;
|
display: none;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
}
|
}
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
&:hover {
|
&:hover {
|
@ -1,45 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="time-capsule">
|
<div class="time-capsule">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<hourglass-full
|
<hourglass-full theme="two-tone" size="24" :fill="['#efefef', '#00000020']" />
|
||||||
theme="two-tone"
|
|
||||||
size="24"
|
|
||||||
:fill="['#efefef', '#00000020']"
|
|
||||||
/>
|
|
||||||
<span>时光胶囊</span>
|
<span>时光胶囊</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="text"
|
<span class="text">今日已经度过了 {{ timeData.day.elapsed }} 小时</span>
|
||||||
>今日已经度过了 {{ timeData.day.elapsed }} 小时</span
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="timeData.day.pass" />
|
||||||
>
|
<span class="text">本周已经度过了 {{ timeData.week.elapsed }} 天</span>
|
||||||
<el-progress
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="timeData.week.pass" />
|
||||||
:text-inside="true"
|
<span class="text">本月已经度过了 {{ timeData.month.elapsed }} 天</span>
|
||||||
:stroke-width="20"
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="timeData.month.pass" />
|
||||||
:percentage="timeData.day.pass"
|
<span class="text">今年已经度过了 {{ timeData.year.elapsed }} 个月</span>
|
||||||
/>
|
<el-progress :text-inside="true" :stroke-width="20" :percentage="timeData.year.pass" />
|
||||||
<span class="text"
|
|
||||||
>本周已经度过了 {{ timeData.week.elapsed }} 天</span
|
|
||||||
>
|
|
||||||
<el-progress
|
|
||||||
:text-inside="true"
|
|
||||||
:stroke-width="20"
|
|
||||||
:percentage="timeData.week.pass"
|
|
||||||
/>
|
|
||||||
<span class="text"
|
|
||||||
>本月已经度过了 {{ timeData.month.elapsed }} 天</span
|
|
||||||
>
|
|
||||||
<el-progress
|
|
||||||
:text-inside="true"
|
|
||||||
:stroke-width="20"
|
|
||||||
:percentage="timeData.month.pass"
|
|
||||||
/>
|
|
||||||
<span class="text"
|
|
||||||
>今年已经度过了 {{ timeData.year.elapsed }} 个月</span
|
|
||||||
>
|
|
||||||
<el-progress
|
|
||||||
:text-inside="true"
|
|
||||||
:stroke-width="20"
|
|
||||||
:percentage="timeData.year.pass"
|
|
||||||
/>
|
|
||||||
<div v-if="startDate?.length >= 4 && store.siteStartShow">
|
<div v-if="startDate?.length >= 4 && store.siteStartShow">
|
||||||
<span class="text" v-html="startDateText" />
|
<span class="text" v-html="startDateText" />
|
||||||
<!-- <el-progress
|
<!-- <el-progress
|
||||||
@ -54,7 +26,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onBeforeUnmount, ref } from "vue";
|
|
||||||
import { HourglassFull } from "@icon-park/vue-next";
|
import { HourglassFull } from "@icon-park/vue-next";
|
||||||
import { getTimeCapsule, siteDateStatistics } from "@/utils/getTime.js";
|
import { getTimeCapsule, siteDateStatistics } from "@/utils/getTime.js";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
@ -69,8 +40,7 @@ const timeInterval = ref(null);
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
timeInterval.value = setInterval(() => {
|
timeInterval.value = setInterval(() => {
|
||||||
timeData.value = getTimeCapsule();
|
timeData.value = getTimeCapsule();
|
||||||
if (startDate.value)
|
if (startDate.value) startDateText.value = siteDateStatistics(new Date(startDate.value));
|
||||||
startDateText.value = siteDateStatistics(new Date(startDate.value));
|
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
102
src/components/Weather.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div class="weather" v-if="weatherData.adCode.city && weatherData.weather.weather">
|
||||||
|
<span>{{ weatherData.adCode.city }} </span>
|
||||||
|
<span>{{ weatherData.weather.weather }} </span>
|
||||||
|
<span>{{ weatherData.weather.temperature }}℃</span>
|
||||||
|
<span class="sm-hidden">
|
||||||
|
{{
|
||||||
|
weatherData.weather.winddirection?.endsWith("风")
|
||||||
|
? weatherData.weather.winddirection
|
||||||
|
: weatherData.weather.winddirection + "风"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<span class="sm-hidden">{{ weatherData.weather.windpower }} 级</span>
|
||||||
|
</div>
|
||||||
|
<div class="weather" v-else>
|
||||||
|
<span>天气数据获取失败</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { getAdcode, getWeather, getOtherWeather } from "@/api";
|
||||||
|
import { Error } from "@icon-park/vue-next";
|
||||||
|
|
||||||
|
// 高德开发者 Key
|
||||||
|
const mainKey = import.meta.env.VITE_WEATHER_KEY;
|
||||||
|
|
||||||
|
// 天气数据
|
||||||
|
const weatherData = reactive({
|
||||||
|
adCode: {
|
||||||
|
city: null, // 城市
|
||||||
|
adcode: null, // 城市编码
|
||||||
|
},
|
||||||
|
weather: {
|
||||||
|
weather: null, // 天气现象
|
||||||
|
temperature: null, // 实时气温
|
||||||
|
winddirection: null, // 风向描述
|
||||||
|
windpower: null, // 风力级别
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取天气数据
|
||||||
|
const getWeatherData = async () => {
|
||||||
|
try {
|
||||||
|
// 获取地理位置信息
|
||||||
|
if (!mainKey) {
|
||||||
|
console.log("未配置,使用备用天气接口");
|
||||||
|
const result = await getOtherWeather();
|
||||||
|
console.log(result);
|
||||||
|
const data = result.result;
|
||||||
|
weatherData.adCode = {
|
||||||
|
city: data.city.city_name || "未知地区",
|
||||||
|
// adcode: data.city.cityId,
|
||||||
|
};
|
||||||
|
weatherData.weather = {
|
||||||
|
weather: data.condition.condition,
|
||||||
|
temperature: data.condition.temp,
|
||||||
|
winddirection: data.condition.windDir,
|
||||||
|
windpower: data.condition.windLevel,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 获取 Adcode
|
||||||
|
const adCode = await getAdcode(mainKey);
|
||||||
|
console.log(adCode);
|
||||||
|
if (adCode.infocode !== "10000") {
|
||||||
|
throw "地区查询失败";
|
||||||
|
}
|
||||||
|
weatherData.adCode = {
|
||||||
|
city: adCode.city,
|
||||||
|
adcode: adCode.adcode,
|
||||||
|
};
|
||||||
|
// 获取天气信息
|
||||||
|
const result = await getWeather(mainKey, weatherData.adCode.adcode);
|
||||||
|
weatherData.weather = {
|
||||||
|
weather: result.lives[0].weather,
|
||||||
|
temperature: result.lives[0].temperature,
|
||||||
|
winddirection: result.lives[0].winddirection,
|
||||||
|
windpower: result.lives[0].windpower,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("天气信息获取失败:" + error);
|
||||||
|
onError("天气信息获取失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 报错信息
|
||||||
|
const onError = (message) => {
|
||||||
|
ElMessage({
|
||||||
|
message,
|
||||||
|
icon: h(Error, {
|
||||||
|
theme: "filled",
|
||||||
|
fill: "#efefef",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
console.error(message);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 调用获取天气
|
||||||
|
getWeatherData();
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,110 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="weather" v-if="weatherData.adCode.city && weatherData.weather.weather">
|
|
||||||
<span>{{ weatherData.adCode.city }} </span>
|
|
||||||
<span>{{ weatherData.weather.weather }} </span>
|
|
||||||
<span>{{ weatherData.weather.temperature }}℃</span>
|
|
||||||
<span class="sm-hidden">
|
|
||||||
{{
|
|
||||||
weatherData.weather.winddirection?.endsWith("风")
|
|
||||||
? weatherData.weather.winddirection
|
|
||||||
: weatherData.weather.winddirection + "风"
|
|
||||||
}}
|
|
||||||
</span>
|
|
||||||
<span class="sm-hidden">{{ weatherData.weather.windpower }} 级</span>
|
|
||||||
</div>
|
|
||||||
<div class="weather" v-else>
|
|
||||||
<span>天气数据获取失败</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { onMounted, reactive, h } from "vue";
|
|
||||||
import { getAdcode, getWeather, getOtherWeather } from "@/api";
|
|
||||||
import { Error } from "@icon-park/vue-next";
|
|
||||||
|
|
||||||
// 高德开发者 Key
|
|
||||||
const mainKey = import.meta.env.VITE_WEATHER_KEY;
|
|
||||||
|
|
||||||
// 天气数据
|
|
||||||
const weatherData = reactive({
|
|
||||||
adCode: {
|
|
||||||
city: null, // 城市
|
|
||||||
adcode: null, // 城市编码
|
|
||||||
},
|
|
||||||
weather: {
|
|
||||||
weather: null, // 天气现象
|
|
||||||
temperature: null, // 实时气温
|
|
||||||
winddirection: null, // 风向描述
|
|
||||||
windpower: null, // 风力级别
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取天气数据
|
|
||||||
const getWeatherData = () => {
|
|
||||||
// 获取地理位置信息
|
|
||||||
if (!mainKey) {
|
|
||||||
getOtherWeather()
|
|
||||||
.then((res) => {
|
|
||||||
console.log(res);
|
|
||||||
const data = res.result;
|
|
||||||
weatherData.adCode = {
|
|
||||||
city: data.city.name,
|
|
||||||
adcode: data.city.cityId,
|
|
||||||
};
|
|
||||||
weatherData.weather = {
|
|
||||||
weather: data.condition.condition,
|
|
||||||
temperature: data.condition.temp,
|
|
||||||
winddirection: data.condition.windDir,
|
|
||||||
windpower: data.condition.windLevel,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("天气信息获取失败:" + err);
|
|
||||||
onError("天气信息获取失败");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
getAdcode(mainKey)
|
|
||||||
.then((res) => {
|
|
||||||
weatherData.adCode = {
|
|
||||||
city: res.city,
|
|
||||||
adcode: res.adcode,
|
|
||||||
};
|
|
||||||
// 获取天气信息
|
|
||||||
getWeather(mainKey, weatherData.adCode.adcode)
|
|
||||||
.then((res) => {
|
|
||||||
weatherData.weather = {
|
|
||||||
weather: res.lives[0].weather,
|
|
||||||
temperature: res.lives[0].temperature,
|
|
||||||
winddirection: res.lives[0].winddirection,
|
|
||||||
windpower: res.lives[0].windpower,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("天气信息获取失败:" + err);
|
|
||||||
onError("天气信息获取失败");
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error("地理位置获取失败:" + err);
|
|
||||||
onError("地理位置获取失败");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 报错信息
|
|
||||||
const onError = (message) => {
|
|
||||||
ElMessage({
|
|
||||||
message,
|
|
||||||
icon: h(Error, {
|
|
||||||
theme: "filled",
|
|
||||||
fill: "#efefef",
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
console.error(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 调用获取天气
|
|
||||||
getWeatherData();
|
|
||||||
});
|
|
||||||
</script>
|
|
23
src/main.js
@ -1,24 +1,23 @@
|
|||||||
import {
|
import { createApp } from "vue";
|
||||||
createApp
|
import "@/style/style.scss";
|
||||||
} from 'vue';
|
import App from "@/App.vue";
|
||||||
import '@/style/style.scss';
|
|
||||||
import App from '@/App.vue';
|
|
||||||
// 引入 pinia
|
// 引入 pinia
|
||||||
import {
|
import { createPinia } from "pinia";
|
||||||
createPinia
|
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
|
||||||
} from 'pinia';
|
// swiper
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
|
import "swiper/scss";
|
||||||
|
import "swiper/scss/pagination";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
pinia.use(piniaPluginPersistedstate);
|
pinia.use(piniaPluginPersistedstate);
|
||||||
|
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
app.mount('#app')
|
app.mount("#app");
|
||||||
|
|
||||||
// PWA
|
// PWA
|
||||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||||
// 弹出更新提醒
|
// 弹出更新提醒
|
||||||
console.log("站点已更新,刷新后生效");
|
console.log("站点已更新,刷新后生效");
|
||||||
ElMessage("站点已更新,刷新后生效");
|
ElMessage("站点已更新,刷新后生效");
|
||||||
})
|
});
|
||||||
|
@ -3,9 +3,11 @@ import { defineStore } from "pinia";
|
|||||||
export const mainStore = defineStore("main", {
|
export const mainStore = defineStore("main", {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
|
imgLoadStatus: false, // 壁纸加载状态
|
||||||
innerWidth: null, // 当前窗口宽度
|
innerWidth: null, // 当前窗口宽度
|
||||||
coverType: "0", // 壁纸种类
|
coverType: "0", // 壁纸种类
|
||||||
siteStartShow: true, // 建站日期显示
|
siteStartShow: false, // 建站日期显示
|
||||||
|
musicClick: false, // 音乐链接是否跳转
|
||||||
musicIsOk: false, // 音乐是否加载完成
|
musicIsOk: false, // 音乐是否加载完成
|
||||||
musicVolume: 0, // 音乐音量;
|
musicVolume: 0, // 音乐音量;
|
||||||
musicOpenState: false, // 音乐面板开启状态
|
musicOpenState: false, // 音乐面板开启状态
|
||||||
@ -18,7 +20,11 @@ export const mainStore = defineStore("main", {
|
|||||||
playerTitle: null, // 当前播放歌曲名
|
playerTitle: null, // 当前播放歌曲名
|
||||||
playerArtist: null, // 当前播放歌手名
|
playerArtist: null, // 当前播放歌手名
|
||||||
playerLrc: "歌词加载中", // 当前播放歌词
|
playerLrc: "歌词加载中", // 当前播放歌词
|
||||||
musicClick: false, // 音乐链接是否跳转
|
playerLrcShow: true, // 是否显示底栏歌词
|
||||||
|
footerBlur: true, // 底栏模糊
|
||||||
|
playerAutoplay: false, // 是否自动播放
|
||||||
|
playerLoop: "all", // 循环播放 "all", "one", "none"
|
||||||
|
playerOrder: "list", // 循环顺序 "list", "random"
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
@ -64,10 +70,24 @@ export const mainStore = defineStore("main", {
|
|||||||
this.playerTitle = title;
|
this.playerTitle = title;
|
||||||
this.playerArtist = artist;
|
this.playerArtist = artist;
|
||||||
},
|
},
|
||||||
|
// 更改壁纸加载状态
|
||||||
|
setImgLoadStatus(value) {
|
||||||
|
this.imgLoadStatus = value;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
persist: {
|
persist: {
|
||||||
key: "data",
|
key: "data",
|
||||||
storage: window.localStorage,
|
storage: window.localStorage,
|
||||||
paths: ["coverType", "musicVolume", "siteStartShow", "musicClick"],
|
paths: [
|
||||||
|
"coverType",
|
||||||
|
"musicVolume",
|
||||||
|
"siteStartShow",
|
||||||
|
"musicClick",
|
||||||
|
"playerLrcShow",
|
||||||
|
"footerBlur",
|
||||||
|
"playerAutoplay",
|
||||||
|
"playerLoop",
|
||||||
|
"playerOrder",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// scss 全局变量
|
// scss 全局变量
|
||||||
|
|
||||||
// 响应式布局
|
// 响应式布局
|
||||||
@mixin changeWidth($maxWidth:1200px) {
|
@mixin changeWidth($maxWidth: 1200px) {
|
||||||
.container {
|
.container {
|
||||||
max-width: $maxWidth;
|
max-width: $maxWidth;
|
||||||
}
|
}
|
||||||
@ -17,19 +17,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 小于1200px时 */
|
/* 小于1280px时 */
|
||||||
@media (max-width: 1200px) {
|
@media (max-width: 1280px) {
|
||||||
@include changeWidth($maxWidth:1000px);
|
@include changeWidth($maxWidth: 1100px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 小于992px时 */
|
/* 小于992px时 */
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
@include changeWidth($maxWidth:900px);
|
@include changeWidth($maxWidth: 900px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 小于720px时 */
|
/* 小于720px时 */
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
|
|
||||||
// 隐藏元素
|
// 隐藏元素
|
||||||
.xs-hidden {
|
.xs-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -13,6 +13,8 @@ html,
|
|||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-family: "HarmonyOS_Regular", sans-serif;
|
font-family: "HarmonyOS_Regular", sans-serif;
|
||||||
@ -23,8 +25,6 @@ a,
|
|||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
-webkit-user-select: none;
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -38,11 +38,13 @@ p {
|
|||||||
// 字体文件
|
// 字体文件
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Pacifico-Regular";
|
font-family: "Pacifico-Regular";
|
||||||
|
font-display: swap;
|
||||||
src: url("/font/Pacifico-Regular.ttf") format("truetype");
|
src: url("/font/Pacifico-Regular.ttf") format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "UnidreamLED";
|
font-family: "UnidreamLED";
|
||||||
|
font-display: swap;
|
||||||
src: url("/font/UnidreamLED.ttf") format("truetype");
|
src: url("/font/UnidreamLED.ttf") format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,19 +61,18 @@ p {
|
|||||||
// 卡片样式
|
// 卡片样式
|
||||||
.cards {
|
.cards {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: #00000040;
|
background-color: #00000040;
|
||||||
-webkit-backdrop-filter: blur(10px);
|
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
transition: all 0.3s;
|
transition:
|
||||||
}
|
backdrop-filter 0.3s,
|
||||||
|
transform 0.3s;
|
||||||
.cards:hover {
|
&:hover {
|
||||||
transform: scale(1.01);
|
transform: scale(1.01);
|
||||||
}
|
}
|
||||||
|
&:active {
|
||||||
.cards:active {
|
|
||||||
transform: scale(0.98);
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 文字超出
|
// 文字超出
|
||||||
@ -103,13 +104,11 @@ p {
|
|||||||
.el-progress-bar__outer {
|
.el-progress-bar__outer {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background-color: #00000020;
|
background-color: #00000020;
|
||||||
|
|
||||||
.el-progress-bar__inner {
|
.el-progress-bar__inner {
|
||||||
background-color: #efefef;
|
background-color: #efefef;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: "UnidreamLED";
|
font-family: "UnidreamLED";
|
||||||
|
|
||||||
span {
|
span {
|
||||||
color: #564d59;
|
color: #564d59;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@ -129,31 +128,59 @@ p {
|
|||||||
border-radius: 8px !important;
|
border-radius: 8px !important;
|
||||||
border: 1px solid transparent !important;
|
border: 1px solid transparent !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
|
||||||
.el-card__header {
|
.el-card__header {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 16px 20px !important;
|
padding: 16px 20px !important;
|
||||||
background-color: #ffffff30 !important;
|
background-color: #ffffff30 !important;
|
||||||
border-bottom: 1px solid transparent !important;
|
border-bottom: 1px solid transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-card__body {
|
.el-card__body {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
background-color: #ffffff10 !important;
|
background-color: #ffffff10 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渐入动画
|
// Transition 动画
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyframes 动画
|
||||||
@keyframes fade {
|
@keyframes fade {
|
||||||
0% {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
to {
|
||||||
100% {
|
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fade-blur-in {
|
||||||
|
from {
|
||||||
|
filter: blur(20px) brightness(0.3);
|
||||||
|
transform: scale(1.6);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
filter: blur(0) brightness(1);
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-blur-main-in {
|
||||||
|
from {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 隐藏元素
|
// 隐藏元素
|
||||||
@media (min-width: 910px) and (max-width: 1200px) {
|
@media (min-width: 910px) and (max-width: 1200px) {
|
||||||
.sm-hidden {
|
.sm-hidden {
|
||||||
|
@ -1,21 +1,26 @@
|
|||||||
var CURSOR;
|
let mainCursor;
|
||||||
|
|
||||||
Math.lerp = (a, b, n) => (1 - n) * a + n * b;
|
Math.lerp = (a, b, n) => (1 - n) * a + n * b;
|
||||||
|
|
||||||
const getStyle = (el, attr) => {
|
const getStyle = (el, attr) => {
|
||||||
try {
|
try {
|
||||||
return window.getComputedStyle ?
|
return window.getComputedStyle ? window.getComputedStyle(el)[attr] : el.currentStyle[attr];
|
||||||
window.getComputedStyle(el)[attr] :
|
} catch (e) {
|
||||||
el.currentStyle[attr];
|
console.error(e);
|
||||||
} catch (e) {}
|
}
|
||||||
return "";
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cursorInit = () => {
|
||||||
|
mainCursor = new Cursor();
|
||||||
|
return mainCursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Cursor {
|
class Cursor {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.pos = {
|
this.pos = {
|
||||||
curr: null,
|
curr: null,
|
||||||
prev: null
|
prev: null,
|
||||||
};
|
};
|
||||||
this.pt = [];
|
this.pt = [];
|
||||||
this.create();
|
this.create();
|
||||||
@ -37,10 +42,9 @@ class Cursor {
|
|||||||
document.body.append(this.cursor);
|
document.body.append(this.cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
var el = document.getElementsByTagName('*');
|
var el = document.getElementsByTagName("*");
|
||||||
for (let i = 0; i < el.length; i++)
|
for (let i = 0; i < el.length; i++)
|
||||||
if (getStyle(el[i], "cursor") == "pointer")
|
if (getStyle(el[i], "cursor") == "pointer") this.pt.push(el[i].outerHTML);
|
||||||
this.pt.push(el[i].outerHTML);
|
|
||||||
|
|
||||||
document.body.appendChild((this.scr = document.createElement("style")));
|
document.body.appendChild((this.scr = document.createElement("style")));
|
||||||
this.scr.innerHTML = `* {cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' width='10px' height='10px'><circle cx='4' cy='4' r='4' fill='white' /></svg>") 4 4, auto !important}`;
|
this.scr.innerHTML = `* {cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' width='10px' height='10px'><circle cx='4' cy='4' r='4' fill='white' /></svg>") 4 4, auto !important}`;
|
||||||
@ -51,7 +55,7 @@ class Cursor {
|
|||||||
this.cursor.classList.remove("active");
|
this.cursor.classList.remove("active");
|
||||||
this.pos = {
|
this.pos = {
|
||||||
curr: null,
|
curr: null,
|
||||||
prev: null
|
prev: null,
|
||||||
};
|
};
|
||||||
this.pt = [];
|
this.pt = [];
|
||||||
|
|
||||||
@ -61,18 +65,18 @@ class Cursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
document.onmousemove = e => {
|
document.onmousemove = (e) => {
|
||||||
(this.pos.curr == null) && this.move(e.clientX - 8, e.clientY - 8);
|
this.pos.curr == null && this.move(e.clientX - 8, e.clientY - 8);
|
||||||
this.pos.curr = {
|
this.pos.curr = {
|
||||||
x: e.clientX - 8,
|
x: e.clientX - 8,
|
||||||
y: e.clientY - 8
|
y: e.clientY - 8,
|
||||||
};
|
};
|
||||||
this.cursor.classList.remove("hidden");
|
this.cursor.classList.remove("hidden");
|
||||||
};
|
};
|
||||||
document.onmouseenter = e => this.cursor.classList.remove("hidden");
|
document.onmouseenter = () => this.cursor.classList.remove("hidden");
|
||||||
document.onmouseleave = e => this.cursor.classList.add("hidden");
|
document.onmouseleave = () => this.cursor.classList.add("hidden");
|
||||||
document.onmousedown = e => this.cursor.classList.add("active");
|
document.onmousedown = () => this.cursor.classList.add("active");
|
||||||
document.onmouseup = e => this.cursor.classList.remove("active");
|
document.onmouseup = () => this.cursor.classList.remove("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -87,8 +91,4 @@ class Cursor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cursorInit = () => {
|
|
||||||
CURSOR = new Cursor();
|
|
||||||
};
|
|
||||||
|
|
||||||
export default cursorInit;
|
export default cursorInit;
|
@ -12,10 +12,10 @@ function debounce(func, wait = 300, immediate = false) {
|
|||||||
timeout = setTimeout(function () {
|
timeout = setTimeout(function () {
|
||||||
timeout = null;
|
timeout = null;
|
||||||
}, wait);
|
}, wait);
|
||||||
if (callNow) typeof func === 'function' && func();
|
if (callNow) typeof func === "function" && func();
|
||||||
} else {
|
} else {
|
||||||
timeout = setTimeout(function () {
|
timeout = setTimeout(function () {
|
||||||
typeof func === 'function' && func();
|
typeof func === "function" && func();
|
||||||
}, wait);
|
}, wait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,12 @@ import { SpaCandle } from "@icon-park/vue-next";
|
|||||||
export const getCurrentTime = () => {
|
export const getCurrentTime = () => {
|
||||||
let time = new Date();
|
let time = new Date();
|
||||||
let year = time.getFullYear();
|
let year = time.getFullYear();
|
||||||
let month =
|
let month = time.getMonth() + 1 < 10 ? "0" + (time.getMonth() + 1) : time.getMonth() + 1;
|
||||||
time.getMonth() + 1 < 10
|
|
||||||
? "0" + (time.getMonth() + 1)
|
|
||||||
: time.getMonth() + 1;
|
|
||||||
let day = time.getDate() < 10 ? "0" + time.getDate() : time.getDate();
|
let day = time.getDate() < 10 ? "0" + time.getDate() : time.getDate();
|
||||||
let hour = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();
|
let hour = time.getHours() < 10 ? "0" + time.getHours() : time.getHours();
|
||||||
let minute =
|
let minute = time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
|
||||||
time.getMinutes() < 10 ? "0" + time.getMinutes() : time.getMinutes();
|
let second = time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
|
||||||
let second =
|
let weekday = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
|
||||||
time.getSeconds() < 10 ? "0" + time.getSeconds() : time.getSeconds();
|
|
||||||
let weekday = [
|
|
||||||
"星期日",
|
|
||||||
"星期一",
|
|
||||||
"星期二",
|
|
||||||
"星期三",
|
|
||||||
"星期四",
|
|
||||||
"星期五",
|
|
||||||
"星期六",
|
|
||||||
];
|
|
||||||
let currentTime = {
|
let currentTime = {
|
||||||
year,
|
year,
|
||||||
month,
|
month,
|
||||||
@ -122,7 +109,7 @@ export const checkDays = () => {
|
|||||||
const mon = myDate.getMonth() + 1;
|
const mon = myDate.getMonth() + 1;
|
||||||
const date = myDate.getDate();
|
const date = myDate.getDate();
|
||||||
const key = `${mon}.${date}`;
|
const key = `${mon}.${date}`;
|
||||||
if (anniversaries.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(anniversaries, key)) {
|
||||||
console.log(`今天是${anniversaries[key]}`);
|
console.log(`今天是${anniversaries[key]}`);
|
||||||
const gray = document.createElement("style");
|
const gray = document.createElement("style");
|
||||||
gray.innerHTML = "html{filter: grayscale(100%)}";
|
gray.innerHTML = "html{filter: grayscale(100%)}";
|
||||||
@ -144,11 +131,11 @@ export const siteDateStatistics = (startDate) => {
|
|||||||
const differenceInYears = differenceInMonths / 12;
|
const differenceInYears = differenceInMonths / 12;
|
||||||
if (differenceInYears >= 1) {
|
if (differenceInYears >= 1) {
|
||||||
return `本站已经苟活了 ${Math.floor(differenceInYears)} 年 ${Math.floor(
|
return `本站已经苟活了 ${Math.floor(differenceInYears)} 年 ${Math.floor(
|
||||||
differenceInMonths % 12
|
differenceInMonths % 12,
|
||||||
)} 月 ${Math.round(differenceInDays % 30)} 天`;
|
)} 月 ${Math.round(differenceInDays % 30)} 天`;
|
||||||
} else if (differenceInMonths >= 1) {
|
} else if (differenceInMonths >= 1) {
|
||||||
return `本站已经苟活了 ${Math.floor(differenceInMonths)} 月 ${Math.round(
|
return `本站已经苟活了 ${Math.floor(differenceInMonths)} 月 ${Math.round(
|
||||||
differenceInDays % 30
|
differenceInDays % 30,
|
||||||
)} 天`;
|
)} 天`;
|
||||||
} else {
|
} else {
|
||||||
return `本站已经苟活了 ${Math.round(differenceInDays)} 天`;
|
return `本站已经苟活了 ${Math.round(differenceInDays)} 天`;
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
/*!
|
|
||||||
* china-lantern v1.6.0
|
|
||||||
* (c) 2020-2021 fz6m
|
|
||||||
* Released under the MIT License.
|
|
||||||
*/
|
|
||||||
!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){"use strict";!function(t,e){void 0===e&&(e={});var n=e.insertAt;if(t&&"undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===n&&r.firstChild?r.insertBefore(a,r.firstChild):r.appendChild(a),a.styleSheet?a.styleSheet.cssText=t:a.appendChild(document.createTextNode(t))}}('@charset "UTF-8";.lantern__warpper{position:fixed;top:12px;left:40px;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:999}.lantern__warpper.lantern__secondary{left:calc(100% - 130px)}.lantern__warpper.lantern__secondary .lantern__box{-webkit-animation-duration:3s;animation-duration:3s;animation-delay:1s;}.lantern__box{position:relative;display:inline-block;width:90px;height:70px;background:rgba(216,0,15,.8);border-radius:50% 50%;animation:lantern-swing 3s ease-in-out infinite alternate-reverse;-webkit-transform-origin:50% -70px;-ms-transform-origin:50% -70px;transform-origin:50% -70px;-webkit-box-shadow:-5px 5px 50px 4px #fa6c00;box-shadow:-5px 5px 50px 4px #fa6c00}.lantern__box:after,.lantern__box:before{content:"";position:absolute;height:8px;width:45px;left:50%;border:1px solid #dc8f03;background:-webkit-gradient(linear,left top,right top,from(#dc8f03),color-stop(orange),color-stop(#dc8f03),color-stop(orange),to(#dc8f03));background:-o-linear-gradient(left,#dc8f03,orange,#dc8f03,orange,#dc8f03);background:linear-gradient(90deg,#dc8f03,orange,#dc8f03,orange,#dc8f03)}.lantern__box:before{top:0;border-radius:5px 5px 0 0;-webkit-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.lantern__box:after{bottom:0;border-radius:0 0 5px 5px;-webkit-transform:translate(-50%,50%);-ms-transform:translate(-50%,50%);transform:translate(-50%,50%)}.lantern__line{position:absolute;width:2px;height:12px;top:0;left:50%;-webkit-transform:translate(-50%,-100%);-ms-transform:translate(-50%,-100%);transform:translate(-50%,-100%);background:#dc8f03}.lantern__circle{width:80%;-webkit-box-sizing:border-box;box-sizing:border-box}.lantern__circle,.lantern__circle .lantern__ellipse{height:100%;margin:0 auto;border-radius:50%;border:2px solid #dc8f03}.lantern__circle .lantern__ellipse{width:50%}.lantern__circle .lantern__text{font-family:华文行楷,Microsoft YaHei,sans-serif;font-size:24.3px;color:#dc8f03;font-weight:700;line-height:66px;text-align:center}.lantern__tail{position:relative;width:4px;height:12px;margin:0 auto;animation:lantern-swing 4s ease-in-out infinite alternate-reverse;background:orange;border-radius:0 0 5px 5px}.lantern__tail .lantern__junction{position:absolute;top:0;left:50%;width:8px;height:8px;-webkit-transform:translate(-50%,8.4px);-ms-transform:translate(-50%,8.4px);transform:translate(-50%,8.4px);background:#e69603;border-radius:50%}.lantern__tail .lantern__rect{position:absolute;top:0;left:50%;-webkit-transform:translate(-50%,10.8px);-ms-transform:translate(-50%,10.8px);transform:translate(-50%,10.8px);width:8px;height:24px;background:orange;border-radius:5px 5px 0 5px}@-webkit-keyframes lantern-swing{0%{-webkit-transform:rotate(-8deg);transform:rotate(-8deg)}to{-webkit-transform:rotate(8deg);transform:rotate(8deg)}}@keyframes lantern-swing{0%{-webkit-transform:rotate(-8deg);transform:rotate(-8deg)}to{-webkit-transform:rotate(8deg);transform:rotate(8deg)}}@media (max-width:520px){.j-china-lantern{display: none;}');var t;(t=document.createElement("div")).className="j-china-lantern",t.innerHTML='<div class="lantern__warpper"><div class="lantern__box"><div class="lantern__line"></div><div class="lantern__circle"><div class="lantern__ellipse"><div class="lantern__text">新</div></div></div><div class="lantern__tail"><div class="lantern__rect"></div><div class="lantern__junction"></div></div></div></div><div class="lantern__warpper lantern__secondary"><div class="lantern__box"><div class="lantern__line"></div><div class="lantern__circle"><div class="lantern__ellipse"><div class="lantern__text">年</div></div></div><div class="lantern__tail"><div class="lantern__rect"></div><div class="lantern__junction"></div></div></div></div>',document.body.appendChild(t)}));
|
|
@ -1,9 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="box cards" @mouseenter="closeShow = true" @mouseleave="closeShow = false">
|
||||||
class="box cards"
|
|
||||||
@mouseenter="closeShow = true"
|
|
||||||
@mouseleave="closeShow = false"
|
|
||||||
>
|
|
||||||
<transition name="el-fade-in-linear">
|
<transition name="el-fade-in-linear">
|
||||||
<close-one
|
<close-one
|
||||||
class="close"
|
class="close"
|
||||||
@ -25,16 +21,18 @@
|
|||||||
/>
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<!-- 可在此处自定义任意内容 -->
|
||||||
<TimeCapsule />
|
<TimeCapsule />
|
||||||
|
<GithubProject />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
|
||||||
import { CloseOne, SettingTwo } from "@icon-park/vue-next";
|
import { CloseOne, SettingTwo } from "@icon-park/vue-next";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import TimeCapsule from "@/components/TimeCapsule/index.vue";
|
import TimeCapsule from "@/components/TimeCapsule.vue";
|
||||||
|
import GithubProject from "@/components/GithubProject.vue";
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
const closeShow = ref(false);
|
const closeShow = ref(false);
|
||||||
@ -45,9 +43,9 @@ const closeShow = ref(false);
|
|||||||
flex: 1 0 0%;
|
flex: 1 0 0%;
|
||||||
margin-left: 0.75rem;
|
margin-left: 0.75rem;
|
||||||
height: 80%;
|
height: 80%;
|
||||||
|
max-width: 50%;
|
||||||
position: relative;
|
position: relative;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
@ -60,7 +58,9 @@ const closeShow = ref(false);
|
|||||||
right: 14px;
|
right: 14px;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
transition: transform 0.3s, opacity 0.3s;
|
transition:
|
||||||
|
transform 0.3s,
|
||||||
|
opacity 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<Hitokoto />
|
<Hitokoto />
|
||||||
<Music />
|
<Music v-if="playerHasId" />
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -18,11 +18,7 @@
|
|||||||
<span class="sm-hidden">{{ currentTime.weekday }}</span>
|
<span class="sm-hidden">{{ currentTime.weekday }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span>
|
<span> {{ currentTime.hour }}:{{ currentTime.minute }}:{{ currentTime.second }}</span>
|
||||||
{{ currentTime.hour }}:{{ currentTime.minute }}:{{
|
|
||||||
currentTime.second
|
|
||||||
}}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Weather />
|
<Weather />
|
||||||
@ -33,12 +29,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onBeforeUnmount } from "vue";
|
|
||||||
import { getCurrentTime } from "@/utils/getTime";
|
import { getCurrentTime } from "@/utils/getTime";
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import Music from "@/components/Music/index.vue";
|
import Music from "@/components/Music.vue";
|
||||||
import Hitokoto from "@/components/Hitokoto/index.vue";
|
import Hitokoto from "@/components/Hitokoto.vue";
|
||||||
import Weather from "@/components/Weather/index.vue";
|
import Weather from "@/components/Weather.vue";
|
||||||
|
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
@ -46,6 +41,9 @@ const store = mainStore();
|
|||||||
const currentTime = ref({});
|
const currentTime = ref({});
|
||||||
const timeInterval = ref(null);
|
const timeInterval = ref(null);
|
||||||
|
|
||||||
|
// 播放器 id
|
||||||
|
const playerHasId = import.meta.env.VITE_SONG_ID;
|
||||||
|
|
||||||
// 更新时间
|
// 更新时间
|
||||||
const updateTimeData = () => {
|
const updateTimeData = () => {
|
||||||
currentTime.value = getCurrentTime();
|
currentTime.value = getCurrentTime();
|
||||||
@ -114,8 +112,7 @@ onBeforeUnmount(() => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
.time {
|
.time {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import Message from "@/components/Message/index.vue";
|
import Message from "@/components/Message.vue";
|
||||||
import SocialLinks from "@/components/SocialLinks/index.vue";
|
import SocialLinks from "@/components/SocialLinks.vue";
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -15,14 +15,22 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import Func from "@/views/Func/index.vue";
|
import Func from "@/views/Func/index.vue";
|
||||||
import Link from "@/components/Links/index.vue";
|
import Link from "@/components/Links.vue";
|
||||||
const store = mainStore();
|
const store = mainStore();
|
||||||
|
|
||||||
// 站点链接
|
// 站点链接
|
||||||
const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
const siteUrl = computed(() => {
|
||||||
|
const url = import.meta.env.VITE_SITE_URL;
|
||||||
|
if (!url) return "imsyy.top".split(".");
|
||||||
|
// 判断协议前缀
|
||||||
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||||
|
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||||
|
return urlFormat.split(".");
|
||||||
|
}
|
||||||
|
return url.split(".");
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.right {
|
.right {
|
||||||
// flex: 1 0 0%;
|
// flex: 1 0 0%;
|
||||||
@ -36,9 +44,8 @@ const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
|||||||
top: 6%;
|
top: 6%;
|
||||||
left: 0;
|
left: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: all 0.3s;
|
transition: transform 0.3s;
|
||||||
animation: fade;
|
animation: fade 0.5s;
|
||||||
-webkit-animation: fade 0.5s;
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: scale(0.95);
|
transform: scale(0.95);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="set" @mouseenter="closeShow = true" @mouseleave="closeShow = false" @click.stop>
|
||||||
class="set"
|
|
||||||
@mouseenter="closeShow = true"
|
|
||||||
@mouseleave="closeShow = false"
|
|
||||||
@click.stop
|
|
||||||
>
|
|
||||||
<transition name="el-fade-in-linear">
|
<transition name="el-fade-in-linear">
|
||||||
<close-one
|
<close-one
|
||||||
class="close"
|
class="close"
|
||||||
@ -23,17 +18,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="version">
|
<div class="version">
|
||||||
<div class="num">v {{ config.version }}</div>
|
<div class="num">v {{ config.version }}</div>
|
||||||
<el-tooltip
|
<el-tooltip content="Github 源代码仓库" placement="right" :show-arrow="false">
|
||||||
content="Github 源代码仓库"
|
<github-one class="github" theme="outline" size="24" @click="jumpTo(config.github)" />
|
||||||
placement="right"
|
|
||||||
:show-arrow="false"
|
|
||||||
>
|
|
||||||
<github-one
|
|
||||||
class="github"
|
|
||||||
theme="outline"
|
|
||||||
size="24"
|
|
||||||
@click="jumpTo(config.github)"
|
|
||||||
/>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<el-card class="update">
|
<el-card class="update">
|
||||||
@ -66,23 +52,25 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref } from "vue";
|
import { CloseOne, SettingTwo, GithubOne, AddOne, Bug } from "@icon-park/vue-next";
|
||||||
import {
|
|
||||||
CloseOne,
|
|
||||||
SettingTwo,
|
|
||||||
GithubOne,
|
|
||||||
AddOne,
|
|
||||||
Bug,
|
|
||||||
} from "@icon-park/vue-next";
|
|
||||||
import { mainStore } from "@/store";
|
import { mainStore } from "@/store";
|
||||||
import Set from "@/components/Set/index.vue";
|
import Set from "@/components/Set.vue";
|
||||||
import config from "@/../package.json";
|
import config from "@/../package.json";
|
||||||
const store = mainStore();
|
|
||||||
|
|
||||||
|
const store = mainStore();
|
||||||
const closeShow = ref(false);
|
const closeShow = ref(false);
|
||||||
|
|
||||||
// 站点链接
|
// 站点链接
|
||||||
const siteUrl = import.meta.env.VITE_SITE_URL.split(".");
|
const siteUrl = computed(() => {
|
||||||
|
const url = import.meta.env.VITE_SITE_URL;
|
||||||
|
if (!url) return "imsyy.top".split(".");
|
||||||
|
// 判断协议前缀
|
||||||
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||||
|
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||||
|
return urlFormat.split(".");
|
||||||
|
}
|
||||||
|
return url.split(".");
|
||||||
|
});
|
||||||
|
|
||||||
// 更新日志
|
// 更新日志
|
||||||
const upData = reactive({
|
const upData = reactive({
|
||||||
@ -92,12 +80,7 @@ const upData = reactive({
|
|||||||
"壁纸支持个性化设置",
|
"壁纸支持个性化设置",
|
||||||
"音乐播放器支持音量控制",
|
"音乐播放器支持音量控制",
|
||||||
],
|
],
|
||||||
fix: [
|
fix: ["修复天气 API", "时光胶囊显示错误", "移动端动画及细节", "图标更换为 IconPark"],
|
||||||
"修复天气 API",
|
|
||||||
"时光胶囊显示错误",
|
|
||||||
"移动端动画及细节",
|
|
||||||
"图标更换为 IconPark",
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 跳转源代码仓库
|
// 跳转源代码仓库
|
||||||
@ -150,10 +133,10 @@ const jumpTo = (url) => {
|
|||||||
.logo {
|
.logo {
|
||||||
transform: translateY(-8%);
|
transform: translateY(-8%);
|
||||||
font-family: "Pacifico-Regular";
|
font-family: "Pacifico-Regular";
|
||||||
// line-height: 5rem;
|
padding-left: 22px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 260px;
|
height: 260px;
|
||||||
|
min-height: 140px;
|
||||||
.bg {
|
.bg {
|
||||||
font-size: 5rem;
|
font-size: 5rem;
|
||||||
}
|
}
|
||||||
|
167
vite.config.js
@ -1,135 +1,122 @@
|
|||||||
import {
|
/* eslint-disable no-undef */
|
||||||
defineConfig,
|
import { defineConfig, loadEnv } from "vite";
|
||||||
loadEnv
|
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||||
} from 'vite';
|
import { resolve } from "path";
|
||||||
import vue from '@vitejs/plugin-vue';
|
import { VitePWA } from "vite-plugin-pwa";
|
||||||
import AutoImport from 'unplugin-auto-import/vite'
|
import vue from "@vitejs/plugin-vue";
|
||||||
import Components from 'unplugin-vue-components/vite'
|
import AutoImport from "unplugin-auto-import/vite";
|
||||||
import {
|
import Components from "unplugin-vue-components/vite";
|
||||||
ElementPlusResolver
|
import viteCompression from "vite-plugin-compression";
|
||||||
} from 'unplugin-vue-components/resolvers'
|
|
||||||
import {
|
|
||||||
createHtmlPlugin
|
|
||||||
} from 'vite-plugin-html';
|
|
||||||
import {
|
|
||||||
resolve
|
|
||||||
} from 'path';
|
|
||||||
import {
|
|
||||||
VitePWA
|
|
||||||
} from 'vite-plugin-pwa';
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default ({
|
export default ({ mode }) =>
|
||||||
mode
|
defineConfig({
|
||||||
}) => defineConfig({
|
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
|
imports: ["vue"],
|
||||||
resolvers: [ElementPlusResolver()],
|
resolvers: [ElementPlusResolver()],
|
||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
resolvers: [ElementPlusResolver()],
|
resolvers: [ElementPlusResolver()],
|
||||||
}),
|
}),
|
||||||
createHtmlPlugin({
|
|
||||||
minify: true,
|
|
||||||
inject: {
|
|
||||||
data: {
|
|
||||||
logo: loadEnv(mode, process.cwd()).VITE_SITE_LOGO,
|
|
||||||
appleLogo: loadEnv(mode, process.cwd()).VITE_SITE_APPLE_LOGO,
|
|
||||||
title: loadEnv(mode, process.cwd()).VITE_SITE_NAME,
|
|
||||||
author: loadEnv(mode, process.cwd()).VITE_SITE_ANTHOR,
|
|
||||||
keywords: loadEnv(mode, process.cwd()).VITE_SITE_KEYWORDS,
|
|
||||||
description: loadEnv(mode, process.cwd()).VITE_SITE_DES,
|
|
||||||
tongji: loadEnv(mode, process.cwd()).VITE_SITE_BAIDUTONGJI,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: "autoUpdate",
|
||||||
workbox: {
|
workbox: {
|
||||||
skipWaiting: true,
|
skipWaiting: true,
|
||||||
clientsClaim: true,
|
clientsClaim: true,
|
||||||
runtimeCaching: [{
|
runtimeCaching: [
|
||||||
|
{
|
||||||
urlPattern: /(.*?)\.(js|css|woff2|woff|ttf)/, // js / css 静态资源缓存
|
urlPattern: /(.*?)\.(js|css|woff2|woff|ttf)/, // js / css 静态资源缓存
|
||||||
handler: 'CacheFirst',
|
handler: "CacheFirst",
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'js-css-cache',
|
cacheName: "js-css-cache",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urlPattern: /(.*?)\.(png|jpe?g|svg|gif|bmp|psd|tiff|tga|eps)/, // 图片缓存
|
urlPattern: /(.*?)\.(png|jpe?g|svg|gif|bmp|psd|tiff|tga|eps)/, // 图片缓存
|
||||||
handler: 'CacheFirst',
|
handler: "CacheFirst",
|
||||||
options: {
|
options: {
|
||||||
cacheName: 'image-cache',
|
cacheName: "image-cache",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
manifest: {
|
manifest: {
|
||||||
"name": loadEnv(mode, process.cwd()).VITE_SITE_NAME,
|
name: loadEnv(mode, process.cwd()).VITE_SITE_NAME,
|
||||||
"short_name": loadEnv(mode, process.cwd()).VITE_SITE_NAME,
|
short_name: loadEnv(mode, process.cwd()).VITE_SITE_NAME,
|
||||||
"description": loadEnv(mode, process.cwd()).VITE_SITE_DES,
|
description: loadEnv(mode, process.cwd()).VITE_SITE_DES,
|
||||||
"display": "standalone",
|
display: "standalone",
|
||||||
"start_url": "/",
|
start_url: "/",
|
||||||
"theme_color": "#424242",
|
theme_color: "#424242",
|
||||||
"background_color": "#424242",
|
background_color: "#424242",
|
||||||
"icons": [{
|
icons: [
|
||||||
"src": "/images/icon/48.png",
|
{
|
||||||
"sizes": "48x48",
|
src: "/images/icon/48.png",
|
||||||
"type": "image/png"
|
sizes: "48x48",
|
||||||
}, {
|
type: "image/png",
|
||||||
"src": "/images/icon/72.png",
|
},
|
||||||
"sizes": "72x72",
|
{
|
||||||
"type": "image/png"
|
src: "/images/icon/72.png",
|
||||||
}, {
|
sizes: "72x72",
|
||||||
"src": "/images/icon/96.png",
|
type: "image/png",
|
||||||
"sizes": "96x96",
|
},
|
||||||
"type": "image/png"
|
{
|
||||||
}, {
|
src: "/images/icon/96.png",
|
||||||
"src": "/images/icon/128.png",
|
sizes: "96x96",
|
||||||
"sizes": "128x128",
|
type: "image/png",
|
||||||
"type": "image/png"
|
},
|
||||||
}, {
|
{
|
||||||
"src": "/images/icon/144.png",
|
src: "/images/icon/128.png",
|
||||||
"sizes": "144x144",
|
sizes: "128x128",
|
||||||
"type": "image/png"
|
type: "image/png",
|
||||||
}, {
|
},
|
||||||
"src": "/images/icon/192.png",
|
{
|
||||||
"sizes": "192x192",
|
src: "/images/icon/144.png",
|
||||||
"type": "image/png"
|
sizes: "144x144",
|
||||||
}, {
|
type: "image/png",
|
||||||
"src": "/images/icon/512.png",
|
},
|
||||||
"sizes": "512x512",
|
{
|
||||||
"type": "image/png"
|
src: "/images/icon/192.png",
|
||||||
}]
|
sizes: "192x192",
|
||||||
}
|
type: "image/png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/images/icon/512.png",
|
||||||
|
sizes: "512x512",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
|
viteCompression(),
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
port: "3000",
|
port: "3000",
|
||||||
hmr: true,
|
open: true,
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: [{
|
alias: [
|
||||||
find: '@',
|
{
|
||||||
|
find: "@",
|
||||||
replacement: resolve(__dirname, "src"),
|
replacement: resolve(__dirname, "src"),
|
||||||
}, ]
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
scss: {
|
scss: {
|
||||||
charset: false,
|
charset: false,
|
||||||
additionalData: `@import "./src/style/global.scss";`
|
additionalData: `@import "./src/style/global.scss";`,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
minify: 'terser',
|
minify: "terser",
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
compress: {
|
compress: {
|
||||||
// 生产环境时移除 console
|
pure_funcs: ["console.log"],
|
||||||
pure_funcs: ['console.log'],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|