Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"typescript": "^4.7.2",
"vite": "^2.9.8",
"vite-plugin-electron": "^0.4.5",
"vite-plugin-resolve": "^2.1.2",
"vite-plugin-resolve": "2.1.2",
"vue": "^3.2.36",
"vue-router": "^4.0.16",
"vue-tsc": "^0.35.2"
Expand All @@ -58,6 +58,7 @@
"address": "^1.2.0",
"axios": "^0.27.2",
"echarts": "^5.3.2",
"express": "^4.18.2",
"fs-extra": "^11.1.0",
"handlebars": "^4.7.7",
"http": "0.0.1-security",
Expand Down
72 changes: 72 additions & 0 deletions packages/features/portal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"name": "dokit-studio-plugin-demo",
"description": "a DoKit desktop application",
"homepage": "https://www.dokit.cn/#/index/home",
"version": "1.0.0",
"main": "dist/main/index.cjs",
"author": "[email protected]",
"license": "MIT",
"repository": "",
"scripts": {
"dev": "node scripts/watch.mjs",
"prebuild": "vue-tsc --noEmit --p packages/renderer/tsconfig.json && node scripts/build.mjs",
"build": "electron-builder",
"init": "git config core.hooksPath .git/hooks/ && rm -rf .git/hooks && npx simple-git-hooks",
"test:e2e": "npx playwright test",
"test:e2e:headless": "npx playwright test --headed"
},
"engines": {
"node": ">=14.16.0"
},
"devDependencies": {
"@arco-design/web-vue": "^2.30.1",
"@playwright/test": "^1.22.2",
"@types/lowdb": "^1.0.11",
"@vitejs/plugin-vue": "^2.3.2",
"electron": "19.0.1",
"electron-builder": "^23.0.3",
"nano-staged": "^0.8.0",
"simple-git-hooks": "^2.8.0",
"typescript": "^4.7.2",
"vite": "^2.9.8",
"vite-plugin-electron": "^0.4.5",
"vite-plugin-resolve": "2.1.2",
"vue": "^3.2.36",
"vue-router": "^4.0.16",
"vue-tsc": "^0.35.2"
},
"env": {
"VITE_DEV_SERVER_HOST": "0.0.0.0",
"VITE_DEV_SERVER_PORT": 8080
},
"keywords": [
"electron",
"rollup",
"vite",
"vue3",
"vue"
],
"dependencies": {
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vueuse/core": "^8.6.0",
"address": "^1.2.0",
"axios": "^0.27.2",
"echarts": "^5.3.2",
"http": "0.0.1-security",
"less": "^4.1.3",
"lodash-id": "^0.14.1",
"lowdb": "^1.0.0",
"mitt": "^3.0.0",
"mockjs": "^1.1.0",
"moment": "^2.29.3",
"nprogress": "^0.2.0",
"pinia": "^2.0.14",
"portfinder": "^1.0.28",
"query-string": "^7.1.1",
"vite-svg-loader": "^3.3.0",
"vue-echarts": "^6.0.3",
"vue-i18n": "^9.1.10",
"vue3-json-viewer": "^2.2.2",
"ws": "^7.5.8"
}
}
116 changes: 116 additions & 0 deletions packages/features/portal/packages/main/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
const express = require("express");
const http = require("http");
const WS = require("ws");
const os = require("os");
const { ipcMain, BrowserWindow } = require('electron')

const getWsAddress = () => {
// 设定一个局域网的默认值
const port = process.env.PORT || 10086;
let host = "localhost";
let address = `ws://${host}:${port}`;

try {
// networkInterfaces这个方法详见:http://nodejs.cn/api/os.html#os_os_networkinterfaces
const ifaces = os.networkInterfaces();

for (let dev in ifaces) {
ifaces[dev].forEach((details) => {
// 寻找IPv4协议族,并且地址不是本地地址或者回环地址的地址即可。
console.log(details)
if (
details.family === "IPv4" &&
details.address !== "127.0.0.1" &&
!details.internal
) {
host = details.address;
return host;
}
});
}
address = `ws://${host}:${port}`;
} catch (e) {
console.log(e);
}

console.log("ws服务地址是: ", address);
return host;
}

module.exports = () => {
return {
onReady(ctx) {
console.log('portal onReady')
const app = express();

// 创建 HTTP 服务器
const server = http.createServer(app);

app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
});

// 初始化用户和信息列表
const clientMap = [];
const msgList = [];


// 创建 WS 服务器
const wss = new WS.Server({ server });

// 处理 WS 连接
wss.on("connection", function connection(ws, req) {
// 电脑可以连接ws,但手机无法连接ws,是因为协议不同,这里在服务端修改协议
if (req.headers['sec-websocket-extensions']) {
req.headers['sec-websocket-extensions'] = 'permessage-deflate';
}
console.log("New client connected");

const urlParams = new URLSearchParams(req.url.split("?")[1]);
const clientName = urlParams.get("clientName");
const clientId = parseInt(urlParams.get("clientId")) || clientMap.length + 1;
const existedClient = clientMap.find(client => {
return client.clientId === clientId && client.clientName === clientName
})

if (!existedClient) clientMap.push({ clientId: clientMap.length + 1, clientName });
if (ws.readyState === 1) {
ws.send(
JSON.stringify({
type: "register",
value: { clientId, clientName }
})
);
}

// 发送欢迎消息给新连接的客户端
if (ws.readyState === 1) {
ws.send(JSON.stringify({ type: "history", value: msgList }));
}

// 处理接收到的消息
ws.on("message", function incoming(message) {
const formatMsg = JSON.parse(message);
msgList.push(formatMsg.value);
// 广播收到的消息给所有客户端
wss.clients.forEach(function each(client) {
if (client.readyState === WS.OPEN) {
client.send(message);
}
});
});
});

// 启动服务器
const port = process.env.PORT || 10086;
server.listen(port, function () {
console.log(`Server listening on port ${port}`);
});

ipcMain.handle('get-ws-address', (event) => {
const address = getWsAddress();
return address;
});
}
}
}
32 changes: 32 additions & 0 deletions packages/features/portal/packages/main/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { join } from 'path'
import { builtinModules } from 'module'
import { defineConfig } from 'vite'
import pkg from '../../package.json'

export default defineConfig({
root: __dirname,
build: {
outDir: '../../dist/main',
emptyOutDir: true,
minify: process.env./* from mode option */NODE_ENV === 'production',
// https://github.com/caoxiemeihao/electron-vue-vite/issues/61
sourcemap: 'inline',
rollupOptions: {
input: {
// multiple entry
index: join(__dirname, 'index.ts'),
},
output: {
format: 'cjs',
entryFileNames: '[name].cjs',
manualChunks: {},
},
external: [
'electron',
...builtinModules,
// @ts-ignore
...Object.keys(pkg.dependencies || {}),
],
},
},
})
16 changes: 16 additions & 0 deletions packages/features/portal/packages/preload/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { domReady } from './utils'
import { useLoading } from './loading'
const { contextBridge, ipcRenderer } = require('electron');
const { appendLoading, removeLoading } = useLoading()
window.removeLoading = removeLoading

// domReady().then(appendLoading)
// 在预加载脚本中

contextBridge.exposeInMainWorld('electronAPI', {
getWsAddress: async () => {
const address = await ipcRenderer.invoke('get-ws-address');
console.log(address);
return address;
}
});
67 changes: 67 additions & 0 deletions packages/features/portal/packages/preload/loading.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* https://tobiasahlin.com/spinkit
* https://connoratherton.com/loaders
* https://projects.lukehaas.me/css-loaders
* https://matejkustec.github.io/SpinThatShit
*/
export function useLoading() {
const className = `loaders-css__square-spin`
const styleContent = `
@keyframes square-spin {
25% { transform: perspective(100px) rotateX(180deg) rotateY(0); }
50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg); }
75% { transform: perspective(100px) rotateX(0) rotateY(180deg); }
100% { transform: perspective(100px) rotateX(0) rotateY(0); }
}
.${className} > div {
animation-fill-mode: both;
width: 50px;
height: 50px;
background: #fff;
animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
}
.app-loading-wrap {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #282c34;
z-index: 9;
}
`
const oStyle = document.createElement('style')
const oDiv = document.createElement('div')

oStyle.id = 'app-loading-style'
oStyle.innerHTML = styleContent
oDiv.className = 'app-loading-wrap'
oDiv.innerHTML = `<div class="${className}"><div></div></div>`

return {
appendLoading() {
safe.append(document.head, oStyle)
safe.append(document.body, oDiv)
},
removeLoading() {
safe.remove(document.head, oStyle)
safe.remove(document.body, oDiv)
},
}
}

const safe = {
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find(e => e === child)) {
return parent.appendChild(child)
}
},
remove(parent: HTMLElement, child: HTMLElement) {
if (Array.from(parent.children).find(e => e === child)) {
return parent.removeChild(child)
}
},
}
15 changes: 15 additions & 0 deletions packages/features/portal/packages/preload/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

/** docoment ready */
export function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
return new Promise(resolve => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}
32 changes: 32 additions & 0 deletions packages/features/portal/packages/preload/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { join } from 'path'
import { builtinModules } from 'module'
import { defineConfig } from 'vite'
import pkg from '../../package.json'

export default defineConfig({
root: __dirname,
build: {
outDir: '../../dist/preload',
emptyOutDir: true,
minify: process.env./* from mode option */NODE_ENV === 'production',
// https://github.com/caoxiemeihao/electron-vue-vite/issues/61
sourcemap: 'inline',
rollupOptions: {
input: {
// multiple entry
index: join(__dirname, 'index.ts'),
},
output: {
format: 'cjs',
entryFileNames: '[name].cjs',
manualChunks: {},
},
external: [
'electron',
...builtinModules,
// @ts-ignore
...Object.keys(pkg.dependencies || {}),
],
},
},
})
18 changes: 18 additions & 0 deletions packages/features/portal/packages/renderer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!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" />
<meta http-equiv="X-Content-Security-Policy"
content="default-src 'self' 'unsafe-eval'; script-src 'self' 'unsafe-eval'" />
<title>Portal</title>
</head>

<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>

</html>
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading