V0.1
This commit is contained in:
commit
6d9c19f7da
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
out
|
||||
.DS_Store
|
||||
.eslintcache
|
||||
*.log*
|
||||
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
57
.idea/codeStyles/Project.xml
Normal file
57
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<HTMLCodeStyleSettings>
|
||||
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
|
||||
</HTMLCodeStyleSettings>
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<TypeScriptCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</TypeScriptCodeStyleSettings>
|
||||
<VueCodeStyleSettings>
|
||||
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
|
||||
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
|
||||
</VueCodeStyleSettings>
|
||||
<codeStyleSettings language="HTML">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="TypeScript">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Vue">
|
||||
<option name="SOFT_MARGINS" value="80" />
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
4
.idea/deployment.xml
Normal file
4
.idea/deployment.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PublishConfigData" serverName="RK3566Linux" remoteFilesAllowedToDisappearOnAutoupload="false" />
|
||||
</project>
|
||||
12
.idea/electron_oh_bs.iml
Normal file
12
.idea/electron_oh_bs.iml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/electron_oh_bs.iml" filepath="$PROJECT_DIR$/.idea/electron_oh_bs.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
2
.npmrc
Normal file
2
.npmrc
Normal file
@ -0,0 +1,2 @@
|
||||
electron_mirror=https://npmmirror.com/mirrors/electron/
|
||||
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
|
||||
6
.prettierignore
Normal file
6
.prettierignore
Normal file
@ -0,0 +1,6 @@
|
||||
out
|
||||
dist
|
||||
pnpm-lock.yaml
|
||||
LICENSE.md
|
||||
tsconfig.json
|
||||
tsconfig.*.json
|
||||
4
.prettierrc.yaml
Normal file
4
.prettierrc.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
singleQuote: true
|
||||
semi: false
|
||||
printWidth: 100
|
||||
trailingComma: none
|
||||
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["dbaeumer.vscode-eslint"]
|
||||
}
|
||||
39
.vscode/launch.json
vendored
Normal file
39
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Main Process",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
|
||||
},
|
||||
"runtimeArgs": ["--sourcemap"],
|
||||
"env": {
|
||||
"REMOTE_DEBUGGING_PORT": "9222"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug Renderer Process",
|
||||
"port": 9222,
|
||||
"request": "attach",
|
||||
"type": "chrome",
|
||||
"webRoot": "${workspaceFolder}/src/renderer",
|
||||
"timeout": 60000,
|
||||
"presentation": {
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Debug All",
|
||||
"configurations": ["Debug Main Process", "Debug Renderer Process"],
|
||||
"presentation": {
|
||||
"order": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
34
README.md
Normal file
34
README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# electron_oh_bs
|
||||
|
||||
An Electron application with Vue and TypeScript
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||
|
||||
## Project Setup
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
$ npm run dev
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
# For windows
|
||||
$ npm run build:win
|
||||
|
||||
# For macOS
|
||||
$ npm run build:mac
|
||||
|
||||
# For Linux
|
||||
$ npm run build:linux
|
||||
```
|
||||
12
build/entitlements.mac.plist
Normal file
12
build/entitlements.mac.plist
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
build/icon.icns
Normal file
BIN
build/icon.icns
Normal file
Binary file not shown.
BIN
build/icon.ico
Normal file
BIN
build/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
BIN
build/icon.png
Normal file
BIN
build/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
3
dev-app-update.yml
Normal file
3
dev-app-update.yml
Normal file
@ -0,0 +1,3 @@
|
||||
provider: generic
|
||||
url: https://example.com/auto-updates
|
||||
updaterCacheDirName: electron_oh_bs-updater
|
||||
45
electron-builder.yml
Normal file
45
electron-builder.yml
Normal file
@ -0,0 +1,45 @@
|
||||
appId: com.electron.app
|
||||
productName: electron_oh_bs
|
||||
directories:
|
||||
buildResources: build
|
||||
files:
|
||||
- '!**/.vscode/*'
|
||||
- '!src/*'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintcache,eslint.config.mjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
|
||||
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
|
||||
asarUnpack:
|
||||
- resources/**
|
||||
win:
|
||||
executableName: electron_oh_bs
|
||||
nsis:
|
||||
artifactName: ${name}-${version}-setup.${ext}
|
||||
shortcutName: ${productName}
|
||||
uninstallDisplayName: ${productName}
|
||||
createDesktopShortcut: always
|
||||
mac:
|
||||
entitlementsInherit: build/entitlements.mac.plist
|
||||
extendInfo:
|
||||
- NSCameraUsageDescription: Application requests access to the device's camera.
|
||||
- NSMicrophoneUsageDescription: Application requests access to the device's microphone.
|
||||
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
|
||||
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
|
||||
notarize: false
|
||||
dmg:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
linux:
|
||||
target:
|
||||
- AppImage
|
||||
- snap
|
||||
- deb
|
||||
maintainer: electronjs.org
|
||||
category: Utility
|
||||
appImage:
|
||||
artifactName: ${name}-${version}.${ext}
|
||||
npmRebuild: false
|
||||
publish:
|
||||
provider: generic
|
||||
url: https://example.com/auto-updates
|
||||
electronDownload:
|
||||
mirror: https://npmmirror.com/mirrors/electron/
|
||||
18
electron.vite.config.ts
Normal file
18
electron.vite.config.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'electron-vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
export default defineConfig({
|
||||
main: {},
|
||||
preload: {},
|
||||
renderer: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@renderer': resolve('src/renderer/src'),
|
||||
'@': fileURLToPath(new URL('src/renderer/src', import.meta.url))
|
||||
}
|
||||
},
|
||||
plugins: [vue()],
|
||||
},
|
||||
})
|
||||
40
eslint.config.mjs
Normal file
40
eslint.config.mjs
Normal file
@ -0,0 +1,40 @@
|
||||
import { defineConfig } from 'eslint/config'
|
||||
import tseslint from '@electron-toolkit/eslint-config-ts'
|
||||
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
|
||||
import eslintPluginVue from 'eslint-plugin-vue'
|
||||
import vueParser from 'vue-eslint-parser'
|
||||
|
||||
export default defineConfig(
|
||||
{ ignores: ['**/node_modules', '**/dist', '**/out'] },
|
||||
tseslint.configs.recommended,
|
||||
eslintPluginVue.configs['flat/recommended'],
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parser: vueParser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
},
|
||||
extraFileExtensions: ['.vue'],
|
||||
parser: tseslint.parser
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.{ts,mts,tsx,vue}'],
|
||||
rules: {
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/block-lang': [
|
||||
'error',
|
||||
{
|
||||
script: {
|
||||
lang: 'ts'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
eslintConfigPrettier
|
||||
)
|
||||
11885
package-lock.json
generated
Normal file
11885
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
87
package.json
Normal file
87
package.json
Normal file
@ -0,0 +1,87 @@
|
||||
{
|
||||
"name": "electron_oh_bs",
|
||||
"version": "1.0.0",
|
||||
"description": "An Electron application with Vue and TypeScript",
|
||||
"main": "./out/main/index.js",
|
||||
"author": {
|
||||
"name": "example.com",
|
||||
"email": "your-email@example.com"
|
||||
},
|
||||
"homepage": "https://electron-vite.org",
|
||||
"build": {
|
||||
"appId": "com.electron.oh.bs",
|
||||
"productName": "OH_BS_APP",
|
||||
"linux": {
|
||||
"target": [
|
||||
"AppImage",
|
||||
"deb"
|
||||
],
|
||||
"category": "Utility",
|
||||
"maintainer": "Your Name <your-email@example.com>",
|
||||
"executableArgs": [
|
||||
"--show-fps-counter",
|
||||
"--no-sandbox",
|
||||
"--enable-gpu-rasterization",
|
||||
"--enable-gpu-compositing",
|
||||
"--use-gl=angle",
|
||||
"--use-angle=gl-egl",
|
||||
"--enable-features=VaapiVideoDecoder,VaapiVideoEncoder"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint --cache .",
|
||||
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
|
||||
"typecheck:web": "vue-tsc --noEmit -p tsconfig.web.json --composite false",
|
||||
"typecheck": "npm run typecheck:node && npm run typecheck:web",
|
||||
"start": "electron-vite preview",
|
||||
"dev": "electron-vite dev",
|
||||
"build": "npm run typecheck && electron-vite build",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"build:unpack": "npm run build && electron-builder --dir",
|
||||
"build:win": "npm run build && electron-builder --win",
|
||||
"build:mac": "npm run build && electron-builder --mac",
|
||||
"build:linux": "npm run build && electron-builder --linux",
|
||||
"build:arm64": "electron-builder --linux --arm64"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/preload": "^3.0.2",
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"@element-plus/icons-vue": "^2.3.2",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"axios": "^1.13.2",
|
||||
"electron-packager": "^17.1.2",
|
||||
"electron-updater": "^6.3.9",
|
||||
"element-plus": "^2.12.0",
|
||||
"nprogress": "^0.2.0",
|
||||
"simple-keyboard": "^3.8.93",
|
||||
"simple-keyboard-layouts": "^3.4.147",
|
||||
"vant": "^4.9.21",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-router": "^4.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config-prettier": "3.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
||||
"@electron-toolkit/tsconfig": "^2.0.0",
|
||||
"@types/node": "^22.19.1",
|
||||
"@vitejs/plugin-vue": "^6.0.2",
|
||||
"electron": "^39.2.6",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-vite": "^5.0.0",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-plugin-vue": "^10.6.2",
|
||||
"less": "^4.4.2",
|
||||
"prettier": "^3.7.4",
|
||||
"sass-embedded": "^1.97.1",
|
||||
"sass-loader": "^10.4.1",
|
||||
"typescript": "^5.9.3",
|
||||
"unplugin-auto-import": "^20.3.0",
|
||||
"unplugin-vue-components": "^30.0.0",
|
||||
"vite": "^7.2.6",
|
||||
"vue": "^3.5.25",
|
||||
"vue-eslint-parser": "^10.2.0",
|
||||
"vue-tsc": "^3.1.6"
|
||||
}
|
||||
}
|
||||
BIN
resources/icon.png
Normal file
BIN
resources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
110
src/main/index.ts
Normal file
110
src/main/index.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { app, shell, BrowserWindow, ipcMain } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
|
||||
import icon from '../../resources/icon.png?asset'
|
||||
import { exec } from 'child_process';
|
||||
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
|
||||
if (!gotTheLock) {
|
||||
app.quit()
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
if (process.platform === 'linux' && process.arch === 'arm64') {
|
||||
app.commandLine.appendSwitch('no-sandbox');
|
||||
app.commandLine.appendSwitch('enable-gpu-rasterization');
|
||||
app.commandLine.appendSwitch('enable-gpu-compositing');
|
||||
app.commandLine.appendSwitch('use-gl', 'angle');
|
||||
app.commandLine.appendSwitch('use-angle', 'gl-egl');
|
||||
app.commandLine.appendSwitch('enable-features', 'VaapiVideoDecoder,VaapiVideoEncoder');
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1280,
|
||||
height: 800,
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
...(process.platform === 'linux' ? { icon } : {}),
|
||||
webPreferences: {
|
||||
preload: join(__dirname, '../preload/index.js'),
|
||||
sandbox: false
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
mainWindow.show()
|
||||
})
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler((details) => {
|
||||
shell.openExternal(details.url)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
|
||||
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
||||
}
|
||||
else {
|
||||
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
||||
}
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
electronApp.setAppUserModelId('com.electron')
|
||||
app.on('browser-window-created', (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window)
|
||||
})
|
||||
ipcMain.on('ping', () => console.log('pong'))
|
||||
createWindow()
|
||||
app.on('activate', function () {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('show-keyboard', () => {
|
||||
if (process.platform === 'linux') {
|
||||
const sudoUser = process.env.SUDO_USER;
|
||||
if (sudoUser) {
|
||||
exec(`sudo -u ${sudoUser} DISPLAY=:0 onboard &`);
|
||||
}
|
||||
else {
|
||||
exec('onboard &');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('close-keyboard', () => {
|
||||
if (process.platform === 'linux') {
|
||||
const sudoUser = process.env.SUDO_USER;
|
||||
if (sudoUser) {
|
||||
exec(`sudo -u ${sudoUser} DISPLAY=:0 dbus-send --type=method_call --dest=org.onboard.Onboard /org/onboard/Onboard/Keyboard org.onboard.Onboard.Keyboard.Hide`, (error) => {
|
||||
if (error) {
|
||||
exec(`sudo -u ${sudoUser} DISPLAY=:0 wmctrl -r "Onboard" -e 0,-100,-100,0,0`, (err) => {
|
||||
if (err) {
|
||||
exec(`sudo -u ${sudoUser} pkill -f onboard`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
exec('dbus-send --type=method_call --dest=org.onboard.Onboard /org/onboard/Onboard/Keyboard org.onboard.Onboard.Keyboard.Hide', (error) => {
|
||||
if (error) {
|
||||
exec('wmctrl -r "Onboard" -e 0,-100,-100,0,0', (err) => {
|
||||
if (err) {
|
||||
exec('pkill -f onboard');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
8
src/preload/index.d.ts
vendored
Normal file
8
src/preload/index.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import { ElectronAPI } from '@electron-toolkit/preload'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electron: ElectronAPI
|
||||
api: unknown
|
||||
}
|
||||
}
|
||||
26
src/preload/index.ts
Normal file
26
src/preload/index.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { contextBridge,ipcRenderer } from 'electron'
|
||||
import { electronAPI } from '@electron-toolkit/preload'
|
||||
|
||||
// Custom APIs for renderer
|
||||
const api = {}
|
||||
|
||||
// Use `contextBridge` APIs to expose Electron APIs to
|
||||
// renderer only if context isolation is enabled, otherwise
|
||||
// just add to the DOM global.
|
||||
if (process.contextIsolated) {
|
||||
try {
|
||||
contextBridge.exposeInMainWorld('electron', electronAPI)
|
||||
contextBridge.exposeInMainWorld('api', api)
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
showKeyboard: () => ipcRenderer.send('show-keyboard'),
|
||||
closeKeyboard: () => ipcRenderer.send('close-keyboard')
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
} else {
|
||||
// @ts-ignore (define in dts)
|
||||
window.electron = electronAPI
|
||||
// @ts-ignore (define in dts)
|
||||
window.api = api
|
||||
}
|
||||
1
src/renderer/dict/address.json
Normal file
1
src/renderer/dict/address.json
Normal file
File diff suppressed because one or more lines are too long
409
src/renderer/dict/baseDict.json
Normal file
409
src/renderer/dict/baseDict.json
Normal file
@ -0,0 +1,409 @@
|
||||
{
|
||||
"a": "阿啊呵腌嗄吖锕",
|
||||
"e": "额阿俄恶鹅遏鄂厄饿峨扼娥鳄哦蛾噩愕讹锷垩婀鹗萼谔莪腭锇颚呃阏屙苊轭",
|
||||
"ai": "爱埃艾碍癌哀挨矮隘蔼唉皑哎霭捱暧嫒嗳瑷嗌锿砹",
|
||||
"ei": "诶",
|
||||
"xi": "系西席息希习吸喜细析戏洗悉锡溪惜稀袭夕洒晰昔牺腊烯熙媳栖膝隙犀蹊硒兮熄曦禧嬉玺奚汐徙羲铣淅嘻歙熹矽蟋郗唏皙隰樨浠忾蜥檄郄翕阋鳃舾屣葸螅咭粞觋欷僖醯鼷裼穸饩舄禊诶菥蓰",
|
||||
"yi": "一以已意议义益亿易医艺食依移衣异伊仪宜射遗疑毅谊亦疫役忆抑尾乙译翼蛇溢椅沂泄逸蚁夷邑怡绎彝裔姨熠贻矣屹颐倚诣胰奕翌疙弈轶蛾驿壹猗臆弋铱旖漪迤佚翊诒怿痍懿饴峄揖眙镒仡黟肄咿翳挹缢呓刈咦嶷羿钇殪荑薏蜴镱噫癔苡悒嗌瘗衤佾埸圯舣酏劓",
|
||||
"an": "安案按岸暗鞍氨俺胺铵谙庵黯鹌桉埯犴揞厂广",
|
||||
"han": "厂汉韩含旱寒汗涵函喊憾罕焊翰邯撼瀚憨捍酣悍鼾邗颔蚶晗菡旰顸犴焓撖",
|
||||
"ang": "昂仰盎肮",
|
||||
"ao": "奥澳傲熬凹鳌敖遨鏖袄坳翱嗷拗懊岙螯骜獒鏊艹媪廒聱",
|
||||
"wa": "瓦挖娃洼袜蛙凹哇佤娲呙腽",
|
||||
"yu": "于与育余预域予遇奥语誉玉鱼雨渔裕愈娱欲吁舆宇羽逾豫郁寓吾狱喻御浴愉禹俞邪榆愚渝尉淤虞屿峪粥驭瑜禺毓钰隅芋熨瘀迂煜昱汩於臾盂聿竽萸妪腴圄谕觎揄龉谀俣馀庾妤瘐鬻欤鹬阈嵛雩鹆圉蜮伛纡窬窳饫蓣狳肀舁蝓燠",
|
||||
"niu": "牛纽扭钮拗妞忸狃",
|
||||
"o": "哦噢喔",
|
||||
"ba": "把八巴拔伯吧坝爸霸罢芭跋扒叭靶疤笆耙鲅粑岜灞钯捌菝魃茇",
|
||||
"pa": "怕帕爬扒趴琶啪葩耙杷钯筢",
|
||||
"pi": "被批副否皮坏辟啤匹披疲罢僻毗坯脾譬劈媲屁琵邳裨痞癖陂丕枇噼霹吡纰砒铍淠郫埤濞睥芘蚍圮鼙罴蜱疋貔仳庀擗甓陴",
|
||||
"bi": "比必币笔毕秘避闭佛辟壁弊彼逼碧鼻臂蔽拂泌璧庇痹毙弼匕鄙陛裨贲敝蓖吡篦纰俾铋毖筚荸薜婢哔跸濞秕荜愎睥妣芘箅髀畀滗狴萆嬖襞舭",
|
||||
"bai": "百白败摆伯拜柏佰掰呗擘捭稗",
|
||||
"bo": "波博播勃拨薄佛伯玻搏柏泊舶剥渤卜驳簿脖膊簸菠礴箔铂亳钵帛擘饽跛钹趵檗啵鹁擗踣",
|
||||
"bei": "北被备倍背杯勃贝辈悲碑臂卑悖惫蓓陂钡狈呗焙碚褙庳鞴孛鹎邶鐾",
|
||||
"ban": "办版半班般板颁伴搬斑扮拌扳瓣坂阪绊钣瘢舨癍",
|
||||
"pan": "判盘番潘攀盼拚畔胖叛拌蹒磐爿蟠泮袢襻丬",
|
||||
"bin": "份宾频滨斌彬濒殡缤鬓槟摈膑玢镔豳髌傧",
|
||||
"bang": "帮邦彭旁榜棒膀镑绑傍磅蚌谤梆浜蒡",
|
||||
"pang": "旁庞乓磅螃彷滂逄耪",
|
||||
"beng": "泵崩蚌蹦迸绷甭嘣甏堋",
|
||||
"bao": "报保包宝暴胞薄爆炮饱抱堡剥鲍曝葆瀑豹刨褒雹孢苞煲褓趵鸨龅勹",
|
||||
"bu": "不部步布补捕堡埔卜埠簿哺怖钚卟瓿逋晡醭钸",
|
||||
"pu": "普暴铺浦朴堡葡谱埔扑仆蒲曝瀑溥莆圃璞濮菩蹼匍噗氆攵镨攴镤",
|
||||
"mian": "面棉免绵缅勉眠冕娩腼渑湎沔黾宀眄",
|
||||
"po": "破繁坡迫颇朴泊婆泼魄粕鄱珀陂叵笸泺皤钋钷",
|
||||
"fan": "反范犯繁饭泛翻凡返番贩烦拚帆樊藩矾梵蕃钒幡畈蘩蹯燔",
|
||||
"fu": "府服副负富复福夫妇幅付扶父符附腐赴佛浮覆辅傅伏抚赋辐腹弗肤阜袱缚甫氟斧孚敷俯拂俘咐腑孵芙涪釜脯茯馥宓绂讣呋罘麸蝠匐芾蜉跗凫滏蝮驸绋蚨砩桴赙菔呒趺苻拊阝鲋怫稃郛莩幞祓艴黻黼鳆",
|
||||
"ben": "本体奔苯笨夯贲锛畚坌",
|
||||
"feng": "风丰封峰奉凤锋冯逢缝蜂枫疯讽烽俸沣酆砜葑唪",
|
||||
"bian": "变便边编遍辩鞭辨贬匾扁卞汴辫砭苄蝙鳊弁窆笾煸褊碥忭缏",
|
||||
"pian": "便片篇偏骗翩扁骈胼蹁谝犏缏",
|
||||
"zhen": "镇真针圳振震珍阵诊填侦臻贞枕桢赈祯帧甄斟缜箴疹砧榛鸩轸稹溱蓁胗椹朕畛浈",
|
||||
"biao": "表标彪镖裱飚膘飙镳婊骠飑杓髟鳔灬瘭",
|
||||
"piao": "票朴漂飘嫖瓢剽缥殍瞟骠嘌莩螵",
|
||||
"huo": "和活或货获火伙惑霍祸豁嚯藿锪蠖钬耠镬夥灬劐攉",
|
||||
"bie": "别鳖憋瘪蹩",
|
||||
"min": "民敏闽闵皿泯岷悯珉抿黾缗玟愍苠鳘",
|
||||
"fen": "分份纷奋粉氛芬愤粪坟汾焚酚吩忿棼玢鼢瀵偾鲼",
|
||||
"bing": "并病兵冰屏饼炳秉丙摒柄槟禀枋邴冫",
|
||||
"geng": "更耕颈庚耿梗埂羹哽赓绠鲠",
|
||||
"fang": "方放房防访纺芳仿坊妨肪邡舫彷枋鲂匚钫",
|
||||
"xian": "现先县见线限显险献鲜洗宪纤陷闲贤仙衔掀咸嫌掺羡弦腺痫娴舷馅酰铣冼涎暹籼锨苋蚬跹岘藓燹鹇氙莶霰跣猃彡祆筅",
|
||||
"fou": "不否缶",
|
||||
"ca": "拆擦嚓礤",
|
||||
"cha": "查察差茶插叉刹茬楂岔诧碴嚓喳姹杈汊衩搽槎镲苴檫馇锸猹",
|
||||
"cai": "才采财材菜彩裁蔡猜踩睬",
|
||||
"can": "参残餐灿惨蚕掺璨惭粲孱骖黪",
|
||||
"shen": "信深参身神什审申甚沈伸慎渗肾绅莘呻婶娠砷蜃哂椹葚吲糁渖诜谂矧胂",
|
||||
"cen": "参岑涔",
|
||||
"san": "三参散伞叁糁馓毵",
|
||||
"cang": "藏仓苍沧舱臧伧",
|
||||
"zang": "藏脏葬赃臧奘驵",
|
||||
"chen": "称陈沈沉晨琛臣尘辰衬趁忱郴宸谌碜嗔抻榇伧谶龀肜",
|
||||
"cao": "草操曹槽糙嘈漕螬艚屮",
|
||||
"ce": "策测册侧厕栅恻",
|
||||
"ze": "责则泽择侧咋啧仄箦赜笮舴昃迮帻",
|
||||
"zhai": "债择齐宅寨侧摘窄斋祭翟砦瘵哜",
|
||||
"dao": "到道导岛倒刀盗稻蹈悼捣叨祷焘氘纛帱忉",
|
||||
"ceng": "层曾蹭噌",
|
||||
"zha": "查扎炸诈闸渣咋乍榨楂札栅眨咤柞喳喋铡蚱吒怍砟揸痄哳齄",
|
||||
"chai": "差拆柴钗豺侪虿瘥",
|
||||
"ci": "次此差词辞刺瓷磁兹慈茨赐祠伺雌疵鹚糍呲粢",
|
||||
"zi": "资自子字齐咨滋仔姿紫兹孜淄籽梓鲻渍姊吱秭恣甾孳訾滓锱辎趑龇赀眦缁呲笫谘嵫髭茈粢觜耔",
|
||||
"cuo": "措错磋挫搓撮蹉锉厝嵯痤矬瘥脞鹾",
|
||||
"chan": "产单阐崭缠掺禅颤铲蝉搀潺蟾馋忏婵孱觇廛谄谗澶骣羼躔蒇冁",
|
||||
"shan": "山单善陕闪衫擅汕扇掺珊禅删膳缮赡鄯栅煽姗跚鳝嬗潸讪舢苫疝掸膻钐剡蟮芟埏彡骟",
|
||||
"zhan": "展战占站崭粘湛沾瞻颤詹斩盏辗绽毡栈蘸旃谵搌",
|
||||
"xin": "新心信辛欣薪馨鑫芯锌忻莘昕衅歆囟忄镡",
|
||||
"lian": "联连练廉炼脸莲恋链帘怜涟敛琏镰濂楝鲢殓潋裢裣臁奁莶蠊蔹",
|
||||
"chang": "场长厂常偿昌唱畅倡尝肠敞倘猖娼淌裳徜昶怅嫦菖鲳阊伥苌氅惝鬯",
|
||||
"zhang": "长张章障涨掌帐胀彰丈仗漳樟账杖璋嶂仉瘴蟑獐幛鄣嫜",
|
||||
"chao": "超朝潮炒钞抄巢吵剿绰嘲晁焯耖怊",
|
||||
"zhao": "着照招找召朝赵兆昭肇罩钊沼嘲爪诏濯啁棹笊",
|
||||
"zhou": "调州周洲舟骤轴昼宙粥皱肘咒帚胄绉纣妯啁诌繇碡籀酎荮",
|
||||
"che": "车彻撤尺扯澈掣坼砗屮",
|
||||
"ju": "车局据具举且居剧巨聚渠距句拒俱柜菊拘炬桔惧矩鞠驹锯踞咀瞿枸掬沮莒橘飓疽钜趄踽遽琚龃椐苣裾榘狙倨榉苴讵雎锔窭鞫犋屦醵",
|
||||
"cheng": "成程城承称盛抢乘诚呈净惩撑澄秤橙骋逞瞠丞晟铛埕塍蛏柽铖酲裎枨",
|
||||
"rong": "容荣融绒溶蓉熔戎榕茸冗嵘肜狨蝾",
|
||||
"sheng": "生声升胜盛乘圣剩牲甸省绳笙甥嵊晟渑眚",
|
||||
"deng": "等登邓灯澄凳瞪蹬噔磴嶝镫簦戥",
|
||||
"zhi": "制之治质职只志至指织支值知识直致执置止植纸拓智殖秩旨址滞氏枝芝脂帜汁肢挚稚酯掷峙炙栉侄芷窒咫吱趾痔蜘郅桎雉祉郦陟痣蛭帙枳踯徵胝栀贽祗豸鸷摭轵卮轾彘觯絷跖埴夂黹忮骘膣踬",
|
||||
"zheng": "政正证争整征郑丁症挣蒸睁铮筝拯峥怔诤狰徵钲",
|
||||
"tang": "堂唐糖汤塘躺趟倘棠烫淌膛搪镗傥螳溏帑羰樘醣螗耥铴瑭",
|
||||
"chi": "持吃池迟赤驰尺斥齿翅匙痴耻炽侈弛叱啻坻眙嗤墀哧茌豉敕笞饬踟蚩柢媸魑篪褫彳鸱螭瘛眵傺",
|
||||
"shi": "是时实事市十使世施式势视识师史示石食始士失适试什泽室似诗饰殖释驶氏硕逝湿蚀狮誓拾尸匙仕柿矢峙侍噬嗜栅拭嘘屎恃轼虱耆舐莳铈谥炻豕鲥饣螫酾筮埘弑礻蓍鲺贳",
|
||||
"qi": "企其起期气七器汽奇齐启旗棋妻弃揭枝歧欺骑契迄亟漆戚岂稽岐琦栖缉琪泣乞砌祁崎绮祺祈凄淇杞脐麒圻憩芪伎俟畦耆葺沏萋骐鳍綦讫蕲屺颀亓碛柒啐汔綮萁嘁蛴槭欹芑桤丌蜞",
|
||||
"chuai": "揣踹啜搋膪",
|
||||
"tuo": "托脱拓拖妥驼陀沱鸵驮唾椭坨佗砣跎庹柁橐乇铊沲酡鼍箨柝",
|
||||
"duo": "多度夺朵躲铎隋咄堕舵垛惰哆踱跺掇剁柁缍沲裰哚隳",
|
||||
"xue": "学血雪削薛穴靴谑噱鳕踅泶彐",
|
||||
"chong": "重种充冲涌崇虫宠忡憧舂茺铳艟",
|
||||
"chou": "筹抽绸酬愁丑臭仇畴稠瞅踌惆俦瘳雠帱",
|
||||
"qiu": "求球秋丘邱仇酋裘龟囚遒鳅虬蚯泅楸湫犰逑巯艽俅蝤赇鼽糗",
|
||||
"xiu": "修秀休宿袖绣臭朽锈羞嗅岫溴庥馐咻髹鸺貅",
|
||||
"chu": "出处础初助除储畜触楚厨雏矗橱锄滁躇怵绌搐刍蜍黜杵蹰亍樗憷楮",
|
||||
"tuan": "团揣湍疃抟彖",
|
||||
"zhui": "追坠缀揣椎锥赘惴隹骓缒",
|
||||
"chuan": "传川船穿串喘椽舛钏遄氚巛舡",
|
||||
"zhuan": "专转传赚砖撰篆馔啭颛",
|
||||
"yuan": "元员院原源远愿园援圆缘袁怨渊苑宛冤媛猿垣沅塬垸鸳辕鸢瑗圜爰芫鼋橼螈眢箢掾",
|
||||
"cuan": "窜攒篡蹿撺爨汆镩",
|
||||
"chuang": "创床窗闯幢疮怆",
|
||||
"zhuang": "装状庄壮撞妆幢桩奘僮戆",
|
||||
"chui": "吹垂锤炊椎陲槌捶棰",
|
||||
"chun": "春纯醇淳唇椿蠢鹑朐莼肫蝽",
|
||||
"zhun": "准屯淳谆肫窀",
|
||||
"cu": "促趋趣粗簇醋卒蹴猝蹙蔟殂徂",
|
||||
"dun": "吨顿盾敦蹲墩囤沌钝炖盹遁趸砘礅",
|
||||
"qu": "区去取曲趋渠趣驱屈躯衢娶祛瞿岖龋觑朐蛐癯蛆苣阒诎劬蕖蘧氍黢蠼璩麴鸲磲",
|
||||
"xu": "需许续须序徐休蓄畜虚吁绪叙旭邪恤墟栩絮圩婿戌胥嘘浒煦酗诩朐盱蓿溆洫顼勖糈砉醑",
|
||||
"xv": "需许续须序徐休蓄畜虚吁绪叙旭邪恤墟栩絮圩婿戌胥嘘浒煦酗诩朐盱蓿溆洫顼勖糈砉醑",
|
||||
"chuo": "辍绰戳淖啜龊踔辶",
|
||||
"zu": "组族足祖租阻卒俎诅镞菹",
|
||||
"ji": "济机其技基记计系期际及集级几给积极己纪即继击既激绩急奇吉季齐疾迹鸡剂辑籍寄挤圾冀亟寂暨脊跻肌稽忌饥祭缉棘矶汲畸姬藉瘠骥羁妓讥稷蓟悸嫉岌叽伎鲫诘楫荠戟箕霁嵇觊麂畿玑笈犄芨唧屐髻戢佶偈笄跽蒺乩咭赍嵴虮掎齑殛鲚剞洎丌墼蕺彐芰哜",
|
||||
"cong": "从丛匆聪葱囱琮淙枞骢苁璁",
|
||||
"zong": "总从综宗纵踪棕粽鬃偬枞腙",
|
||||
"cou": "凑辏腠楱",
|
||||
"cui": "衰催崔脆翠萃粹摧璀瘁悴淬啐隹毳榱",
|
||||
"wei": "为位委未维卫围违威伟危味微唯谓伪慰尾魏韦胃畏帷喂巍萎蔚纬潍尉渭惟薇苇炜圩娓诿玮崴桅偎逶倭猥囗葳隗痿猬涠嵬韪煨艉隹帏闱洧沩隈鲔軎",
|
||||
"cun": "村存寸忖皴",
|
||||
"zuo": "作做座左坐昨佐琢撮祚柞唑嘬酢怍笮阼胙",
|
||||
"zuan": "钻纂攥缵躜",
|
||||
"da": "大达打答搭沓瘩惮嗒哒耷鞑靼褡笪怛妲",
|
||||
"dai": "大代带待贷毒戴袋歹呆隶逮岱傣棣怠殆黛甙埭诒绐玳呔迨",
|
||||
"tai": "大台太态泰抬胎汰钛苔薹肽跆邰鲐酞骀炱",
|
||||
"ta": "他它她拓塔踏塌榻沓漯獭嗒挞蹋趿遢铊鳎溻闼",
|
||||
"dan": "但单石担丹胆旦弹蛋淡诞氮郸耽殚惮儋眈疸澹掸膻啖箪聃萏瘅赕",
|
||||
"lu": "路六陆录绿露鲁卢炉鹿禄赂芦庐碌麓颅泸卤潞鹭辘虏璐漉噜戮鲈掳橹轳逯渌蓼撸鸬栌氇胪镥簏舻辂垆",
|
||||
"tan": "谈探坦摊弹炭坛滩贪叹谭潭碳毯瘫檀痰袒坍覃忐昙郯澹钽锬",
|
||||
"ren": "人任认仁忍韧刃纫饪妊荏稔壬仞轫衽",
|
||||
"jie": "家结解价界接节她届介阶街借杰洁截姐揭捷劫戒皆竭桔诫楷秸睫藉拮芥诘碣嗟颉蚧孑婕疖桀讦疥偈羯袷哜喈卩鲒骱",
|
||||
"yan": "研严验演言眼烟沿延盐炎燕岩宴艳颜殷彦掩淹阎衍铅雁咽厌焰堰砚唁焉晏檐蜒奄俨腌妍谚兖筵焱偃闫嫣鄢湮赝胭琰滟阉魇酽郾恹崦芫剡鼹菸餍埏谳讠厣罨",
|
||||
"dang": "当党档荡挡宕砀铛裆凼菪谠",
|
||||
"tao": "套讨跳陶涛逃桃萄淘掏滔韬叨洮啕绦饕鼗",
|
||||
"tiao": "条调挑跳迢眺苕窕笤佻啁粜髫铫祧龆蜩鲦",
|
||||
"te": "特忑忒铽慝",
|
||||
"de": "的地得德底锝",
|
||||
"dei": "得",
|
||||
"di": "的地第提低底抵弟迪递帝敌堤蒂缔滴涤翟娣笛棣荻谛狄邸嘀砥坻诋嫡镝碲骶氐柢籴羝睇觌",
|
||||
"ti": "体提题弟替梯踢惕剔蹄棣啼屉剃涕锑倜悌逖嚏荑醍绨鹈缇裼",
|
||||
"tui": "推退弟腿褪颓蜕忒煺",
|
||||
"you": "有由又优游油友右邮尤忧幼犹诱悠幽佑釉柚铀鱿囿酉攸黝莠猷蝣疣呦蚴莸莜铕宥繇卣牖鼬尢蚰侑",
|
||||
"dian": "电点店典奠甸碘淀殿垫颠滇癫巅惦掂癜玷佃踮靛钿簟坫阽",
|
||||
"tian": "天田添填甜甸恬腆佃舔钿阗忝殄畋栝掭",
|
||||
"zhu": "主术住注助属逐宁著筑驻朱珠祝猪诸柱竹铸株瞩嘱贮煮烛苎褚蛛拄铢洙竺蛀渚伫杼侏澍诛茱箸炷躅翥潴邾槠舳橥丶瘃麈疰",
|
||||
"nian": "年念酿辗碾廿捻撵拈蔫鲶埝鲇辇黏",
|
||||
"diao": "调掉雕吊钓刁貂凋碉鲷叼铫铞",
|
||||
"yao": "要么约药邀摇耀腰遥姚窑瑶咬尧钥谣肴夭侥吆疟妖幺杳舀窕窈曜鹞爻繇徭轺铫鳐崾珧",
|
||||
"die": "跌叠蝶迭碟爹谍牒耋佚喋堞瓞鲽垤揲蹀",
|
||||
"she": "设社摄涉射折舍蛇拾舌奢慑赦赊佘麝歙畲厍猞揲滠",
|
||||
"ye": "业也夜叶射野液冶喝页爷耶邪咽椰烨掖拽曳晔谒腋噎揶靥邺铘揲",
|
||||
"xie": "些解协写血叶谢械鞋胁斜携懈契卸谐泄蟹邪歇泻屑挟燮榭蝎撷偕亵楔颉缬邂鲑瀣勰榍薤绁渫廨獬躞",
|
||||
"zhe": "这者着著浙折哲蔗遮辙辄柘锗褶蜇蛰鹧谪赭摺乇磔螫",
|
||||
"ding": "定订顶丁鼎盯钉锭叮仃铤町酊啶碇腚疔玎耵",
|
||||
"diu": "丢铥",
|
||||
"ting": "听庭停厅廷挺亭艇婷汀铤烃霆町蜓葶梃莛",
|
||||
"dong": "动东董冬洞懂冻栋侗咚峒氡恫胴硐垌鸫岽胨",
|
||||
"tong": "同通统童痛铜桶桐筒彤侗佟潼捅酮砼瞳恸峒仝嗵僮垌茼",
|
||||
"zhong": "中重种众终钟忠仲衷肿踵冢盅蚣忪锺舯螽夂",
|
||||
"zhon": "中重种众终钟忠仲衷肿踵冢盅蚣忪锺舯螽夂",
|
||||
"zho": "钟中调种州重周洲舟忠肿众终仲骤衷轴昼宙粥皱肘咒帚胄绉纣妯啁诌繇碡籀酎荮踵冢盅蚣忪锺舯螽夂",
|
||||
"dou": "都斗读豆抖兜陡逗窦渎蚪痘蔸钭篼",
|
||||
"du": "度都独督读毒渡杜堵赌睹肚镀渎笃竺嘟犊妒牍蠹椟黩芏髑",
|
||||
"duan": "断段短端锻缎煅椴簖",
|
||||
"dui": "对队追敦兑堆碓镦怼憝",
|
||||
"rui": "瑞兑锐睿芮蕊蕤蚋枘",
|
||||
"yue": "月说约越乐跃兑阅岳粤悦曰钥栎钺樾瀹龠哕刖",
|
||||
"tun": "吞屯囤褪豚臀饨暾氽",
|
||||
"hui": "会回挥汇惠辉恢徽绘毁慧灰贿卉悔秽溃荟晖彗讳诲珲堕诙蕙晦睢麾烩茴喙桧蛔洄浍虺恚蟪咴隳缋哕",
|
||||
"wu": "务物无五武午吴舞伍污乌误亡恶屋晤悟吾雾芜梧勿巫侮坞毋诬呜钨邬捂鹜兀婺妩於戊鹉浯蜈唔骛仵焐芴鋈庑鼯牾怃圬忤痦迕杌寤阢",
|
||||
"ya": "亚压雅牙押鸭呀轧涯崖邪芽哑讶鸦娅衙丫蚜碣垭伢氩桠琊揠吖睚痖疋迓岈砑",
|
||||
"he": "和合河何核盖贺喝赫荷盒鹤吓呵苛禾菏壑褐涸阂阖劾诃颌嗬貉曷翮纥盍",
|
||||
"wo": "我握窝沃卧挝涡斡渥幄蜗喔倭莴龌肟硪",
|
||||
"en": "恩摁蒽",
|
||||
"n": "嗯唔",
|
||||
"er": "而二尔儿耳迩饵洱贰铒珥佴鸸鲕",
|
||||
"fa": "发法罚乏伐阀筏砝垡珐",
|
||||
"quan": "全权券泉圈拳劝犬铨痊诠荃醛蜷颧绻筌鬈悛辁畎",
|
||||
"fei": "费非飞肥废菲肺啡沸匪斐蜚妃诽扉翡霏吠绯腓痱芾淝悱狒榧砩鲱篚镄",
|
||||
"pei": "配培坏赔佩陪沛裴胚妃霈淠旆帔呸醅辔锫",
|
||||
"ping": "平评凭瓶冯屏萍苹乒坪枰娉俜鲆",
|
||||
"fo": "佛",
|
||||
"hu": "和护许户核湖互乎呼胡戏忽虎沪糊壶葫狐蝴弧瑚浒鹄琥扈唬滹惚祜囫斛笏芴醐猢怙唿戽槲觳煳鹕冱瓠虍岵鹱烀轷",
|
||||
"ga": "夹咖嘎尬噶旮伽尕钆尜",
|
||||
"ge": "个合各革格歌哥盖隔割阁戈葛鸽搁胳舸疙铬骼蛤咯圪镉颌仡硌嗝鬲膈纥袼搿塥哿虼",
|
||||
"ha": "哈蛤铪",
|
||||
"xia": "下夏峡厦辖霞夹虾狭吓侠暇遐瞎匣瑕唬呷黠硖罅狎瘕柙",
|
||||
"gai": "改该盖概溉钙丐芥赅垓陔戤",
|
||||
"hai": "海还害孩亥咳骸骇氦嗨胲醢",
|
||||
"gan": "干感赶敢甘肝杆赣乾柑尴竿秆橄矸淦苷擀酐绀泔坩旰疳澉",
|
||||
"gang": "港钢刚岗纲冈杠缸扛肛罡戆筻",
|
||||
"jiang": "将强江港奖讲降疆蒋姜浆匠酱僵桨绛缰犟豇礓洚茳糨耩",
|
||||
"hang": "行航杭巷夯吭桁沆绗颃",
|
||||
"gong": "工公共供功红贡攻宫巩龚恭拱躬弓汞蚣珙觥肱廾",
|
||||
"hong": "红宏洪轰虹鸿弘哄烘泓訇蕻闳讧荭黉薨",
|
||||
"guang": "广光逛潢犷胱咣桄",
|
||||
"qiong": "穷琼穹邛茕筇跫蛩銎",
|
||||
"gao": "高告搞稿膏糕镐皋羔锆杲郜睾诰藁篙缟槁槔",
|
||||
"hao": "好号毫豪耗浩郝皓昊皋蒿壕灏嚎濠蚝貉颢嗥薅嚆",
|
||||
"li": "理力利立里李历例离励礼丽黎璃厉厘粒莉梨隶栗荔沥犁漓哩狸藜罹篱鲤砺吏澧俐骊溧砾莅锂笠蠡蛎痢雳俪傈醴栎郦俚枥喱逦娌鹂戾砬唳坜疠蜊黧猁鬲粝蓠呖跞疬缡鲡鳢嫠詈悝苈篥轹",
|
||||
"jia": "家加价假佳架甲嘉贾驾嫁夹稼钾挟拮迦伽颊浃枷戛荚痂颉镓笳珈岬胛袈郏葭袷瘕铗跏蛱恝哿",
|
||||
"luo": "落罗络洛逻螺锣骆萝裸漯烙摞骡咯箩珞捋荦硌雒椤镙跞瘰泺脶猡倮蠃",
|
||||
"ke": "可科克客刻课颗渴壳柯棵呵坷恪苛咳磕珂稞瞌溘轲窠嗑疴蝌岢铪颏髁蚵缂氪骒钶锞",
|
||||
"qia": "卡恰洽掐髂袷咭葜",
|
||||
"gei": "给",
|
||||
"gen": "根跟亘艮哏茛",
|
||||
"hen": "很狠恨痕哏",
|
||||
"gou": "构购够句沟狗钩拘勾苟垢枸篝佝媾诟岣彀缑笱鞲觏遘",
|
||||
"kou": "口扣寇叩抠佝蔻芤眍筘",
|
||||
"gu": "股古顾故固鼓骨估谷贾姑孤雇辜菇沽咕呱锢钴箍汩梏痼崮轱鸪牯蛊诂毂鹘菰罟嘏臌觚瞽蛄酤牿鲴",
|
||||
"pai": "牌排派拍迫徘湃俳哌蒎",
|
||||
"gua": "括挂瓜刮寡卦呱褂剐胍诖鸹栝呙",
|
||||
"tou": "投头透偷愉骰亠",
|
||||
"guai": "怪拐乖",
|
||||
"kuai": "会快块筷脍蒯侩浍郐蒉狯哙",
|
||||
"guan": "关管观馆官贯冠惯灌罐莞纶棺斡矜倌鹳鳏盥掼涫",
|
||||
"wan": "万完晚湾玩碗顽挽弯蔓丸莞皖宛婉腕蜿惋烷琬畹豌剜纨绾脘菀芄箢",
|
||||
"ne": "呢哪呐讷疒",
|
||||
"gui": "规贵归轨桂柜圭鬼硅瑰跪龟匮闺诡癸鳜桧皈鲑刽晷傀眭妫炅庋簋刿宄匦",
|
||||
"jun": "军均俊君峻菌竣钧骏龟浚隽郡筠皲麇捃",
|
||||
"jiong": "窘炯迥炅冂扃",
|
||||
"jue": "决绝角觉掘崛诀獗抉爵嚼倔厥蕨攫珏矍蹶谲镢鳜噱桷噘撅橛孓觖劂爝",
|
||||
"gun": "滚棍辊衮磙鲧绲",
|
||||
"hun": "婚混魂浑昏棍珲荤馄诨溷阍",
|
||||
"guo": "国过果郭锅裹帼涡椁囗蝈虢聒埚掴猓崞蜾呙馘",
|
||||
"hei": "黑嘿嗨",
|
||||
"kan": "看刊勘堪坎砍侃嵌槛瞰阚龛戡凵莰",
|
||||
"heng": "衡横恒亨哼珩桁蘅",
|
||||
"mo": "万没么模末冒莫摩墨默磨摸漠脉膜魔沫陌抹寞蘑摹蓦馍茉嘿谟秣蟆貉嫫镆殁耱嬷麽瘼貊貘",
|
||||
"peng": "鹏朋彭膨蓬碰苹棚捧亨烹篷澎抨硼怦砰嘭蟛堋",
|
||||
"hou": "后候厚侯猴喉吼逅篌糇骺後鲎瘊堠",
|
||||
"hua": "化华划话花画滑哗豁骅桦猾铧砉",
|
||||
"huai": "怀坏淮徊槐踝",
|
||||
"huan": "还环换欢患缓唤焕幻痪桓寰涣宦垸洹浣豢奂郇圜獾鲩鬟萑逭漶锾缳擐",
|
||||
"xun": "讯训迅孙寻询循旬巡汛勋逊熏徇浚殉驯鲟薰荀浔洵峋埙巽郇醺恂荨窨蕈曛獯",
|
||||
"huang": "黄荒煌皇凰慌晃潢谎惶簧璜恍幌湟蝗磺隍徨遑肓篁鳇蟥癀",
|
||||
"nai": "能乃奶耐奈鼐萘氖柰佴艿",
|
||||
"luan": "乱卵滦峦鸾栾銮挛孪脔娈",
|
||||
"qie": "切且契窃茄砌锲怯伽惬妾趄挈郄箧慊",
|
||||
"jian": "建间件见坚检健监减简艰践兼鉴键渐柬剑尖肩舰荐箭浅剪俭碱茧奸歼拣捡煎贱溅槛涧堑笺谏饯锏缄睑謇蹇腱菅翦戬毽笕犍硷鞯牮枧湔鲣囝裥踺搛缣鹣蒹谫僭戋趼楗",
|
||||
"nan": "南难男楠喃囡赧腩囝蝻",
|
||||
"qian": "前千钱签潜迁欠纤牵浅遣谦乾铅歉黔谴嵌倩钳茜虔堑钎骞阡掮钤扦芊犍荨仟芡悭缱佥愆褰凵肷岍搴箝慊椠",
|
||||
"qiang": "强抢疆墙枪腔锵呛羌蔷襁羟跄樯戕嫱戗炝镪锖蜣",
|
||||
"xiang": "向项相想乡象响香降像享箱羊祥湘详橡巷翔襄厢镶飨饷缃骧芗庠鲞葙蟓",
|
||||
"jiao": "教交较校角觉叫脚缴胶轿郊焦骄浇椒礁佼蕉娇矫搅绞酵剿嚼饺窖跤蛟侥狡姣皎茭峤铰醮鲛湫徼鹪僬噍艽挢敫",
|
||||
"zhuo": "着著缴桌卓捉琢灼浊酌拙茁涿镯淖啄濯焯倬擢斫棹诼浞禚",
|
||||
"qiao": "桥乔侨巧悄敲俏壳雀瞧翘窍峭锹撬荞跷樵憔鞘橇峤诮谯愀鞒硗劁缲",
|
||||
"xiao": "小效销消校晓笑肖削孝萧俏潇硝宵啸嚣霄淆哮筱逍姣箫骁枭哓绡蛸崤枵魈",
|
||||
"si": "司四思斯食私死似丝饲寺肆撕泗伺嗣祀厮驷嘶锶俟巳蛳咝耜笥纟糸鸶缌澌姒汜厶兕",
|
||||
"kai": "开凯慨岂楷恺揩锴铠忾垲剀锎蒈",
|
||||
"jin": "进金今近仅紧尽津斤禁锦劲晋谨筋巾浸襟靳瑾烬缙钅矜觐堇馑荩噤廑妗槿赆衿卺",
|
||||
"qin": "亲勤侵秦钦琴禽芹沁寝擒覃噙矜嗪揿溱芩衾廑锓吣檎螓",
|
||||
"jing": "经京精境竞景警竟井惊径静劲敬净镜睛晶颈荆兢靖泾憬鲸茎腈菁胫阱旌粳靓痉箐儆迳婧肼刭弪獍",
|
||||
"ying": "应营影英景迎映硬盈赢颖婴鹰荧莹樱瑛蝇萦莺颍膺缨瀛楹罂荥萤鹦滢蓥郢茔嘤璎嬴瘿媵撄潆",
|
||||
"jiu": "就究九酒久救旧纠舅灸疚揪咎韭玖臼柩赳鸠鹫厩啾阄桕僦鬏",
|
||||
"zui": "最罪嘴醉咀蕞觜",
|
||||
"juan": "卷捐圈眷娟倦绢隽镌涓鹃鄄蠲狷锩桊",
|
||||
"suan": "算酸蒜狻",
|
||||
"yun": "员运云允孕蕴韵酝耘晕匀芸陨纭郧筠恽韫郓氲殒愠昀菀狁",
|
||||
"qun": "群裙逡麇",
|
||||
"ka": "卡喀咖咔咯佧胩",
|
||||
"kang": "康抗扛慷炕亢糠伉钪闶",
|
||||
"keng": "坑铿吭",
|
||||
"kao": "考靠烤拷铐栲尻犒",
|
||||
"ken": "肯垦恳啃龈裉",
|
||||
"yin": "因引银印音饮阴隐姻殷淫尹荫吟瘾寅茵圻垠鄞湮蚓氤胤龈窨喑铟洇狺夤廴吲霪茚堙",
|
||||
"kong": "空控孔恐倥崆箜",
|
||||
"ku": "苦库哭酷裤枯窟挎骷堀绔刳喾",
|
||||
"kua": "跨夸垮挎胯侉",
|
||||
"kui": "亏奎愧魁馈溃匮葵窥盔逵睽馗聩喟夔篑岿喹揆隗傀暌跬蒉愦悝蝰",
|
||||
"kuan": "款宽髋",
|
||||
"kuang": "况矿框狂旷眶匡筐邝圹哐贶夼诳诓纩",
|
||||
"que": "确却缺雀鹊阙瘸榷炔阕悫",
|
||||
"kun": "困昆坤捆琨锟鲲醌髡悃阃",
|
||||
"kuo": "扩括阔廓蛞",
|
||||
"la": "拉落垃腊啦辣蜡喇剌旯砬邋瘌",
|
||||
"lai": "来莱赖睐徕籁涞赉濑癞崃疠铼",
|
||||
"lan": "兰览蓝篮栏岚烂滥缆揽澜拦懒榄斓婪阑褴罱啉谰镧漤",
|
||||
"lin": "林临邻赁琳磷淋麟霖鳞凛拎遴蔺吝粼嶙躏廪檩啉辚膦瞵懔",
|
||||
"lang": "浪朗郎廊狼琅榔螂阆锒莨啷蒗稂",
|
||||
"liang": "量两粮良辆亮梁凉谅粱晾靓踉莨椋魉墚",
|
||||
"lao": "老劳落络牢捞涝烙姥佬崂唠酪潦痨醪铑铹栳耢",
|
||||
"mu": "目模木亩幕母牧莫穆姆墓慕牟牡募睦缪沐暮拇姥钼苜仫毪坶",
|
||||
"le": "了乐勒肋叻鳓嘞仂泐",
|
||||
"lei": "类累雷勒泪蕾垒磊擂镭肋羸耒儡嫘缧酹嘞诔檑",
|
||||
"sui": "随岁虽碎尿隧遂髓穗绥隋邃睢祟濉燧谇眭荽",
|
||||
"lie": "列烈劣裂猎冽咧趔洌鬣埒捩躐",
|
||||
"leng": "冷愣棱楞塄",
|
||||
"ling": "领令另零灵龄陵岭凌玲铃菱棱伶羚苓聆翎泠瓴囹绫呤棂蛉酃鲮柃",
|
||||
"lia": "俩",
|
||||
"liao": "了料疗辽廖聊寥缪僚燎缭撂撩嘹潦镣寮蓼獠钌尥鹩",
|
||||
"liu": "流刘六留柳瘤硫溜碌浏榴琉馏遛鎏骝绺镏旒熘鹨锍",
|
||||
"lun": "论轮伦仑纶沦抡囵",
|
||||
"lv": "率律旅绿虑履吕铝屡氯缕滤侣驴榈闾偻褛捋膂稆",
|
||||
"lou": "楼露漏陋娄搂篓喽镂偻瘘髅耧蝼嵝蒌",
|
||||
"mao": "贸毛矛冒貌茂茅帽猫髦锚懋袤牦卯铆耄峁瑁蟊茆蝥旄泖昴瞀",
|
||||
"long": "龙隆弄垄笼拢聋陇胧珑窿茏咙砻垅泷栊癃",
|
||||
"nong": "农浓弄脓侬哝",
|
||||
"shuang": "双爽霜孀泷",
|
||||
"shu": "术书数属树输束述署朱熟殊蔬舒疏鼠淑叔暑枢墅俞曙抒竖蜀薯梳戍恕孰沭赎庶漱塾倏澍纾姝菽黍腧秫毹殳疋摅",
|
||||
"shuai": "率衰帅摔甩蟀",
|
||||
"lve": "略掠锊",
|
||||
"ma": "么马吗摩麻码妈玛嘛骂抹蚂唛蟆犸杩",
|
||||
"me": "么麽",
|
||||
"mai": "买卖麦迈脉埋霾荬劢",
|
||||
"man": "满慢曼漫埋蔓瞒蛮鳗馒幔谩螨熳缦镘颟墁鞔",
|
||||
"mi": "米密秘迷弥蜜谜觅靡泌眯麋猕谧咪糜宓汨醚嘧弭脒冖幂祢縻蘼芈糸敉",
|
||||
"men": "们门闷瞒汶扪焖懑鞔钔",
|
||||
"mang": "忙盲茫芒氓莽蟒邙硭漭",
|
||||
"meng": "蒙盟梦猛孟萌氓朦锰檬勐懵蟒蜢虻黾蠓艨甍艋瞢礞",
|
||||
"miao": "苗秒妙描庙瞄缪渺淼藐缈邈鹋杪眇喵",
|
||||
"mou": "某谋牟缪眸哞鍪蛑侔厶",
|
||||
"miu": "缪谬",
|
||||
"mei": "美没每煤梅媒枚妹眉魅霉昧媚玫酶镁湄寐莓袂楣糜嵋镅浼猸鹛",
|
||||
"wen": "文问闻稳温纹吻蚊雯紊瘟汶韫刎璺玟阌",
|
||||
"mie": "灭蔑篾乜咩蠛",
|
||||
"ming": "明名命鸣铭冥茗溟酩瞑螟暝",
|
||||
"na": "内南那纳拿哪娜钠呐捺衲镎肭",
|
||||
"nei": "内那哪馁",
|
||||
"nuo": "难诺挪娜糯懦傩喏搦锘",
|
||||
"ruo": "若弱偌箬",
|
||||
"nang": "囊馕囔曩攮",
|
||||
"nao": "脑闹恼挠瑙淖孬垴铙桡呶硇猱蛲",
|
||||
"ni": "你尼呢泥疑拟逆倪妮腻匿霓溺旎昵坭铌鲵伲怩睨猊",
|
||||
"nen": "嫩恁",
|
||||
"neng": "能",
|
||||
"nin": "您恁",
|
||||
"niao": "鸟尿溺袅脲茑嬲",
|
||||
"nie": "摄聂捏涅镍孽捻蘖啮蹑嗫臬镊颞乜陧",
|
||||
"niang": "娘酿",
|
||||
"ning": "宁凝拧泞柠咛狞佞聍甯",
|
||||
"nu": "努怒奴弩驽帑孥胬",
|
||||
"nv": "女钕衄恧",
|
||||
"ru": "入如女乳儒辱汝茹褥孺濡蠕嚅缛溽铷洳薷襦颥蓐",
|
||||
"nuan": "暖",
|
||||
"nve": "虐疟",
|
||||
"re": "热若惹喏",
|
||||
"ou": "区欧偶殴呕禺藕讴鸥瓯沤耦怄",
|
||||
"pao": "跑炮泡抛刨袍咆疱庖狍匏脬",
|
||||
"pou": "剖掊裒",
|
||||
"pen": "喷盆湓",
|
||||
"pie": "瞥撇苤氕丿",
|
||||
"pin": "品贫聘频拼拚颦姘嫔榀牝",
|
||||
"se": "色塞瑟涩啬穑铯槭",
|
||||
"qing": "情青清请亲轻庆倾顷卿晴氢擎氰罄磬蜻箐鲭綮苘黥圊檠謦",
|
||||
"zan": "赞暂攒堑昝簪糌瓒錾趱拶",
|
||||
"shao": "少绍召烧稍邵哨韶捎勺梢鞘芍苕劭艄筲杓潲",
|
||||
"sao": "扫骚嫂梢缫搔瘙臊埽缲鳋",
|
||||
"sha": "沙厦杀纱砂啥莎刹杉傻煞鲨霎嗄痧裟挲铩唼歃",
|
||||
"xuan": "县选宣券旋悬轩喧玄绚渲璇炫萱癣漩眩暄煊铉楦泫谖痃碹揎镟儇",
|
||||
"ran": "然染燃冉苒髯蚺",
|
||||
"rang": "让壤攘嚷瓤穰禳",
|
||||
"rao": "绕扰饶娆桡荛",
|
||||
"reng": "仍扔",
|
||||
"ri": "日",
|
||||
"rou": "肉柔揉糅鞣蹂",
|
||||
"ruan": "软阮朊",
|
||||
"run": "润闰",
|
||||
"sa": "萨洒撒飒卅仨脎",
|
||||
"suo": "所些索缩锁莎梭琐嗦唆唢娑蓑羧挲桫嗍睃",
|
||||
"sai": "思赛塞腮噻鳃",
|
||||
"shui": "说水税谁睡氵",
|
||||
"sang": "桑丧嗓搡颡磉",
|
||||
"sen": "森",
|
||||
"seng": "僧",
|
||||
"shai": "筛晒",
|
||||
"shang": "上商尚伤赏汤裳墒晌垧觞殇熵绱",
|
||||
"xing": "行省星腥猩惺兴刑型形邢饧醒幸杏性姓陉荇荥擤悻硎",
|
||||
"shou": "收手受首售授守寿瘦兽狩绶艏扌",
|
||||
"shuo": "说数硕烁朔铄妁槊蒴搠",
|
||||
"su": "速素苏诉缩塑肃俗宿粟溯酥夙愫簌稣僳谡涑蔌嗉觫",
|
||||
"shua": "刷耍唰",
|
||||
"shuan": "栓拴涮闩",
|
||||
"shun": "顺瞬舜吮",
|
||||
"song": "送松宋讼颂耸诵嵩淞怂悚崧凇忪竦菘",
|
||||
"sou": "艘搜擞嗽嗖叟馊薮飕嗾溲锼螋瞍",
|
||||
"sun": "损孙笋荪榫隼狲飧",
|
||||
"teng": "腾疼藤滕誊",
|
||||
"tie": "铁贴帖餮萜",
|
||||
"tu": "土突图途徒涂吐屠兔秃凸荼钍菟堍酴",
|
||||
"wai": "外歪崴",
|
||||
"wang": "王望往网忘亡旺汪枉妄惘罔辋魍",
|
||||
"weng": "翁嗡瓮蓊蕹",
|
||||
"zhua": "抓挝爪",
|
||||
"yang": "样养央阳洋扬杨羊详氧仰秧痒漾疡泱殃恙鸯徉佯怏炀烊鞅蛘",
|
||||
"xiong": "雄兄熊胸凶匈汹芎",
|
||||
"yo": "哟唷",
|
||||
"yong": "用永拥勇涌泳庸俑踊佣咏雍甬镛臃邕蛹恿慵壅痈鳙墉饔喁",
|
||||
"za": "杂扎咱砸咋匝咂拶",
|
||||
"zai": "在再灾载栽仔宰哉崽甾",
|
||||
"zao": "造早遭枣噪灶燥糟凿躁藻皂澡蚤唣",
|
||||
"zei": "贼",
|
||||
"zen": "怎谮",
|
||||
"zeng": "增曾综赠憎锃甑罾缯",
|
||||
"zhei": "这",
|
||||
"zou": "走邹奏揍诹驺陬楱鄹鲰",
|
||||
"zhuai": "转拽",
|
||||
"zun": "尊遵鳟樽撙",
|
||||
"dia": "嗲",
|
||||
"nou": "耨"
|
||||
}
|
||||
1
src/renderer/dict/chowder.json
Normal file
1
src/renderer/dict/chowder.json
Normal file
File diff suppressed because one or more lines are too long
18
src/renderer/index.html
Normal file
18
src/renderer/index.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>OH_BS</title>
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src
|
||||
'self' data:; connect-src 'self' ws://127.0.0.1:1949 http://127.0.0.1:1949"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
64
src/renderer/router/router.js
Normal file
64
src/renderer/router/router.js
Normal file
@ -0,0 +1,64 @@
|
||||
import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router'
|
||||
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'// nprogress样式文件
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/Home',
|
||||
name: 'home',
|
||||
component: () => import('../src/components/Home/Home.vue'),
|
||||
meta: {
|
||||
title: 'Home',
|
||||
index: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/Upgrade',
|
||||
name: 'upgrade',
|
||||
component: () => import('../src/components/Upgrade/Upgrade.vue'),
|
||||
meta: {
|
||||
title: 'Upgrade',
|
||||
index: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/Setting',
|
||||
name: 'setting',
|
||||
component: () => import('../src/components/Setting/Setting.vue'),
|
||||
meta: {
|
||||
title: 'Setting',
|
||||
index: 3
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
// history: createWebHistory(import.meta.env.BASE_URL),
|
||||
history:createWebHashHistory(import.meta.env.BASE_URL),
|
||||
routes,
|
||||
});
|
||||
|
||||
// //当路由开始跳转时
|
||||
// router.beforeEach((to, from , next) => {
|
||||
// // 开启进度条
|
||||
// NProgress.start();
|
||||
// // 这个一定要加,没有next()页面不会跳转的。这部分还不清楚的去翻一下官网就明白了
|
||||
// next();
|
||||
// });
|
||||
// //当路由跳转结束后
|
||||
// router.afterEach(() => {
|
||||
// // 关闭进度条
|
||||
// NProgress.done()
|
||||
// });
|
||||
//
|
||||
// NProgress.configure({
|
||||
// easing: 'ease', // 动画方式
|
||||
// speed: 500, // 递增进度条的速度
|
||||
// showSpinner: true, // 是否显示加载ico
|
||||
// trickleSpeed: 200, // 自动递增间隔
|
||||
// minimum: 0.3 // 初始化时的最小百分比
|
||||
// })
|
||||
|
||||
|
||||
export default router
|
||||
186
src/renderer/src/App.vue
Normal file
186
src/renderer/src/App.vue
Normal file
@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="appBack wrapper" :class="isFullscreen() ? 'hide-cursor':''">
|
||||
<div class="animation">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="transitionName">
|
||||
<component :is="Component" :class="isFullscreen() ? 'hide-cursor':''"/>
|
||||
</transition>
|
||||
</router-view>
|
||||
</div>
|
||||
<van-tabbar
|
||||
route
|
||||
active-color="#8DDAFC"
|
||||
inactive-color="#FFFFFF"
|
||||
:border="false"
|
||||
style="background-color: transparent;"
|
||||
class="tabbar-item-css"
|
||||
:class="isFullscreen() ? 'hide-cursor':''"
|
||||
>
|
||||
<van-tabbar-item replace to="/Home" @click.stop="showClick">
|
||||
<el-row>
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<span>
|
||||
首页
|
||||
</span>
|
||||
</el-row>
|
||||
</van-tabbar-item>
|
||||
<van-tabbar-item replace to="/Upgrade" @click.stop="showClick">
|
||||
<el-row>
|
||||
<el-icon><UploadFilled /></el-icon>
|
||||
<span>
|
||||
系统升级
|
||||
</span>
|
||||
</el-row>
|
||||
</van-tabbar-item>
|
||||
<van-tabbar-item replace to="/Setting" @click.stop="showClick">
|
||||
<el-row>
|
||||
<el-icon><Setting /></el-icon>
|
||||
<span>
|
||||
系统设置
|
||||
</span>
|
||||
</el-row>
|
||||
</van-tabbar-item>
|
||||
</van-tabbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, onUnmounted, reactive, ref } from "vue";
|
||||
import { useRouter } from 'vue-router';
|
||||
import { HomeFilled } from "@element-plus/icons-vue";
|
||||
import { Config, Init, isFullscreen, Release, setupFullscreenChangeListener } from "@renderer/JS/Config";
|
||||
import { ElMessage } from "element-plus";
|
||||
import Upgrade from "@renderer/components/Upgrade/Upgrade.vue";
|
||||
|
||||
|
||||
let router = useRouter();
|
||||
const active = ref(0);
|
||||
let transitionName = ref();
|
||||
|
||||
router.beforeEach((to, from) => {
|
||||
// 根据路由标记判断触发哪个动画
|
||||
if (to.meta.index > from.meta.index) {
|
||||
// 从右往左动画
|
||||
transitionName.value = 'slide-right';
|
||||
}
|
||||
else if (to.meta.index < from.meta.index) {
|
||||
// 从左往右动画
|
||||
transitionName.value = 'slide-left';
|
||||
}
|
||||
else {
|
||||
transitionName.value = '';
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(()=>{
|
||||
router.push("/Home")
|
||||
setupFullscreenChangeListener();
|
||||
Init();
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
Release();
|
||||
});
|
||||
|
||||
function showClick(){
|
||||
Config.show = false;
|
||||
setTimeout(()=>{
|
||||
Config.show = true;
|
||||
},100)
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
color: white;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.appBack {
|
||||
background-image: url("./assets/media/back.jpeg");
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
/*
|
||||
.hide-cursor {
|
||||
cursor: none !important;
|
||||
.van-tabbar-item{
|
||||
font-size: 20px;
|
||||
background-color: transparent;
|
||||
--van-tabbar-background-color: transparent;
|
||||
cursor: none !important;
|
||||
}
|
||||
}
|
||||
*/
|
||||
.tabbar-item-css{
|
||||
.van-tabbar-item{
|
||||
font-size: 20px;
|
||||
background-color: transparent;
|
||||
--van-tabbar-background-color: transparent;
|
||||
}
|
||||
}
|
||||
.wrapper {
|
||||
.animation {
|
||||
/* 修复后的动画定义 */
|
||||
.slide-left-enter-active,
|
||||
.slide-left-leave-active,
|
||||
.slide-right-enter-active,
|
||||
.slide-right-leave-active {
|
||||
transition: transform 0.5s ease;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* 从右向左滑动 - 进入的页面从右边进入 */
|
||||
.slide-right-enter-from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
.slide-right-enter-to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
/* 从右向左滑动 - 离开的页面向左滑出 */
|
||||
.slide-right-leave-from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.slide-right-leave-to {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* 从左向右滑动 - 进入的页面从左边进入 */
|
||||
.slide-left-enter-from {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.slide-left-enter-to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
/* 从左向右滑动 - 离开的页面向右滑出 */
|
||||
.slide-left-leave-from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.slide-left-leave-to {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
8
src/renderer/src/JS/Api.js
Normal file
8
src/renderer/src/JS/Api.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { reactive } from "vue";
|
||||
|
||||
export const ApiUrl = 'http://127.0.0.1:1949';
|
||||
|
||||
export const Api = reactive({
|
||||
getUpgradePackage: '/api/getUpgradePackage',
|
||||
getUpStatus: '/api/getUpStatus',
|
||||
})
|
||||
233
src/renderer/src/JS/Config.js
Normal file
233
src/renderer/src/JS/Config.js
Normal file
@ -0,0 +1,233 @@
|
||||
import { reactive } from "vue";
|
||||
import axios from "axios";
|
||||
import { ElNotification } from "element-plus";
|
||||
|
||||
export const Config = reactive({
|
||||
show: true,
|
||||
showKeyboard: false,
|
||||
isFullscreen: false,
|
||||
ServerName:'IP网络广播系统',
|
||||
ServerVer:'BS2V0.2.2(251211)',
|
||||
ServerVer2:'',
|
||||
ServerStatus:0,
|
||||
ServerIP:'127.0.0.1',
|
||||
IPList:[
|
||||
'127.0.0.1',
|
||||
'192.168.2.208',
|
||||
],
|
||||
DHCP:true,
|
||||
DHCPMutex:false,
|
||||
ServerHTTPPort:9091,
|
||||
ServerHTTPSPort:9090,
|
||||
ServerOrderPort:10060,
|
||||
ServerGW:'192.168.2.254',
|
||||
ServerNM:'255.255.255.0',
|
||||
Password:'',
|
||||
PasswordOrder:'123456',
|
||||
UpgradeList:[],
|
||||
selectedVersion:'',
|
||||
versionOptions:[],
|
||||
UpDateBtn: false,
|
||||
UpDateIndex:0,
|
||||
DownValue: 0,
|
||||
});
|
||||
let wsManager = null;
|
||||
export function Init(){
|
||||
ConnectWebSocket();
|
||||
}
|
||||
export function Release(){
|
||||
if(wsManager){
|
||||
wsManager.disconnect();
|
||||
}
|
||||
}
|
||||
function setSetting(setting){
|
||||
if(!Config.DHCPMutex){
|
||||
Config.DHCP = setting.DHCPFlag === 1;
|
||||
}
|
||||
else{
|
||||
Config.DHCP = false;
|
||||
}
|
||||
Config.ServerName = setting.ServerName;
|
||||
Config.ServerVer = setting.Version1 + setting.Version2;
|
||||
Config.ServerVer2 = setting.Version2;
|
||||
Config.ServerStatus = setting.ServerStatus;
|
||||
Config.ServerIP = setting.ServerIP;
|
||||
Config.IPList = setting.ServerAddress;
|
||||
Config.ServerHTTPPort = setting.WebPortHttp;
|
||||
Config.ServerHTTPSPort = setting.WebPort;
|
||||
Config.ServerOrderPort = setting.OrderPort;
|
||||
Config.ServerGW = setting.IPGw;
|
||||
Config.ServerNM = setting.IPNm;
|
||||
}
|
||||
class WebSocketManager {
|
||||
constructor() {
|
||||
this.ws = null;
|
||||
this.reconnectInterval = 3000; // 重连间隔时间,3秒
|
||||
this.maxReconnectAttempts = 30; // 最大重连次数
|
||||
this.reconnectAttempts = 0; // 当前重连次数
|
||||
this.shouldReconnect = true; // 是否应该重连
|
||||
}
|
||||
connect(url) {
|
||||
this.ws = new WebSocket(url);
|
||||
this.ws.binaryType = 'arraybuffer';
|
||||
this.ws.onopen = () => {
|
||||
console.log('WebSocket连接已建立');
|
||||
this.reconnectAttempts = 0;
|
||||
this.sendMessage(JSON.stringify({
|
||||
Key:'getSetting'
|
||||
}));
|
||||
// ElNotification.success('WebSocket连接已建立')
|
||||
};
|
||||
this.ws.onmessage = (event) => {
|
||||
if(typeof event.data === 'string'){
|
||||
try {
|
||||
const json = JSON.parse(event.data);
|
||||
if(json.Key === "getSetting"){
|
||||
const data = json.Setting;
|
||||
const MData = json.DHCPMutex;
|
||||
Config.DHCPMutex = MData === 1;
|
||||
setSetting(data);
|
||||
}
|
||||
else if(json.Key === "UpDate"){
|
||||
const Code = json.Code;
|
||||
if(Code === 0){
|
||||
Config.UpDateBtn = false;
|
||||
Config.UpDateIndex = 0;
|
||||
ElNotification.error('下载升级包失败')
|
||||
}
|
||||
else if(Code === 1){
|
||||
Config.UpDateBtn = true;
|
||||
Config.UpDateIndex = 1;
|
||||
ElNotification.success('开始下载升级包')
|
||||
}
|
||||
else if(Code === 2){
|
||||
Config.UpDateBtn = true;
|
||||
Config.UpDateIndex = 2;
|
||||
}
|
||||
else if(Code === 3){
|
||||
Config.UpDateIndex = 3;
|
||||
Config.DownValue = 100;
|
||||
ElNotification.success('开始解压升级包')
|
||||
}
|
||||
else if(Code === 4){
|
||||
Config.UpDateIndex = 4;
|
||||
ElNotification.success('开始安装升级包,即将重启')
|
||||
}
|
||||
}
|
||||
else if(json.Key === "DownProgress"){
|
||||
if(json.Value !== undefined){
|
||||
Config.DownValue = json.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e){
|
||||
console.log('this.ws.onmessage:',e);
|
||||
}
|
||||
}
|
||||
else if (event.data instanceof ArrayBuffer){
|
||||
|
||||
}
|
||||
};
|
||||
this.ws.onclose = () => {
|
||||
console.log('WebSocket连接已关闭');
|
||||
if (this.shouldReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
this.reconnectAttempts++;
|
||||
console.log(`尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
|
||||
setTimeout(() => {
|
||||
this.connect(url);
|
||||
}, this.reconnectInterval);
|
||||
}
|
||||
};
|
||||
this.ws.onerror = (error) => {
|
||||
console.error('WebSocket错误:', error);
|
||||
};
|
||||
}
|
||||
disconnect() {
|
||||
this.shouldReconnect = false;
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
}
|
||||
}
|
||||
sendMessage(text){
|
||||
this.ws.send(text);
|
||||
}
|
||||
sendBuffer(arrayBuffer){
|
||||
this.ws.send(arrayBuffer)
|
||||
}
|
||||
}
|
||||
export function sendMessage(text){
|
||||
if(wsManager){
|
||||
wsManager.sendMessage(text);
|
||||
}
|
||||
}
|
||||
function ConnectWebSocket(){
|
||||
if (wsManager) {
|
||||
wsManager.disconnect();
|
||||
}
|
||||
wsManager = new WebSocketManager();
|
||||
wsManager.connect('ws://127.0.0.1:1949/GUI');
|
||||
}
|
||||
export const setupFullscreenChangeListener = () => {
|
||||
const handler = () => {
|
||||
Config.isFullscreen = !!(
|
||||
document.fullscreenElement ||
|
||||
document.webkitFullscreenElement ||
|
||||
document.mozFullScreenElement ||
|
||||
document.msFullscreenElement
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('fullscreenchange', handler)
|
||||
document.addEventListener('webkitfullscreenchange', handler)
|
||||
document.addEventListener('mozfullscreenchange', handler)
|
||||
document.addEventListener('MSFullscreenChange', handler)
|
||||
|
||||
return handler
|
||||
}
|
||||
const enterFullscreen = () => {
|
||||
const element = document.documentElement
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen()
|
||||
} else if (element.webkitRequestFullscreen) {
|
||||
element.webkitRequestFullscreen()
|
||||
} else if (element.mozRequestFullScreen) {
|
||||
element.mozRequestFullScreen()
|
||||
} else if (element.msRequestFullscreen) {
|
||||
element.msRequestFullscreen()
|
||||
}
|
||||
Config.isFullscreen = true
|
||||
}
|
||||
const exitFullscreen = () => {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen()
|
||||
} else if (document.webkitExitFullscreen) {
|
||||
document.webkitExitFullscreen()
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen()
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen()
|
||||
}
|
||||
Config.isFullscreen = false
|
||||
}
|
||||
export function toggleFullscreen() {
|
||||
if (Config.isFullscreen) {
|
||||
exitFullscreen()
|
||||
}
|
||||
else {
|
||||
enterFullscreen()
|
||||
}
|
||||
}
|
||||
export function isFullscreen() {
|
||||
return Config.isFullscreen
|
||||
}
|
||||
export function PostData(url,data, callback = null,errCallback = null){
|
||||
axios.post(url,data).then(response=>{
|
||||
if(callback){
|
||||
callback(response);
|
||||
}
|
||||
}).catch(error=>{
|
||||
if(errCallback){
|
||||
errCallback(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
BIN
src/renderer/src/assets/media/back.jpeg
Normal file
BIN
src/renderer/src/assets/media/back.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 222 KiB |
83
src/renderer/src/components/Home/Home.vue
Normal file
83
src/renderer/src/components/Home/Home.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<el-container class="common-layout">
|
||||
<el-header height="30px" style="margin-left: 10px;margin-right: 10px;">
|
||||
<el-row style="" class="headerBox">
|
||||
<span @click.stop="toggleFullscreen">
|
||||
Ver: {{ Config.ServerVer }} [{{ formatTime(Date.now()) }}]
|
||||
</span>
|
||||
<span>
|
||||
System: {{ getSystemType() }}
|
||||
</span>
|
||||
</el-row>
|
||||
</el-header>
|
||||
<el-main>
|
||||
<el-row class="Banner">
|
||||
|
||||
<span>{{ Config.ServerName }}</span>
|
||||
</el-row>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Config, toggleFullscreen } from "@renderer/JS/Config";
|
||||
import { onMounted, onUnmounted } from "vue";
|
||||
|
||||
const formatTime = (timestamp) => {
|
||||
return new Date(timestamp).toLocaleString()
|
||||
}
|
||||
const getSystemType = () => {
|
||||
const userAgent = navigator.userAgent.toLowerCase()
|
||||
if (userAgent.includes('win')) {
|
||||
return 'Windows'
|
||||
} else if (userAgent.includes('linux')) {
|
||||
return 'Linux'
|
||||
} else if (userAgent.includes('mac')) {
|
||||
return 'MacOS'
|
||||
} else {
|
||||
return 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.common-layout{
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.el-header) {
|
||||
padding: 0;
|
||||
}
|
||||
:deep(.el-main) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.headerBox{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.Banner{
|
||||
margin-top: 10%;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
background-color: rgba(74, 196, 237, 0.3);
|
||||
align-items: center;
|
||||
span{
|
||||
margin-top: -10px;
|
||||
font-size: 50px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
269
src/renderer/src/components/MiscellaneousItems/KeyBoard2.vue
Normal file
269
src/renderer/src/components/MiscellaneousItems/KeyBoard2.vue
Normal file
@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<div ref="keyboardWrapRef" class="keyboard-wrap" @click="focusInput">
|
||||
<el-input ref="inputRef" v-model="model" @keyup.enter="handleEnter" :disabled="disabled" v-bind="$attrs">
|
||||
<template v-for="(index) in $slots" :key="index" #[index]>
|
||||
<slot :name="index"></slot>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-popover
|
||||
v-if="visible"
|
||||
:visible="true"
|
||||
:virtual-ref="inputRef"
|
||||
virtual-triggering
|
||||
placement="bottom"
|
||||
:width="width"
|
||||
:show-arrow="false"
|
||||
:hide-after="0"
|
||||
popper-style="padding: 0px;color:#000"
|
||||
popper-class="keyboard-popper"
|
||||
@after-enter="keyboardInit"
|
||||
>
|
||||
<div class="simple-keyboard"></div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Keyboard from 'simple-keyboard'
|
||||
import 'simple-keyboard/build/css/index.css'
|
||||
import layout from 'simple-keyboard-layouts/build/layouts/chinese.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { computed, onUnmounted, ref } from "vue"; // 添加此行以解决报错
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false
|
||||
})
|
||||
const model = defineModel<string>()
|
||||
const emits = defineEmits(['onChange', 'enter', 'close', 'focus'])
|
||||
const props = defineProps({
|
||||
layoutName: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
// 保留几位小数 layoutName为number时生效
|
||||
precision: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
// 获取焦点打开键盘
|
||||
isOpen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: Boolean
|
||||
})
|
||||
const { t } = useI18n()
|
||||
const keyboard = ref<any>(null)
|
||||
const keyboardWrapRef = ref(null)
|
||||
const visible = ref(false)
|
||||
const inputRef = ref()
|
||||
const width = ref(1000)
|
||||
if (props.layoutName == 'number') width.value = 300
|
||||
|
||||
const currentLang = ''
|
||||
|
||||
|
||||
const commonClear = computed(() => t('common.clear'))
|
||||
const commonClose = computed(() => t('common.close'))
|
||||
|
||||
const displayDefault = ref({
|
||||
'{bksp}': 'backspace',
|
||||
'{lock}': 'caps',
|
||||
'{enter}': 'enter',
|
||||
'{tab}': 'tab',
|
||||
'{shift}': 'shift',
|
||||
'{change}': 'en',
|
||||
'{space}': 'space',
|
||||
'{clear}': commonClear,
|
||||
'{close}': commonClose,
|
||||
'{arrowleft}': '←',
|
||||
'{arrowright}': '→'
|
||||
})
|
||||
|
||||
const open = () => {
|
||||
if (visible.value) return
|
||||
inputRef.value.focus()
|
||||
emits('focus')
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const focusInput = () => {
|
||||
if (props.disabled) return
|
||||
if (visible.value) return
|
||||
emits('focus')
|
||||
if (props.isOpen) visible.value = true
|
||||
}
|
||||
|
||||
const lang: any = {
|
||||
'zh-cn': {
|
||||
// 默认布局
|
||||
default: [
|
||||
'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
|
||||
'{tab} q w e r t y u i o p [ ] \\',
|
||||
"{lock} a s d f g h j k l ; ' {enter}",
|
||||
'{change} z x c v b n m , . / {clear}',
|
||||
'{arrowleft} {arrowright} {space} {close}'
|
||||
],
|
||||
// 大小写
|
||||
shift: [
|
||||
'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
|
||||
'{tab} Q W E R T Y U I O P { } |',
|
||||
'{lock} A S D F G H J K L : " {enter}',
|
||||
'{change} Z X C V B N M < > ? {clear}',
|
||||
'{arrowleft} {arrowright} {space} {close}'
|
||||
]
|
||||
},
|
||||
th: {
|
||||
default: [
|
||||
'\u005F \u0E45 \u002F \u002D \u0E20 \u0E16 \u0E38 \u0E36 \u0E04 \u0E15 \u0E08 \u0E02 \u0E0A {bksp}',
|
||||
'{tab} \u0E46 \u0E44 \u0E33 \u0E1E \u0E30 \u0E31 \u0E35 \u0E23 \u0E19 \u0E22 \u0E1A \u0E25 \u0E03',
|
||||
'{lock} \u0E1F \u0E2B \u0E01 \u0E14 \u0E40 \u0E49 \u0E48 \u0E32 \u0E2A \u0E27 \u0E07 {enter}',
|
||||
'{shift} \u0E1C \u0E1B \u0E41 \u0E2D \u0E34 \u0E37 \u0E17 \u0E21 \u0E43 \u0E1D {clear}',
|
||||
'{arrowleft} {arrowright} {space} {close}'
|
||||
],
|
||||
shift: [
|
||||
'% + \u0E51 \u0E52 \u0E53 \u0E54 \u0E39 \u0E3F \u0E55 \u0E56 \u0E57 \u0E58 \u0E59 {bksp}',
|
||||
'{tab} \u0E50 \u0022 \u0E0E \u0E11 \u0E18 \u0E4D \u0E4A \u0E13 \u0E2F \u0E0D \u0E10 \u002C \u0E05',
|
||||
'{lock} \u0E24 \u0E06 \u0E0F \u0E42 \u0E0C \u0E47 \u0E4B \u0E29 \u0E28 \u0E0B \u002E {enter}',
|
||||
'{shift} ( ) \u0E09 \u0E2E \u0E3A \u0E4C \u003F \u0E12 \u0E2C \u0E26 {clear}',
|
||||
'{arrowleft} {arrowright} {space} {close}'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const keyboardInit = () => {
|
||||
let keyboardLayout = {
|
||||
// 数字布局
|
||||
number: ['7 8 9', '4 5 6', '1 2 3', '. 0 {bksp}', '{arrowleft} {arrowright} {clear} {close}']
|
||||
}
|
||||
|
||||
if (lang[currentLang]) {
|
||||
keyboardLayout = { ...lang[currentLang], ...keyboardLayout }
|
||||
}
|
||||
keyboard.value = new Keyboard('simple-keyboard', {
|
||||
onChange: onChange,
|
||||
onKeyPress: onKeyPress,
|
||||
onInit: onInit,
|
||||
layout: keyboardLayout,
|
||||
layoutName: props.layoutName,
|
||||
display: displayDefault.value
|
||||
// theme: 'hg-theme-default init-keyboard' // 添加自定义class处理清空逻辑
|
||||
})
|
||||
}
|
||||
|
||||
const onInit = (keyboard: any) => {
|
||||
keyboard.setInput(model.value)
|
||||
keyboard.setCaretPosition(inputRef.value?.ref.selectionEnd)
|
||||
document.addEventListener('click', handlePopClose)
|
||||
}
|
||||
const onChange = (input: any) => {
|
||||
model.value = input
|
||||
emits('onChange', input)
|
||||
}
|
||||
|
||||
const onKeyPress = (button: any) => {
|
||||
if (button === '{lock}') return handleLock()
|
||||
if (button === '{change}') return handleChange()
|
||||
if (button === '{clear}') return handleClear()
|
||||
if (button === '{enter}') return handleEnter()
|
||||
if (button === '{close}') return close()
|
||||
if (button === '{arrowleft}') return handleArrow(0)
|
||||
if (button === '{arrowright}') return handleArrow(1)
|
||||
}
|
||||
const handleLock = () => {
|
||||
let currentLayout = keyboard.value.options.layoutName
|
||||
let shiftToggle = currentLayout === 'default' ? 'shift' : 'default'
|
||||
keyboard.value.setOptions({
|
||||
layoutName: shiftToggle
|
||||
})
|
||||
}
|
||||
const handleChange = () => {
|
||||
let layoutCandidates = keyboard.value.options.layoutCandidates
|
||||
// 切换中英文输入法
|
||||
if (layoutCandidates != null && layoutCandidates != undefined) {
|
||||
displayDefault.value['{change}'] = 'en'
|
||||
keyboard.value.setOptions({
|
||||
layoutName: 'default',
|
||||
layoutCandidates: null,
|
||||
display: displayDefault.value
|
||||
})
|
||||
} else {
|
||||
displayDefault.value['{change}'] = 'cn'
|
||||
keyboard.value.setOptions({
|
||||
layoutName: 'default',
|
||||
layoutCandidates: (layout as any)?.layoutCandidates,
|
||||
display: displayDefault.value
|
||||
})
|
||||
}
|
||||
}
|
||||
const handleClear = () => {
|
||||
keyboard.value.clearInput()
|
||||
model.value = ''
|
||||
}
|
||||
const handleEnter = () => {
|
||||
emits('enter')
|
||||
}
|
||||
const close = () => {
|
||||
if (props.layoutName == 'number') {
|
||||
// 处理精度
|
||||
model.value = model.value?.replace(new RegExp(`(\\d+)\\.(\\d{${props.precision}}).*$`), '$1.$2').replace(/\.$/, '')
|
||||
}
|
||||
document.removeEventListener('click', handlePopClose)
|
||||
visible.value = false
|
||||
emits('close')
|
||||
}
|
||||
const handleArrow = (num: number) => {
|
||||
// 处理左右箭头下标位置
|
||||
const index = keyboard.value.getCaretPositionEnd()
|
||||
if (num == 0 && index - 1 >= 0) {
|
||||
keyboard.value.setCaretPosition(index - 1)
|
||||
} else if (num == 1 && index + 1 <= (model.value?.length || 0)) {
|
||||
keyboard.value.setCaretPosition(index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const handlePopClose = (e: any) => {
|
||||
// 虚拟键盘区域 输入框区域 中文选项区域
|
||||
if (
|
||||
(e.target as Element).closest('.keyboard-popper') ||
|
||||
(e.target as Element).closest('.keyboard-wrap') == keyboardWrapRef.value ||
|
||||
/hg-candidate-box/.test(e.target.className)
|
||||
) {
|
||||
const index = keyboard.value.getCaretPositionEnd()
|
||||
inputRef.value.ref.selectionStart = inputRef.value.ref.selectionEnd = index
|
||||
inputRef.value.focus()
|
||||
} else {
|
||||
close()
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
// 某些情况下未触发动画关闭时销毁事件。此处销毁做后备处理
|
||||
document.removeEventListener('click', handlePopClose)
|
||||
})
|
||||
|
||||
defineExpose({ inputRef, visible, open, close, keyboardInit })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.keyboard-wrap{
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.hg-theme-default .hg-button.hg-button-arrowleft,
|
||||
.hg-theme-default .hg-button.hg-button-arrowright {
|
||||
max-width: 70px;
|
||||
}
|
||||
.hg-theme-default .hg-button.hg-button-close {
|
||||
max-width: 100px;
|
||||
}
|
||||
.hg-layout-number .hg-button.hg-button-close {
|
||||
max-width: none;
|
||||
}
|
||||
.hg-layout-number .hg-button.hg-button-bksp {
|
||||
max-width: 92px;
|
||||
}
|
||||
</style>
|
||||
|
||||
151
src/renderer/src/components/MiscellaneousItems/Keyboard.vue
Normal file
151
src/renderer/src/components/MiscellaneousItems/Keyboard.vue
Normal file
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div style="">
|
||||
<div
|
||||
v-show="Config.showKeyboard"
|
||||
@mousedown="startDrag"
|
||||
>
|
||||
<SimpleKeyboard
|
||||
ref="refSimpleKeyboard"
|
||||
class="Keyboard"
|
||||
@onChange="onChangeKeyboard"
|
||||
@empty="empty"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import SimpleKeyboard from './SimpleKeyboard.vue'
|
||||
import { Config } from "@renderer/JS/Config";
|
||||
export default {
|
||||
name: 'Keyboard',
|
||||
computed: {
|
||||
Config() {
|
||||
return Config
|
||||
}
|
||||
},
|
||||
components: {
|
||||
SimpleKeyboard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: '',
|
||||
key: '',
|
||||
isDragging: false,
|
||||
dragOffset: { x: 0, y: 0 }
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
key(val) {
|
||||
this.key = val
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
startDrag(event) {
|
||||
// 只在拖拽手柄区域响应
|
||||
if (!event.target.classList.contains('drag-handle') &&
|
||||
!event.target.parentElement.classList.contains('drag-handle')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const container = this.$refs.refSimpleKeyboard;
|
||||
const rect = container.getBoundingClientRect();
|
||||
|
||||
this.dragOffset.x = event.clientX - rect.left;
|
||||
this.dragOffset.y = event.clientY - rect.top;
|
||||
|
||||
this.isDragging = true;
|
||||
|
||||
document.addEventListener('mousemove', this.onDrag);
|
||||
document.addEventListener('mouseup', this.stopDrag);
|
||||
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
onDrag(event) {
|
||||
if (!this.isDragging) return;
|
||||
|
||||
const container = this.$refs.refSimpleKeyboard;
|
||||
const x = event.clientX - this.dragOffset.x;
|
||||
const y = event.clientY - this.dragOffset.y;
|
||||
|
||||
container.style.position = 'fixed';
|
||||
container.style.left = `${x}px`;
|
||||
container.style.top = `${y}px`;
|
||||
},
|
||||
|
||||
stopDrag() {
|
||||
this.isDragging = false;
|
||||
document.removeEventListener('mousemove', this.onDrag);
|
||||
document.removeEventListener('mouseup', this.stopDrag);
|
||||
},
|
||||
// inpuit获取焦点显示虚拟键盘
|
||||
onInputFocus(res) {
|
||||
Config.showKeyboard = true
|
||||
},
|
||||
// 给输入框赋值
|
||||
onChangeKeyboard(input) {
|
||||
this.$emit('input', { value: input, key: this.key });
|
||||
},
|
||||
// 隐藏键盘 父组件调用
|
||||
closeInputFocus() {
|
||||
Config.showKeyboard = false
|
||||
},
|
||||
// 隐藏键盘 子组件调用
|
||||
closekeyboard() {
|
||||
Config.showKeyboard = false
|
||||
},
|
||||
// 清空输入框
|
||||
empty() {
|
||||
this.$emit('input', { value: '', key: this.key });
|
||||
},
|
||||
// 给虚拟键盘赋当前输入框的值
|
||||
setKeyboardInput(input) {
|
||||
this.$refs.refSimpleKeyboard.onChangeFocus(input)
|
||||
},
|
||||
// 在 Keyboard.vue 的 methods 中添加
|
||||
showNumericKeyboard() {
|
||||
this.isNumeric = true;
|
||||
Config.showKeyboard = true;
|
||||
},
|
||||
|
||||
hideNumericKeyboard() {
|
||||
this.isNumeric = false;
|
||||
Config.showKeyboard = false;
|
||||
},
|
||||
|
||||
// 在 methods 中添加数字键盘事件处理
|
||||
onNumericInput(value) {
|
||||
// 处理数字输入
|
||||
this.$emit('input', { value: this.currentValue + value, key: this.key });
|
||||
},
|
||||
|
||||
onNumericBackspace() {
|
||||
// 处理退格
|
||||
if (this.currentValue.length > 0) {
|
||||
this.currentValue = this.currentValue.slice(0, -1);
|
||||
this.$emit('input', { value: this.currentValue, key: this.key });
|
||||
}
|
||||
},
|
||||
|
||||
onNumericClear() {
|
||||
// 清空输入
|
||||
this.currentValue = '';
|
||||
this.$emit('input', { value: '', key: this.key });
|
||||
},
|
||||
|
||||
onNumericConfirm() {
|
||||
// 确认输入
|
||||
Config.showKeyboard = false;
|
||||
this.$emit('confirm', { value: this.currentValue, key: this.key });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
// 键盘样式
|
||||
.Keyboard{
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="numeric-keyboard" v-show="visible">
|
||||
<div class="keyboard-header">
|
||||
<span class="close-btn" @click="closeKeyboard">关闭</span>
|
||||
</div>
|
||||
<div class="keyboard-body">
|
||||
<div class="keyboard-row" v-for="(row, index) in keyboardLayout" :key="index">
|
||||
<div
|
||||
v-for="key in row"
|
||||
:key="key.value"
|
||||
class="key"
|
||||
:class="getKeyClass(key.value)"
|
||||
@click="handleKeyPress(key.value)"
|
||||
>
|
||||
{{ key.label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NumericKeyboard',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyboardLayout: [
|
||||
[
|
||||
{ value: '1', label: '1' },
|
||||
{ value: '2', label: '2' },
|
||||
{ value: '3', label: '3' }
|
||||
],
|
||||
[
|
||||
{ value: '4', label: '4' },
|
||||
{ value: '5', label: '5' },
|
||||
{ value: '6', label: '6' }
|
||||
],
|
||||
[
|
||||
{ value: '7', label: '7' },
|
||||
{ value: '8', label: '8' },
|
||||
{ value: '9', label: '9' }
|
||||
],
|
||||
[
|
||||
{ value: '.', label: '.' },
|
||||
{ value: '0', label: '0' },
|
||||
{ value: 'backspace', label: '⌫' }
|
||||
],
|
||||
[
|
||||
{ value: 'clear', label: '清空' },
|
||||
{ value: 'confirm', label: '确认', colSpan: 2 }
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleKeyPress(value) {
|
||||
switch (value) {
|
||||
case 'backspace':
|
||||
this.$emit('backspace');
|
||||
break;
|
||||
case 'clear':
|
||||
this.$emit('clear');
|
||||
break;
|
||||
case 'confirm':
|
||||
this.$emit('confirm');
|
||||
break;
|
||||
case 'close':
|
||||
this.closeKeyboard();
|
||||
break;
|
||||
default:
|
||||
this.$emit('input', value);
|
||||
}
|
||||
},
|
||||
getKeyClass(value) {
|
||||
return {
|
||||
'backspace': value === 'backspace',
|
||||
'clear': value === 'clear',
|
||||
'confirm': value === 'confirm',
|
||||
'close': value === 'close'
|
||||
}
|
||||
},
|
||||
closeKeyboard() {
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.numeric-keyboard {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #f5f5f5;
|
||||
border-top: 1px solid #ccc;
|
||||
z-index: 9999;
|
||||
padding: 10px;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.keyboard-header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.keyboard-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.keyboard-row {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.key {
|
||||
flex: 1;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.key:active {
|
||||
background: #e6e6e6;
|
||||
}
|
||||
|
||||
.backspace, .clear, .confirm {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.confirm {
|
||||
flex: 2;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<div :class="keyboardClass"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Keyboard from 'simple-keyboard'
|
||||
import 'simple-keyboard/build/css/index.css'
|
||||
import layout from 'simple-keyboard-layouts/build/layouts/chinese' // 中文字库
|
||||
export default {
|
||||
name: 'SimpleKeyboard',
|
||||
props: {
|
||||
keyboardClass: {
|
||||
default: 'simple-keyboard',
|
||||
type: String,
|
||||
},
|
||||
maxLength: { default: '' },
|
||||
},
|
||||
data: () => ({
|
||||
keyboard: null,
|
||||
displayDefault: {
|
||||
'{bksp}': 'backspace',
|
||||
'{lock}': '切换',
|
||||
'{enter}': '←┘enter',
|
||||
'{tab}': 'tab',
|
||||
'{shift}': 'shift',
|
||||
'{change}': 'Ctrl',
|
||||
'{space}': ' ',
|
||||
'{clear}': '清空',
|
||||
'{close}': '关闭'
|
||||
}
|
||||
}),
|
||||
mounted() {
|
||||
this.keyboard = new Keyboard(this.keyboardClass, {
|
||||
onChange: this.onChange,
|
||||
onKeyPress: this.onKeyPress,
|
||||
layoutCandidates: layout.layout,
|
||||
layout: {
|
||||
// 默认布局
|
||||
default: [
|
||||
'` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
|
||||
'{tab} q w e r t y u i o p [ ] \\',
|
||||
"{lock} a s d f g h j k l ; ' {enter}",
|
||||
'{shift} z x c v b n m , . / {clear}',
|
||||
'{change} {space} {close}',
|
||||
],
|
||||
// shift布局
|
||||
shift: [
|
||||
'~ ! @ # $ % ^ & * ( ) _ + {bksp}',
|
||||
'{tab} Q W E R T Y U I O P { } |',
|
||||
'{lock} A S D F G H J K L : " {enter}',
|
||||
'{shift} Z X C V B N M < > ? {clear}',
|
||||
'{change} {space} {close}',
|
||||
],
|
||||
},
|
||||
// 按钮展示文字
|
||||
display: this.displayDefault,
|
||||
// 按钮样式
|
||||
buttonTheme: [
|
||||
{
|
||||
class: 'hg-red close',
|
||||
buttons: '{close}',
|
||||
},
|
||||
{
|
||||
class: 'change',
|
||||
buttons: '{change}',
|
||||
},
|
||||
],
|
||||
// 输入限制长度
|
||||
maxLength: this.maxLength,
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onChange(input) {
|
||||
this.$emit('onChange', input) // 输入值向外传递
|
||||
},
|
||||
// 重写清空按钮
|
||||
onChangeKey(){
|
||||
this.keyboard.setInput('')
|
||||
this.$emit('empty')
|
||||
},
|
||||
// @focus 触发时赋值 封装组件调用
|
||||
onChangeFocus(value) {
|
||||
this.keyboard.setInput(value)
|
||||
},
|
||||
// 点击键盘
|
||||
onKeyPress(button, $event) {
|
||||
// 点击关闭
|
||||
if (button === '{close}') {
|
||||
// 子组件调用父组件的关闭按钮方法
|
||||
this.$parent.closekeyboard()
|
||||
return false
|
||||
}
|
||||
else if (button === '{change}') {
|
||||
// 切换中英文输入法
|
||||
if (this.keyboard.options.layoutCandidates !== null) {
|
||||
this.$set(this.displayDefault, '{change}', '英文')
|
||||
// 切换至英文
|
||||
this.keyboard.setOptions({
|
||||
layoutCandidates: null,
|
||||
display: this.displayDefault,
|
||||
})
|
||||
} else {
|
||||
// 切换至中文
|
||||
this.$set(this.displayDefault, '{change}', '中文')
|
||||
this.keyboard.setOptions({
|
||||
layoutCandidates: layout.layoutCandidates,
|
||||
display: this.displayDefault,
|
||||
})
|
||||
}
|
||||
}
|
||||
else if (button === '{clear}') {
|
||||
this.onChangeKey()
|
||||
}
|
||||
else {
|
||||
// 检查 $event 是否存在,避免访问 undefined 的属性
|
||||
let value = '';
|
||||
if ($event && $event.target) {
|
||||
// 如果有事件对象,尝试从相关元素获取值
|
||||
const targetElement = $event.target.offsetParent?.parentElement?.children[0]?.children[0];
|
||||
if (targetElement && targetElement.value) {
|
||||
value = targetElement.value;
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框有默认值时,覆写
|
||||
if (value) {
|
||||
this.keyboard.setInput(value)
|
||||
}
|
||||
this.$emit('onKeyPress', button)
|
||||
}
|
||||
if (button === '{shift}' || button === '{lock}') this.handleShift()
|
||||
},
|
||||
// 切换shift/默认布局
|
||||
handleShift() {
|
||||
let currentLayout = this.keyboard.options.layoutName
|
||||
let shiftToggle = currentLayout === 'default' ? 'shift' : 'default'
|
||||
this.keyboard.setOptions({
|
||||
layoutName: shiftToggle,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less"> //这块样式可以根据自己的需求调整
|
||||
@deep: ~'>>>';
|
||||
.hg-candidate-box{
|
||||
position: fixed;
|
||||
width:100%;
|
||||
font-size: 42px;
|
||||
background: rgba(256, 256, 256);
|
||||
z-index: 9999;
|
||||
.hg-candidate-box-list{
|
||||
.hg-candidate-box-list-item{
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.hg-rows{
|
||||
width: 100% !important;
|
||||
.hg-row {
|
||||
height: 60px;
|
||||
.hg-button{
|
||||
height: 60px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.hg-theme-default {
|
||||
width: 1080px;
|
||||
height: 330px;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
color: black;
|
||||
.hg-button {
|
||||
&.hg-red {
|
||||
background: #db3e5d;
|
||||
color: white;
|
||||
&.close {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
&.change {
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
369
src/renderer/src/components/Setting/Setting.vue
Normal file
369
src/renderer/src/components/Setting/Setting.vue
Normal file
@ -0,0 +1,369 @@
|
||||
<template>
|
||||
<el-container class="common-layout">
|
||||
<el-main style="padding: 20px;">
|
||||
<el-scrollbar ref="scrollContainer">
|
||||
<el-form
|
||||
:model="Config"
|
||||
label-width="auto"
|
||||
label-position="left"
|
||||
class="formBox"
|
||||
:class="Config.showKeyboard ? 'formBox formBoxBkey' : 'formBox'"
|
||||
>
|
||||
<el-form-item label="本服务器版本:" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerVer"
|
||||
style="max-width: 600px;"
|
||||
:disabled="true"
|
||||
size="large"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="Web服务状态:" class="lBox">
|
||||
|
||||
<el-text type="success" v-if="Config.ServerStatus === 1" size="large">
|
||||
运行中...
|
||||
</el-text>
|
||||
<el-text type="warning" v-else-if="Config.ServerStatus === 2" size="large">
|
||||
加载中...
|
||||
</el-text>
|
||||
<el-tag type="danger" v-else-if="Config.ServerStatus === 0" size="large">
|
||||
未执行
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="DHCP:" class="lBox" v-if="!Config.DHCPMutex">
|
||||
|
||||
<el-switch
|
||||
v-model="Config.DHCP"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器IP地址:" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerIP"
|
||||
style="max-width: 600px;"
|
||||
v-if="!Config.DHCP"
|
||||
size="large"
|
||||
keyboard="true"
|
||||
ref="formBoxInput1"
|
||||
/>
|
||||
<el-select
|
||||
v-model="Config.ServerIP"
|
||||
v-else-if="Config.DHCP"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in Config.IPList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器网关:" v-if="!Config.DHCP" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerGW"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
ref="formBoxInput2"
|
||||
keyboard="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器子网掩码:" v-if="!Config.DHCP" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerNM"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
ref="formBoxInput3"
|
||||
keyboard="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器HTTP端口:" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerHTTPPort"
|
||||
style="max-width: 600px;"
|
||||
min="1024"
|
||||
max="65535"
|
||||
type="number"
|
||||
size="large"
|
||||
ref="formBoxInput4"
|
||||
keyboard="true"
|
||||
@focus="focusInput('formBoxInput4')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器HTTPS端口:" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerHTTPSPort"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
min="1024"
|
||||
max="65535"
|
||||
type="number"
|
||||
ref="formBoxInput5"
|
||||
keyboard="true"
|
||||
@focus="focusInput('formBoxInput5')"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="本服务器指令端口:" class="lBox">
|
||||
|
||||
<el-input
|
||||
v-model="Config.ServerOrderPort"
|
||||
style="max-width: 600px;"
|
||||
size="large"
|
||||
min="1024"
|
||||
max="65535"
|
||||
type="number"
|
||||
ref="formBoxInput6"
|
||||
@focus="focusInput('formBoxInput6')"
|
||||
keyboard="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item class="lBox">
|
||||
<el-button type="primary" size="large" @click.stop="Save">
|
||||
保存设置
|
||||
</el-button>
|
||||
<el-button type="danger" size="large" @click.stop="Exit">
|
||||
退出系统
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
<keyboard
|
||||
:transitionTime="'0.5s'"
|
||||
:maxQuantify="10"
|
||||
:showKeyboard="showKeyboard"
|
||||
@clickKey="clickKey"
|
||||
float
|
||||
:manyDict="manyDict"
|
||||
:singleDict="singleDict"
|
||||
@clickNumber="clickNumber"
|
||||
@clickShow="showKeyboardClick"
|
||||
@clickHide="hideKeyboardClick"
|
||||
:blurHide="false"
|
||||
></keyboard>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { h, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
||||
import { Config, sendMessage } from "@renderer/JS/Config";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import keyboard from '@renderer/components/keyboard/keyboardIndex.vue';
|
||||
|
||||
|
||||
const formBoxInput1 = ref();
|
||||
const formBoxInput2 = ref();
|
||||
const formBoxInput3 = ref();
|
||||
const formBoxInput4 = ref();
|
||||
const formBoxInput5 = ref();
|
||||
const formBoxInput6 = ref();
|
||||
const scrollContainer = ref()
|
||||
const ClickIndex = ref(0);
|
||||
const manyDict = ref("@renderer/dict/chowder.json")
|
||||
const singleDict = ref("@renderer/dict/baseDict.json")
|
||||
const showKeyboard = ref(false);
|
||||
const inputElement = ref();
|
||||
const targetH = ref(0);
|
||||
|
||||
onMounted(()=>{
|
||||
sendMessage(JSON.stringify({
|
||||
Key:'getSetting'
|
||||
}))
|
||||
Config.showKeyboard = false;
|
||||
});
|
||||
onUnmounted(()=>{
|
||||
|
||||
});
|
||||
//------------------------------------------------------------------------------
|
||||
const clickKey = (key) => {
|
||||
console.log("key-->>",key);
|
||||
}
|
||||
//点击键盘时数字的值
|
||||
const clickNumber = (key) => {
|
||||
console.log("key-->>",key);
|
||||
}
|
||||
function showKeyboardClick(){
|
||||
if(!Config.showKeyboard){
|
||||
Config.showKeyboard = true;
|
||||
setTimeout(()=>{
|
||||
if (scrollContainer.value) {
|
||||
const container = scrollContainer.value.$el.querySelector('.el-scrollbar__wrap');
|
||||
container.style.scrollBehavior = 'smooth'; // 添加平滑滚动效果
|
||||
container.scrollTop = targetH.value;
|
||||
targetH.value = 0;
|
||||
}
|
||||
},300)
|
||||
}
|
||||
}
|
||||
function hideKeyboardClick(){
|
||||
Config.showKeyboard = false;
|
||||
}
|
||||
function focusInput(id){
|
||||
let element;
|
||||
|
||||
if(id === "formBoxInput1"){
|
||||
element = formBoxInput1.value;
|
||||
}
|
||||
else if(id === "formBoxInput2"){
|
||||
element = formBoxInput2.value;
|
||||
}
|
||||
else if(id === "formBoxInput3"){
|
||||
element = formBoxInput3.value;
|
||||
}
|
||||
else if(id === "formBoxInput4"){
|
||||
element = formBoxInput4.value;
|
||||
}
|
||||
else if(id === "formBoxInput5"){
|
||||
element = formBoxInput5.value;
|
||||
}
|
||||
else if(id === "formBoxInput6"){
|
||||
element = formBoxInput6.value;
|
||||
}
|
||||
|
||||
// 正确获取输入框元素
|
||||
if (element) {
|
||||
// 对于 Element Plus 的 el-input,需要获取内部的 input 元素
|
||||
inputElement.value = element.$el ? element.$el.querySelector('input') : element;
|
||||
}
|
||||
|
||||
if (inputElement.value) {
|
||||
console.log('inputElement', inputElement.value);
|
||||
console.log('tar', inputElement.value.getBoundingClientRect());
|
||||
targetH.value = inputElement.value.getBoundingClientRect().top;
|
||||
}
|
||||
else {
|
||||
console.log('inputElement not found for', id);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
function PasswordFun(Confirm = null,Cannel = null) {
|
||||
const passwordRef = ref('');
|
||||
|
||||
ElMessageBox({
|
||||
title: '请输入密码',
|
||||
message: () =>
|
||||
h('div', [
|
||||
h('input', {
|
||||
type: 'password',
|
||||
placeholder: '请输入密码',
|
||||
value: passwordRef.value,
|
||||
// 监听输入框点击事件
|
||||
onclick: (event) => {
|
||||
// console.log('密码输入框被点击');
|
||||
|
||||
// 在这里添加点击事件的处理逻辑
|
||||
},
|
||||
// 监听输入事件
|
||||
oninput: (event) => {
|
||||
passwordRef.value = event.target.value;
|
||||
},
|
||||
// 监听获得焦点事件
|
||||
onfocus: (event) => {
|
||||
console.log('密码输入框获得焦点');
|
||||
toggleScreenKeyboard(true);
|
||||
},
|
||||
// 监听失去焦点事件
|
||||
onblur: (event) => {
|
||||
console.log('密码输入框失去焦点');
|
||||
toggleScreenKeyboard(false);
|
||||
},
|
||||
style: {
|
||||
width: '380px',
|
||||
padding: '8px',
|
||||
border: '1px solid #dcdfe6',
|
||||
borderRadius: '4px'
|
||||
}
|
||||
})
|
||||
]),
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
}).then(() => {
|
||||
if(Confirm && passwordRef.value === Config.PasswordOrder){
|
||||
Confirm();
|
||||
}
|
||||
else{
|
||||
ElMessage.error('密码错误');
|
||||
}
|
||||
}).catch(() => {
|
||||
if(Cannel){
|
||||
Cannel();
|
||||
}
|
||||
toggleScreenKeyboard(false);
|
||||
})
|
||||
}
|
||||
function Save(){
|
||||
ClickIndex.value = 0;
|
||||
Config.Password = '';
|
||||
PasswordFun(()=>{
|
||||
sendMessage(JSON.stringify({
|
||||
Key:'setSetting',
|
||||
DHCPFlag:Config.DHCP ? 1 : 0,
|
||||
ServerIP:Config.ServerIP,
|
||||
ServerNM:Config.ServerNM,
|
||||
ServerGW:Config.ServerGW,
|
||||
ServerHTTPPort:Config.ServerHTTPPort,
|
||||
ServerHTTPSPort:Config.ServerHTTPSPort,
|
||||
ServerOrderPort:Config.ServerOrderPort,
|
||||
}));
|
||||
ElMessage.success('保存成功');
|
||||
});
|
||||
}
|
||||
function Reset(){
|
||||
ClickIndex.value = 1;
|
||||
Config.Password = '';
|
||||
PasswordFun(()=>{
|
||||
ElMessage.success('重置成功');
|
||||
});
|
||||
}
|
||||
function Exit(){
|
||||
ClickIndex.value = 2;
|
||||
Config.Password = '';
|
||||
PasswordFun(()=>{
|
||||
sendMessage(JSON.stringify({
|
||||
Key:"exitSys"
|
||||
}));
|
||||
});
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.common-layout{
|
||||
width: 100%;
|
||||
}
|
||||
.formBox {
|
||||
width: 100%;
|
||||
height: calc(100vh - 80px);
|
||||
}
|
||||
.formBoxBkey {
|
||||
height: calc(100vh - 430px);
|
||||
}
|
||||
.formBox :deep(.el-form-item) {
|
||||
margin-bottom: 45px;
|
||||
}
|
||||
:deep(.el-form-item__label) {
|
||||
color: white !important;
|
||||
font-size: 30px !important;
|
||||
}
|
||||
.lBox{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.formBox {
|
||||
width: 100%;
|
||||
height: calc(100vh - 80px);
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
.formBoxBkey {
|
||||
height: calc(100vh - 358px); /* 调整这个值以适应键盘高度 */
|
||||
|
||||
}
|
||||
</style>
|
||||
233
src/renderer/src/components/Upgrade/Upgrade.vue
Normal file
233
src/renderer/src/components/Upgrade/Upgrade.vue
Normal file
@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<el-container class="common-layout">
|
||||
<el-card class="upgrade-card">
|
||||
<!-- 卡片头部 - 标题 -->
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<el-typography-title :level="3">
|
||||
软件版本升级
|
||||
</el-typography-title>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 卡片内容区域 -->
|
||||
<div class="upgrade-content">
|
||||
<!-- 版本选择区域 -->
|
||||
<div class="version-section">
|
||||
<span class="section-label">选择升级版本</span>
|
||||
<el-select
|
||||
v-model="Config.selectedVersion"
|
||||
placeholder="请选择版本"
|
||||
class="version-select"
|
||||
>
|
||||
<el-option
|
||||
v-for="version in Config.versionOptions"
|
||||
:key="version.ID"
|
||||
:label="version.Version"
|
||||
:value="version.ID"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<!-- 当前版本信息 -->
|
||||
<div class="current-version">
|
||||
当前版本:{{ Config.ServerVer2 }}
|
||||
</div>
|
||||
|
||||
<!-- 升级特性列表 -->
|
||||
<div class="feature-list">
|
||||
<el-scrollbar>
|
||||
<span style="font-size: 14px;">
|
||||
更新说明:
|
||||
</span>
|
||||
<el-text
|
||||
style="font-size: 14px; white-space: pre-line; display: block; margin-top: 8px;"
|
||||
>
|
||||
{{ getUpDateText(Config.selectedVersion) }}
|
||||
</el-text>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<div class="UPGRADE-PROGRESS-BAR">
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="20"
|
||||
:percentage="Config.DownValue"
|
||||
:striped="Config.UpDateIndex === 3 || Config.UpDateIndex === 4"
|
||||
:striped-flow="Config.UpDateIndex === 3 || Config.UpDateIndex === 4"
|
||||
style="border-radius: 1px;"
|
||||
>
|
||||
<span v-if="Config.UpDateIndex === 1">
|
||||
下载进度: {{ Config.DownValue }} %
|
||||
</span>
|
||||
<span v-if="Config.UpDateIndex === 3">
|
||||
正在解压
|
||||
</span>
|
||||
<span v-if="Config.UpDateIndex === 4">
|
||||
正在安装升级包...
|
||||
</span>
|
||||
</el-progress>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="action-buttons">
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="handleUpgrade"
|
||||
:disabled="Config.UpDateBtn"
|
||||
v-loading="Config.UpDateBtn"
|
||||
>
|
||||
立即升级
|
||||
</el-button>
|
||||
<el-button
|
||||
@click="handleCancel"
|
||||
>
|
||||
更新列表
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onBeforeMount, onMounted, ref } from "vue";
|
||||
import { Config, PostData, sendMessage } from "@renderer/JS/Config";
|
||||
import { Api, ApiUrl } from "@renderer/JS/Api";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
onMounted(()=>{
|
||||
if(Config.UpgradeList.length === 0){
|
||||
getUpdateList();
|
||||
}
|
||||
getUpStatus();
|
||||
});
|
||||
onBeforeMount(()=>{
|
||||
|
||||
});
|
||||
|
||||
function handleUpgrade(){
|
||||
if(Config.selectedVersion === ''){
|
||||
ElMessage.error('请选择升级版本');
|
||||
return;
|
||||
}
|
||||
sendMessage(JSON.stringify({
|
||||
Key:'upgradeProgram',
|
||||
ID: Config.selectedVersion
|
||||
}));
|
||||
}
|
||||
function getUpDateText(ID){
|
||||
let item = null;
|
||||
for (let i = 0; i < Config.versionOptions.length; i++){
|
||||
const I = Config.versionOptions[i];
|
||||
if(I.ID === ID){
|
||||
item = I;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(item){
|
||||
return item.Description;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
function handleCancel() {
|
||||
getUpdateList();
|
||||
}
|
||||
function InitList(){
|
||||
Config.versionOptions = [];
|
||||
console.log('初始化列表',Config.UpgradeList)
|
||||
for (let i = 0; i < Config.UpgradeList.length; i++){
|
||||
const item = Config.UpgradeList[i];
|
||||
Config.versionOptions.push({
|
||||
ID: item.ID,
|
||||
Name: item.Name,
|
||||
Version: item.Version,
|
||||
Size: item.Size,
|
||||
Description: item.Description,
|
||||
URL: item.URL,
|
||||
Date: item.Date_t
|
||||
});
|
||||
}
|
||||
if(Config.versionOptions.length > 0){
|
||||
Config.selectedVersion = Config.versionOptions[0].ID;
|
||||
}
|
||||
}
|
||||
function getUpdateList() {
|
||||
PostData(ApiUrl + Api.getUpgradePackage,{},function(res){
|
||||
const data = res.data;
|
||||
if(data.Code === 1){
|
||||
Config.UpgradeList = data.List;
|
||||
InitList();
|
||||
}
|
||||
},function(err){
|
||||
Config.UpgradeList = [];
|
||||
});
|
||||
}
|
||||
function getUpStatus(){
|
||||
PostData(ApiUrl + Api.getUpgradePackage,{},function(res){
|
||||
const data = res.data;
|
||||
if(data.Code === 1){
|
||||
Config.UpDateIndex = data.Status;
|
||||
Config.UpDateBtn = data.downloadStatus === 1;
|
||||
}
|
||||
},function(err){
|
||||
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.common-layout{
|
||||
width: 100%;
|
||||
}
|
||||
/* 卡片整体样式 */
|
||||
.upgrade-card {
|
||||
width: 520px; /* 可根据设计调整宽度 */
|
||||
margin: 60px auto; /* 页面居中 */
|
||||
background: linear-gradient(to right, #eaf5ff, #d9edff); /* 渐变背景(参考原型风格) */
|
||||
}
|
||||
|
||||
/* 卡片头部标题 */
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 版本选择区域 */
|
||||
.version-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.version-section .section-label {
|
||||
margin-right: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.version-select {
|
||||
width: 360px; /* 下拉框宽度 */
|
||||
}
|
||||
|
||||
/* 当前版本信息 */
|
||||
.current-version {
|
||||
margin-bottom: 16px;
|
||||
font-size: 16px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 升级特性列表 */
|
||||
.feature-list {
|
||||
margin-bottom: 24px;
|
||||
height: 330px;
|
||||
}
|
||||
|
||||
.UPGRADE-PROGRESS-BAR{
|
||||
margin-bottom: 24px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
/* 操作按钮区域 */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
22
src/renderer/src/components/keyboard/fullTriangle.vue
Normal file
22
src/renderer/src/components/keyboard/fullTriangle.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 48 48"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M22.2692 6.98965C23.0395 5.65908 24.9605 5.65908 25.7309 6.98965L44.262 38.9979C45.0339 40.3313 44.0718 42 42.5311 42H5.4689C3.92823 42 2.96611 40.3313 3.73804 38.9979L22.2692 6.98965Z"
|
||||
fill="#fff"
|
||||
stroke="#fff"
|
||||
stroke-width="4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
<script setup></script>
|
||||
<style scoped></style>
|
||||
14
src/renderer/src/components/keyboard/index.js
Normal file
14
src/renderer/src/components/keyboard/index.js
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
import keyboardIndex from './keyboardIndex.vue'
|
||||
|
||||
const keyboard = {
|
||||
install(Vue) {
|
||||
Vue.component('vue-virtual-keyboard-cn', keyboardIndex)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
window.Vue.use(keyboard);
|
||||
}
|
||||
|
||||
export default keyboard
|
||||
390
src/renderer/src/components/keyboard/index.scss
Normal file
390
src/renderer/src/components/keyboard/index.scss
Normal file
@ -0,0 +1,390 @@
|
||||
.keyUp {
|
||||
}
|
||||
.keyDown {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
.keyboardTransition-enter-active,
|
||||
.keyboardTransition-leave-active {
|
||||
max-height: 500px;
|
||||
}
|
||||
.keyboardTransition-enter,
|
||||
.keyboardTransition-leave-to {
|
||||
max-height: 0px;
|
||||
}
|
||||
|
||||
.disabled_key {
|
||||
background: #f2f2f2 !important;
|
||||
cursor: default !important;
|
||||
color: rgb(170, 170, 170);
|
||||
border-color: rgba(118, 118, 118, 0.3);
|
||||
}
|
||||
i {
|
||||
font-style: normal;
|
||||
}
|
||||
.num-del > svg {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.def-del > svg {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.hand-del > svg {
|
||||
margin-top: 0px;
|
||||
}
|
||||
.my-keyboard {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
z-index: 10;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
// min-width: 1024px;
|
||||
font-family: "Avenir", Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
.pinyin,
|
||||
.select-list {
|
||||
> div {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.item_main {
|
||||
width: 86%;
|
||||
}
|
||||
}
|
||||
.pinyin {
|
||||
// height: 30px;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(209, 209, 209, 1);
|
||||
padding: 0 20px;
|
||||
text-align: left;
|
||||
> div span {
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.select-list {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(209, 209, 209, 1);
|
||||
border-top: none;
|
||||
padding: 0 20px;
|
||||
text-align: left;
|
||||
> div {
|
||||
position: relative;
|
||||
}
|
||||
.select-text {
|
||||
cursor: pointer;
|
||||
line-height: 40px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
& + .select-text {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
.page {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0px;
|
||||
width: 120px;
|
||||
height: 40px;
|
||||
.next {
|
||||
transform: scaleX(2) rotate(180deg);
|
||||
}
|
||||
> p {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
transform: scaleX(2);
|
||||
width: 30px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
background: #344a5d;
|
||||
color: #fff;
|
||||
border: 1px solid #d7d7d7;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
&:active {
|
||||
background: #fff;
|
||||
color: #344a5d;
|
||||
}
|
||||
& + p {
|
||||
margin-left: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-keyboard {
|
||||
padding: 15px 14px;
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
height: 305px;
|
||||
.key {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
width: 100px;
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: 8px;
|
||||
margin-top: 8px;
|
||||
box-shadow: 1px 1px 2px rgba(20, 20, 20, 0.3);
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
&:active {
|
||||
background: #d0d0d0;
|
||||
}
|
||||
|
||||
// & + .key {
|
||||
// margin-left: 10px;
|
||||
// }
|
||||
}
|
||||
|
||||
.number-box {
|
||||
width: 720px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.number {
|
||||
width: 210px;
|
||||
height: 65px;
|
||||
font-size: 46px;
|
||||
line-height: 65px;
|
||||
}
|
||||
.del-box {
|
||||
width: 260px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
.key {
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
.hand-left-box {
|
||||
width: 155px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
.key {
|
||||
margin-left: 0px;
|
||||
//margin-top: 20px;
|
||||
&:nth-of-type(1) {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
> span {
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
.cap_change {
|
||||
width: 140px;
|
||||
color: #fff;
|
||||
background: #344a5d;
|
||||
// &:active {
|
||||
// background: #728fa8;
|
||||
// }
|
||||
}
|
||||
.key_hide {
|
||||
background: #d6d1d0;
|
||||
> .jp {
|
||||
height: 50px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
> span {
|
||||
padding-left: 10px;
|
||||
font-size: 18px;
|
||||
line-height: 18px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.blue {
|
||||
// color: #fff;
|
||||
width: 180px;
|
||||
// background: #ff9213; // #344a5d;
|
||||
&:active {
|
||||
// background: #728fa8;
|
||||
}
|
||||
.blue_default {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.red {
|
||||
color: #fff;
|
||||
background: #f56c6c;
|
||||
&:active {
|
||||
background: #f89e9e;
|
||||
}
|
||||
}
|
||||
.space {
|
||||
width: 367px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no_del_box {
|
||||
.num {
|
||||
.number:nth-last-child(2) {
|
||||
width: 430px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.pc {
|
||||
min-width: 1100px;
|
||||
.def-del {
|
||||
width: 140px !important;
|
||||
}
|
||||
.no_del_box {
|
||||
height: 333px !important;
|
||||
}
|
||||
.hide12key {
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
.phone {
|
||||
.hide12key {
|
||||
height: 25px;
|
||||
svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
.select-list {
|
||||
white-space: nowrap;
|
||||
.item_main {
|
||||
overflow: auto;
|
||||
width: 91%;
|
||||
.select-text {
|
||||
font-size: 19px;
|
||||
}
|
||||
}
|
||||
.page {
|
||||
right: 17px;
|
||||
text-align: right;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
.next {
|
||||
width: 23px;
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.no_del_box {
|
||||
height: 253px !important;
|
||||
}
|
||||
.main-keyboard {
|
||||
padding: 0px;
|
||||
height: 235px;
|
||||
margin-left: -8px;
|
||||
.select_cn {
|
||||
overflow: auto;
|
||||
width: 71% !important;
|
||||
height: 94%;
|
||||
background: #fff;
|
||||
margin-top: 7px;
|
||||
border-radius: 10px;
|
||||
.select_cn_main {
|
||||
display: flex;
|
||||
// height: 100%;
|
||||
flex-wrap: wrap;
|
||||
.item {
|
||||
height: 20px;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid;
|
||||
font-size: 19px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.number-box {
|
||||
width: 75%;
|
||||
.number {
|
||||
font-size: 26px;
|
||||
width: 29%;
|
||||
height: 45px;
|
||||
}
|
||||
}
|
||||
.del-box {
|
||||
width: 25%;
|
||||
span {
|
||||
width: 80%;
|
||||
}
|
||||
.number {
|
||||
font-size: 20px;
|
||||
}
|
||||
.key_hide {
|
||||
width: 80% !important;
|
||||
|
||||
span {
|
||||
margin-bottom: 2px;
|
||||
padding-left: 0px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
.num-del {
|
||||
svg {
|
||||
width: 48%;
|
||||
height: 9%;
|
||||
margin-top: -26px;
|
||||
position: relative;
|
||||
top: 13px;
|
||||
}
|
||||
}
|
||||
.blue {
|
||||
font-size: 26px !important;
|
||||
}
|
||||
}
|
||||
.key {
|
||||
width: 8%;
|
||||
height: 18%;
|
||||
margin-left: 6px !important;
|
||||
line-height: 45px;
|
||||
}
|
||||
|
||||
.letter {
|
||||
font-size: 24px;
|
||||
}
|
||||
.blue {
|
||||
width: 12%;
|
||||
font-size: 15px;
|
||||
.blue_default {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
::v-deep .num-del {
|
||||
height: 45px;
|
||||
svg {
|
||||
height: 38px;
|
||||
margin-left: -3px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
::v-deep .def-del {
|
||||
width: 12% !important;
|
||||
svg {
|
||||
margin-top: 6px;
|
||||
height: 31px;
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.key_hide {
|
||||
width: 20% !important;
|
||||
span {
|
||||
padding-left: 0px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
.case {
|
||||
}
|
||||
.space {
|
||||
width: 30%;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
src/renderer/src/components/keyboard/index.worker.js
Normal file
154
src/renderer/src/components/keyboard/index.worker.js
Normal file
@ -0,0 +1,154 @@
|
||||
// const obj = self.importScripts("/vocabulary.js")
|
||||
|
||||
self.addEventListener('message', (e) => {
|
||||
// console.log('子线程', e)
|
||||
|
||||
const { method, dataKey } = e.data
|
||||
|
||||
if (method === 'init') {
|
||||
self[dataKey] = Object.freeze(e.data.data)
|
||||
self.dataKey = dataKey
|
||||
}
|
||||
if (method === 'setCn_input') {
|
||||
setCn_input(e)
|
||||
}
|
||||
if (method === 'search') {
|
||||
console.time("searchDict");
|
||||
let { key } = e.data
|
||||
const doubleSpell = self.doubleSpell || {}
|
||||
|
||||
let cn_input = key
|
||||
let keys = cn_input.split("'")
|
||||
const dict = doubleSpell[cn_input.charAt(0)]
|
||||
if (!dict) return
|
||||
|
||||
if (["an"].includes(keys[keys.length - 1])) {
|
||||
let tempStr = keys[keys.length - 2];
|
||||
if (["n"].includes(tempStr.charAt(tempStr.length - 1))) {
|
||||
let newTempStr = tempStr.slice(0, tempStr.length - 1);
|
||||
keys = [
|
||||
newTempStr,
|
||||
tempStr.slice(tempStr.length - 1) + keys[keys.length - 1],
|
||||
];
|
||||
cn_input = keys.join("'");
|
||||
}
|
||||
}
|
||||
|
||||
let keyResult = Object.keys(dict).filter((key) => {
|
||||
const keys = key.split("'");
|
||||
const cn_inputList = cn_input.split("'");
|
||||
const isLen = cn_inputList.length === keys.length;
|
||||
if (!isLen) return
|
||||
let result = true
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (keys[i].charAt(0) != cn_inputList[i].charAt(0)) {
|
||||
result = false
|
||||
} else {
|
||||
const keyItemList = keys[i].split('')
|
||||
const strList = cn_inputList[i].split('')
|
||||
for (let j = 0; j < strList.length; j++) {
|
||||
if (!strList[j]) break
|
||||
if (keyItemList[j] != strList[j]) {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result && isLen) {
|
||||
return dict[key];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let strList = [];
|
||||
let singleDictList = []
|
||||
const singleDict = self.dict
|
||||
for (let key of keyResult) {
|
||||
let keyList = key.split("'")
|
||||
// console.log('dict[key]', dict[key])
|
||||
strList.push(dict[key].split(","));
|
||||
for (let item of keyList) {
|
||||
// console.log('singleDict[item]', singleDict[item])
|
||||
if (singleDict[item]) {
|
||||
singleDictList.push(singleDict[item].split(""));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
singleDictList = Array.from(new Set(singleDictList.flat(2)))
|
||||
strList = strList
|
||||
.flat(2)
|
||||
.sort((a, b) => {
|
||||
if (b.length > a.length) return -1;
|
||||
})
|
||||
.reverse();
|
||||
const result = strList.concat(singleDictList)
|
||||
console.timeEnd("searchDict");
|
||||
self.postMessage({ method: 'search', data: result, cn_input });
|
||||
}
|
||||
|
||||
}, false);
|
||||
|
||||
const setCn_input = function (e) {
|
||||
let { cn_input, text } = e.data
|
||||
const singleDict = self.dict
|
||||
let itemList = []
|
||||
for (let key in singleDict) {
|
||||
let value = singleDict[key]
|
||||
let valueList = value.split('')
|
||||
let item = valueList.find(item => item === text)
|
||||
if (item) {
|
||||
itemList.push(key)
|
||||
}
|
||||
}
|
||||
let str = ''
|
||||
const cn_inputList = cn_input.split("'")
|
||||
for (let i = 0; i < cn_inputList.length; i++) {
|
||||
let item = cn_inputList[i]
|
||||
for (let key of itemList) {
|
||||
let list = key.split('')
|
||||
for (let k = 0; k < list.length; k++) {
|
||||
if (key.charAt(k) === item.charAt(k)) {
|
||||
str = item
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let result = cn_inputList.filter(item => item != str).join("'")
|
||||
|
||||
self.postMessage({ method: 'setCn_input', cn_input: result });
|
||||
}
|
||||
|
||||
// const findInitialCn = function (cn_input, data) {
|
||||
// console.time("for2");
|
||||
// let strList = [];
|
||||
// let count = 0
|
||||
// Object.keys(data).filter((key) => {
|
||||
// const keys = key.split("'");
|
||||
// let i = 0;
|
||||
// const bool = keys.every((item, index) => {
|
||||
// ++count
|
||||
// if (index === 0) {
|
||||
// if (item.charAt(0) === cn_input.charAt(0)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// i += 2;
|
||||
// if (item.charAt() === cn_input.charAt(i)) return true;
|
||||
// }
|
||||
// });
|
||||
// if (bool) {
|
||||
// strList.push(data[key]);
|
||||
// }
|
||||
|
||||
// });
|
||||
// console.log('count', count, strList)
|
||||
// console.timeEnd("for2");
|
||||
// let keys = cn_input.split("'")
|
||||
// strList = strList.filter(item => item.length === keys.length);
|
||||
|
||||
// return strList
|
||||
|
||||
// }
|
||||
6
src/renderer/src/components/keyboard/key.js
Normal file
6
src/renderer/src/components/keyboard/key.js
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
number: ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'X', '0', '.'],
|
||||
biaodian: ['@', '#', '$', '¥', '%', '*', '(', ')', '/', '.', '-', ','],
|
||||
letter: ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm'],
|
||||
cap_letter: ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M']
|
||||
}
|
||||
64
src/renderer/src/components/keyboard/keyDel.vue
Normal file
64
src/renderer/src/components/keyboard/keyDel.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<span
|
||||
:class="{ 'key def-del': flagStyle, 'key number num-del': !flagStyle }"
|
||||
@touchend="touchendDel"
|
||||
@touchstart="touchstartDel"
|
||||
@mouseup="touchendDel"
|
||||
@mousedown="touchstartDel"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 1024 1024"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
:width="kWidhth"
|
||||
:height="kHeight"
|
||||
>
|
||||
<path
|
||||
d="M938.8 227.7H284.6L0.1 511.3l284.4 284.4v0.8h654.2c47.1 0 85.3-38.2 85.3-85.3V313c0.1-47.1-38.1-85.3-85.2-85.3z m-172.1 385l-40.2 40.2-100.6-100.6-100.6 100.6-40.2-40.2 100.6-100.6-100.6-100.5 40.2-40.2L625.9 472l100.6-100.6 40.2 40.2-100.6 100.5 100.6 100.6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject, ref } from "vue";
|
||||
|
||||
const mode = inject("mode");
|
||||
const flagStyle = ref(true);
|
||||
let kWidhth = ref("50");
|
||||
let kHeight = ref("50");
|
||||
if (!["cn", "en_cap", "en", "password"].includes(mode.value)) {
|
||||
flagStyle.value = false;
|
||||
kWidhth.value = "65"
|
||||
kHeight.value = "65"
|
||||
}
|
||||
const interval = ref();
|
||||
const isIntervalDel = ref(false);
|
||||
const emits = defineEmits(["del"]);
|
||||
|
||||
const touchstartDel = (e) => {
|
||||
e.preventDefault();
|
||||
if (!interval.value) {
|
||||
e.currentTarget.style.background = "#d0d0d0";
|
||||
interval.value = setInterval(() => {
|
||||
isIntervalDel.value = true;
|
||||
emits("del", e);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
const touchendDel = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
clearInterval(interval.value);
|
||||
if (!isIntervalDel.value) {
|
||||
emits("del", e);
|
||||
}
|
||||
e.currentTarget.style.background = "#fff";
|
||||
isIntervalDel.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* 样式代码 */
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
1044
src/renderer/src/components/keyboard/keyboardIndex.vue
Normal file
1044
src/renderer/src/components/keyboard/keyboardIndex.vue
Normal file
File diff suppressed because it is too large
Load Diff
39
src/renderer/src/main.ts
Normal file
39
src/renderer/src/main.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { createApp } from "vue";
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import App from './App.vue'
|
||||
import router from "../router/router.js";
|
||||
// import Antd from 'ant-design-vue';
|
||||
import Vant from 'vant'
|
||||
import 'vant/lib/index.css'
|
||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import axios from "axios";
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false, // 添加此行以启用 Composition API 模式
|
||||
locale: 'zh-cn', // 设置默认语言
|
||||
messages: {
|
||||
// 添加翻译文本
|
||||
'zh-cn': {
|
||||
common: {
|
||||
clear: '清除',
|
||||
close: '关闭'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||
app.component(key, component)
|
||||
}
|
||||
|
||||
|
||||
app.use(router);
|
||||
app.use(Vant);
|
||||
app.use(i18n) // 注册 i18n 插件
|
||||
app.use(axios)
|
||||
app.use(ElementPlus)
|
||||
app.mount('#app')
|
||||
4
tsconfig.json
Normal file
4
tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [{ "path": "./tsconfig.node.json" }, { "path": "./tsconfig.web.json" }]
|
||||
}
|
||||
8
tsconfig.node.json
Normal file
8
tsconfig.node.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "@electron-toolkit/tsconfig/tsconfig.node.json",
|
||||
"include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"types": ["electron-vite/node"]
|
||||
}
|
||||
}
|
||||
18
tsconfig.web.json
Normal file
18
tsconfig.web.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "@electron-toolkit/tsconfig/tsconfig.web.json",
|
||||
"include": [
|
||||
"src/renderer/src/env.d.ts",
|
||||
"src/renderer/src/**/*",
|
||||
"src/renderer/src/**/*.vue",
|
||||
"src/preload/*.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@renderer/*": [
|
||||
"src/renderer/src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user