初始化

This commit is contained in:
ZilongYang 2021-10-13 20:59:12 +08:00
commit 56a79617f0
73 changed files with 13328 additions and 0 deletions

24
.gitignore vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

180
src/App.vue Normal file
View 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
View 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;
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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();
});
}
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>

View 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
View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@ -0,0 +1,18 @@
<template>
<div id="topmenu">
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
#topmenu{
flex: 1;
}
</style>

View File

View 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>

View File

View File

View 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>

View File

View File

13
src/views/fm/FM.vue Normal file
View File

@ -0,0 +1,13 @@
<template>
FM
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@ -0,0 +1,13 @@
<template>
朋友
</template>
<script>
export default {
}
</script>
<style>
</style>

0
src/views/videos/MV.vue Normal file
View File

0
src/views/videos/V.vue Normal file
View File

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View 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
View File

@ -0,0 +1,4 @@
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

23
vite.config.js Normal file
View 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:[
// '.'
// ]
// }
// }
})

10858
yarn.lock Normal file

File diff suppressed because it is too large Load Diff