初始化
24
.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
/dist_electron
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Vue 3 + Vite
|
||||||
|
|
||||||
|
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||||
|
|
||||||
|
## Recommended IDE Setup
|
||||||
|
|
||||||
|
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
|
50
electron/electron.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// electron/electron.js
|
||||||
|
const path = require('path');
|
||||||
|
const { app, BrowserWindow } = require('electron');
|
||||||
|
|
||||||
|
const isDev = process.env.IS_DEV == "true" ? true : false;
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
// Create the browser window.
|
||||||
|
const mainWindow = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
|
nodeIntegration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// and load the index.html of the app.
|
||||||
|
// win.loadFile("index.html");
|
||||||
|
mainWindow.loadURL(
|
||||||
|
isDev
|
||||||
|
? 'http://localhost:3000'
|
||||||
|
: `file://${path.join(__dirname, '../dist/index.html')}`
|
||||||
|
);
|
||||||
|
// Open the DevTools.
|
||||||
|
if (isDev) {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will be called when Electron has finished
|
||||||
|
// initialization and is ready to create browser windows.
|
||||||
|
// Some APIs can only be used after this event occurs.
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
createWindow()
|
||||||
|
app.on('activate', function () {
|
||||||
|
// On macOS it's common to re-create a window in the app when the
|
||||||
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Quit when all windows are closed, except on macOS. There, it's common
|
||||||
|
// for applications and their menu bar to stay active until the user quits
|
||||||
|
// explicitly with Cmd + Q.
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
14
electron/preload.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// electron/preload.js
|
||||||
|
|
||||||
|
// All of the Node.js APIs are available in the preload process.
|
||||||
|
// It has the same sandbox as a Chrome extension.
|
||||||
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const replaceText = (selector, text) => {
|
||||||
|
const element = document.getElementById(selector)
|
||||||
|
if (element) element.innerText = text
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const dependency of ['chrome', 'node', 'electron']) {
|
||||||
|
replaceText(`${dependency}-version`, process.versions[dependency])
|
||||||
|
}
|
||||||
|
})
|
13
index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>zmusic</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
76
package.json
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"name": "zmusic",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": "zlyum",
|
||||||
|
"main": "electron/electron.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"serve": "vite preview",
|
||||||
|
"electron": "wait-on tcp:3000 && cross-env IS_DEV=true electron .",
|
||||||
|
"electron:pack": "electron-builder --dir",
|
||||||
|
"electron:dev": "concurrently -k \"cross-env BROWSER=none yarn dev\" \"yarn electron\"",
|
||||||
|
"electron:builder": "electron-builder",
|
||||||
|
"build:for:electron": "cross-env ELECTRON=true vite build",
|
||||||
|
"app:pack": "yarn build:for:electron && yarn electron:pack",
|
||||||
|
"app:build": "yarn build:for:electron && yarn electron:builder"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.22.0",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"dayjs": "^1.10.7",
|
||||||
|
"element-plus": "^1.1.0-beta.19",
|
||||||
|
"pubsub-js": "^1.9.3",
|
||||||
|
"unplugin-vue-components": "^0.15.6",
|
||||||
|
"vue": "^3.2.16",
|
||||||
|
"vue-router": "^4.0.0-0",
|
||||||
|
"vue3-styled-components": "^1.2.1",
|
||||||
|
"vuex": "^4.0.0-0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^1.9.3",
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/compiler-sfc": "^3.0.0",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"concurrently": "^6.3.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
|
"electron": "^15.1.2",
|
||||||
|
"electron-builder": "^22.13.1",
|
||||||
|
"electron-devtools-installer": "^3.1.0",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
|
"eslint-plugin-vue": "^7.0.0",
|
||||||
|
"less": "^3.0.4",
|
||||||
|
"less-loader": "^5.0.0",
|
||||||
|
"naive-ui": "^2.19.3",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"vite": "^2.6.4",
|
||||||
|
"vite-svg-loader": "^2.2.0",
|
||||||
|
"wait-on": "^6.0.0"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"appId": "com.zlyum.zmusic",
|
||||||
|
"productName": "zmusic",
|
||||||
|
"copyright": "Copyright © 2021 ${author}",
|
||||||
|
"mac": {
|
||||||
|
"category": "public.app-category.utilities"
|
||||||
|
},
|
||||||
|
"nsis": {
|
||||||
|
"oneClick": false,
|
||||||
|
"allowToChangeInstallationDirectory": true
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"electron/**/*"
|
||||||
|
],
|
||||||
|
"directories": {
|
||||||
|
"buildResources": "assets",
|
||||||
|
"output": "dist_electron"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
180
src/App.vue
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<script setup>
|
||||||
|
import { h, ref, onMounted, onUnmounted } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import styled from "vue3-styled-components";
|
||||||
|
import Nav from "@/views/common/Nav.vue";
|
||||||
|
import TopMenu from "./views/common/TopMenu.vue";
|
||||||
|
import Search from "./views/common/Search.vue";
|
||||||
|
import Settings from "./views/common/Settings.vue";
|
||||||
|
import MainMenu from "./views/common/MainMenu.vue";
|
||||||
|
import SongInfo from "./views/common/SongInfo.vue";
|
||||||
|
import SongCtrl from "./views/common/SongCtrl.vue";
|
||||||
|
import SongStatus from "./views/common/SongStatus.vue";
|
||||||
|
import SongProgress from "@/views/common/SongProgress.vue";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import { NConfigProvider, darkTheme } from "naive-ui";
|
||||||
|
// import { CloudCircleSharp } from "@vicons/ionicons5";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type import('naive-ui').GlobalThemeOverrides
|
||||||
|
*/
|
||||||
|
// const themeOverrides = {
|
||||||
|
// common: {
|
||||||
|
// primaryColor: "#5C18A0FF",
|
||||||
|
// primaryColorHover: "#7536ADFF",
|
||||||
|
// primaryColorPressed: "#690D7EFF",
|
||||||
|
// primaryColorSuppl: "#511D77FF",
|
||||||
|
// textColorBase: "#1F1F1FFF",
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
//载入localstorage的设置
|
||||||
|
store.commit("loadSettings");
|
||||||
|
|
||||||
|
//处理route消息
|
||||||
|
const routeToken = pubsub.subscribe(
|
||||||
|
"router",
|
||||||
|
(msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "router.beforeEach":
|
||||||
|
case "router.afterEach":
|
||||||
|
store.commit("saveSettings", {
|
||||||
|
currentRoute: data.to.fullPath,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(routeToken);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-config-provider
|
||||||
|
theme
|
||||||
|
:theme-overrides="store.state.theme.themeOverrides"
|
||||||
|
>
|
||||||
|
<div id="wp">
|
||||||
|
<!-- <NThemeEditor/> -->
|
||||||
|
<div id="top">
|
||||||
|
<Nav></Nav>
|
||||||
|
<TopMenu></TopMenu>
|
||||||
|
<Search></Search>
|
||||||
|
<Settings></Settings>
|
||||||
|
</div>
|
||||||
|
<div id="content">
|
||||||
|
<div id="side">
|
||||||
|
<Personal></Personal>
|
||||||
|
<MainMenu></MainMenu>
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<div id="songDetail"></div>
|
||||||
|
<div id="songProgress">
|
||||||
|
<SongProgress/>
|
||||||
|
</div>
|
||||||
|
<div id="songCtrl">
|
||||||
|
<SongInfo />
|
||||||
|
<SongCtrl />
|
||||||
|
<SongStatus />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import "@/assets/css/common.less";
|
||||||
|
body {
|
||||||
|
// margin: 0;
|
||||||
|
// padding: 0;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.3;
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-menu {
|
||||||
|
margin-top: -44px;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
.zm-top-menu.n-menu.n-menu--horizontal
|
||||||
|
.n-menu-item-content {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.main-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 160px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 64px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
padding-right: 2px;
|
||||||
|
|
||||||
|
.lmt-width {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 8px 12px 8px 8px;
|
||||||
|
max-width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#wp {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
#top {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
#side {
|
||||||
|
width: 160px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
#main {
|
||||||
|
flex: 1;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
#songDetail{
|
||||||
|
|
||||||
|
}
|
||||||
|
#songProgress{
|
||||||
|
height: 3px;
|
||||||
|
// background-color: red;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
#songCtrl {
|
||||||
|
height: 64px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
22
src/assets/css/common.css
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.text-el-line {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
.text-el-line1 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
}
|
||||||
|
.text-el-line2 {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
17
src/assets/css/common.less
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.text-el-line{
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-el-line1{
|
||||||
|
.text-el-line();
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-el-line2{
|
||||||
|
.text-el-line();
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
BIN
src/assets/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
1
src/assets/svgs/ArrowsSplit2.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 17h-5.397a5 5 0 0 1-4.096-2.133l-.514-.734A5 5 0 0 0 6.897 12H3"></path><path d="M21 7h-5.395a5 5 0 0 0-4.098 2.135l-.51.73A5 5 0 0 1 6.9 12H3"></path><path d="M18 10l3-3l-3-3"></path><path d="M18 20l3-3l-3-3"></path></g></svg>
|
After Width: | Height: | Size: 444 B |
1
src/assets/svgs/ChevronBack.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M328 112L184 256l144 144"></path></svg>
|
After Width: | Height: | Size: 252 B |
1
src/assets/svgs/ChevronForward.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M184 112l144 144l-144 144"></path></svg>
|
After Width: | Height: | Size: 253 B |
1
src/assets/svgs/HeartOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M352.92 80C288 80 256 144 256 144s-32-64-96.92-64c-52.76 0-94.54 44.14-95.08 96.81c-1.1 109.33 86.73 187.08 183 252.42a16 16 0 0 0 18 0c96.26-65.34 184.09-143.09 183-252.42c-.54-52.67-42.32-96.81-95.08-96.81z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 436 B |
1
src/assets/svgs/MailOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><rect x="48" y="96" width="416" height="320" rx="40" ry="40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></rect><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M112 160l144 112l144-112"></path></svg>
|
After Width: | Height: | Size: 419 B |
1
src/assets/svgs/Pause.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M208 432h-48a16 16 0 0 1-16-16V96a16 16 0 0 1 16-16h48a16 16 0 0 1 16 16v320a16 16 0 0 1-16 16z" fill="currentColor"></path><path d="M352 432h-48a16 16 0 0 1-16-16V96a16 16 0 0 1 16-16h48a16 16 0 0 1 16 16v320a16 16 0 0 1-16 16z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 377 B |
1
src/assets/svgs/PauseCircle.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208s208-93.31 208-208S370.69 48 256 48zm-32 272a16 16 0 0 1-32 0V192a16 16 0 0 1 32 0zm96 0a16 16 0 0 1-32 0V192a16 16 0 0 1 32 0z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 328 B |
1
src/assets/svgs/PlayCircle.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208s208-93.31 208-208S370.69 48 256 48zm74.77 217.3l-114.45 69.14a10.78 10.78 0 0 1-16.32-9.31V186.87a10.78 10.78 0 0 1 16.32-9.31l114.45 69.14a10.89 10.89 0 0 1 0 18.6z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 367 B |
1
src/assets/svgs/PlaySkipBack.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M112 64a16 16 0 0 1 16 16v136.43L360.77 77.11a35.13 35.13 0 0 1 35.77-.44c12 6.8 19.46 20 19.46 34.33v290c0 14.37-7.46 27.53-19.46 34.33a35.14 35.14 0 0 1-35.77-.45L128 295.57V432a16 16 0 0 1-32 0V80a16 16 0 0 1 16-16z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 367 B |
1
src/assets/svgs/PlaySkipForward.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M400 64a16 16 0 0 0-16 16v136.43L151.23 77.11a35.13 35.13 0 0 0-35.77-.44C103.46 83.47 96 96.63 96 111v290c0 14.37 7.46 27.53 19.46 34.33a35.14 35.14 0 0 0 35.77-.45L384 295.57V432a16 16 0 0 0 32 0V80a16 16 0 0 0-16-16z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 368 B |
1
src/assets/svgs/Play_.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M133 440a35.37 35.37 0 0 1-17.5-4.67c-12-6.8-19.46-20-19.46-34.33V111c0-14.37 7.46-27.53 19.46-34.33a35.13 35.13 0 0 1 35.77.45l247.85 148.36a36 36 0 0 1 0 61l-247.89 148.4A35.5 35.5 0 0 1 133 440z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 346 B |
1
src/assets/svgs/Playlist.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><path d="M4 6h18v2H4z" fill="currentColor"></path><path d="M4 12h18v2H4z" fill="currentColor"></path><path d="M4 18h12v2H4z" fill="currentColor"></path><path d="M21 18l7 5l-7 5V18z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 318 B |
1
src/assets/svgs/PlaylistMusic.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="14" cy="17" r="3"></circle><path d="M17 17V4h4"></path><path d="M13 5H3"></path><path d="M3 9h10"></path><path d="M9 13H3"></path></g></svg>
|
After Width: | Height: | Size: 356 B |
1
src/assets/svgs/Random.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1634115462354" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4006" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M726.6 774H594.4L458.8 512l135.6-262h132.2v98.7l200-125-200-125V200H564.4L430.7 457.7 297.4 200h-200v50h169.2l135.9 262-135.9 262H97.4v50h200l133.3-257.7L564.4 824h162.2v101.3l200-125-200-125z" fill="" p-id="4007"></path></svg>
|
After Width: | Height: | Size: 604 B |
43
src/assets/svgs/RandomOutline.svg
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 49.7 49.7" style="enable-background:new 0 0 49.7 49.7;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M27,13.85h9v8.964l13.7-9.964L36,2.886v8.964h-9c-7.168,0-13,5.832-13,13c0,6.065-4.935,11-11,11H1c-0.553,0-1,0.447-1,1
|
||||||
|
s0.447,1,1,1h2c7.168,0,13-5.832,13-13C16,18.785,20.935,13.85,27,13.85z M38,6.814l8.3,6.036L38,18.886V6.814z"/>
|
||||||
|
<path d="M1,13.85h2c2.713,0,5.318,0.994,7.336,2.799c0.191,0.171,0.43,0.255,0.667,0.255c0.274,0,0.548-0.112,0.745-0.333
|
||||||
|
c0.368-0.412,0.333-1.044-0.078-1.412C9.285,13.025,6.206,11.85,3,11.85H1c-0.553,0-1,0.447-1,1S0.447,13.85,1,13.85z"/>
|
||||||
|
<path d="M36,35.85h-9c-2.685,0-5.27-0.976-7.278-2.748c-0.411-0.365-1.044-0.327-1.411,0.089c-0.365,0.414-0.326,1.046,0.089,1.411
|
||||||
|
c2.374,2.095,5.429,3.248,8.601,3.248h9v8.964l13.7-9.964L36,26.886V35.85z M38,30.814l8.3,6.036L38,42.886V30.814z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
src/assets/svgs/Random_bold.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M504.971 359.029c9.373 9.373 9.373 24.569 0 33.941l-80 79.984c-15.01 15.01-40.971 4.49-40.971-16.971V416h-58.785a12.004 12.004 0 0 1-8.773-3.812l-70.556-75.596l53.333-57.143L352 336h32v-39.981c0-21.438 25.943-31.998 40.971-16.971l80 79.981zM12 176h84l52.781 56.551l53.333-57.143l-70.556-75.596A11.999 11.999 0 0 0 122.785 96H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12zm372 0v39.984c0 21.46 25.961 31.98 40.971 16.971l80-79.984c9.373-9.373 9.373-24.569 0-33.941l-80-79.981C409.943 24.021 384 34.582 384 56.019V96h-58.785a12.004 12.004 0 0 0-8.773 3.812L96 336H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h110.785c3.326 0 6.503-1.381 8.773-3.812L352 176h32z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 822 B |
1
src/assets/svgs/RepeatOne.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32"><path d="M6 6h20.172l-3.586-3.586L24 1l6 6l-6 6l-1.414-1.414L26.172 8H6v7H4V8a2.002 2.002 0 0 1 2-2z" fill="currentColor"></path><path d="M9.414 20.414L5.828 24H26v-7h2v7a2.002 2.002 0 0 1-2 2H5.828l3.586 3.586L8 31l-6-6l6-6z" fill="currentColor"></path><path d="M17 19v-8h-2v1h-2v2h2v5h-2v2h6v-2h-2z" fill="currentColor"></path></svg>
|
After Width: | Height: | Size: 438 B |
1
src/assets/svgs/RepeatOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M320 120l48 48l-48 48"></path><path d="M352 168H144a80.24 80.24 0 0 0-80 80v16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M192 392l-48-48l48-48"></path><path d="M160 344h208a80.24 80.24 0 0 0 80-80v-16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 700 B |
1
src/assets/svgs/SettingsOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M262.29 192.31a64 64 0 1 0 57.4 57.4a64.13 64.13 0 0 0-57.4-57.4zM416.39 256a154.34 154.34 0 0 1-1.53 20.79l45.21 35.46a10.81 10.81 0 0 1 2.45 13.75l-42.77 74a10.81 10.81 0 0 1-13.14 4.59l-44.9-18.08a16.11 16.11 0 0 0-15.17 1.75A164.48 164.48 0 0 1 325 400.8a15.94 15.94 0 0 0-8.82 12.14l-6.73 47.89a11.08 11.08 0 0 1-10.68 9.17h-85.54a11.11 11.11 0 0 1-10.69-8.87l-6.72-47.82a16.07 16.07 0 0 0-9-12.22a155.3 155.3 0 0 1-21.46-12.57a16 16 0 0 0-15.11-1.71l-44.89 18.07a10.81 10.81 0 0 1-13.14-4.58l-42.77-74a10.8 10.8 0 0 1 2.45-13.75l38.21-30a16.05 16.05 0 0 0 6-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 0 0-6.07-13.94l-38.19-30A10.81 10.81 0 0 1 49.48 186l42.77-74a10.81 10.81 0 0 1 13.14-4.59l44.9 18.08a16.11 16.11 0 0 0 15.17-1.75A164.48 164.48 0 0 1 187 111.2a15.94 15.94 0 0 0 8.82-12.14l6.73-47.89A11.08 11.08 0 0 1 213.23 42h85.54a11.11 11.11 0 0 1 10.69 8.87l6.72 47.82a16.07 16.07 0 0 0 9 12.22a155.3 155.3 0 0 1 21.46 12.57a16 16 0 0 0 15.11 1.71l44.89-18.07a10.81 10.81 0 0 1 13.14 4.58l42.77 74a10.8 10.8 0 0 1-2.45 13.75l-38.21 30a16.05 16.05 0 0 0-6.05 14.08c.33 4.14.55 8.3.55 12.47z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
src/assets/svgs/TrashOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M112 112l20 320c.95 18.49 14.4 32 32 32h184c17.67 0 30.87-13.51 32-32l20-320" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M80 112h352" fill="currentColor"></path><path d="M192 112V72h0a23.93 23.93 0 0 1 24-24h80a23.93 23.93 0 0 1 24 24h0v40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M256 176v224"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M184 176l8 224"></path><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M328 176l-8 224"></path></svg>
|
After Width: | Height: | Size: 1017 B |
1
src/assets/svgs/VolumeHighOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M126 192H56a8 8 0 0 0-8 8v112a8 8 0 0 0 8 8h69.65a15.93 15.93 0 0 1 10.14 3.54l91.47 74.89A8 8 0 0 0 240 392V120a8 8 0 0 0-12.74-6.43l-91.47 74.89A15 15 0 0 1 126 192z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M320 320c9.74-19.38 16-40.84 16-64c0-23.48-6-44.42-16-64" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M368 368c19.48-33.92 32-64.06 32-112s-12-77.74-32-112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M416 416c30-46 48-91.43 48-160s-18-113-48-160" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 900 B |
1
src/assets/svgs/VolumeLowOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M189.65 192H120a8 8 0 0 0-8 8v112a8 8 0 0 0 8 8h69.65a16 16 0 0 1 10.14 3.63l91.47 75a8 8 0 0 0 12.74-6.46V119.83a8 8 0 0 0-12.74-6.44l-91.47 75a16 16 0 0 1-10.14 3.61z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M384 320c9.74-19.41 16-40.81 16-64c0-23.51-6-44.4-16-64" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 568 B |
1
src/assets/svgs/VolumeMediumOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M157.65 192H88a8 8 0 0 0-8 8v112a8 8 0 0 0 8 8h69.65a16 16 0 0 1 10.14 3.63l91.47 75a8 8 0 0 0 12.74-6.46V119.83a8 8 0 0 0-12.74-6.44l-91.47 75a16 16 0 0 1-10.14 3.61z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M352 320c9.74-19.41 16-40.81 16-64c0-23.51-6-44.4-16-64" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path><path d="M400 368c19.48-34 32-64 32-112s-12-77.7-32-112" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 730 B |
1
src/assets/svgs/VolumeOffOutline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512"><path d="M237.65 192H168a8 8 0 0 0-8 8v112a8 8 0 0 0 8 8h69.65a16 16 0 0 1 10.14 3.63l91.47 75a8 8 0 0 0 12.74-6.46V119.83a8 8 0 0 0-12.74-6.44l-91.47 75a16 16 0 0 1-10.14 3.61z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"></path></svg>
|
After Width: | Height: | Size: 396 B |
1
src/assets/svgs/music_random.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1634115041269" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2211" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1022.544 246.976c-0.32-1.072-0.56-2.16-0.992-3.2-0.464-1.088-1.088-2.096-1.664-3.12-0.432-0.8-0.784-1.632-1.28-2.368a33.008 33.008 0 0 0-4.016-4.912l-127.984-127.984a32 32 0 1 0-45.248 45.248L914.752 224h-160l-512 512H32a32 32 0 0 0 0 64h237.248l512-512h133.504l-73.376 73.376a32 32 0 1 0 45.248 45.248l127.984-127.984c1.488-1.488 2.832-3.136 4.016-4.912 0.496-0.752 0.848-1.584 1.28-2.368 0.56-1.024 1.184-2.032 1.664-3.12 0.416-1.04 0.672-2.128 0.992-3.2 0.272-0.928 0.624-1.808 0.832-2.768a32.368 32.368 0 0 0 0-12.528c-0.224-0.96-0.576-1.856-0.848-2.768z" p-id="2212"></path><path d="M1021.568 780.24c0.416-1.04 0.672-2.128 0.992-3.2 0.272-0.928 0.624-1.808 0.832-2.768a32.368 32.368 0 0 0 0-12.528c-0.208-0.96-0.56-1.84-0.832-2.768-0.32-1.072-0.56-2.16-0.992-3.2-0.464-1.088-1.088-2.096-1.664-3.12-0.432-0.8-0.784-1.632-1.28-2.368a33.008 33.008 0 0 0-4.016-4.912l-127.984-127.984a32 32 0 1 0-45.248 45.248L914.752 736h-133.504l-150.624-150.624a32 32 0 1 0-45.248 45.248L754.752 800h160l-73.376 73.376a32 32 0 1 0 45.248 45.248l127.984-127.984c1.488-1.488 2.832-3.136 4.016-4.912 0.496-0.752 0.848-1.584 1.28-2.368 0.56-1.024 1.184-2.032 1.664-3.12zM32 288h210.752l150.624 150.624c6.256 6.256 14.432 9.376 22.624 9.376s16.368-3.12 22.624-9.376a32 32 0 0 0 0-45.248L269.248 224H32a32 32 0 0 0 0 64z" p-id="2213"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
80
src/background.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { app, protocol, BrowserWindow } from "electron";
|
||||||
|
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
|
||||||
|
import installExtension, { VUEJS3_DEVTOOLS } from "electron-devtools-installer";
|
||||||
|
const isDevelopment = process.env.NODE_ENV !== "production";
|
||||||
|
|
||||||
|
// Scheme must be registered before the app is ready
|
||||||
|
protocol.registerSchemesAsPrivileged([
|
||||||
|
{ scheme: "app", privileges: { secure: true, standard: true } },
|
||||||
|
]);
|
||||||
|
|
||||||
|
async function createWindow() {
|
||||||
|
// Create the browser window.
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
// Use pluginOptions.nodeIntegration, leave this alone
|
||||||
|
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
|
||||||
|
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
|
||||||
|
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.WEBPACK_DEV_SERVER_URL) {
|
||||||
|
// Load the url of the dev server if in development mode
|
||||||
|
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
|
||||||
|
if (!process.env.IS_TEST) win.webContents.openDevTools();
|
||||||
|
} else {
|
||||||
|
createProtocol("app");
|
||||||
|
// Load the index.html when not in development
|
||||||
|
win.loadURL("app://./index.html");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quit when all windows are closed.
|
||||||
|
app.on("window-all-closed", () => {
|
||||||
|
// On macOS it is common for applications and their menu bar
|
||||||
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
|
if (process.platform !== "darwin") {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on("activate", () => {
|
||||||
|
// On macOS it's common to re-create a window in the app when the
|
||||||
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
// This method will be called when Electron has finished
|
||||||
|
// initialization and is ready to create browser windows.
|
||||||
|
// Some APIs can only be used after this event occurs.
|
||||||
|
app.on("ready", async () => {
|
||||||
|
if (isDevelopment && !process.env.IS_TEST) {
|
||||||
|
// Install Vue Devtools
|
||||||
|
try {
|
||||||
|
await installExtension(VUEJS3_DEVTOOLS);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Vue Devtools failed to install:", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createWindow();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Exit cleanly on request from parent process in development mode.
|
||||||
|
if (isDevelopment) {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
process.on("message", (data) => {
|
||||||
|
if (data === "graceful-exit") {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
130
src/components/HelloWorld.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<div class="hello">
|
||||||
|
<h1>{{ msg }}</h1>
|
||||||
|
<p>
|
||||||
|
For a guide and recipes on how to configure / customize this project,<br />
|
||||||
|
check out the
|
||||||
|
<a href="https://cli.vuejs.org" target="_blank" rel="noopener"
|
||||||
|
>vue-cli documentation</a
|
||||||
|
>.
|
||||||
|
</p>
|
||||||
|
<h3>Installed CLI Plugins</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>babel</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-router"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>router</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-vuex"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>vuex</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>eslint</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Essential Links</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://forum.vuejs.org" target="_blank" rel="noopener"
|
||||||
|
>Forum</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://chat.vuejs.org" target="_blank" rel="noopener"
|
||||||
|
>Community Chat</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://twitter.com/vuejs" target="_blank" rel="noopener"
|
||||||
|
>Twitter</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Ecosystem</h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://router.vuejs.org" target="_blank" rel="noopener"
|
||||||
|
>vue-router</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/vue-devtools#vue-devtools"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>vue-devtools</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener"
|
||||||
|
>vue-loader</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://github.com/vuejs/awesome-vue"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
>awesome-vue</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "HelloWorld",
|
||||||
|
props: {
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped lang="less">
|
||||||
|
h3 {
|
||||||
|
margin: 40px 0 0;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #42b983;
|
||||||
|
}
|
||||||
|
</style>
|
6
src/main.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { createApp } from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
import router from "./router";
|
||||||
|
import store from "./store";
|
||||||
|
|
||||||
|
createApp(App).use(store).use(router).mount("#app");
|
65
src/network/discover.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import {request} from './request'
|
||||||
|
|
||||||
|
// banner
|
||||||
|
// 说明 : 调用此接口 , 可获取 banner( 轮播图 ) 数据
|
||||||
|
// 可选参数 :
|
||||||
|
// type:资源类型,对应以下类型,默认为 0 即PC
|
||||||
|
// 0: pc
|
||||||
|
// 1: android
|
||||||
|
// 2: iphone
|
||||||
|
// 3: ipad
|
||||||
|
export function getBanner(type=0){
|
||||||
|
return request({
|
||||||
|
url: '/banner',
|
||||||
|
params:{
|
||||||
|
type
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推荐歌单
|
||||||
|
// 说明 : 调用此接口 , 可获取推荐歌单
|
||||||
|
// 可选参数 : limit: 取出数量 , 默认为 30 (不支持 offset)
|
||||||
|
// 接口地址 : /personalized
|
||||||
|
// 调用例子 : /personalized?limit=1
|
||||||
|
export function getPersonalized(limit=30){
|
||||||
|
return request({
|
||||||
|
url: '/personalized',
|
||||||
|
params:{
|
||||||
|
limit
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新歌速递
|
||||||
|
// 说明 : 调用此接口 , 可获取新歌速递
|
||||||
|
// 必选参数 :
|
||||||
|
// type: 地区类型 id,对应以下:
|
||||||
|
// 全部:0
|
||||||
|
// 华语:7
|
||||||
|
// 欧美:96
|
||||||
|
// 日本:8
|
||||||
|
// 韩国:16
|
||||||
|
// 接口地址 : /top/song
|
||||||
|
// 调用例子 : /top/song?type=96
|
||||||
|
export function getTopSong(){
|
||||||
|
return request({
|
||||||
|
url: '/top/song',
|
||||||
|
params:{
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推荐 mv
|
||||||
|
// 说明 : 调用此接口 , 可获取推荐 mv
|
||||||
|
// 接口地址 : /personalized/mv
|
||||||
|
// 调用例子 : /personalized/mv
|
||||||
|
export function getPersonalizedMV(){
|
||||||
|
return request({
|
||||||
|
url: '/personalized/mv',
|
||||||
|
params:{
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
11
src/network/request.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export function request(config){
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: 'http://localhost:3300',
|
||||||
|
timeout: 5000,
|
||||||
|
})
|
||||||
|
|
||||||
|
return instance(config)
|
||||||
|
|
||||||
|
}
|
33
src/network/song.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import {request} from './request'
|
||||||
|
|
||||||
|
// 获取音乐url
|
||||||
|
export function getSongUrl(id){
|
||||||
|
return request({
|
||||||
|
url: '/song/url',
|
||||||
|
params:{
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取歌曲详情
|
||||||
|
export function getSongDetial(ids,limit,offset){
|
||||||
|
return request({
|
||||||
|
url: '/song/detail',
|
||||||
|
params: {
|
||||||
|
ids,
|
||||||
|
limit,
|
||||||
|
offset
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取歌词
|
||||||
|
export function getLyric(id){
|
||||||
|
return request({
|
||||||
|
url: '/lyric',
|
||||||
|
params:{
|
||||||
|
id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
112
src/router/index.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import { createRouter, createWebHashHistory } from "vue-router";
|
||||||
|
import pubsub from 'pubsub-js'
|
||||||
|
import Home from "../views/Home.vue";
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
redirect: "/discover/recommend",
|
||||||
|
name: "index",
|
||||||
|
component: ()=> import('@/views/Home.vue'),
|
||||||
|
meta:{
|
||||||
|
title:'zmusic',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/discover",
|
||||||
|
name: "discover",
|
||||||
|
component: ()=> import('../views/discover/Discover.vue'),
|
||||||
|
children:[
|
||||||
|
{
|
||||||
|
path: "recommend",
|
||||||
|
name: "discover.recommend",
|
||||||
|
component: ()=> import('@/views/discover/Recommend.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "songlist",
|
||||||
|
name: "discover.songlist",
|
||||||
|
component: ()=> import('../views/discover/Songlist.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "anchor",
|
||||||
|
name: "discover.anchor",
|
||||||
|
component: ()=> import('../views/discover/Anchor.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "ranking",
|
||||||
|
name: "discover.ranking",
|
||||||
|
component: ()=> import('../views/discover/Ranking.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "singer",
|
||||||
|
name: "discover.singer",
|
||||||
|
component: ()=> import('../views/discover/Singer.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "latest",
|
||||||
|
name: "discover.latest",
|
||||||
|
component: ()=> import('../views/discover/Latest.vue'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/fm",
|
||||||
|
name: "fm",
|
||||||
|
component: ()=> import('../views/fm/FM.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/videos",
|
||||||
|
name: "videos",
|
||||||
|
component: ()=> import('../views/videos/Videos.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "v",
|
||||||
|
name: "videos.v",
|
||||||
|
component: ()=> import('../views/videos/V.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "mv",
|
||||||
|
name: "videos.mv",
|
||||||
|
component: ()=> import('../views/videos/MV.vue'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/friends",
|
||||||
|
name: "friends",
|
||||||
|
component: ()=> import('../views/friends/Friends.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/about",
|
||||||
|
name: "About",
|
||||||
|
// route level code-splitting
|
||||||
|
// this generates a separate chunk (about.[hash].js) for this route
|
||||||
|
// which is lazy-loaded when the route is visited.
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "about" */ "../views/About.vue"),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
//发布router.beforeEach
|
||||||
|
pubsub.publish('router.beforeEach', {to: to, frmo: from})
|
||||||
|
// to and from are both route objects. must call `next`.
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
// to and from are both route objects.
|
||||||
|
|
||||||
|
//发布router.afterEach订阅
|
||||||
|
pubsub.publish('router.afterEach', {to: to, frmo: from})
|
||||||
|
// console.log('router----',to.path)
|
||||||
|
if (to.meta.title) document.title = to.meta.title;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default router;
|
80
src/store/index.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { createStore } from "vuex";
|
||||||
|
|
||||||
|
export default createStore({
|
||||||
|
state: {
|
||||||
|
appVersion: "0.0.1",
|
||||||
|
debugStr: "测试debug字符",
|
||||||
|
settings: {
|
||||||
|
currentRoute: "/discover/recommend", //当前路由
|
||||||
|
songId: 0, //歌曲id
|
||||||
|
},
|
||||||
|
caches: {},
|
||||||
|
theme: {
|
||||||
|
//主题覆盖变量
|
||||||
|
themeOverrides: {
|
||||||
|
common: {
|
||||||
|
primaryColor: "#5C18A0FF",
|
||||||
|
primaryColorHover: "#7536ADFF",
|
||||||
|
primaryColorPressed: "#690D7EFF",
|
||||||
|
primaryColorSuppl: "#511D77FF",
|
||||||
|
textColorBase: "#1F1F1FFF",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
zmusic: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
//根据当前路由计算主菜单的选择项
|
||||||
|
mainMenuSelected: (state) => (menuOptions) => {
|
||||||
|
return menuOptions.find((item) => {
|
||||||
|
return (
|
||||||
|
state.settings.currentRoute.indexOf(item.key) > -1
|
||||||
|
);
|
||||||
|
})?.key;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
//载入settings设置
|
||||||
|
loadSettings(state) {
|
||||||
|
const l = localStorage.getItem("zmusic.settings");
|
||||||
|
if (l) state.settings = JSON.parse(l);
|
||||||
|
},
|
||||||
|
//保存settings设置
|
||||||
|
saveSettings(state, settings) {
|
||||||
|
state.settings = { ...state.settings, ...settings };
|
||||||
|
saveLoaclSettings(state.settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
//保存当前路由
|
||||||
|
saveCurrentRoute(state, currentRoute) {
|
||||||
|
state.settings.currentRoute = currentRoute;
|
||||||
|
saveLoaclSettings(state.settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
//载入theme设置
|
||||||
|
loadTheme(state) {
|
||||||
|
const l = localStorage.getItem("zmusic.theme");
|
||||||
|
if (l) state.theme = JSON.parse(l);
|
||||||
|
},
|
||||||
|
//保存theme设置
|
||||||
|
saveTheme(state, theme) {
|
||||||
|
state.theme = { ...state.theme, ...theme };
|
||||||
|
saveLoaclTheme(state.theme);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {},
|
||||||
|
modules: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
function saveLoaclSettings(s) {
|
||||||
|
localStorage.setItem(
|
||||||
|
"zmusic.settings",
|
||||||
|
JSON.stringify(s)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function saveLoaclTheme(s) {
|
||||||
|
localStorage.setItem(
|
||||||
|
"zmusic.theme",
|
||||||
|
JSON.stringify(s)
|
||||||
|
);
|
||||||
|
}
|
5
src/views/About.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<div class="about">
|
||||||
|
<h1>This is an about page</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
18
src/views/Home.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home">
|
||||||
|
<img alt="Vue logo" src="../assets/logo.png" />
|
||||||
|
<HelloWorld msg="Welcome to Your Vue.js App" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import HelloWorld from "../components/HelloWorld.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
HelloWorld,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
108
src/views/common/MainMenu.vue
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
h,
|
||||||
|
ref,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
nextTick,
|
||||||
|
} from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import {
|
||||||
|
RouterLink,
|
||||||
|
useRoute,
|
||||||
|
useRouter,
|
||||||
|
} from "vue-router";
|
||||||
|
import { NMenu, NIcon } from "naive-ui";
|
||||||
|
|
||||||
|
const menuOptions = ref([
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/recommend",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "发现" }
|
||||||
|
),
|
||||||
|
key: "/discover",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/videos/v",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "视频" }
|
||||||
|
),
|
||||||
|
key: "/videos",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/played",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "最近播放" }
|
||||||
|
),
|
||||||
|
key: "/played",
|
||||||
|
},
|
||||||
|
//#region 其他
|
||||||
|
// {
|
||||||
|
// label: () =>
|
||||||
|
// h(
|
||||||
|
// RouterLink,
|
||||||
|
// {
|
||||||
|
// to: {
|
||||||
|
// path: '/fm'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// { default: () => '私人FM' }
|
||||||
|
// ),
|
||||||
|
// key: '/fm',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// label: () =>
|
||||||
|
// h(
|
||||||
|
// RouterLink,
|
||||||
|
// {
|
||||||
|
// to: {
|
||||||
|
// path: '/friends'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// { default: () => '朋友' }
|
||||||
|
// ),
|
||||||
|
// key: '/friends',
|
||||||
|
// },
|
||||||
|
//#endregion
|
||||||
|
]);
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const {mainMenuSelected} = store.getters
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<n-menu
|
||||||
|
:options="menuOptions"
|
||||||
|
:value="
|
||||||
|
mainMenuSelected(menuOptions)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
// beforeRouteEnter(to, from, next) {
|
||||||
|
// console.log("MainMenu beforeRouteEnter", to, from);
|
||||||
|
// next();
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
34
src/views/common/Nav.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script setup>
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import { NButton, NIcon, NSpace } from "naive-ui";
|
||||||
|
import ChevronForward from '@/assets/svgs/ChevronForward.svg'
|
||||||
|
import ChevronBack from '@/assets/svgs/ChevronBack.svg'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<NSpace id="nav" justify="end">
|
||||||
|
<n-button circle size="small" @click="router.back()" >
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ChevronBack />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle size="small" @click="router.forward()">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ChevronForward />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</NSpace>
|
||||||
|
</template>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#nav {
|
||||||
|
width: 150px;
|
||||||
|
// text-align: right;
|
||||||
|
// padding-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
19
src/views/common/Search.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<script setup>
|
||||||
|
import {NInput} from 'naive-ui'
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div id="search">
|
||||||
|
<n-input size="small" round placeholder="请搜索..." />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
39
src/views/common/Settings.vue
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<script setup>
|
||||||
|
import { NButton, NIcon, NSpace } from "naive-ui";
|
||||||
|
import SettingsOutline from "@/assets/svgs/SettingsOutline.svg";
|
||||||
|
import MailOutline from "@/assets/svgs/MailOutline.svg";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<NSpace id="settings" >
|
||||||
|
<n-button circle size="small" >
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<SettingsOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle size="small" >
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<MailOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
|
||||||
|
</NSpace>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#settings{
|
||||||
|
// width: 100px;
|
||||||
|
margin: 0 15px
|
||||||
|
}
|
||||||
|
</style>
|
219
src/views/common/SongCtrl.vue
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { NButton, NIcon, NSpace } from "naive-ui";
|
||||||
|
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
|
||||||
|
import PlaySkipForward from "@/assets/svgs/PlaySkipForward.svg";
|
||||||
|
import PlaySkipBack from "@/assets/svgs/PlaySkipBack.svg";
|
||||||
|
import HeartOutline from "@/assets/svgs/HeartOutline.svg";
|
||||||
|
import TrashOutline from "@/assets/svgs/TrashOutline.svg";
|
||||||
|
import PauseCircle from "@/assets/svgs/PauseCircle.svg";
|
||||||
|
import { getSongUrl } from "@/network/song";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const { settings } = store.state;
|
||||||
|
const audioEl = ref("");
|
||||||
|
const playing = ref(false);
|
||||||
|
let currentTime = 0;
|
||||||
|
let lastPause = Date.now()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
audioEl.value.addEventListener("play", onPlay);
|
||||||
|
audioEl.value.addEventListener("pause", onPause);
|
||||||
|
audioEl.value.addEventListener("ended", onEnd);
|
||||||
|
|
||||||
|
if (settings.songId) {
|
||||||
|
pubsub.publish("zp.play", {
|
||||||
|
id: settings.songId,
|
||||||
|
im: false,
|
||||||
|
});
|
||||||
|
// play(settings.songId, false)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
console.log("另外一个Unmounted");
|
||||||
|
// audioEl.value.removeEventListener("play", onPlay);
|
||||||
|
// audioEl.value.removeEventListener("pause", onPause);
|
||||||
|
// audioEl.value.removeEventListener("ended", onEnd);
|
||||||
|
});
|
||||||
|
|
||||||
|
const onPlay = () => {
|
||||||
|
console.log("onPlay");
|
||||||
|
};
|
||||||
|
const onPause = () => {
|
||||||
|
console.log("onPause");
|
||||||
|
};
|
||||||
|
const onEnd = () => {
|
||||||
|
playing.value = false;
|
||||||
|
currentTime = 0;
|
||||||
|
console.log("onEnd");
|
||||||
|
};
|
||||||
|
|
||||||
|
const play = async (id, im = true) => {
|
||||||
|
console.log(id);
|
||||||
|
await getSongUrl(id)
|
||||||
|
.then((res) => {
|
||||||
|
audioEl.value.src = res.data.data[0].url;
|
||||||
|
store.commit("saveSettings", {
|
||||||
|
songId: id,
|
||||||
|
});
|
||||||
|
if (im) {
|
||||||
|
audioEl.value.play();
|
||||||
|
playing.value = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getSongUrl err", err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const pause = () => {
|
||||||
|
audioEl.value.pause();
|
||||||
|
playing.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const resume = async () => {
|
||||||
|
if (audioEl.value.readyState) {
|
||||||
|
//如果暂停过了5分钟,需要再次载入歌曲
|
||||||
|
// console.log(Date.now() - lastPause);
|
||||||
|
if((Date.now() - lastPause) > 1000 * 60 * 5){
|
||||||
|
console.log('暂停过了5分钟,再次载入歌曲');
|
||||||
|
await play(settings.songId, false);
|
||||||
|
audioEl.value.currentTime = currentTime;
|
||||||
|
}
|
||||||
|
audioEl.value.play();
|
||||||
|
playing.value = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setProgressScale = (scale) => {
|
||||||
|
if (audioEl.value.readyState) {
|
||||||
|
// console.log(progress);
|
||||||
|
audioEl.value.currentTime = currentTime =
|
||||||
|
scale * audioEl.value.duration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const favorite = () => {
|
||||||
|
// console.log(audioEl.value.currentTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
let interval;
|
||||||
|
watch(playing, (val, old) => {
|
||||||
|
if (val === true) {
|
||||||
|
interval = setInterval(() => {
|
||||||
|
// console.log(audioEl.value.currentTime);
|
||||||
|
currentTime = audioEl.value.currentTime;
|
||||||
|
pubsub.publish("zp.progress", {
|
||||||
|
progress: audioEl.value.currentTime,
|
||||||
|
total: audioEl.value.duration,
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
} else {
|
||||||
|
clearInterval(interval);
|
||||||
|
lastPause = Date.now();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//#region 处理消息订阅
|
||||||
|
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "zp.play":
|
||||||
|
play(data.id, data.im);
|
||||||
|
break;
|
||||||
|
case "zp.setProgressScale":
|
||||||
|
setProgressScale(data.scale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(psToken);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- <div id="songsCtrl"> -->
|
||||||
|
<audio src="" ref="audioEl"></audio>
|
||||||
|
<n-space
|
||||||
|
id="songCtrl"
|
||||||
|
align="center"
|
||||||
|
:size="[6]"
|
||||||
|
style="padding-top: 2px"
|
||||||
|
>
|
||||||
|
<n-button circle @click="favorite">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<HeartOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<PlaySkipBack />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button
|
||||||
|
v-if="!playing"
|
||||||
|
text
|
||||||
|
class="start-play"
|
||||||
|
style="font-size: 56px"
|
||||||
|
type="primary"
|
||||||
|
@click="resume"
|
||||||
|
>
|
||||||
|
<!-- <template #icon> -->
|
||||||
|
<n-icon>
|
||||||
|
<PlayCircle />
|
||||||
|
</n-icon>
|
||||||
|
<!-- </template> -->
|
||||||
|
</n-button>
|
||||||
|
<n-button
|
||||||
|
v-if="playing"
|
||||||
|
text
|
||||||
|
class="start-play"
|
||||||
|
style="font-size: 56px"
|
||||||
|
type="primary"
|
||||||
|
@click="pause"
|
||||||
|
>
|
||||||
|
<!-- <template #icon> -->
|
||||||
|
<n-icon size="56">
|
||||||
|
<PauseCircle />
|
||||||
|
</n-icon>
|
||||||
|
<!-- </template> -->
|
||||||
|
</n-button>
|
||||||
|
<!-- <n-button circle color="#18a058"> -->
|
||||||
|
<n-button circle>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<PlaySkipForward />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<TrashOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</n-space>
|
||||||
|
|
||||||
|
<!-- </div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#songCtrl {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
115
src/views/common/SongInfo.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
onUnmounted,
|
||||||
|
reactive,
|
||||||
|
toRef,
|
||||||
|
toRefs,
|
||||||
|
} from "vue";
|
||||||
|
import { NAvatar } from "naive-ui";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import { getSongDetial } from "@/network/song";
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import 'dayjs/locale/zh-cn'
|
||||||
|
import duration from 'dayjs/plugin/duration'
|
||||||
|
|
||||||
|
const showInfo = ref(true);
|
||||||
|
const info = reactive({
|
||||||
|
name: "",
|
||||||
|
artists: "",
|
||||||
|
albumPicUrl: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
//#region 取得歌曲信息
|
||||||
|
const songInfo = (id) => {
|
||||||
|
getSongDetial(id)
|
||||||
|
.then((res) => {
|
||||||
|
showInfo.value = true;
|
||||||
|
info.name = res.data.songs[0].name;
|
||||||
|
info.artists = res.data.songs[0].ar[0].name;
|
||||||
|
info.albumPicUrl = res.data.songs[0].al.picUrl;
|
||||||
|
})
|
||||||
|
.catch((err) => {});
|
||||||
|
};
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 处理消息订阅
|
||||||
|
let totalTime = ref("03:13");
|
||||||
|
let currTime = ref("00:03");
|
||||||
|
|
||||||
|
dayjs.extend(duration)
|
||||||
|
function zpTime(time) {
|
||||||
|
return dayjs.duration(time).format('mm:ss')
|
||||||
|
}
|
||||||
|
// totalTime.value = zpTime(12345)
|
||||||
|
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "zp.play":
|
||||||
|
songInfo(data.id);
|
||||||
|
break;
|
||||||
|
case "zp.progress":
|
||||||
|
totalTime.value = zpTime(data.total * 1000)
|
||||||
|
currTime.value = zpTime(data.progress * 1000)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(psToken);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="songInfo">
|
||||||
|
<NAvatar
|
||||||
|
:size="40"
|
||||||
|
v-show="showInfo"
|
||||||
|
:src="info.albumPicUrl"
|
||||||
|
></NAvatar>
|
||||||
|
<div class="song" v-show="showInfo">
|
||||||
|
<div class="w-song">
|
||||||
|
<div class="song-name">{{ info.name }}</div>
|
||||||
|
<div class="song-author">{{ info.artists }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="song-time">
|
||||||
|
<span class="played-time">{{ currTime }}</span>/<span class="total-time">{{ totalTime }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#songInfo {
|
||||||
|
flex: 3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 12px;
|
||||||
|
|
||||||
|
.song {
|
||||||
|
padding-left: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.w-song {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.song-author {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.song-time {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: Courier, monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
114
src/views/common/SongProgress.vue
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
onUnmounted,
|
||||||
|
reactive,
|
||||||
|
toRef,
|
||||||
|
toRefs,
|
||||||
|
} from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { NProgress } from "naive-ui";
|
||||||
|
import pubsub from "pubsub-js";
|
||||||
|
import { getSongDetial } from "@/network/song";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import "dayjs/locale/zh-cn";
|
||||||
|
import duration from "dayjs/plugin/duration";
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
const progress = ref("");
|
||||||
|
const wpProgress = ref("");
|
||||||
|
const setTime = (e) => {
|
||||||
|
//设定状态条长度
|
||||||
|
rightDot.value = wpProgress.value.clientWidth - e.offsetX + 'px'
|
||||||
|
percentage.value = e.offsetX / wpProgress.value.clientWidth * 100
|
||||||
|
// console.log(rightDot.value);
|
||||||
|
//发布 设置进度条消息
|
||||||
|
pubsub.publish("zp.setProgressScale", {
|
||||||
|
scale: e.offsetX / wpProgress.value.clientWidth,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// const primaryColor = store.state.theme.themeOverrides.common.primaryColor;
|
||||||
|
const rightDot = ref("px");
|
||||||
|
//#region 处理消息订阅
|
||||||
|
|
||||||
|
let percentage = ref(0.0);
|
||||||
|
const psToken = pubsub.subscribe("zp", (msg, data) => {
|
||||||
|
switch (msg) {
|
||||||
|
case "zp.progress":
|
||||||
|
percentage.value = (data.progress * 100) / data.total;
|
||||||
|
rightDot.value =
|
||||||
|
(1 - data.progress / (data.total - 0)) *
|
||||||
|
wpProgress.value.clientWidth +
|
||||||
|
"px";
|
||||||
|
// console.log(rightDot.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//卸载组件
|
||||||
|
onUnmounted(() => {
|
||||||
|
pubsub.unsubscribe(psToken);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div id="wpProgress" ref="wpProgress">
|
||||||
|
<n-progress
|
||||||
|
class="progress"
|
||||||
|
type="line"
|
||||||
|
:percentage="percentage"
|
||||||
|
:show-indicator="false"
|
||||||
|
:color="
|
||||||
|
store.state.theme.themeOverrides.common.primaryColor
|
||||||
|
"
|
||||||
|
:height="3"
|
||||||
|
:border-radius="0"
|
||||||
|
ref="progress"
|
||||||
|
@click="setTime"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="dot"
|
||||||
|
:style="{
|
||||||
|
backgroundColor:
|
||||||
|
store.state.theme.themeOverrides.common
|
||||||
|
.primaryColor,
|
||||||
|
right: rightDot,
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scope>
|
||||||
|
#wpProgress {
|
||||||
|
position: relative;
|
||||||
|
// overflow: visible;
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
position: absolute;
|
||||||
|
// background-color: red;
|
||||||
|
height: 10px;
|
||||||
|
width: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
top: -4px;
|
||||||
|
// left: -4px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.dot {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
83
src/views/common/SongStatus.vue
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { NButton, NIcon, NSpace } from "naive-ui";
|
||||||
|
import PlaylistMusic from "@/assets/svgs/PlaylistMusic.svg";
|
||||||
|
import VolumeOffOutline from "@/assets/svgs/VolumeOffOutline.svg";
|
||||||
|
import RepeatOutline from "@/assets/svgs/RepeatOutline.svg";
|
||||||
|
import RepeatOne from "@/assets/svgs/RepeatOne.svg";
|
||||||
|
import Playlist from "@/assets/svgs/Playlist.svg";
|
||||||
|
import Random from "@/assets/svgs/Random.svg";
|
||||||
|
|
||||||
|
|
||||||
|
//播放模式:0-3,顺序,循环,单曲,随机。
|
||||||
|
const playMode = ref(0)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- <div id="songsCtrl"> -->
|
||||||
|
<n-space
|
||||||
|
id="songStatus"
|
||||||
|
justify="end"
|
||||||
|
align="center"
|
||||||
|
:size="[6]"
|
||||||
|
style="padding-top: 2px; padding-right: 8px"
|
||||||
|
>
|
||||||
|
<n-button circle v-if="playMode==1">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<RepeatOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle v-if="playMode==2">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<RepeatOne />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle v-if="playMode==0">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<Playlist />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle v-if="playMode==3">
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<Random />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<PlaylistMusic />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
<n-button circle>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<VolumeOffOutline />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
</n-button>
|
||||||
|
</n-space>
|
||||||
|
|
||||||
|
<!-- </div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#songStatus {
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
</style>
|
18
src/views/common/TopMenu.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div id="topmenu">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
#topmenu{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
0
src/views/discover/Anchor.vue
Normal file
130
src/views/discover/Discover.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<script setup>
|
||||||
|
import { h, ref, onMounted, onUnmounted } from "vue";
|
||||||
|
import {
|
||||||
|
RouterLink,
|
||||||
|
useRoute,
|
||||||
|
useRouter,
|
||||||
|
onBeforeRouteUpdate,
|
||||||
|
onBeforeRouteLeave,
|
||||||
|
} from "vue-router";
|
||||||
|
|
||||||
|
import {
|
||||||
|
NButton,
|
||||||
|
NSpace,
|
||||||
|
NIcon,
|
||||||
|
NMenu,
|
||||||
|
NScrollbar,
|
||||||
|
} from "naive-ui";
|
||||||
|
|
||||||
|
const menuOptions = [
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/recommend",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "推荐" }
|
||||||
|
),
|
||||||
|
key: "/discover/recommend",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/songlist",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "歌单" }
|
||||||
|
),
|
||||||
|
key: "/discover/songlist",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/anchor",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "主播" }
|
||||||
|
),
|
||||||
|
key: "/discover/anchor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/ranking",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "排行" }
|
||||||
|
),
|
||||||
|
key: "/discover/ranking",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/singer",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "歌手" }
|
||||||
|
),
|
||||||
|
key: "/discover/singer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/discover/latest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "最新" }
|
||||||
|
),
|
||||||
|
key: "/discover/latest",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="top-menu">
|
||||||
|
<n-menu
|
||||||
|
:options="menuOptions"
|
||||||
|
mode="horizontal"
|
||||||
|
class="zm-top-menu"
|
||||||
|
:value="route.path"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="main-content">
|
||||||
|
<NScrollbar >
|
||||||
|
<div class="ld-width">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</NScrollbar>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
// beforeRouteEnter(to, from, next) {
|
||||||
|
// // console.log('Discover beforeRouteEnter', to, from);
|
||||||
|
// next();
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
</style>
|
0
src/views/discover/Latest.vue
Normal file
0
src/views/discover/Ranking.vue
Normal file
410
src/views/discover/Recommend.vue
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lmt-width">
|
||||||
|
<n-carousel
|
||||||
|
show-arrow
|
||||||
|
trigger="hover"
|
||||||
|
:autoplay="true"
|
||||||
|
style="margin: 0 auto; max-width: 800px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="wp-carousel"
|
||||||
|
v-for="(b, idx) in banners"
|
||||||
|
:key="idx"
|
||||||
|
>
|
||||||
|
<img class="carousel-img" :src="b.imageUrl" />
|
||||||
|
<span class="title">{{ b.typeTitle }}</span>
|
||||||
|
</div>
|
||||||
|
</n-carousel>
|
||||||
|
<!-- 最新音乐 -->
|
||||||
|
<div>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
icon-placement="right"
|
||||||
|
size="large"
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 1.3em; margin-top: 6px"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ChevronForward />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
最新音乐
|
||||||
|
</n-button>
|
||||||
|
<n-grid
|
||||||
|
:x-gap="18"
|
||||||
|
:y-gap="8"
|
||||||
|
:cols="2"
|
||||||
|
style="margin: 6px 0"
|
||||||
|
>
|
||||||
|
<n-grid-item
|
||||||
|
v-for="(song, idx) in topSongs"
|
||||||
|
key="idx"
|
||||||
|
>
|
||||||
|
<div class="c2-list">
|
||||||
|
<div class="play-btn">
|
||||||
|
<img :src="song.album.blurPicUrl" />
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
class="start-play-bg"
|
||||||
|
type="info"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<PlayCircle @click="play(song.id)" />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
class="start-play"
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<Play @click="play(song.id)"/>
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<div class="title">
|
||||||
|
<span class="name">
|
||||||
|
{{ song.name }}
|
||||||
|
<span class="alias">{{
|
||||||
|
songAlias(song.alias)
|
||||||
|
}}</span>
|
||||||
|
</span>
|
||||||
|
<span class="artist">{{
|
||||||
|
songArtists(song.artists)
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<span class="icon"></span>
|
||||||
|
</div>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</div>
|
||||||
|
<!-- 推荐MV -->
|
||||||
|
<div>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
icon-placement="right"
|
||||||
|
size="large"
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 1.3em; margin-top: 6px"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ChevronForward />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
推荐MV
|
||||||
|
</n-button>
|
||||||
|
<!-- 列表 -->
|
||||||
|
<n-grid
|
||||||
|
:x-gap="18"
|
||||||
|
:y-gap="8"
|
||||||
|
:cols="4"
|
||||||
|
style="margin: 6px 0"
|
||||||
|
>
|
||||||
|
<n-grid-item
|
||||||
|
v-for="(mv, idx) in personalizedMV"
|
||||||
|
key="idx"
|
||||||
|
>
|
||||||
|
<div class="mv-c2-list">
|
||||||
|
<div class="play-mv">
|
||||||
|
<div>
|
||||||
|
<img :src="mv.picUrl" />
|
||||||
|
</div>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
class="start-play-bg"
|
||||||
|
type="info"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<PlayCircle />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
class="start-play"
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
<n-icon>
|
||||||
|
<Play />
|
||||||
|
</n-icon>
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<div class="title">
|
||||||
|
<span class="name">
|
||||||
|
{{ mv.name }}
|
||||||
|
</span>
|
||||||
|
<span class="artist">{{
|
||||||
|
mv.artistName
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</div>
|
||||||
|
<!-- 推荐歌单 -->
|
||||||
|
<div>
|
||||||
|
<n-button
|
||||||
|
text
|
||||||
|
icon-placement="right"
|
||||||
|
size="large"
|
||||||
|
type="primary"
|
||||||
|
style="font-size: 1.3em; margin-top: 6px"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<n-icon>
|
||||||
|
<ChevronForward />
|
||||||
|
</n-icon>
|
||||||
|
</template>
|
||||||
|
推荐歌单
|
||||||
|
</n-button>
|
||||||
|
<n-grid
|
||||||
|
:x-gap="18"
|
||||||
|
:y-gap="8"
|
||||||
|
:cols="4"
|
||||||
|
style="margin: 6px 0"
|
||||||
|
>
|
||||||
|
<n-grid-item v-for="p in personalized">
|
||||||
|
<n-card
|
||||||
|
title
|
||||||
|
hoverable
|
||||||
|
content-style="padding: 2px 6px;"
|
||||||
|
>
|
||||||
|
<template #cover>
|
||||||
|
<img :src="p.picUrl" />
|
||||||
|
</template>
|
||||||
|
<span class="card-span">{{ p.name }}</span>
|
||||||
|
</n-card>
|
||||||
|
</n-grid-item>
|
||||||
|
</n-grid>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import {
|
||||||
|
NCarousel,
|
||||||
|
NScrollbar,
|
||||||
|
NGrid,
|
||||||
|
NGridItem,
|
||||||
|
NCard,
|
||||||
|
NButton,
|
||||||
|
NIcon,
|
||||||
|
NImage,
|
||||||
|
} from "naive-ui";
|
||||||
|
// import {
|
||||||
|
// ChevronForward,
|
||||||
|
// PlayCircle,
|
||||||
|
// Play,
|
||||||
|
// } from "@vicons/ionicons5";
|
||||||
|
import PlayCircle from "@/assets/svgs/PlayCircle.svg";
|
||||||
|
import Play from "@/assets/svgs/Play_.svg";
|
||||||
|
import ChevronForward from "@/assets/svgs/ChevronForward.svg";
|
||||||
|
import {
|
||||||
|
getBanner,
|
||||||
|
getPersonalized,
|
||||||
|
getTopSong,
|
||||||
|
getPersonalizedMV,
|
||||||
|
} from "@/network/discover";
|
||||||
|
import pubsub from 'pubsub-js'
|
||||||
|
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const play=(id)=>{
|
||||||
|
pubsub.publish('zp.play', {id, im: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region 初始载入数据
|
||||||
|
//轮播图片
|
||||||
|
let banners = ref([]);
|
||||||
|
getBanner(0)
|
||||||
|
.then((res) => {
|
||||||
|
banners.value = res.data.banners;
|
||||||
|
// console.log(banners.value);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getBanner err", err);
|
||||||
|
});
|
||||||
|
//最新音乐
|
||||||
|
let topSongs = ref([]);
|
||||||
|
getTopSong()
|
||||||
|
.then((res) => {
|
||||||
|
topSongs.value = res.data.data.filter((item, index) => {
|
||||||
|
return index < 10;
|
||||||
|
});
|
||||||
|
// console.log(topSongs.value);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getTopSong err", err);
|
||||||
|
});
|
||||||
|
function songAlias(alias) {
|
||||||
|
if (alias.length > 0) return "[" + alias.join(",") + "]";
|
||||||
|
}
|
||||||
|
function songArtists(artists) {
|
||||||
|
if (artists.length > 0) {
|
||||||
|
return artists
|
||||||
|
.map((a) => {
|
||||||
|
return a.name;
|
||||||
|
})
|
||||||
|
.join(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//推荐歌单
|
||||||
|
let personalized = ref([]);
|
||||||
|
getPersonalized(8)
|
||||||
|
.then((res) => {
|
||||||
|
personalized.value = res.data.result;
|
||||||
|
// console.log(personalized.value);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getPersonalized err", err);
|
||||||
|
});
|
||||||
|
//推荐MV
|
||||||
|
let personalizedMV = ref([]);
|
||||||
|
getPersonalizedMV()
|
||||||
|
.then((res) => {
|
||||||
|
personalizedMV.value = res.data.result;
|
||||||
|
// console.log(personalized.value);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log("getPersonalizedMV err", err);
|
||||||
|
});
|
||||||
|
//#endregion
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import "@/assets/css/common.less";
|
||||||
|
.wp-carousel {
|
||||||
|
position: relative;
|
||||||
|
// width: 20em;
|
||||||
|
// font-size: 1vw;
|
||||||
|
.carousel-img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #5c18a0ff;
|
||||||
|
bottom: 0px;
|
||||||
|
right: 0;
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
border-bottom-right-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-span {
|
||||||
|
.text-el-line2();
|
||||||
|
}
|
||||||
|
|
||||||
|
.mv-c2-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
.play-mv {
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
border-top-left-radius: 6px;
|
||||||
|
border-top-right-radius: 6px;
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-play-bg{
|
||||||
|
font-size: 38px;
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 42px;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
.start-play{
|
||||||
|
font-size: 25px;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover{
|
||||||
|
button{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding: 3px;
|
||||||
|
.name {
|
||||||
|
.text-el-line();
|
||||||
|
.alias {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.artist {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c2-list {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 60px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-play-bg{
|
||||||
|
font-size: 30px;
|
||||||
|
position: absolute;
|
||||||
|
left: 16px;
|
||||||
|
top: 17px;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-play{
|
||||||
|
font-size: 16px;
|
||||||
|
position: absolute;
|
||||||
|
left: 24px;
|
||||||
|
top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
padding-left: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
.text-el-line();
|
||||||
|
.alias {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.artist {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
.text-el-line();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// .icon {
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
</style>
|
0
src/views/discover/Singer.vue
Normal file
0
src/views/discover/Songlist.vue
Normal file
13
src/views/fm/FM.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
FM
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
13
src/views/friends/Friends.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<template>
|
||||||
|
朋友
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
0
src/views/videos/MV.vue
Normal file
0
src/views/videos/V.vue
Normal file
57
src/views/videos/Videos.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<script setup>
|
||||||
|
import { h } from "vue";
|
||||||
|
import { RouterLink, useRoute } from "vue-router";
|
||||||
|
import { NButton, NSpace, NIcon, NMenu } from "naive-ui";
|
||||||
|
|
||||||
|
const menuOptions = [
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/videos/v",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "视频" }
|
||||||
|
),
|
||||||
|
key: "/videos/v",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
path: "/videos/mv",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => "MV" }
|
||||||
|
),
|
||||||
|
key: "/videos/mv",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="top-menu">
|
||||||
|
<n-menu
|
||||||
|
:options="menuOptions"
|
||||||
|
mode="horizontal"
|
||||||
|
class="zm-top-menu"
|
||||||
|
:value="route.path"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<router-view />
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
21
src_bak/App.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<script setup>
|
||||||
|
// This starter template is using Vue 3 <script setup> SFCs
|
||||||
|
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
|
||||||
|
import HelloWorld from './components/HelloWorld.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<img alt="Vue logo" src="./assets/logo.png" />
|
||||||
|
<HelloWorld msg="Hello Vue 3 + Vite" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-align: center;
|
||||||
|
color: #2c3e50;
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
</style>
|
BIN
src_bak/assets/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
40
src_bak/components/HelloWorld.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
msg: String
|
||||||
|
})
|
||||||
|
|
||||||
|
const count = ref(0)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h1>{{ msg }}</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Recommended IDE setup:
|
||||||
|
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
|
||||||
|
+
|
||||||
|
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="https://vitejs.dev/guide/features.html" target="_blank">
|
||||||
|
Vite Documentation
|
||||||
|
</a>
|
||||||
|
|
|
||||||
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Documentation</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button type="button" @click="count++">count is: {{ count }}</button>
|
||||||
|
<p>
|
||||||
|
Edit
|
||||||
|
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
a {
|
||||||
|
color: #42b983;
|
||||||
|
}
|
||||||
|
</style>
|
4
src_bak/main.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
createApp(App).mount('#app')
|
23
vite.config.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import path from 'path'
|
||||||
|
import svgLoader from 'vite-svg-loader'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
resolve:{
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, '/src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
base: process.env.ELECTRON=="true" ? './' : "",
|
||||||
|
plugins: [vue(), svgLoader()],
|
||||||
|
// server:{
|
||||||
|
// fs:{
|
||||||
|
// strict: false,
|
||||||
|
// allow:[
|
||||||
|
// '.'
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
})
|