新增electron相关页面

This commit is contained in:
wanglin2 2023-03-06 20:59:00 +08:00
parent 6bc309e3fa
commit c8a3c569e1
15 changed files with 1596 additions and 14 deletions

26
web/main.js Normal file
View File

@ -0,0 +1,26 @@
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 1200,
height: 800,
frame: false,
titleBarStyle: 'hiddenInset'
})
win.loadURL('http://192.168.3.125:8080/#/workbenche')
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// win.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

1046
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
"name": "thoughts",
"version": "0.1.0",
"private": true,
"main": "main.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build && node ../copy.js",
@ -9,13 +10,15 @@
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/full.js --dest ../simple-mind-map/dist",
"format": "prettier --write src/* src/*/* src/*/*/* src/*/*/*/*",
"buildDoc": "node ./scripts/buildDoc.js",
"autoBuildDoc": "node ./scripts/autoBuildDoc.js"
"autoBuildDoc": "node ./scripts/autoBuildDoc.js",
"start": "electron ."
},
"dependencies": {
"@toast-ui/editor": "^3.1.5",
"core-js": "^3.6.5",
"element-ui": "^2.15.1",
"highlight.js": "^10.7.3",
"uuid": "^3.4.0",
"v-viewer": "^1.6.4",
"vue": "^2.6.11",
"vue-i18n": "^8.27.2",
@ -29,6 +32,7 @@
"@vue/cli-service": "^4.5.0",
"babel-eslint": "^10.1.0",
"chokidar": "^3.5.3",
"electron": "^23.1.1",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^3.12.2",

BIN
web/src/.DS_Store vendored

Binary file not shown.

3
web/src/css/global.css Normal file
View File

@ -0,0 +1,3 @@
.noDrag {
-webkit-app-region: no-drag;
}

View File

@ -8,6 +8,7 @@ import '@/assets/icon-font/iconfont.css'
import 'viewerjs/dist/viewer.css'
import VueViewer from 'v-viewer'
import i18n from './i18n'
import './css/global.css'
Vue.config.productionTip = false
Vue.prototype.$bus = new Vue()

View File

@ -0,0 +1,35 @@
<template>
<div class="workbencheContainer">
<Header></Header>
<div class="workbencheContent">
<router-view></router-view>
</div>
</div>
</template>
<script>
import Header from './components/Header.vue';
export default {
name: 'Workbenche',
components: {
Header
}
}
</script>
<style lang="less" scoped>
.workbencheContainer {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.workbencheContent {
flex-grow: 1;
}
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<div class="workbencheHeaderContainer">
<div class="placeholder"></div>
<div class="home noDrag" :class="{active: isInHome}">
<span class="icon iconfont iconzhuye"></span>
<span class="text">主页</span>
</div>
<ScrollTab></ScrollTab>
</div>
</template>
<script>
import ScrollTab from './ScrollTab.vue'
export default {
components: {
ScrollTab
},
computed: {
isInHome() {
return this.$route.path.includes('home')
}
}
}
</script>
<style lang="less" scoped>
.workbencheHeaderContainer {
width: 100%;
height: 40px;
background-color: #ebeef1;
-webkit-app-region: drag;
display: flex;
align-items: center;
flex-shrink: 0;
.placeholder {
width: 100px;
height: 100%;
flex-shrink: 0;
}
.home {
padding: 0 10px;
height: 100%;
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
background-color: #e3e6e9;
flex-shrink: 0;
font-size: 14px;
&.active {
background-color: #fff;
}
.icon {
margin-right: 5px;
}
}
}
</style>

View File

@ -0,0 +1,227 @@
<template>
<div class="workbencheScrollTabContainer" ref="container">
<div class="workbencheScrollTabBox noDrag">
<div class="workbencheScrollTabList" ref="list" :style="{ transform: `translateX(${listTranslateX}px)` }">
<div class="workbencheScrollTabItem" v-for="(item, index) in localEditList" :key="item.id"
:style="{ width: tabWidth + 'px' }" :class="{ active: $route.params.id === item.id }"
@click="openTab(item)">
<span class="icon iconfont icondiannao"></span>
<span class="text">{{ item.name }}</span>
<span class="mask"></span>
<span class="icon closeIcon el-icon-close" @click="deleteFile(index)"></span>
</div>
</div>
</div>
<div class="workbencheScrollTabControl noDrag" ref="control">
<div class="workbencheScrollTabBtn el-icon-plus" @click="addFile"></div>
<div class="workbencheScrollTabBtn el-icon-arrow-left" @click="scrollLeft"></div>
<div class="workbencheScrollTabBtn el-icon-arrow-right" @click="scrollRight"></div>
</div>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import { v4 as uuidv4 } from 'uuid';
const MIN_TAB_WIDTH = 100
const MAX_TAB_WIDTH = 220
export default {
data() {
return {
tabWidth: 0,
tabTotalWidth: 0,
listTranslateX: 0
}
},
computed: {
...mapState(['localEditList']),
},
mounted() {
this.computeTabWidth()
},
methods: {
...mapMutations(['setLocalEditList']),
addFile() {
let item = {
id: uuidv4(),
name: '新建文件',
path: ''
}
this.setLocalEditList([...this.localEditList, item])
this.$nextTick(() => {
this.openTab(item)
this.computeTabWidth()
this.scrollToEnd()
})
},
deleteFile(index) {
let arr = [...this.localEditList]
arr.splice(index, 1)
this.setLocalEditList(arr)
this.$nextTick(() => {
this.computeTabWidth()
})
},
computeTabWidth() {
let containerWidth = this.$refs.container.getBoundingClientRect().width
let controlWidth = this.$refs.control.getBoundingClientRect().width
this.tabTotalWidth = containerWidth - controlWidth
let length = this.localEditList.length
let tabWidth = Math.floor(this.tabTotalWidth / length)
if (tabWidth >= MAX_TAB_WIDTH) {
this.tabWidth = MAX_TAB_WIDTH
} else if (tabWidth <= MIN_TAB_WIDTH) {
this.tabWidth = MIN_TAB_WIDTH
} else {
this.tabWidth = tabWidth
}
},
scrollLeft() {
if (this.listTranslateX + this.tabWidth < 0) {
this.listTranslateX += this.tabWidth
} else {
this.listTranslateX = 0
}
},
scrollRight() {
let maxScroll = this.tabTotalWidth - this.localEditList.length * this.tabWidth
if (this.listTranslateX - this.tabWidth > maxScroll) {
this.listTranslateX -= this.tabWidth
} else {
this.listTranslateX = maxScroll
}
},
scrollToEnd() {
if (this.localEditList.length * this.tabWidth <= this.tabTotalWidth) {
return
}
this.listTranslateX = this.tabTotalWidth - this.localEditList.length * this.tabWidth
},
openTab(item) {
this.$router.push({
name: 'WorkbencheEdit',
params: {
id: item.id
}
})
}
}
}
</script>
<style lang="less" scoped>
.workbencheScrollTabContainer {
flex-grow: 1;
height: 100%;
display: flex;
align-items: center;
overflow: hidden;
.workbencheScrollTabBox {
overflow: hidden;
height: 100%;
.workbencheScrollTabList {
display: flex;
width: max-content;
height: 100%;
transition: all 0.3s;
.workbencheScrollTabItem {
flex-shrink: 0;
height: 100%;
font-size: 12px;
padding: 0 10px;
position: relative;
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
.icon {
&.closeIcon {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: none;
}
}
.mask {
position: absolute;
right: 0;
top: 0;
width: 20px;
height: 100%;
background-color: #fff;
box-shadow: -10px 0 10px #fff;
display: none;
}
&:hover {
background-color: #fff;
.mask {
display: block;
}
.closeIcon {
display: block;
}
}
&::after {
content: '';
position: absolute;
width: 1px;
height: 10px;
background-color: #999;
top: 50%;
transform: translateY(-50%);
right: 0;
}
&.active {
background-color: #fff;
&::after {
display: none;
}
}
.text {}
}
}
}
.workbencheScrollTabControl {
flex-shrink: 0;
padding: 0 10px;
height: 100%;
display: flex;
.workbencheScrollTabBtn {
width: 20px;
height: 100%;
cursor: pointer;
font-size: 14px;
color: #000;
margin: 0 5px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<div class="workbencheHomeSidebarContainer">
<div class="workbencheMenuList">
<div class="workbencheMenuItem" v-for="item in menuList" :key="item.name"
:class="{ active: $route.name === item.routerName }" @click="toMenu(item.rou
)">
<span class="icon iconfont" :class="[item.icon]"></span>
<span class="text">{{ item.name }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
menuList: [
{
name: '本地',
icon: 'iconbendi1x',
routerName: 'WorkbencheHomeLocal'
}
]
}
},
methods: {
toMenu(routerName) {
this.$router.push(routerName)
}
}
}
</script>
<style lang="less" scoped>
.workbencheHomeSidebarContainer {
width: 80px;
background-color: #fff;
height: 100%;
flex-shrink: 0;
padding: 20px 0;
.workbencheMenuList {
display: flex;
flex-direction: column;
align-items: center;
.workbencheMenuItem {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #000;
width: 60px;
height: 60px;
border-radius: 5px;
cursor: pointer;
&.active {
background-color: #f3fbf4;
color: #56b74b;
}
.icon {
margin-bottom: 5px;
}
.text {
font-size: 14px;
}
}
}
}
</style>

View File

@ -0,0 +1,21 @@
<template>
<div class="workbencheHeaderContainer">
<Edit :key="$route.params.id"></Edit>
</div>
</template>
<script>
import Edit from '../../Edit/Index.vue';
export default {
components: {
Edit
}
}
</script>
<style lang="less" scoped>
.workbencheHeaderContainer {
}
</style>

View File

@ -0,0 +1,32 @@
<template>
<div class="workbencheHomeContainer">
<Sidebar></Sidebar>
<div class="workbencheHomeContent">
<router-view></router-view>
</div>
</div>
</template>
<script>
import Sidebar from '../components/Sidebar.vue'
export default {
components: {
Sidebar
}
}
</script>
<style lang="less" scoped>
.workbencheHomeContainer {
background-color: #f6f8f9;
width: 100%;
height: 100%;
display: flex;
.workbencheHomeContent {
flex-grow: 1;
padding: 20px;
}
}
</style>

View File

@ -0,0 +1,20 @@
<template>
<div class="workbencheLocalContainer">
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
.workbencheLocalContainer {
width: 100%;
height: 100%;
border-radius: 5px;
background-color: #fff;
}
</style>

View File

@ -3,25 +3,54 @@ import VueRouter from 'vue-router'
import EditPage from '@/pages/Edit/Index'
import DocPage from '@/pages/Doc/Index'
import routerList from '@/pages/Doc/routerList'
import WorkbenchePage from '@/pages/Workbenche/Index'
import WorkbencheHomePage from '@/pages/Workbenche/views/Home'
import WorkbencheEditPage from '@/pages/Workbenche/views/Edit'
import WorkbencheHomeLocalPage from '@/pages/Workbenche/views/Local'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Edit',
component: EditPage
{
path: '/',
name: 'Edit',
component: EditPage
},
{
path: '/workbenche',
name: 'Workbenche',
component: WorkbenchePage,
redirect: '/workbenche/home/local',
children: [
{
path: 'home',
name: 'WorkbencheHome',
component: WorkbencheHomePage,
children: [
{
path: 'local',
name: 'WorkbencheHomeLocal',
component: WorkbencheHomeLocalPage,
}
]
},
{
path: 'edit/:id',
name: 'WorkbencheEdit',
component: WorkbencheEditPage,
}
]
},
...routerList.map((item) => {
return {
path: `/doc/${item.lang}/`,
return {
path: `/doc/${item.lang}/`,
redirect: `/doc/${item.lang}/introduction/`
}
}),
...routerList.map((item) => {
return {
path: `/doc/${item.lang}/`,
component: DocPage,
return {
path: `/doc/${item.lang}/`,
component: DocPage,
children: item.children.map((child) => {
return {
path: `${child.path}/:h?`,

View File

@ -15,7 +15,8 @@ const store = new Vuex.Store({
// 是否开启节点富文本
openNodeRichText: true
},
activeSidebar: '' // 当前显示的侧边栏
activeSidebar: '', // 当前显示的侧边栏
localEditList: []// 客户端中正在编辑的思维导图列表
},
mutations: {
/**
@ -59,6 +60,11 @@ const store = new Vuex.Store({
*/
setActiveSidebar(state, data) {
state.activeSidebar = data
},
// 设置客户端中当前正在编辑的思维导图列表
setLocalEditList(state, list) {
state.localEditList = list
}
},
actions: {