提交 cd69c556 authored 作者: 蔡芬's avatar 蔡芬

Merge branch 'process'

VUE_APP_IS_WEB=true
IS_WEB=true
\ No newline at end of file
{ {
"name": "feidao", "name": "feidao",
"version": "0.1.2", "version": "0.1.8",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve --mode web",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"build:web": "vue-cli-service build --mode web",
"test:unit": "vue-cli-service test:unit", "test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e", "test:e2e": "vue-cli-service test:e2e",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
"axios": "^0.24.0", "axios": "^0.24.0",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"element-ui": "^2.15.6", "element-ui": "^2.15.6",
"js-cookie": "^3.0.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-i18n": "^8.26.7", "vue-i18n": "^8.26.7",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
...@@ -48,6 +50,7 @@ ...@@ -48,6 +50,7 @@
"less-loader": "^5.0.0", "less-loader": "^5.0.0",
"prettier": "^2.2.1", "prettier": "^2.2.1",
"spectron": "15.0.0", "spectron": "15.0.0",
"terser-webpack-plugin": "4",
"vue-cli-plugin-electron-builder": "~2.1.1", "vue-cli-plugin-electron-builder": "~2.1.1",
"vue-template-compiler": "^2.6.11" "vue-template-compiler": "^2.6.11"
} }
......
<template>
<div id="app" ref="appcontainer" :style="style">
<!-- <div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div> -->
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
style: { height: 'auto' }
};
},
mounted() {
this.style.height = document.documentElement.clientHeight + 'px';
window.onresize = () => {
this.style.height = document.documentElement.clientHeight + 'px';
};
}
}
</script>
<style>
@import './assets/css/normalize.css'; /*引入样式*/
</style>
<style lang="less">
#app {
}
@import './assets/css/common.less'; /*引入公共样式*/
</style>
@import './mixin.less';
@import './transition.less';
@import './sidebar.less';
ul { ul {
list-style:none; list-style:none;
margin: 0; margin: 0;
......
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
@mixin scrollBar {
&::-webkit-scrollbar-track-piece {
background: #d3dce6;
}
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
background: #99a9bf;
border-radius: 20px;
}
}
@mixin relative {
position: relative;
width: 100%;
height: 100%;
}
#app {
// 主体区域
.main-container {
min-height: 100%;
transition: margin-left .28s;
margin-left: 180px;
}
// 侧边栏
.sidebar-container {
.horizontal-collapse-transition {
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
}
transition: width .28s;
width: 180px !important;
height: 100%;
position: fixed;
font-size: 0px;
top: 0;
bottom: 0;
left: 0;
z-index: 1001;
overflow: hidden;
a {
display: inline-block;
width: 100%;
}
.svg-icon {
margin-right: 16px;
}
.el-menu {
border: none;
width: 100% !important;
}
}
.hideSidebar {
.sidebar-container {
// width: 36px !important;
width: 0 !important;
}
.main-container {
// margin-left: 36px;
margin-left: 0;
}
.submenu-title-noDropdown {
padding-left: 10px !important;
position: relative;
.el-tooltip {
padding: 0 10px !important;
}
}
.el-submenu {
&>.el-submenu__title {
padding-left: 10px !important;
&>span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
.el-submenu__icon-arrow {
display: none;
}
}
}
}
.sidebar-container .nest-menu .el-submenu>.el-submenu__title,
.sidebar-container .el-submenu .el-menu-item {
min-width: 180px !important;
background-color: #1f2d3d !important;
&:hover {
background-color: #001528 !important;
}
}
.el-menu--collapse .el-menu .el-submenu {
min-width: 180px !important;
}
//适配移动端
// .mobile {
// .main-container {
// margin-left: 0px;
// }
// .sidebar-container {
// top: 50px;
// transition: transform .28s;
// width: 180px !important;
// }
// &.hideSidebar {
// .sidebar-container {
// transition-duration: 0.3s;
// transform: translate3d(-180px, 0, 0);
// }
// }
// }
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
}
}
}
//globl transition css
/*fade*/
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.28s;
}
.fade-enter,
.fade-leave-active {
opacity: 0;
}
/*fade*/
.breadcrumb-enter-active,
.breadcrumb-leave-active {
transition: all .5s;
}
.breadcrumb-enter,
.breadcrumb-leave-active {
opacity: 0;
transform: translateX(20px);
}
.breadcrumb-move {
transition: all .5s;
}
.breadcrumb-leave-active {
position: absolute;
}
import Vue from 'vue'; import Vue from 'vue';
import Config from '../config.js'; import Config from '../config.js';
import {post,get,patch,put,del} from './index'; import {post,get,patch,put,del} from '../utils/request';
Vue.prototype.$post=post; Vue.prototype.$post=post;
Vue.prototype.$get=get; Vue.prototype.$get=get;
Vue.prototype.$patch=patch; Vue.prototype.$patch=patch;
......
import * as request from '@/libs/utils/request'
export function login(username, password) {
return request.post({
url: '/user/login',
data: {
username,
password
}
})
}
export function getInfo(token) {
return request.get({
url: '/user/info',
params: { token }
})
}
export function logout() {
return request.post({
url: '/user/logout'
})
}
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
...@@ -2,7 +2,7 @@ import * as Vue from 'vue' ...@@ -2,7 +2,7 @@ import * as Vue from 'vue'
import axios from 'axios'; import axios from 'axios';
import Config from '../config.js'; import Config from '../config.js';
import { Message } from 'element-ui';// 我用的mint的框架来弹出我的错误返回 大家可以用别的提示 import { Message } from 'element-ui';
// import router from '../router' // import router from '../router'
// Message('这是一条消息提示'); // Message('这是一条消息提示');
...@@ -83,7 +83,7 @@ axios.interceptors.response.use( ...@@ -83,7 +83,7 @@ axios.interceptors.response.use(
* @param params * @param params
* @returns {Promise} * @returns {Promise}
*/ */
export function get(url,params={}){ export function get({url,params={}}){
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
axios.get(url,{ axios.get(url,{
params:params params:params
...@@ -114,7 +114,7 @@ axios.interceptors.response.use( ...@@ -114,7 +114,7 @@ axios.interceptors.response.use(
* @param data * @param data
* @returns {Promise} * @returns {Promise}
*/ */
export function post(url,data = {}){ export function post({url,data = {}}){
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
axios.post(url,data) axios.post(url,data)
.then(response => { .then(response => {
...@@ -140,7 +140,7 @@ export function post(url,data = {}){ ...@@ -140,7 +140,7 @@ export function post(url,data = {}){
* @param data * @param data
* @returns {Promise} * @returns {Promise}
*/ */
export function patch(url,data = {}){ export function patch({url,data = {}}){
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
axios.patch(url,data) axios.patch(url,data)
.then(response => { .then(response => {
...@@ -165,7 +165,7 @@ export function patch(url,data = {}){ ...@@ -165,7 +165,7 @@ export function patch(url,data = {}){
* @param data * @param data
* @returns {Promise} * @returns {Promise}
*/ */
export function put(url,data = {}){ export function put({url,data = {}}){
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
axios.put(url,data) axios.put(url,data)
.then(response => { .then(response => {
...@@ -184,7 +184,7 @@ export function put(url,data = {}){ ...@@ -184,7 +184,7 @@ export function put(url,data = {}){
}) })
} }
export function del(url,data = {}){ export function del({url,data = {}}){
return new Promise((resolve,reject) => { return new Promise((resolve,reject) => {
axios.delete(url,data) axios.delete(url,data)
.then(response => { .then(response => {
......
import { app } from 'electron'
class AppEvents {
create (appManager) {
this.appManager = appManager
this.windowManager = appManager.windowManager
app.on('activate', () => {
if (this.windowManager.mainWindow.win === null) {
console.log('Main window is null!')
}
})
/* 在Electron加载前需要进行初始化
Before electron app is ready, we should initial */
app.on('ready', async () => {
appManager.initApp()
})
/* app退出之前执行
Do something before we quit */
app.on('before-quit', () => {
// appManager.tray.destroy()
})
// 所有窗口都被关闭
app.on('window-all-closed', () => {
this.windowManager.mainWindow.win = null
if (process.platform === 'darwin') {
return
}
app.quit();
// 设置app托盘菜单 / Set the app tray
// appManager.tray.setToolTip('窗口被关闭了!\nWindow is closed!')
// appManager.tray.displayBalloon({
// title: '嗨~',
// content: '我在这里哦,并没有退出',
// noSound: true
// })
})
// Quit when all windows are closed.
// app.on("window-all-closed", () => {
// this.windowManager.mainWindow.win = null
// // 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();
// }
// });
}
}
export default new AppEvents()
import { ipcMain, dialog } from 'electron'
class IpcEvents {
create (appManager) {
this.appManager = appManager
/* 翻译器函数
Translator function */
// const $t = appManager.translator.get()
// ipc通信示例 / ipc demo
ipcMain.on('showDialog', (sys, msg) => {
dialog.showMessageBox({
type: 'info',
title: '收到消息!',
// 在任何能调用翻译器函数的地方都能使用多语言
// Multi-language support where translator functions are available
// message: $t('reciveFromRenderer'),
message: 'reciveFromRenderer',
detail: msg
})
})
// 语言变更事件 / language change event
ipcMain.on('appLanguageChange', (sys, lang) => {
this.appManager.languageChange(lang)
})
}
}
export default new IpcEvents()
/* 主进程入口文件
Main process entry file */
/* 保存此文件时electron将会重启
Electron will restart when saving this file */
/* AppManager负责管理整个app
AppManager is responsible for managing the entire app */
import AppManager from './managers/app'
import { protocol } from 'electron'
//热加载
try {
require('electron-reloader')(module);
} catch {}
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
const app = new AppManager()
/* 可通过electron remote从渲染进程(vue)获取到appManager
You can access appManager with electron remote from renderer process (vue) */
global.appManager = app
export default app
/* eslint-disable no-undef */
import path from 'path'
import { Tray, nativeImage } from 'electron'
import EventManager from './event'
import WindowManager from './window'
import MenuManager from './menu'
// import Translator from '../plugins/translator'
class AppManager {
constructor () {
// this.translator = new Translator()
this.windowManager = new WindowManager(this)
this.menuManager = new MenuManager(this)
this.eventManager = new EventManager(this)
}
/* 初始化app,创建窗口及托盘
Initialize the app, create windows and tray */
initApp () {
this.windowManager.createAllWindows()
// this.createAppTray()
}
languageChange (lang) {
// this.translator.changeLang(lang)
/* 重新设置托盘菜单(变更语言)
Reset the language of the tray menu to change language of the tray */
// this.setAppTrayMenu()
}
/* Create app tray
创建托盘 */
createAppTray () {
// try {
// const iconPath = path.join(__static, 'app.ico')
// const trayIcon = nativeImage.createFromPath(iconPath)
// this.tray = new Tray(trayIcon)
// this.setAppTrayMenu()
// } catch (err) {
// console.error('Failed to create app tray, error:', err)
// }
}
/* Create tray menu
创建托盘菜单 */
setAppTrayMenu () {
// const menu = this.menuManager.AppTrayMenu()
// this.tray.setToolTip('运行中!Still Working!')
// this.tray.setContextMenu(menu)
}
}
export default AppManager
import app from '../events/app'
import ipc from '../events/ipc'
class EventManager {
constructor (appManager) {
this.appManager = appManager
this.createEvents()
}
createEvents () {
/* Create electron ipc and app events
创建app、ipc事件 */
app.create(this.appManager)
ipc.create(this.appManager)
}
}
export default EventManager
import { app, Menu, dialog } from 'electron'
class MenuManager {
constructor (appManager) {
this.appManager = appManager
this.windowManager = appManager.windowManager
// this.translator = appManager.translator
}
AppTrayMenu () {
// const $t = this.translator.get()
// // Menu template
// const template = [
// {
// key: '1',
// label: $t('trayMenu.reset'), // 支持多国语言 / support multi-languauge
// click: () => {
// if (!this.windowManager.mainWindow.win) {
// this.windowManager.mainWindow.createWindow()
// }
// /* 执行electron窗口对象方法
// Execute electron window method */
// this.windowManager.mainWindow.win.restore() //将窗口从最小化状态恢复到以前的状态
// this.windowManager.mainWindow.win.moveTop() //无论焦点如何, 将窗口移至顶端(z轴上的顺序).
// }
// },
// {
// key: '2',
// label: $t('trayMenu.openLink'),
// click: () => {
// const { shell } = require('electron')
// shell.openExternal('https://www.electronjs.org/docs')
// }
// },
// {
// key: '3',
// label: $t('trayMenu.openDialog'),
// click: () => {
// dialog.showMessageBox({
// type: 'info',
// title: $t('trayMenu.dialog.title'),
// message: $t('trayMenu.dialog.message'),
// detail: $t('trayMenu.dialog.detail')
// })
// }
// },
// {
// key: '4',
// label: $t('trayMenu.exit'),
// click: () => {
// app.exit()
// }
// }
// ]
// return Menu.buildFromTemplate(template)
}
}
export default MenuManager
import MainWindow from '../windows/mainWindow'
class WindowManager {
constructor () {
this.mainWindow = new MainWindow()
}
/* Create all windows
创建所有窗口 */
createAllWindows () {
this.mainWindow.createWindow()
}
}
export default WindowManager
// import i18n from '../../plugins/i18n'
class Translator {
constructor (locale, messages, fallbackLocale) {
// this.locale = locale || i18n.locale
// this.messages = messages || i18n.messages
// this.fallbackLocale = fallbackLocale || i18n.fallbackLocale
}
/* Change language
改变翻译器语言 */
changeLang (locale) {
// this.locale = locale
}
/* 获取翻译函数(为了保持this正确指向)
Get the translation function (to keep this pointed to correctly) */
get () {
return i => {
// return this.$t(i)
return 1
}
}
/* 翻译函数
Translation function */
$t (original) {
// function $query (trans) {
// for (let i = 0; i < textList.length; i++) {
// const key = textList[i]
// if (typeof trans === 'object') trans = trans[key]
// }
// return trans || original
// }
// const textList = original.split('.')
// let re = $query(this.messages[this.locale])
// if (re === original) re = $query(this.messages[this.fallbackLocale])
// return re
return 1
}
}
export default Translator
import { BrowserWindow, Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
class MainWindow {
constructor (win) {
/* win代表electron窗口实例
win is this electron window instance */
this.win = win
}
initBrowserPage () {
// Dev or not
if (process.env.WEBPACK_DEV_SERVER_URL) {
this.win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
/* 开发环境下自启动开发者工具
start developer tools in the development environment */
this.win.webContents.openDevTools({ mode: 'detach' })
} else {
createProtocol('app')
this.win.loadURL('app://./index.html')
}
this.win.on('closed', () => {
this.win = null
console.log('windows closed')
})
}
createWindow () {
if (this.win) {
console.warn('window is already exists!')
return
}
const win = new BrowserWindow({
width: 1100,
height: 770,
minWidth: 1100,
minHeight: 770,
webPreferences: {
/* 注意,这些设置有关程序的安全性,请谨慎使用!
Note: these settings are related to the security of the program, please use it with caution! */
enableRemoteModule: true, // Electron 10.x起需要主动启用才可在渲染进程中使用remote / Electron 10.x and above need to be actively enabled in order to use remote in the rendering process
webSecurity: false, // 设为false允许跨域 / Set to false to allow cross-domain requests
nodeIntegration: true, // 允许渲染进程使用node.js / node integration, allow renderer process use node.js!
contextIsolation: false, //nodeIntegration: true 和 contextIsolation: false 才可以 require() 使用
},
// eslint-disable-next-line no-undef
icon: `${__static}/app.ico`,
frame: false
})
this.win = win
this.initBrowserPage()
// this.setWindowMenu()
}
setWindowMenu () {
if (process.platform === 'darwin') {
const template = [
{
label: 'vue-cli-electron-template',
submenu: [
{
role: 'about'
},
{
role: 'quit'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
return
}
Menu.setApplicationMenu(null)
}
}
export default MainWindow
// Electron window global Bus
const { clipboard } = require('electron')
const install = (Vue, options) => {
const Bus = new Vue({
data () {
return {
process,
clipboard, // electron clipboard object
vueSet: Vue.set,
dialog: undefined, // electron dialog
win: undefined, // this electron window
router: options.router,
status: {
isFocus: false,
isBlur: false,
keyPress: {}
}
}
},
created () {
this.init()
this.events()
},
methods: {
init () {
this.win = this.$electron.remote.getCurrentWindow()
this.dialog = this.$electron.remote.dialog
},
events () {
this.win.on('blur', () => {
this.status.isBlur = true
this.status.isFocus = false
this.keyPress = {}
})
this.win.on('focus', () => {
this.status.isFocus = true
this.status.isBlur = false
})
},
getAppManager () {
return this.$electron.remote.getGlobal('appManager')
},
appGetPath (pathName = 'desktop') {
return this.$electron.remote.app.getPath(pathName)
},
// router
changePage (item) {
this.router.push({
name: item.name
})
},
// ---
emit (event, ...args) {
this.$emit(event, ...args)
},
on (event, callback) {
this.$on(event, callback)
},
off (event, callback) {
this.$off(event, callback)
}
}
})
Vue.prototype.$bus = Bus
}
export default install
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
/* 读取语言文件夹下所有的翻译文件及内容
Read all translation files and content in the language folder */
function loadLocaleMessages () {
const locales = require.context('../locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key)
}
})
return messages
}
export default new VueI18n({
locale: 'zh',
fallbackLocale: 'en',
/* 可以在vue页面中使用 console.log(this.$i18n.messages) 看到读取到的翻译内容
You can use console.log (this.$i18n.messages) in the vue page to see the translations read */
messages: loadLocaleMessages()
})
<template>
<div id="app" ref="appcontainer" :style="style" >
<div id="app-bar" v-if="!is_web">
<div id="app-title">
飞稻设计平台
</div>
<div id="app-action">
<div
class="app-action-button"
@click="win.minimize()"
>
<!-- <svg-icon icon-class="app-hidden" /> -->
<span>hide</span>
</div>
<div
class="app-action-button"
@click="autoMaximize()"
>
<!-- <svg-icon icon-class="app-fullsize" /> -->
<span>fullscreen</span>
</div>
<div
class="app-action-button button-red"
@click="win.close()"
>
<!-- <svg-icon icon-class="app-exit" /> -->
<span>exit</span>
</div>
</div>
</div>
<router-view></router-view>
</div>
</template>
<script>
const isWeb = process.env.VUE_APP_IS_WEB;
const { remote } = !isWeb ? window.require('electron') : {};
import { mapState } from 'vuex';
export default {
data() {
return {
style: { height: 'auto' },
win: remote && remote.getCurrentWindow() || null,
originSize: true,
// is_web:isWeb,
};
},
computed: {
...mapState({
isLoading: state => state.app.loading,
}),
is_web() {
return process.env.VUE_APP_IS_WEB;
}
},
mounted() {
console.log(process,process.env.VUE_APP_IS_WEB,isWeb,this.is_web, this.$router)
this.style.height = document.documentElement.clientHeight + 'px';
window.onresize = () => {
this.style.height = document.documentElement.clientHeight + 'px';
};
},
methods: {
autoMaximize () {
if (this.originSize) this.win.maximize()
else this.win.restore()
this.originSize = !this.originSize
}
},
}
</script>
<style>
@import '../assets/css/normalize.css'; /*引入样式*/
</style>
<style lang="less">
@import '../assets/css/common.less'; /*引入公共样式*/
#app-bar {
background-color: #e7eaed;
color: #57646c;
display: flex;
align-items: center;
justify-content: space-between;
// 如果你想让某区域可以拖动,将其设为drag
// 但是设为drag的区域无法被点击,请注意
// 可以设置为no-drag来恢复点击
// If you want to make a region draggable, set it to drag
// But the area set as drag cannot be clicked, please note
// can be set to no-drag to resume clicks
-webkit-app-region: drag;
height: 40px;
}
#app-action {
padding: 0;
font-size: 16px;
display: flex;
-webkit-app-region: no-drag;
text-align: center;
}
.app-action-button {
padding: 0 8px;
transition: .2s ease;
opacity: 0.7;
line-height: 40px;
}
.app-action-button:hover {
background-color: #cfd2d5;
opacity: 1;
}
</style>
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path" v-if="item.meta.title">
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{item.meta.title}}</span>
<router-link v-else :to="item.redirect||item.path">{{item.meta.title}}</router-link>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
export default {
created() {
this.getBreadcrumb()
},
data() {
return {
levelList: null
}
},
watch: {
$route() {
this.getBreadcrumb()
}
},
methods: {
getBreadcrumb() {
let matched = this.$route.matched.filter(item => item.name)
const first = matched[0]
// if (first && first.name !== 'dashboard') {
// matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
// }
this.levelList = matched
}
}
}
</script>
<style lang="less" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 10px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>
<template>
<div>
<svg t="1492500959545" @click="toggleClick" class="hamburger" :class="{'is-active':isActive}" style="" viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64">
<path d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
p-id="1692"></path>
<path d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
p-id="1693"></path>
<path d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
p-id="1694"></path>
</svg>
</div>
</template>
<script>
export default {
name: 'hamburger',
props: {
isActive: {
type: Boolean,
default: false
},
toggleClick: {
type: Function,
default: null
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
cursor: pointer;
width: 20px;
height: 20px;
transform: rotate(90deg);
transition: .38s;
transform-origin: 50% 50%;
}
.hamburger.is-active {
transform: rotate(0deg);
}
</style>
<template>
<div class="scroll-container" ref="scrollContainer" @wheel.prevent="handleScroll" >
<div class="scroll-wrapper" ref="scrollWrapper" :style="{top: top + 'px'}">
<slot></slot>
</div>
</div>
</template>
<script>
const delta = 15
export default {
name: 'scrollBar',
data() {
return {
top: 0
}
},
methods: {
handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 3
const $container = this.$refs.scrollContainer
const $containerHeight = $container.offsetHeight
const $wrapper = this.$refs.scrollWrapper
const $wrapperHeight = $wrapper.offsetHeight
if (eventDelta > 0) {
this.top = Math.min(0, this.top + eventDelta)
} else {
if ($containerHeight - delta < $wrapperHeight) {
if (this.top < -($wrapperHeight - $containerHeight + delta)) {
this.top = this.top
} else {
this.top = Math.max(this.top + eventDelta, $containerHeight - $wrapperHeight - delta)
}
} else {
this.top = 0
}
}
}
}
}
</script>
<style lang="less" scoped>
.scroll-container {
position: relative;
width: 100%;
height: 100%;
background-color: #304156;
.scroll-wrapper {
position: absolute;
width: 100%!important;
}
}
</style>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</template> </template>
<script> <script>
import tophead from '@/components/scaffold/tophead.vue'; import tophead from '@/renderer/components/scaffold/tophead.vue';
export default { export default {
name: "recursion", name: "recursion",
props: { props: {
......
<template> <template>
<div> <div>
<!-- <img id="logo" src="~@/assets/logo.png" alt="electron-vue"> -->
<button @click="$router.go(-1)">返回</button> <button @click="$router.go(-1)">返回</button>
<div> <div>
是否显示弹窗{{$t('lang.home')}} {{showPop}} 是否显示弹窗{{$t('lang.home')}} {{showPop}}
...@@ -53,13 +54,13 @@ ...@@ -53,13 +54,13 @@
<script> <script>
import { mapState, mapMutations } from 'vuex'; import { mapState, mapMutations } from 'vuex';
import TopHead from '@/components/scaffold/tophead.vue'; import TopHead from '@/renderer/components/scaffold/tophead.vue';
import TopBody from '@/components/scaffold/tobody.vue'; import TopBody from '@/renderer/components/scaffold/tobody.vue';
import SimpleInput from '@/components/common/simpleInput.vue'; import SimpleInput from '@/renderer/components/common/simpleInput.vue';
import RichEditor from '@/components/common/richEditor.vue'; import RichEditor from '@/renderer/components/common/richEditor.vue';
import NumberInput from '@/components/common/numberInput.vue'; import NumberInput from '@/renderer/components/common/numberInput.vue';
import SelectField from '@/components/common/selectField.vue'; import SelectField from '@/renderer/components/common/selectField.vue';
import ImageUpload from '@/components/common/imageUpload.vue'; import ImageUpload from '@/renderer/components/common/imageUpload.vue';
// const { ipcRenderer } = window.require('electron'); //浏览器端报错 // const { ipcRenderer } = window.require('electron'); //浏览器端报错
export default { export default {
props: { props: {
......
...@@ -3,13 +3,12 @@ import App from "./App.vue"; ...@@ -3,13 +3,12 @@ import App from "./App.vue";
import router from "./router"; import router from "./router";
import store from "./store"; import store from "./store";
import VueI18n from 'vue-i18n'; import VueI18n from 'vue-i18n';
import VueElectron from './vue_electron.js';
import { Button, Drawer, Message, MessageBox, Row, Col, Form, import { Button, Drawer, Message, MessageBox, Row, Col, Form,
FormItem, Input, Menu, MenuItem, Submenu, Dropdown, DropdownItem, DropdownMenu, Select, Option, Tabs, TabPane, Tree, Upload, Dialog } from 'element-ui'; FormItem, Input, Menu, MenuItem, Submenu, Dropdown, DropdownItem, DropdownMenu, Select, Option, Tabs, TabPane, Tree, Upload, Dialog, Breadcrumb, BreadcrumbItem,Loading } from 'element-ui';
Vue.config.productionTip = false; Vue.config.productionTip = false;
if(window.require) Vue.use(VueElectron); if(!process.env.VUE_APP_IS_WEB) Vue.use(require('./vue_electron.js'));
Vue.use(VueI18n); Vue.use(VueI18n);
...@@ -33,8 +32,12 @@ Vue.use(TabPane); ...@@ -33,8 +32,12 @@ Vue.use(TabPane);
Vue.use(Tree); Vue.use(Tree);
Vue.use(Upload); Vue.use(Upload);
Vue.use(Dialog); Vue.use(Dialog);
Vue.use(Breadcrumb);
Vue.use(BreadcrumbItem);
Vue.use(Loading.directive);
Vue.prototype.$loading = Loading.service;
Vue.prototype.$confirm = MessageBox.confirm; Vue.prototype.$confirm = MessageBox.confirm;
Vue.prototype.$message = Message; Vue.prototype.$message = Message;
......
...@@ -5,6 +5,7 @@ import routes from './routes'; ...@@ -5,6 +5,7 @@ import routes from './routes';
Vue.use(VueRouter); Vue.use(VueRouter);
const router = new VueRouter({ const router = new VueRouter({
// scrollBehavior: () => ({ y: 0 }),
routes, routes,
}); });
......
import Login from "../views/Account/Login.vue";
import Layout from '../views/layout/Layout'
/**
* hidden: true if `hidden:true` will not show in the sidebar(default is false)
* alwaysShow: true if set true, will always show the root menu, whatever its child routes length
* if not set alwaysShow, only more than one route under the children
* it will becomes nested mode, otherwise not show the root menu
* redirect: noredirect if `redirect:noredirect` will no redirct in the breadcrumb
* name:'router-name' the name is used by <keep-alive> (must set!!!)
* meta : {
title: 'title' the name show in submenu and breadcrumb (recommend set)
icon: 'svg-name' the icon show in the sidebar,
}
**/
export default [
{ path: '/404', component: () => import('../views/404.vue'), hidden: true },
{
path: "/",
name: "Home",
component: Layout,
redirect: '/home',
hidden: false,
children: [{
path: 'home',
name: "Home",
meta: { title: 'Home', icon: 'example' },
component: () => import('../views/Home.vue')
}]
},
{
path: "/login",
name: "Login",
component: Login,
hidden: false,
meta: { title: 'Login', icon: 'example' },
// beforeEnter: (to, from, next) => { //路由独享的守卫
// next();
// }
},
{
path: "/course",
name: "Course",
component: Layout,
redirect: '/course/create',
meta: { title: 'Course', icon: 'example' },
hidden: false,
children: [{
path: 'list',
name: "list",
meta: { title: 'list', icon: 'example' },
component: () => import('../views/Course/index.vue')
},{
path: ':type',
name: "编辑",
meta: { title: '编辑', icon: 'example' },
component: () => import('../views/Course/create.vue')
}]
},
// {
// path: "/course/:type",
// name: "CourseCreate",
// component: () =>
// import(/* webpackChunkName: "about" */ "../views/Course/create.vue"),
// },
{ path: '*', redirect: '/404', hidden: true }
]
\ No newline at end of file
import Vue from "vue"; import Vue from "vue";
import Vuex from "vuex"; import Vuex from "vuex";
import modules from './modules';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -19,5 +20,5 @@ export default new Vuex.Store({ ...@@ -19,5 +20,5 @@ export default new Vuex.Store({
}, },
}, },
actions: {}, actions: {},
modules: {}, modules
}); });
import Cookies from 'js-cookie'
const app = {
state: {
sidebar: {
opened: !+Cookies.get('sidebarStatus'),
withoutAnimation: false
},
device: 'desktop',
loading: false,
},
mutations: {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
state.sidebar.opened = !state.sidebar.opened
},
CLOSE_SIDEBAR: (state, withoutAnimation) => {
Cookies.set('sidebarStatus', 1)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
},
toggle_refresh: (state, status) => {
state.loading = status
}
},
actions: {
ToggleSideBar: ({ commit }) => {
commit('TOGGLE_SIDEBAR')
},
CloseSideBar({ commit }, { withoutAnimation }) {
commit('CLOSE_SIDEBAR', withoutAnimation)
},
ToggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
}
}
}
export default app
/**
* The file enables `@/store/index.js` to import all vuex modules
* in a one-shot manner. There should not be any reason to edit this file.
*/
const files = require.context('.', false, /\.js$/);
const modules = {};
files.keys().forEach((key) => {
if (key === './index.js') return;
modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default;
});
export default modules;
\ No newline at end of file
import { login, logout, getInfo } from '@/libs/api/login'
import { getToken, setToken, removeToken } from '@/libs/utils/auth'
const user = {
state: {
token: getToken(),
name: '',
avatar: '',
roles: []
},
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
}
},
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
return new Promise((resolve, reject) => {
login(username, userInfo.password).then(response => {
const data = response.data
setToken(data.token)
commit('SET_TOKEN', data.token)
resolve()
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo(state.token).then(response => {
const data = response.data
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', data.roles)
} else {
reject('getInfo: roles must be a non-null array !')
}
commit('SET_NAME', data.name)
commit('SET_AVATAR', data.avatar)
resolve(response)
}).catch(error => {
reject(error)
})
})
},
// 登出
LogOut({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
removeToken()
resolve()
}).catch(error => {
reject(error)
})
})
},
// 前端 登出
FedLogOut({ commit }) {
return new Promise(resolve => {
removeToken()
commit('SET_TOKEN', '')
resolve()
})
}
}
}
export default user
<template>
<div style="background:#f0f2f5;margin-top: -20px;">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" :src="img_404" alt="404">
<img class="pic-404__child left" :src="img_404_cloud" alt="404">
<img class="pic-404__child mid" :src="img_404_cloud" alt="404">
<img class="pic-404__child right" :src="img_404_cloud" alt="404">
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">版权所有<a class="link-type" href="https://wallstreetcn.com" target='_blank'>华尔街见闻</a></div>
<div class="bullshit__headline">{{ message }}</div>
<div class="bullshit__info">请检查您输入的网址是否正确,请点击以下按钮返回主页或者发送错误报告</div>
<a href="/" class="bullshit__return-home">返回首页</a>
</div>
</div>
</div>
</template>
<script>
import img_404 from '@/assets/404_images/404.png'
import img_404_cloud from '@/assets/404_images/404_cloud.png'
export default {
data() {
return {
img_404,
img_404_cloud
}
},
computed: {
message() {
return '特朗普说这个页面你不能进......'
}
}
}
</script>
<style lang="less" scoped>
.wscn-http404 {
position: relative;
width: 1200px;
margin: 20px auto 60px;
padding: 0 100px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
padding: 150px 0;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 150px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #1482f0;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</template> </template>
<script> <script>
import { loginApi } from '@/libs/request/api.js'; // import { loginApi } from '@/libs/request/api.js';
export default { export default {
data() { data() {
var validateUserName = (rule, value, callback) => { var validateUserName = (rule, value, callback) => {
......
...@@ -59,8 +59,8 @@ ...@@ -59,8 +59,8 @@
</template> </template>
<script> <script>
import FullPage from '@/components/scaffold/fullpage.vue'; import FullPage from '@/renderer/components/scaffold/fullpage.vue';
import recursion from '@/components/common/recursion.vue'; import recursion from '@/renderer/components/common/recursion.vue';
import listJson from '@/demo.json'; //测试数据 import listJson from '@/demo.json'; //测试数据
let id = 1000; let id = 1000;
export default { export default {
......
...@@ -77,9 +77,9 @@ ...@@ -77,9 +77,9 @@
<script> <script>
// @ is an alias to /src // @ is an alias to /src
import { loginApi } from "@/libs/request/api.js"; // import { loginApi } from "@/libs/request/api.js";
import LiItem from "@/components/Home/li-item.vue"; import LiItem from "@/renderer/components/Home/li-item.vue";
import ToolItem from "@/components/Home/tool-item.vue"; import ToolItem from "@/renderer/components/Home/tool-item.vue";
export default { export default {
name: "Home", name: "Home",
......
<template>
<div class="app-wrapper" :class="classObj">
<sidebar class="sidebar-container" :style="siderbarStyle"></sidebar>
<div class="main-container">
<navbar></navbar>
<app-main></app-main>
</div>
</div>
</template>
<script>
import { Navbar, Sidebar, AppMain } from './components'
import ResizeMixin from './mixin/ResizeHandler'
export default {
name: 'layout',
components: {
Navbar,
Sidebar,
AppMain
},
mixins: [ResizeMixin],
computed: {
sidebar() {
return this.$store.state.app.sidebar
},
device() {
return this.$store.state.app.device
},
siderbarStyle() {
return {
top: process.env.VUE_APP_IS_WEB == 'true' ? 0 : '40px'
}
},
classObj() {
return {
hideSidebar: !this.sidebar.opened,
withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile'
}
}
}
}
</script>
<style lang="less" scoped>
@import "../../../assets/css/mixin.less";
.app-wrapper {
// @include clearfix;
position: relative;
height: 100%;
width: 100%;
}
</style>
<template>
<section class="app-main">
<transition name="fade" mode="out-in">
<!-- <router-view :key="key"></router-view> -->
<router-view></router-view>
</transition>
</section>
</template>
<script>
export default {
name: 'AppMain',
computed: {
// key() {
// return this.$route.name !== undefined ? this.$route.name + +new Date() : this.$route + +new Date()
// }
}
}
</script>
<template>
<el-menu class="navbar" mode="horizontal">
<hamburger class="hamburger-container" :toggleClick="toggleSideBar" :isActive="sidebar.opened"></hamburger>
<breadcrumb></breadcrumb>
<el-dropdown class="avatar-container" trigger="click">
<div class="avatar-wrapper">
<img class="user-avatar" :src="avatar+'?imageView2/1/w/80/h/80'">
<i class="el-icon-caret-bottom"></i>
</div>
<el-dropdown-menu class="user-dropdown" slot="dropdown">
<router-link class="inlineBlock" to="/">
<el-dropdown-item>
Home
</el-dropdown-item>
</router-link>
<el-dropdown-item divided>
<span @click="logout" style="display:block;">LogOut</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-menu>
</template>
<script>
import { mapState } from 'vuex'
import Breadcrumb from '@/renderer/components/Breadcrumb'
import Hamburger from '@/renderer/components/Hamburger'
export default {
components: {
Breadcrumb,
Hamburger
},
computed: {
...mapState({
sidebar: state => state.app.sidebar,
avatar: state => state.user.avatar,
}),
},
methods: {
toggleSideBar() {
this.$store.dispatch('ToggleSideBar')
},
logout() {
this.$store.dispatch('LogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
}
}
}
</script>
<style lang="less" scoped>
.navbar {
height: 50px;
line-height: 50px;
border-radius: 0px !important;
.hamburger-container {
line-height: 58px;
height: 50px;
float: left;
padding: 0 10px;
}
.screenfull {
position: absolute;
right: 90px;
top: 16px;
color: red;
}
.avatar-container {
height: 50px;
display: inline-block;
position: absolute;
right: 35px;
.avatar-wrapper {
cursor: pointer;
margin-top: 5px;
position: relative;
.user-avatar {
width: 40px;
height: 40px;
border-radius: 10px;
}
.el-icon-caret-bottom {
position: absolute;
right: -20px;
top: 25px;
font-size: 12px;
}
}
}
}
</style>
<template>
<div class="menu-wrapper">
<template v-for="item in routes" v-if="!item.hidden&&item.children">
<router-link v-if="hasOneShowingChildren(item.children) && !item.children[0].children&&!item.alwaysShow" :to="item.path+'/'+item.children[0].path"
:key="item.children[0].name">
<el-menu-item :index="item.path+'/'+item.children[0].path" :class="{'submenu-title-noDropdown':!isNest}">
<!-- <svg-icon v-if="item.children[0].meta&&item.children[0].meta.icon" :icon-class="item.children[0].meta.icon"></svg-icon> -->
<span v-if="item.children[0].meta&&item.children[0].meta.title" slot="title">{{item.children[0].meta.title}}</span>
</el-menu-item>
</router-link>
<el-submenu v-else :index="item.name||item.path" :key="item.name">
<template slot="title">
<!-- <svg-icon v-if="item.meta&&item.meta.icon" :icon-class="item.meta.icon"></svg-icon> -->
<span v-if="item.meta&&item.meta.title" slot="title">{{item.meta.title}}</span>
</template>
<template v-for="child in item.children" v-if="!child.hidden">
<sidebar-item :is-nest="true" class="nest-menu" v-if="child.children&&child.children.length>0" :routes="[child]" :key="child.path"></sidebar-item>
<router-link v-else :to="item.path+'/'+child.path" :key="child.name">
<el-menu-item :index="item.path+'/'+child.path">
<!-- <svg-icon v-if="child.meta&&child.meta.icon" :icon-class="child.meta.icon"></svg-icon> -->
<span v-if="child.meta&&child.meta.title" slot="title">{{child.meta.title}}</span>
</el-menu-item>
</router-link>
</template>
</el-submenu>
</template>
</div>
</template>
<script>
export default {
name: 'SidebarItem',
props: {
routes: {
type: Array
},
isNest: {
type: Boolean,
default: false
}
},
methods: {
hasOneShowingChildren(children) {
const showingChildren = children.filter(item => {
return !item.hidden
})
if (showingChildren.length === 1) {
return true
}
return false
}
}
}
</script>
<template>
<scroll-bar>
<el-menu
mode="vertical"
:show-timeout="200"
:default-active="$route.path"
:collapse="isCollapse"
background-color="#304156"
text-color="#bfcbd9"
active-text-color="#409EFF"
>
<sidebar-item :routes="routes"></sidebar-item>
</el-menu>
</scroll-bar>
</template>
<script>
import { mapGetters, mapState } from 'vuex'
import SidebarItem from './SidebarItem'
import ScrollBar from '@/renderer/components/ScrollBar'
export default {
components: { SidebarItem, ScrollBar },
computed: {
...mapState({
sidebar: state => state.app.sidebar,
}),
routes() {
return this.$router.options.routes
},
isCollapse() {
return !this.sidebar.opened
}
}
}
</script>
export { default as Navbar } from './Navbar'
export { default as Sidebar } from './Sidebar'
export { default as AppMain } from './AppMain'
import store from '@/renderer/store'
const { body } = document
const WIDTH = 1024
const RATIO = 3
export default {
watch: {
$route(route) {
if (this.device === 'mobile' && this.sidebar.opened) {
store.dispatch('CloseSideBar', { withoutAnimation: false })
}
}
},
beforeMount() {
window.addEventListener('resize', this.resizeHandler)
},
mounted() {
const isMobile = this.isMobile()
if (isMobile) {
store.dispatch('ToggleDevice', 'mobile')
store.dispatch('CloseSideBar', { withoutAnimation: true })
}
},
methods: {
isMobile() {
const rect = body.getBoundingClientRect()
return rect.width - RATIO < WIDTH
},
resizeHandler() {
if (!document.hidden) {
const isMobile = this.isMobile()
store.dispatch('ToggleDevice', isMobile ? 'mobile' : 'desktop')
if (isMobile) {
store.dispatch('CloseSideBar', { withoutAnimation: true })
}
}
}
}
}
const electron = window.require ? window.require('electron') : {}; const electron = window.require('electron');
module.exports = { module.exports = {
install: function(Vue) { install: function(Vue) {
......
import Home from "../views/Home.vue";
import Login from "../views/Account/Login.vue";
export default [
{
path: "/",
name: "Home",
component: Home,
},
{
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"),
},
{
path: "/login",
name: "Login",
component: Login,
// beforeEnter: (to, from, next) => { //路由独享的守卫
// next();
// }
},
{
path: "/course",
name: "Course",
component: () =>
import(/* webpackChunkName: "about" */ "../views/Course/index.vue"),
},
{
path: "/course/:type",
name: "CourseCreate",
component: () =>
import(/* webpackChunkName: "about" */ "../views/Course/create.vue"),
},
]
\ No newline at end of file
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
import { expect } from "chai"; import { expect } from "chai";
import { shallowMount } from "@vue/test-utils"; import { shallowMount } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue"; import HelloWorld from "@/renderer/components/HelloWorld.vue";
describe("HelloWorld.vue", () => { describe("HelloWorld.vue", () => {
it("renders props.msg when passed", () => { it("renders props.msg when passed", () => {
......
const TerserPlugin = require("terser-webpack-plugin");
module.exports = { module.exports = {
lintOnSave: false, lintOnSave: false,
publicPath: process.env.IS_WEB ? './' : '/',
configureWebpack: { configureWebpack: {
devtool: 'source-map' devtool: 'source-map',
// optimization: {
// minimize: true,
// minimizer: [
// new TerserPlugin({ // 要引用 TerserPlugin
// terserOptions: {
// ecma: undefined,
// warnings: false,
// parse: {},
// compress: {
// drop_console: true,
// drop_debugger: false,
// pure_funcs: ['console.log'] // 移除console
// }
// },
// }),
// ],
// }
},
pages: {
app: {
title: 'FeiDao',
entry: 'src/renderer/main.js',
template: 'public/index.html',
filename: 'index.html'
}
}, },
pluginOptions: { pluginOptions: {
electronBuilder: { electronBuilder: {
preload: 'src/preload.js', preload: 'src/preload.js',
// mainProcessFile: 'src/background.js', mainProcessFile: 'src/main/index.js',
// mainProcessWatch: ['src/main'],
// rendererProcessFile: 'src/main.js', // rendererProcessFile: 'src/main.js',
builderOptions: { builderOptions: {
"productName": 'FeiDao Creation', "productName": 'FeiDao Creation',
"appId": "com.example.yourapp",
// build配置在此处 // build配置在此处
// options placed here will be merged with default configuration and passed to electron-builder // options placed here will be merged with default configuration and passed to electron-builder
// "publish": [ // "publish": [
...@@ -19,6 +48,7 @@ module.exports = { ...@@ -19,6 +48,7 @@ module.exports = {
// } // }
// ], // ],
"win": { "win": {
// icon: './public/app.ico',
"target": [ "target": [
"nsis", "nsis",
"zip" "zip"
...@@ -28,8 +58,10 @@ module.exports = { ...@@ -28,8 +58,10 @@ module.exports = {
"oneClick": false, "oneClick": false,
"allowToChangeInstallationDirectory": true, "allowToChangeInstallationDirectory": true,
"perMachine": true "perMachine": true
},
mac: {
// icon: './public/app.png'
} }
} }
}, },
} }
......
...@@ -1237,7 +1237,7 @@ ...@@ -1237,7 +1237,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/json-schema@^7.0.5": "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8":
version "7.0.9" version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
...@@ -1998,7 +1998,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: ...@@ -1998,7 +1998,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.3, ajv@^6.12.4: ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
version "6.12.6" version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
...@@ -6969,7 +6969,7 @@ javascript-stringify@^2.0.1: ...@@ -6969,7 +6969,7 @@ javascript-stringify@^2.0.1:
resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79" resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-2.1.0.tgz#27c76539be14d8bd128219a2d731b09337904e79"
integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg== integrity sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==
jest-worker@^26.2.1: jest-worker@^26.2.1, jest-worker@^26.5.0:
version "26.6.2" version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
...@@ -6988,6 +6988,11 @@ js-beautify@^1.6.12: ...@@ -6988,6 +6988,11 @@ js-beautify@^1.6.12:
glob "^7.1.3" glob "^7.1.3"
nopt "^5.0.0" nopt "^5.0.0"
js-cookie@^3.0.1:
version "3.0.1"
resolved "https://registry.nlark.com/js-cookie/download/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
integrity sha1-njm0xsL1ZWNwjX0x9vXyGHOpJBQ=
js-message@1.0.7: js-message@1.0.7:
version "1.0.7" version "1.0.7"
resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47" resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47"
...@@ -9998,6 +10003,15 @@ schema-utils@^2.0.0, schema-utils@^2.5.0, schema-utils@^2.6.5, schema-utils@^2.6 ...@@ -9998,6 +10003,15 @@ schema-utils@^2.0.0, schema-utils@^2.5.0, schema-utils@^2.6.5, schema-utils@^2.6
ajv "^6.12.4" ajv "^6.12.4"
ajv-keywords "^3.5.2" ajv-keywords "^3.5.2"
schema-utils@^3.0.0:
version "3.1.1"
resolved "https://registry.npmmirror.com/schema-utils/download/schema-utils-3.1.1.tgz?cache=0&sync_timestamp=1637075928327&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fschema-utils%2Fdownload%2Fschema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
integrity sha1-vHTEtraZXB2I92qLd76nIZ4MgoE=
dependencies:
"@types/json-schema" "^7.0.8"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
select-hose@^2.0.0: select-hose@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
...@@ -10084,6 +10098,13 @@ serialize-javascript@^4.0.0: ...@@ -10084,6 +10098,13 @@ serialize-javascript@^4.0.0:
dependencies: dependencies:
randombytes "^2.1.0" randombytes "^2.1.0"
serialize-javascript@^5.0.1:
version "5.0.1"
resolved "https://registry.nlark.com/serialize-javascript/download/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
integrity sha1-eIbshIBJpGJGepfT2Rjrsqr5NPQ=
dependencies:
randombytes "^2.1.0"
serve-index@^1.9.1: serve-index@^1.9.1:
version "1.9.1" version "1.9.1"
resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
...@@ -10333,6 +10354,14 @@ source-map-support@^0.5.13, source-map-support@^0.5.19, source-map-support@~0.5. ...@@ -10333,6 +10354,14 @@ source-map-support@^0.5.13, source-map-support@^0.5.19, source-map-support@~0.5.
buffer-from "^1.0.0" buffer-from "^1.0.0"
source-map "^0.6.0" source-map "^0.6.0"
source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.npmmirror.com/source-map-support/download/source-map-support-0.5.21.tgz?cache=0&sync_timestamp=1637320298732&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0: source-map-url@^0.4.0:
version "0.4.1" version "0.4.1"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
...@@ -10348,7 +10377,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: ...@@ -10348,7 +10377,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.7.3: source-map@^0.7.3, source-map@~0.7.2:
version "0.7.3" version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
...@@ -10806,6 +10835,21 @@ temp-file@^3.4.0: ...@@ -10806,6 +10835,21 @@ temp-file@^3.4.0:
async-exit-hook "^2.0.1" async-exit-hook "^2.0.1"
fs-extra "^10.0.0" fs-extra "^10.0.0"
terser-webpack-plugin@4:
version "4.2.3"
resolved "https://registry.npmmirror.com/terser-webpack-plugin/download/terser-webpack-plugin-4.2.3.tgz?cache=0&sync_timestamp=1636385968704&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fterser-webpack-plugin%2Fdownload%2Fterser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a"
integrity sha1-KNrvSoO9F8HbApcHCtwH/Iz8apo=
dependencies:
cacache "^15.0.5"
find-cache-dir "^3.3.1"
jest-worker "^26.5.0"
p-limit "^3.0.2"
schema-utils "^3.0.0"
serialize-javascript "^5.0.1"
source-map "^0.6.1"
terser "^5.3.4"
webpack-sources "^1.4.3"
terser-webpack-plugin@^1.4.3, terser-webpack-plugin@^1.4.4: terser-webpack-plugin@^1.4.3, terser-webpack-plugin@^1.4.4:
version "1.4.5" version "1.4.5"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b"
...@@ -10845,6 +10889,15 @@ terser@^4.1.2, terser@^4.8.0: ...@@ -10845,6 +10889,15 @@ terser@^4.1.2, terser@^4.8.0:
source-map "~0.6.1" source-map "~0.6.1"
source-map-support "~0.5.12" source-map-support "~0.5.12"
terser@^5.3.4:
version "5.10.0"
resolved "https://registry.npmmirror.com/terser/download/terser-5.10.0.tgz?cache=0&sync_timestamp=1636988229781&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fterser%2Fdownload%2Fterser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc"
integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.20"
text-table@^0.2.0: text-table@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论