Compare commits

...

15 Commits
v0.1.1 ... main

21 changed files with 6206 additions and 257 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sh eol=lf

4
.gitignore vendored
View File

@ -28,9 +28,9 @@ coverage
*.sw?
*.tsbuildinfo
package-lock.json
components.d.ts
auto-imports.d.ts
# Personal
**/_priv_*
**/_priv_*
Makefile

21
LICENCE.txt Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2024 kerms
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1 +1,18 @@
# 允斯调试器的内嵌网页版上位机
# 允斯无线透传器的内嵌网页版上位机
此项目使用`NPM`包管理, 需要先安装`node`工具。
# 环境准备步骤
##### 本地测试:
1. `npm install`
2. `npm run dev`,或用 `npm run devh` 则可以用其他设备访问,如手机调试移动界面。
3. 根据显示的地址,使用浏览器打开,默认地址为`localhost:5173` 或者其他设备访问`192.168.X.X:5173`
##### 发布至esp32
1. `npm install`
2. `npm run build` -> 会在`dist/`生成`index.html`和`ws.sharedworker.js`
3. 在`dist/`里执行`gzip *` -> -> 会在`dist/`生成`index.html.gz`和`ws.sharedworker.js.gz`
4. 至此可以使用这两个文件覆盖ESP32目录中的`project_components/html`里相对应的文件了。

5365
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,8 +5,10 @@
"type": "module",
"scripts": {
"dev": ". ./set_env.sh && vite",
"devh": ". ./set_env.sh && vite --host",
"build": "run-p type-check \"build-only {@}\" --",
"preview": ". ./set_env.sh && vite preview",
"previewh": ". ./set_env.sh && vite preview --host",
"build-only": ". ./set_env.sh && vite build",
"build:dev": ". ./set_env.sh && vite build --mode development",
"type-check": "vue-tsc --build --force",
@ -14,12 +16,16 @@
"format": "prettier --write src/"
},
"dependencies": {
"element-plus": "^2.6.1",
"@vueuse/core": "^10.9.0",
"ansi_up": "^6.0.2",
"element-plus": "^2.7.3",
"mitt": "^3.0.1",
"pinia": "^2.1.7",
"vue": "^3.4.21",
"vue-draggable-plus": "^0.4.1",
"vue-i18n": "^9.10.2",
"vue-router": "^4.3.0"
"vue-router": "^4.3.0",
"vuetify": "^3.6.5"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.3.3",
@ -40,10 +46,11 @@
"typescript": "~5.4.0",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.1.6",
"vite": "^5.3.3",
"vite-plugin-css-injected-by-js": "^3.5.0",
"vite-plugin-html": "^3.2.2",
"vite-plugin-singlefile": "^2.0.1",
"vite-plugin-singlefile": "^2.0.2",
"vite-plugin-vuetify": "^2.0.3",
"vite-svg-loader": "^5.1.0",
"vue-tsc": "^2.0.6"
}

View File

@ -1,3 +1,7 @@
#!/bin/bash
export VITE_APP_GIT_TAG=$(git describe --tags)
export VITE_APP_LAST_COMMIT=$(git log -1 --format=%cd)
#!/usr/bin/env bash
VITE_APP_GIT_TAG=$(git describe --tags | cut -d'-' -f1,2)
VITE_APP_LAST_COMMIT=$(git log -1 --format=%cd)
export VITE_APP_GIT_TAG
export VITE_APP_LAST_COMMIT

View File

@ -40,7 +40,7 @@ onMounted(() => {
logHelloMessage();
let host = "";
if (isDevMode()) {
host = import.meta.env.VITE_DEVICE_HOST_NAME;
host = import.meta.env.VITE_DEVICE_HOST_NAME || "dap.local";
} else {
host = window.location.host
}
@ -55,8 +55,10 @@ onUnmounted(() => {
</script>
<template>
<header>
<nav-bar/>
</header>
<RouterView/>
<div class="flex flex-col h-screen">
<header>
<nav-bar/>
</header>
<RouterView/>
</div>
</template>

View File

@ -1,47 +1,75 @@
import {type ApiJsonMsg, sendJsonMsg} from '@/api'
import {type ApiJsonMsg, sendJsonMsg, WtModuleID} from '@/api'
export const WifiModuleID = 1;
export enum WifiCmd {
UNKNOWN = 0,
WIFI_API_JSON_STA_GET_AP_INFO,
WIFI_API_JSON_CONNECT,
WIFI_API_JSON_GET_SCAN,
WIFI_API_JSON_DISCONNECT,
WIFI_API_JSON_AP_GET_INFO,
WIFI_API_JSON_STA_GET_AP_INFO = 1,
WIFI_API_JSON_CONNECT = 2,
WIFI_API_JSON_GET_SCAN = 3,
WIFI_API_JSON_DISCONNECT = 4,
WIFI_API_JSON_AP_GET_INFO = 5,
WIFI_API_JSON_GET_MODE = 6,
WIFI_API_JSON_SET_MODE = 7,
WIFI_API_JSON_AP_SET_CRED = 8,
WIFI_API_JSON_STA_GET_STATIC_INFO = 9,
WIFI_API_JSON_STA_SET_STATIC_CONF = 10,
}
interface WifiMsgOut extends ApiJsonMsg {
export enum WifiMode {
/* permanent */
WIFI_AP_AUTO_STA_ON = 0,
WIFI_AP_STA_OFF = 4, /* 100 */
WIFI_AP_OFF_STA_ON = 5, /* 101 */
WIFI_AP_ON_STA_OFF = 6, /* 110 */
WIFI_AP_STA_ON = 7, /* 111 */
/* temporary */
WIFI_AP_STOP = 8,
WIFI_AP_START = 9,
WIFI_STA_STOP = 10,
WIFI_STA_START = 11,
}
export enum WifiStatus {
WIFI_MODE_NULL = 0, /**< null mode */
WIFI_MODE_STA, /**< WiFi station mode */
WIFI_MODE_AP, /**< WiFi soft-AP mode */
WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */
}
export interface WiFiCredential extends ApiJsonMsg {
ssid?: string;
password?: string;
err?: string;
}
export function wifi_get_scan_list() {
const msg : WifiMsgOut = {
module: WifiModuleID,
const msg : WiFiCredential = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_GET_SCAN,
}
sendJsonMsg(msg);
}
export function wifi_sta_get_ap_info() {
const msg : WifiMsgOut = {
module: WifiModuleID,
const msg : WiFiCredential = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_STA_GET_AP_INFO,
}
sendJsonMsg(msg);
}
export function wifi_ap_get_info() {
const msg : WifiMsgOut = {
module: WifiModuleID,
const msg : WiFiCredential = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_AP_GET_INFO,
}
sendJsonMsg(msg);
}
export function wifi_connect_to(ssid: string, password: string) {
const msg: WifiMsgOut = {
module: WifiModuleID,
const msg: WiFiCredential = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_CONNECT,
ssid: ssid,
password: password,
@ -50,6 +78,19 @@ export function wifi_connect_to(ssid: string, password: string) {
}
export interface WifiInfo extends ApiJsonMsg {
rssi: number;
ssid: string;
password: string;
gateway: string;
ip: string;
mac: string;
netmask: string;
dns_main: string;
dns_backup: string;
wifiLogo?: string;
}
export interface WifiScanInfo extends ApiJsonMsg {
rssi: number;
ssid: string;
gateway: string;
@ -59,6 +100,87 @@ export interface WifiInfo extends ApiJsonMsg {
wifiLogo?: string;
}
export interface WifiList {
scan_list: Array<WifiInfo>;
export interface WifiList extends ApiJsonMsg {
scan_list: Array<WifiScanInfo>;
}
export interface IWifiMode extends ApiJsonMsg {
mode?: WifiMode;
status?: WifiStatus;
ap_on_delay?: number;
ap_off_delay?: number;
err?: string;
}
export function wifi_set_mode(req_mode: WifiMode, ap_on_delay = -1, ap_off_delay = -1) {
let msg: IWifiMode;
if (req_mode === WifiMode.WIFI_AP_AUTO_STA_ON && ap_on_delay !== -1 && ap_off_delay !== -1) {
msg = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_SET_MODE,
mode: req_mode,
ap_on_delay: ap_on_delay,
ap_off_delay: ap_off_delay,
};
} else {
msg = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_SET_MODE,
mode: req_mode,
};
}
sendJsonMsg(msg);
}
export function wifi_get_mode() {
const msg: IWifiMode = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_GET_MODE,
};
sendJsonMsg(msg);
}
export function wifi_ap_set_credential(ssid: string, password: string) {
const msg : WiFiCredential = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_AP_SET_CRED,
ssid: ssid,
password: password,
}
sendJsonMsg(msg);
}
export interface IWifiStaStaticInfo {
static_ip_en: number;
static_dns_en: number;
ip: string;
gateway: string;
netmask: string;
dns_main: string;
dns_backup: string;
}
export function wifi_sta_get_static_info() {
const msg: ApiJsonMsg = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_STA_GET_STATIC_INFO,
}
sendJsonMsg(msg);
}
export function wifi_sta_set_static_conf(static_info: IWifiStaStaticInfo) {
const msg: IWifiStaStaticInfo & ApiJsonMsg = {
module: WtModuleID.WIFI,
cmd: WifiCmd.WIFI_API_JSON_STA_SET_STATIC_CONF,
static_dns_en: static_info.static_dns_en,
static_ip_en: static_info.static_ip_en,
ip: static_info.ip,
gateway: static_info.gateway,
netmask: static_info.netmask,
dns_main: static_info.dns_main,
dns_backup: static_info.dns_backup,
}
sendJsonMsg(msg);
}

52
src/api/binDataDef.ts Normal file
View File

@ -0,0 +1,52 @@
import type {WtModuleID} from "@/api/index";
export enum WtDataType {
RESERVED = 0x00,
/* primitive type */
EVENT = 0x02,
ROUTE_HDR = 0x03,
RAW_BROADCAST = 0x04,
/* broadcast data */
CMD_BROADCAST = 0x11,
/* targeted data */
RAW = 0x20,
CMD = 0x21,
RESPONSE = 0x22,
/* standard protocols */
PROTOBUF = 0x40,
JSON = 0x41,
MQTT = 0x42,
}
export interface ApiBinaryMsg {
data_type: WtDataType,
module: WtModuleID,
sub_mod: number,
payload: Uint8Array;
}
export function decodeHeader(arrayBuffer: ArrayBuffer) : ApiBinaryMsg {
// Create a DataView to access the data in the ArrayBuffer
const dataView = new DataView(arrayBuffer);
// Extract the data_type from the first byte
const data_type = dataView.getUint8(0) as WtDataType;
// Extract the module_id and sub_id from the next bytes
const module = dataView.getUint8(1);
const sub_mod = dataView.getUint8(2);
const payload = new Uint8Array(arrayBuffer.slice(4));
// Constructing the header object
return {
data_type,
module,
sub_mod,
payload,
};
}

View File

@ -1,4 +1,5 @@
import {getWebsocketService} from "@/composables/websocket/websocketService";
import type {ApiBinaryMsg} from "@/api/binDataDef";
export interface ApiJsonMsg {
module: number;
@ -26,18 +27,34 @@ export interface ControlMsg {
export interface ServerMsg {
type: "json" | "binary"
data: ApiJsonMsg | object;
data: string | ArrayBuffer;
}
export enum WtModuleID {
WIFI = 1,
DATA_FLOW = 2,
UART = 4,
}
export function sendJsonMsg(apiJsonMsg: ApiJsonMsg) {
const msg: ServerMsg = {
type: "json",
data: apiJsonMsg,
data: JSON.stringify(apiJsonMsg),
};
getWebsocketService().send(msg);
// toServer.postMessage(msg);
}
export function sendBinMsg(msg: ApiJsonMsg) {
// toServer.postMessage(JSON.stringify(msg));
export function sendBinMsg(binMsg: ApiBinaryMsg) {
const buffer = new Uint8Array(4 + binMsg.payload.length);
buffer[0] = binMsg.data_type;
buffer[1] = binMsg.module;
buffer[2] = binMsg.sub_mod;
buffer[3] = 0; // Reserved byte
buffer.set(binMsg.payload, 4); // Append payload after header
const msg: ServerMsg = {
type: "binary",
data: buffer,
};
getWebsocketService().send(msg);
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="m136-80-56-56 264-264H160v-80h320v320h-80v-184L136-80Zm344-400v-320h80v184l264-264 56 56-264 264h184v80H480Z"/></svg>

After

Width:  |  Height:  |  Size: 206 B

1
src/assets/icon/help.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

After

Width:  |  Height:  |  Size: 668 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="#5f6368"><path d="M120-120v-320h80v184l504-504H520v-80h320v320h-80v-184L256-200h184v80H120Z"/></svg>

After

Width:  |  Height:  |  Size: 171 B

View File

@ -1,5 +1,5 @@
.text-layout {
@apply m-auto max-w-2xl min-w-min px-2
@apply mx-auto max-w-2xl w-full sm:min-w-[640px] px-2
}
.page-title {
@ -14,3 +14,8 @@
@apply text-blue-600 font-bold;
cursor: default;
}
.el-checkbox:hover {
background-color: var(--el-color-primary-light-9);
border-color: var(--el-color-primary-light-8);
}

View File

@ -58,6 +58,7 @@ class OneTimeWebsocket implements IWebsocket {
/* did not receive packet "heartBeatTimeout" times,
* connection may be lost: close the socket */
if (this.socket.readyState === this.socket.OPEN) {
console.log("No heart beat, break connection");
this.close();
this.clear();
}
@ -80,31 +81,21 @@ class OneTimeWebsocket implements IWebsocket {
return
const msg: ServerMsg = {
data: {},
data: ev.data,
type: "json",
}
if (typeof ev.data === "string") {
try {
msg.data = JSON.parse(ev.data) as ApiJsonMsg;
if ((msg.data as ApiJsonMsg).cmd === undefined ||
(msg.data as ApiJsonMsg).module === undefined
){
console.log("Server msg has no cmd or module");
return;
}
} catch (e) {
console.log(e);
return;
}
msg.type = "json"
} else {
msg.type = "binary";
msg.data = ev.data;
console.log(typeof ev.data);
}
this.msgCallback(msg);
}
this.socket.onclose = () => {
this.socket.onclose = (ev) => {
if (isDevMode()) {
console.log("ws closed", ev.reason, ev.code);
}
this.socket.onclose = null
this.socket.onopen = null
this.socket.onerror = null
@ -150,11 +141,8 @@ class OneTimeWebsocket implements IWebsocket {
if (isDevMode()) {
console.log('WebSocket proxies data ', msg);
}
if (msg.type === "binary") {
// this.socket.send(msg.data);
} else if (msg.type === "json") {
this.socket.send(JSON.stringify(msg.data));
}
this.socket.send(msg.data);
}
clear() {

View File

@ -1,9 +1,11 @@
import type {ApiJsonMsg, ControlMsg, ServerMsg} from "@/api";
import {isDevMode} from "@/composables/buildMode";
import {type ApiBinaryMsg, decodeHeader} from "@/api/binDataDef";
export interface IModuleCallback {
ctrlCallback: (msg: ControlMsg) => void;
serverMsgCallback: (msg: ServerMsg) => void;
serverJsonMsgCallback: (msg: ApiJsonMsg) => void;
serverBinMsgCallback: (msg: ApiBinaryMsg) => void;
}
const moduleMap = new Map<number, IModuleCallback>();
@ -22,19 +24,47 @@ export function unregisterModule(moduleId: number) {
}
export function routeModuleServerMsg(msg: ServerMsg) {
if (msg.type == "json") {
const module = (msg.data as ApiJsonMsg).module;
if (msg.type === "json") {
let jsonMsg: ApiJsonMsg;
try {
jsonMsg = JSON.parse(msg.data as string) as ApiJsonMsg;
if (jsonMsg.cmd === undefined ||
jsonMsg.module === undefined
){
console.log("Server msg has no cmd or module", msg.data);
return;
}
} catch (e) {
console.log(e);
return;
}
const module = jsonMsg.module;
const moduleHandler = moduleMap.get(module);
if (moduleHandler) {
moduleHandler.serverMsgCallback(msg);
moduleHandler.serverJsonMsgCallback(jsonMsg);
} else {
if (isDevMode()) {
console.log("routeModuleServerMsg module not loaded", module);
}
}
} else {
if (isDevMode()) {
console.log("routeModuleServerMsg ignored:", msg);
const arr = msg.data as ArrayBuffer;
if (arr.byteLength < 4) {
if (isDevMode()) {
console.log("binary message too short");
}
return;
}
const binaryMsg = decodeHeader(msg.data as ArrayBuffer);
const moduleHandler = moduleMap.get(binaryMsg.module);
if (moduleHandler) {
moduleHandler.serverBinMsgCallback(binaryMsg);
} else {
if (isDevMode()) {
console.log("routeModuleServerMsg ignored:", msg, binaryMsg);
}
}
}
}

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
const version = import.meta.env.VITE_APP_GIT_TAG;
const compileTime = import.meta.env.VITE_APP_LAST_COMMIT;
const version = import.meta.env.VITE_APP_GIT_TAG || "v0.0.0";
const compileTime = import.meta.env.VITE_APP_LAST_COMMIT || "1970-00-00";
</script>
<template>
@ -17,23 +17,23 @@ const compileTime = import.meta.env.VITE_APP_LAST_COMMIT;
</el-descriptions>
<el-descriptions title="鸣谢" border :column="1" class="mt-5 description-style">
<el-descriptions-item label="vuejs"><a href="https://github.com/vuejs/vue/blob/main/LICENSE">MIT</a>
<el-descriptions-item label="vuejs"><a target="_blank" href="https://github.com/vuejs/vue/blob/main/LICENSE">MIT</a>
</el-descriptions-item>
<el-descriptions-item label="typescript"><a
href="https://github.com/microsoft/TypeScript/blob/main/LICENSE.txt">Apache 2.0</a></el-descriptions-item>
<el-descriptions-item label="vite"><a href="https://github.com/vitejs/vite/blob/main/LICENSE">MIT</a>
<el-descriptions-item label="vite"><a target="_blank" href="https://github.com/vitejs/vite/blob/main/LICENSE">MIT</a>
</el-descriptions-item>
<el-descriptions-item label="tailwindcss"><a
href="https://github.com/tailwindlabs/tailwindcss/blob/master/LICENSE">MIT</a></el-descriptions-item>
<el-descriptions-item label="element-plus"><a
href="https://github.com/element-plus/element-plus/blob/dev/LICENSE">MIT</a></el-descriptions-item>
<el-descriptions-item label="pinia"><a href="https://github.com/vuejs/pinia/blob/v2/LICENSE">MIT</a>
<el-descriptions-item label="pinia"><a target="_blank" href="https://github.com/vuejs/pinia/blob/v2/LICENSE">MIT</a>
</el-descriptions-item>
<el-descriptions-item label="mitt"><a href="https://github.com/developit/mitt/blob/main/LICENSE">MIT</a>
<el-descriptions-item label="mitt"><a target="_blank" href="https://github.com/developit/mitt/blob/main/LICENSE">MIT</a>
</el-descriptions-item>
<el-descriptions-item label="vue-router"><a
href="https://github.com/vuejs/vue-router/blob/dev/LICENSE">MIT</a></el-descriptions-item>
<el-descriptions-item label="vue-i18n"><a href="https://github.com/kazupon/vue-i18n?tab=MIT-1-ov-file#readme">MIT</a>
<el-descriptions-item label="vue-i18n"><a target="_blank" href="https://github.com/kazupon/vue-i18n?tab=MIT-1-ov-file#readme">MIT</a>
</el-descriptions-item>
<el-descriptions-item label="lightningcss"><a
href="https://github.com/parcel-bundler/lightningcss/blob/master/LICENSE">MPL-2.0 license</a>
@ -42,12 +42,12 @@ const compileTime = import.meta.env.VITE_APP_LAST_COMMIT;
</el-collapse-item>
<el-collapse-item title="关于下位机">
<el-descriptions border :column="1" class="mt-5 description-style">
<el-descriptions-item label="官网"><a href="https://yunsi.studio/wireless-proxy">允斯工作室</a></el-descriptions-item>
<el-descriptions-item label="官网"><a target="_blank" href="https://yunsi.studio/wireless-proxy">允斯工作室</a></el-descriptions-item>
<el-descriptions-item label="版本">-</el-descriptions-item>
</el-descriptions>
<el-descriptions title="鸣谢" border :column="1" class="mt-5 description-style">
<el-descriptions-item label="windowsair"><a href="https://github.com/windowsair/wireless-esp8266-dap">wireless-esp8266-dap</a>
<el-descriptions-item label="windowsair"><a target="_blank" href="https://github.com/windowsair/wireless-esp8266-dap">wireless-esp8266-dap</a>
</el-descriptions-item>
</el-descriptions>
</el-collapse-item>
@ -55,11 +55,11 @@ const compileTime = import.meta.env.VITE_APP_LAST_COMMIT;
<el-descriptions title="作者:空空(kerms)" border :column="1" class="mt-5 description-style">
<el-descriptions-item label="官网"><a href="https://yunsi.studio/">允斯工作室https://yunsi.studio/</a></el-descriptions-item>
<el-descriptions-item label="github"><a href="https://github.com/kerms">https://github.com/kerms</a>
<el-descriptions-item label="官网"><a target="_blank" href="https://yunsi.studio/">允斯工作室https://yunsi.studio/</a></el-descriptions-item>
<el-descriptions-item label="github"><a target="_blank" href="https://github.com/kerms">https://github.com/kerms</a>
</el-descriptions-item>
<el-descriptions-item label="邮箱">kerms@niazo.org</el-descriptions-item>
<el-descriptions-item label="BiliBili"><a href="https://space.bilibili.com/38669852">UID38669852</a>
<el-descriptions-item label="BiliBili"><a target="_blank" href="https://space.bilibili.com/3461571571353885">3461571571353885</a>
</el-descriptions-item>
<el-descriptions-item label="QQ群">642246000</el-descriptions-item>
<el-descriptions-item label="备注">欢迎大家来打扰啊</el-descriptions-item>

View File

@ -5,7 +5,6 @@
</h1>
<el-divider></el-divider>
<h2 class="mb-4 text-xl font-bold tracking-tight md:text-2xl lg:text-3xl">连接Wi-Fi</h2>
<el-form label-width="auto" ref="formRef" :model="ssidValidateForm" class="m-auto">
<el-form-item
@ -45,38 +44,82 @@
clearable
/>
</el-form-item>
<div class="mb-2">
<el-alert type="info" show-icon>
如果不是通过透传器的热点连接更换Wi-Fi将导致此界面与透传器断开连接
</el-alert>
</div>
<div class="flex justify-center">
<el-button @click="onConnectClick" type="primary">连接</el-button>
</div>
</el-form>
<el-divider></el-divider>
<div class="flex items-center">
<h5 class="text-md font-bold text-gray-800 w-32">Wi-Fi模式</h5>
<div class="flex shrink-0">
<el-tooltip effect="light">
<template #content>
<p>热点+终端模式并存会影响稳定性且保持热点开启会增加功耗</p>
<p>
<el-text size="small">智能模式</el-text>
成功连接Wi-Fi30秒后自动关闭热点断开连接5秒后自动打开热点
</p>
<p>
<el-text size="small">热点+终端共存模式</el-text>
方便使用但是影响稳定性
</p>
<p>
<el-text size="small">单热点模式缺点</el-text>
无网络
</p>
</template>
<InlineSvg name="help" class="w-3.5 h-3.5 text-gray-500 cursor-help"></InlineSvg>
</el-tooltip>
</div>
<el-select v-model="wifiMode" :disabled="wsStore.state != ControlEvent.CONNECTED">
<el-option
v-for="item in wifiModeOptions"
:key="item.key"
:value="item.key"
:label="item.label"
/>
</el-select>
<el-button type="primary" @click="wifiChangeMode" :loading="wifiMode_loading">保存</el-button>
</div>
<el-divider></el-divider>
<el-descriptions
title="Wi-Fi终端信息"
title="Wi-Fi终端(STA)信息"
:column="1"
border
class="description-style"
>
<el-descriptions-item label="asd">
<template #label >
<template #extra>
<el-switch v-model="wifiSta_On" :disabled="wsStore.state != ControlEvent.CONNECTED || !wifiAp_On"
active-text="已开启" inactive-text="未开启" :loading="wifiMode_loading"
:before-change="()=>beforeWifiModeChange('STA')"
/>
</template>
<el-descriptions-item span="4">
<template #label>
<div>
信号强度
</div>
</template>
<template #default >
{{ wifiStaApInfo.rssi }}
<template #default>
<p>{{ wifiStaApInfo.rssi }}</p>
</template>
</el-descriptions-item>
<el-descriptions-item span="1">
<el-descriptions-item span="4">
<template #label>
<div>
SSID
Wi-Fi名(SSID)
</div>
</template>
{{ wifiStaApInfo.ssid }}
<p>{{ wifiStaApInfo.ssid }}</p>
</el-descriptions-item>
<!-- <el-descriptions-item span="6" >-->
<!-- <template #label>-->
@ -84,23 +127,21 @@
<!-- 密码-->
<!-- </div>-->
<!-- </template>-->
<!-- <password-viewer password="asdasdasd"></password-viewer>-->
<!-- <password-viewer :password="wifiStaApInfo.password"></password-viewer>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item span="4">
<template #label>
<div>
IP
</div>
</template>
{{ wifiStaApInfo.ip }}
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
MAC
</div>
</template>
{{ wifiStaApInfo.mac }}
<p>{{ wifiStaApInfo.mac }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>IP(内网地址)</div>
</template>
<p>{{ wifiStaApInfo.ip }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
@ -108,43 +149,139 @@
网关
</div>
</template>
{{ wifiStaApInfo.gateway }}
<p>{{ wifiStaApInfo.gateway }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
掩码
</div>
</template>
{{ wifiStaApInfo.netmask }}
<p>{{ wifiStaApInfo.netmask }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
首选DNS
</div>
</template>
<p>{{ wifiStaApInfo.dns_main }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
备用DNS
</div>
</template>
<p>{{ wifiStaApInfo.dns_backup }}</p>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
IP分配模式
</div>
</template>
<el-select v-model="wifiStaticInfo.static_ip_en" :disabled="wsStore.state != ControlEvent.CONNECTED">
<el-option
v-for="item in staIPModeOptions"
:key="item.key"
:value="item.key"
:label="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item span="4" v-if="wifiStaticInfo.static_ip_en">
<template #label>
<div>IP(内网地址)</div>
</template>
<el-input v-model="wifiStaticInfo.ip"></el-input>
</el-descriptions-item>
<el-descriptions-item span="4" v-if="wifiStaticInfo.static_ip_en">
<template #label>
<div>
网关
</div>
</template>
<el-input v-model="wifiStaticInfo.gateway"></el-input>
</el-descriptions-item>
<el-descriptions-item span="4" v-if="wifiStaticInfo.static_ip_en">
<template #label>
<div>
掩码
</div>
</template>
<el-input v-model="wifiStaticInfo.netmask"></el-input>
</el-descriptions-item>
<el-descriptions-item span="4">
<template #label>
<div>
DNS模式
</div>
</template>
<el-select v-model="wifiStaticInfo.static_dns_en" :disabled="wsStore.state != ControlEvent.CONNECTED">
<el-option
v-for="item in staDNSModeOptions"
:key="item.key"
:value="item.key"
:label="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item span="4" v-if="wifiStaticInfo.static_dns_en">
<template #label>
<div>
首选DNS
</div>
</template>
<el-input v-model="wifiStaticInfo.dns_main"></el-input>
</el-descriptions-item>
<el-descriptions-item span="4" v-if="wifiStaticInfo.static_dns_en">
<template #label>
<div>
备用DNS
</div>
</template>
<el-input v-model="wifiStaticInfo.dns_backup"></el-input>
</el-descriptions-item>
</el-descriptions>
<div class="flex justify-center mt-4">
<el-button type="primary" :loading="wifiMode_loading" @click="wifiStaSetStaticInfo">保存</el-button>
</div>
<el-divider></el-divider>
<el-descriptions
title="Wi-Fi热点信息"
title="Wi-Fi自发热点(AP)信息"
:column="1"
border
class="description-style"
>
<template #extra>
<el-switch v-model="wifiAp_On" :disabled="wsStore.state != ControlEvent.CONNECTED || !wifiSta_On"
:loading="wifiMode_loading" active-text="已开启" inactive-text="未开启"
:before-change="()=>beforeWifiModeChange('AP')"
/>
</template>
<el-descriptions-item span="6">
<template #label>
<div>
SSID
Wi-Fi名(SSID)
</div>
</template>
{{ wifiApInfo.ssid }}
<div class="flex">
<el-input v-model="wifiApInfo.ssid"></el-input>
</div>
</el-descriptions-item>
<el-descriptions-item span="6">
<template #label>
<div>
密码
</div>
</template>
<el-input v-model="wifiApInfo.password"></el-input>
</el-descriptions-item>
<!-- <el-descriptions-item span="6">-->
<!-- <template #label>-->
<!-- <div>-->
<!-- 密码-->
<!-- </div>-->
<!-- </template>-->
<!-- <password-viewer password="asdasdasd"></password-viewer>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item span="4">
<template #label>
<div>
@ -181,7 +318,9 @@
{{ wifiApInfo.netmask }}
</el-descriptions-item>
</el-descriptions>
<div class="flex justify-center mt-4">
<el-button type="primary" :loading="wifiMode_loading" @click="wifiApChangeCredential">保存</el-button>
</div>
<el-divider></el-divider>
</div>
@ -190,22 +329,32 @@
<script setup lang="ts">
import {computed, onMounted, onUnmounted, reactive, ref} from "vue";
import {
wifi_sta_get_ap_info,
type IWifiMode,
wifi_ap_get_info,
wifi_ap_set_credential,
wifi_connect_to,
wifi_get_mode,
wifi_get_scan_list,
wifi_set_mode,
wifi_sta_get_ap_info,
WifiCmd,
type WifiInfo,
type WifiList,
WifiModuleID,
wifi_ap_get_info, wifi_connect_to
WifiMode,
type WifiScanInfo,
type WiFiCredential,
WifiStatus, wifi_sta_get_static_info,
type IWifiStaStaticInfo, wifi_sta_set_static_conf,
} from "@/api/apiWifi";
import type {FormInstance} from "element-plus";
import InlineSvg from "@/components/InlineSvg.vue";
import type {ApiJsonMsg, ControlMsg, ServerMsg} from "@/api";
import {ControlEvent, ControlMsgType} from "@/api";
import type {ApiJsonMsg, ControlMsg} from "@/api";
import {ControlEvent, ControlMsgType, WtModuleID} from "@/api";
import {registerModule, unregisterModule} from "@/router/msgRouter";
import {useWsStore} from "@/stores/websocket";
import {globalNotify, globalNotifyRightSide} from "@/composables/notification";
import {isDevMode} from "@/composables/buildMode";
const formRef = ref<FormInstance>()
let wifiListPlaceholder = ref("我的WIFI")
@ -214,6 +363,29 @@ let ssidValidateForm = reactive({
password: "",
})
let wifiSta_On = ref(false);
const wifiMode_loading = ref(false)
let wifiAp_On = ref(false);
let wifiMode = ref(-1);
let wifiModeOptions = [
{
label: "智能热点+常开终端 (AP+STA)",
key: WifiMode.WIFI_AP_AUTO_STA_ON,
}, {
label: "仅开启热点 (AP)",
key: WifiMode.WIFI_AP_ON_STA_OFF,
}, {
label: "[不推荐] 常开热点+常开终端 (AP+STA)",
key: WifiMode.WIFI_AP_STA_ON,
}, /* {
value: "仅开启终端STA",
key: 2,
},*/
]
let wsStore = useWsStore();
@ -223,18 +395,49 @@ const defWifiInfo: WifiInfo = {
gateway: "未连接",
ip: "未连接",
mac: "未连接",
dns_main: "未连接",
dns_backup: "未连接",
rssi: 0,
netmask: "未连接",
ssid: "未连接",
password: "",
}
const staIPModeOptions = [
{
label: "自动 (DHCP)",
key: 0,
}, {
label: "静态IP",
key: 1,
},
]
const staDNSModeOptions = [
{
label: "自动 (使用网关)",
key: 0,
}, {
label: "静态DNS",
key: 1,
},
]
let wifiStaApInfo = reactive<WifiInfo>({...defWifiInfo});
let wifiApInfo = reactive<WifiInfo>({...defWifiInfo});
let wifiStaticInfo = reactive<IWifiStaStaticInfo>({
dns_backup: "0.0.0.0",
dns_main: "0.0.0.0",
gateway: "0.0.0.0",
ip: "0.0.0.0",
netmask: "0.0.0.0",
static_dns_en: 0,
static_ip_en: 0,
});
let scanning = ref(false);
let scan_cb: any;
let connectBtnClicked = 0;
let options: Array<WifiInfo> = [];
let options: Array<WifiScanInfo> = [];
const scanText = computed(() => {
return scanning.value ? "扫描中" : "扫描";
});
@ -247,29 +450,28 @@ const querySearch = (queryString: string, cb: any) => {
}
}
const onClientMsg = (msg: ServerMsg) => {
if (msg.type !== "json") {
return;
}
let json = msg.data as ApiJsonMsg;
switch (json.cmd as WifiCmd) {
const onClientMsg = (msg: ApiJsonMsg) => {
switch (msg.cmd as WifiCmd) {
case WifiCmd.UNKNOWN:
break;
case WifiCmd.WIFI_API_JSON_STA_GET_AP_INFO: {
const info = msg.data as WifiInfo;
Object.assign(wifiStaApInfo, info);
const info = msg as WifiInfo;
if (info.rssi === 0) {
Object.assign(wifiStaApInfo, defWifiInfo);
} else {
Object.assign(wifiStaApInfo, info);
}
if (connectBtnClicked) {
connectBtnClicked = 0;
globalNotifyRightSide(wifiStaApInfo.ssid + " 连接成功", "success");
wifi_sta_get_static_info();
}
break;
}
case WifiCmd.WIFI_API_JSON_CONNECT:
break;
case WifiCmd.WIFI_API_JSON_GET_SCAN: {
const list = msg.data as WifiList;
const list = msg as WifiList;
scanning.value = false;
list.scan_list.forEach(value => {
if (value.rssi > -50) {
@ -291,10 +493,65 @@ const onClientMsg = (msg: ServerMsg) => {
case WifiCmd.WIFI_API_JSON_DISCONNECT:
break;
case WifiCmd.WIFI_API_JSON_AP_GET_INFO: {
const info = msg.data as WifiInfo;
const info = msg as WifiInfo;
Object.assign(wifiApInfo, info);
break;
}
case WifiCmd.WIFI_API_JSON_SET_MODE:
wifi_get_mode();
/* falls through */
case WifiCmd.WIFI_API_JSON_GET_MODE: {
const modeInfo = msg as IWifiMode;
wifiMode_loading.value = false;
if (modeInfo.err !== undefined) {
globalNotifyRightSide("设置失败", "error");
return;
}
if (modeInfo.status !== undefined) {
wifiAp_On.value = modeInfo.status === WifiStatus.WIFI_MODE_AP || modeInfo.status === WifiStatus.WIFI_MODE_APSTA;
wifiSta_On.value = modeInfo.status === WifiStatus.WIFI_MODE_STA || modeInfo.status === WifiStatus.WIFI_MODE_APSTA;
}
if (modeInfo.mode !== undefined) {
if (modeInfo.mode < WifiMode.WIFI_AP_STOP) {
wifiMode.value = modeInfo.mode;
} else if (modeInfo.mode === WifiMode.WIFI_AP_START) {
wifiAp_On.value = true;
} else if (modeInfo.mode === WifiMode.WIFI_AP_STOP) {
wifiAp_On.value = false;
} else if (modeInfo.mode === WifiMode.WIFI_STA_START) {
wifiSta_On.value = true;
} else if (modeInfo.mode === WifiMode.WIFI_STA_STOP) {
wifiSta_On.value = false;
}
}
break;
}
case WifiCmd.WIFI_API_JSON_AP_SET_CRED: {
const wifiCred = msg as WiFiCredential;
if (wifiCred.err !== undefined) {
globalNotifyRightSide(wifiCred.err, "error");
} else {
globalNotifyRightSide("已保存配置", "success");
}
wifiMode_loading.value = false;
break;
}
case WifiCmd.WIFI_API_JSON_STA_GET_STATIC_INFO: {
const staticInfo = msg as IWifiStaStaticInfo & ApiJsonMsg;
console.log("@@@", staticInfo);
Object.assign(wifiStaticInfo, staticInfo);
break;
}
case WifiCmd.WIFI_API_JSON_STA_SET_STATIC_CONF:
wifiMode_loading.value = false;
break;
default:
if (isDevMode()) {
console.log(msg);
}
break;
}
};
@ -311,6 +568,8 @@ const onClientCtrl = (msg: ControlMsg) => {
if (msg.data === ControlEvent.CONNECTED) {
wifi_sta_get_ap_info();
wifi_ap_get_info();
wifi_get_mode();
wifi_sta_get_static_info();
}
};
@ -334,20 +593,54 @@ function onConnectClick() {
}
}
function beforeWifiModeChange(ap_sta: "AP" | "STA" = "AP") {
if (ap_sta === "AP") {
wifiMode_loading.value = true;
wifi_set_mode(wifiAp_On.value ? WifiMode.WIFI_AP_STOP : WifiMode.WIFI_AP_START);
} else {
wifiMode_loading.value = true;
wifi_set_mode(wifiSta_On.value ? WifiMode.WIFI_STA_STOP : WifiMode.WIFI_STA_START);
}
wifi_sta_get_ap_info();
return false;
}
function wifiChangeMode() {
wifiMode_loading.value = true;
wifi_set_mode(wifiMode.value);
}
function wifiApChangeCredential() {
if (wifiApInfo.ssid === "") {
globalNotifyRightSide("请输入AP名称", "error");
return;
}
wifiMode_loading.value = true;
wifi_ap_set_credential(wifiApInfo.ssid, wifiApInfo.password);
}
function wifiStaSetStaticInfo() {
wifiMode_loading.value = true;
wifi_sta_set_static_conf(wifiStaticInfo);
wifi_sta_get_ap_info();
}
onMounted(() => {
registerModule(WifiModuleID, {
registerModule(WtModuleID.WIFI, {
ctrlCallback: onClientCtrl,
serverMsgCallback: onClientMsg
serverJsonMsgCallback: onClientMsg,
serverBinMsgCallback: () => {},
});
wifi_sta_get_ap_info();
wifi_ap_get_info();
wifi_get_mode();
wifi_sta_get_static_info();
});
onUnmounted(() => {
unregisterModule(WifiModuleID);
unregisterModule(WtModuleID.WIFI);
});
</script>

View File

@ -1,25 +1,31 @@
<template>
<nav class="relative px-2 py-1 flex justify-between items-center border-b">
<nav class="relative px-2 py-0.5 sm:py-1 flex justify-between items-center border-b h-full">
<div class="flex">
<button @click.prevent="sideMenuOpen=true" class="flex items-center hover:text-blue-600 p-3">
<svg class="block h-4 w-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<button @click.prevent="sideMenuOpen=true" class="flex items-center hover:text-blue-600 pl-1 mx-4">
<svg class="block h-3 lg:h-4 lg:w-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<title>导航侧栏</title>
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
</svg>
</button>
<router-link to="/" class="text-3xl px-4 font-bold leading-none" title="走,去码头整点薯条">
<InlineSvg name="favicon" class="h-10"></InlineSvg>
<router-link to="/" class="text-3xl px-4 font-bold leading-none hidden items-center sm:flex" title="走,去码头整点薯条">
<InlineSvg name="favicon" class="h-5 lg:h-8"></InlineSvg>
</router-link>
<!-- <a class="text-3xl px-4 font-bold leading-none" href="/">-->
<!-- <InlineSvg name="home" class="h-10"></InlineSvg>-->
<!-- </a>-->
<!-- <router-link to="/" class="flex items-center text-sm text-blue-600 font-bold">主页</router-link>-->
<!-- <a class="flex items-center text-sm text-blue-600 font-bold" href="/">主页6</a>-->
<div class="flex pt-0.5 sm:pt-1 ml-4 text-sm items-center sm:hidden">
<router-link :to="route.fullPath">{{ route.meta.title }}</router-link>
</div>
</div>
<div class="flex">
<ul class="hidden absolute top-1/2 left-1/2 transform -translate-y-1/2 -translate-x-1/2 md:flex md:mx-auto md:items-center md:w-auto md:space-x-6">
<ul class="hidden absolute top-1/2 left-1/2 transform -translate-y-1/2 -translate-x-1/2 sm:flex sm:mx-auto sm:items-center sm:w-auto sm:space-x-6">
<li v-for="(item, index) in menuItems" :key="index" class="router-link">
<router-link :to="item.href" :class="item?.class">{{item.name}}</router-link>
</li>
@ -27,12 +33,22 @@
</div>
<!-- <a class="md:ml-auto md:mr-3"></a>-->
<div class="flex">
<el-button :type="wsColor" size="large" class="transition duration-1000">
<InlineSvg v-show="wsColor!=='success'" name="link-off" class="mr-2" width="20"></InlineSvg>
<InlineSvg v-show="wsColor==='success'" name="link" class="mr-2" width="20"></InlineSvg>
{{ wsState }}
</el-button>
<div class="flex h-full">
<div id="page-spec-slot" class="content-center h-full flex flex-row"></div>
<div class="lg:hidden">
<el-button :type="wsColor" size="small" class="transition duration-1000 min-h-full">
<InlineSvg v-show="wsColor!=='success'" name="link-off" class="mr-2" width="20"></InlineSvg>
<InlineSvg v-show="wsColor==='success'" name="link" class="mr-2" width="20"></InlineSvg>
<div class="text-xs sm:text-sm lg:text-base">{{ wsState }}</div>
</el-button>
</div>
<div class="hidden lg:flex">
<el-button :type="wsColor" size="large" class="transition duration-1000 min-h-full">
<InlineSvg v-show="wsColor!=='success'" name="link-off" class="mr-2" width="20"></InlineSvg>
<InlineSvg v-show="wsColor==='success'" name="link" class="mr-2" width="20"></InlineSvg>
<div class="text-base">{{ wsState }}</div>
</el-button>
</div>
</div>
</nav>
<div :class='["custom-drawer", {open: sideMenuOpen}]'>
@ -42,7 +58,7 @@
size=""
:direction="'ltr'"
>
<div id="testborder" :class="[sideMenuItemClass]" class="pr-6 flex text-gray-500" @click="sideMenuOpen=false">
<div :class="[sideMenuItemClass]" class="pr-6 flex text-gray-500" @click="sideMenuOpen=false">
<InlineSvg name="cross" class="h-6"></InlineSvg>
<div>
<p class="h-6 flex items-center">{{ $t("page.close") }}</p>
@ -59,9 +75,12 @@
<template #footer>
<div>
<p class="text-xs text-center text-gray-400">
<span>Copyright <a href="http://github.com/kerms">kerms</a> 2024</span>
</p>
<el-button @click="toggle">
<InlineSvg v-if="!isFullscreen" name="open-in-full" width="16px" fill="#000000"></InlineSvg>
<p v-if="!isFullscreen">全屏</p>
<InlineSvg v-if="isFullscreen" name="close-fullscreen" width="16px" fill="#000000"></InlineSvg>
<p v-if="isFullscreen">缩小</p>
</el-button>
</div>
</template>
</el-drawer>
@ -90,8 +109,12 @@ import {computed, ref} from "vue";
import {useWsStore} from "@/stores/websocket";
import {translate} from "@/locales";
import {ControlEvent} from "@/api";
import {useRoute} from "vue-router";
import { useFullscreen } from '@vueuse/core'
const wsStore = useWsStore();
const {isFullscreen, toggle} = useFullscreen();
const route = useRoute();
const sideMenuItemClass = "block p-4 text-sm font-semibold hover:bg-blue-50 hover:text-blue-600 rounded"
const sideMenuOpen = ref(false);
@ -136,11 +159,7 @@ const menuItems: Item[] = ([
}, {
name: translate("page.feedback"),
href: "/feedback",
},/* {
name: translate("page.uart"),
href: "/uart",
class: "todo-menu-item",
},*/
},
]);
</script>

View File

@ -2,115 +2,118 @@ import { fileURLToPath, URL } from 'node:url'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vite'
import {ConfigEnv, defineConfig, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import svgLoader from "vite-svg-loader";
import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
import { viteSingleFile } from 'vite-plugin-singlefile'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
svgLoader(),
cssInjectedByJsPlugin(),
viteSingleFile(),
],
define: {
export default ({mode}: ConfigEnv) => {
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
cacheDir: "/tmp/zhuang/cache",
worker: {
rollupOptions: {
output: {
inlineDynamicImports: true,
minifyInternalExports: true,
// entryFileNames: (chunkInfo) => {
// // console.log(chunkInfo)
// if (chunkInfo.name.includes("shared")) {
// console.log(chunkInfo.name);
// }
// return "worker.js";
// },
entryFileNames: "[name].js",
return defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
svgLoader(),
cssInjectedByJsPlugin(),
viteSingleFile(),
],
define: {},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
},
build: {
// target: 'es2015',
outDir: '/tmp/zhuang/dap-web-dist/',
emptyOutDir: true,
cssMinify: 'lightningcss',
},
rollupOptions: {
output: {
inlineDynamicImports: true,
minifyInternalExports: true,
assetFileNames: (assetInfo) => {
if (!assetInfo || !assetInfo.name) {
return 'default-filename.ext';
}
const info = assetInfo.name.split(".");
let extType = info[info.length - 1];
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
extType = "img";
} else if (/woff|woff2/.test(extType)) {
extType = "css";
} else if (/css/.test(extType)) {
extType = "css";
return "style.css"
}
console.log(assetInfo)
return `[name]-[hash][extname]`;
},
// chunkFileNames: "[name]-[hash].js",
// chunkFileNames: "[name][hash].js",
chunkFileNames(chunkInfo) {
// Check if this chunk is your SharedWorker
// console.log(chunkInfo)
cacheDir: process.env.VITE_CACHE_DIR || undefined,
worker: {
rollupOptions: {
output: {
inlineDynamicImports: true,
minifyInternalExports: true,
// entryFileNames: (chunkInfo) => {
// // console.log(chunkInfo)
// if (chunkInfo.name.includes("shared")) {
// console.log(chunkInfo.name);
// }
// return "worker.js";
// },
entryFileNames: "[name].js",
}
}
},
build: {
// target: 'es2015',
outDir: process.env.VITE_OUTPUT_DIR || undefined,
emptyOutDir: true,
cssMinify: 'lightningcss',
// For other chunks, use the default naming scheme
return 'assets/[name]-[hash].js';
},
// entryFileNames: "[name]-[hash].js",
entryFileNames: (chunkInfo) => {
// console.log(chunkInfo)
if (chunkInfo.name.includes("shared")) {
console.log(chunkInfo.name);
}
return "script.js";
},
rollupOptions: {
output: {
inlineDynamicImports: true,
minifyInternalExports: true,
assetFileNames: (assetInfo) => {
if (!assetInfo || !assetInfo.name) {
return 'default-filename.ext';
}
const info = assetInfo.name.split(".");
let extType = info[info.length - 1];
if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
extType = "img";
} else if (/woff|woff2/.test(extType)) {
extType = "css";
} else if (/css/.test(extType)) {
extType = "css";
return "style.css"
}
console.log(assetInfo)
return `[name]-[hash][extname]`;
},
// chunkFileNames: "[name]-[hash].js",
// chunkFileNames: "[name][hash].js",
chunkFileNames(chunkInfo) {
// Check if this chunk is your SharedWorker
// console.log(chunkInfo)
sourcemapFileNames: "map-[name].js",
// sanitizeFileName: "anit-[name].js",
// entryFileNames: (chunkInfo) => {
// console.log(chunkInfo)
// return `${chunkInfo.name}.js`
// },
// manualChunks(id) {
// /* if (id.match('.*!/src/.*shared[a-zA-Z0-9-_]*[.](ts|js).*')) {
// // Prevent bundling node_modules into common chunks
// return 'bundle-shared';
// }
// else */{
// // Prevent bundling node_modules into common chunks
// return 'script'
// }
// },
manualChunks: undefined,
},
}
},
})
// For other chunks, use the default naming scheme
return 'assets/[name]-[hash].js';
},
// entryFileNames: "[name]-[hash].js",
entryFileNames: (chunkInfo) => {
// console.log(chunkInfo)
if (chunkInfo.name.includes("shared")) {
console.log(chunkInfo.name);
}
return "script.js";
},
sourcemapFileNames: "map-[name].js",
// sanitizeFileName: "anit-[name].js",
// entryFileNames: (chunkInfo) => {
// console.log(chunkInfo)
// return `${chunkInfo.name}.js`
// },
// manualChunks(id) {
// /* if (id.match('.*!/src/.*shared[a-zA-Z0-9-_]*[.](ts|js).*')) {
// // Prevent bundling node_modules into common chunks
// return 'bundle-shared';
// }
// else */{
// // Prevent bundling node_modules into common chunks
// return 'script'
// }
// },
manualChunks: undefined,
},
}
},
})
};