feat(i18n) multi-lang on uart page: Chinese, French and English.
This commit is contained in:
parent
dd1b9adc0d
commit
d7d7c94f53
|
@ -10,7 +10,7 @@
|
|||
"dependencies": {
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"ansi_up": "^6.0.2",
|
||||
"element-plus": "^2.7.3",
|
||||
"element-plus": "^2.8.1",
|
||||
"mitt": "^3.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.21",
|
||||
|
@ -979,31 +979,29 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.1.4.tgz",
|
||||
"integrity": "sha512-ROfPepDxZ5Eq+Unbx3M9QcHT7MoE9tYdbkuzLTtxG5rfkEi5RwsDPncjANMOq/gHhIIDlWgqWwS2nXWMGsuj4w==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.0.tgz",
|
||||
"integrity": "sha512-FTla+khE+sYK0qJP+6hwPAAUwiNHVMph4RUXpxf/FIPKUP61NFrVZorml4mjFShnueR2y9/j8/vnh09YwVdH7A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/source-map": "2.1.4"
|
||||
"@volar/source-map": "2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.1.4.tgz",
|
||||
"integrity": "sha512-mCg8IiPZmHZVzqL4Owg+BzQ5ZTG1cVwATxrkrFPZpcAin97Xa3MbchxVhHtHTWTT8ER8bJh5xVjeVxsSN++FUA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"muggle-string": "^0.4.0"
|
||||
}
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.0.tgz",
|
||||
"integrity": "sha512-2ceY8/NEZvN6F44TXw2qRP6AQsvCYhV2bxaBPWxV9HqIfkbRydSksTFObCF1DBDNBfKiZTS8G/4vqV6cvjdOIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.1.4.tgz",
|
||||
"integrity": "sha512-Mt7wOLPkomFnUfVpb5IHlPhSpD7FJAn+FHSsovePmqFNQzFLz16wrpHjAkorPiAnP0847w71NL5fIJyWbAsR8Q==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.0.tgz",
|
||||
"integrity": "sha512-9zx3lQWgHmVd+JRRAHUSRiEhe4TlzL7U7e6ulWXOxHH/WNYxzKwCvZD7WYWEZFdw4dHfTD9vUR0yPQO6GilCaQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.1.4",
|
||||
"path-browserify": "^1.0.1"
|
||||
"@volar/language-core": "2.4.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-uri": "^3.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
|
@ -1052,6 +1050,16 @@
|
|||
"@vue/shared": "3.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-vue2": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
|
||||
"integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz",
|
||||
|
@ -1096,18 +1104,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vue/language-core": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.7.tgz",
|
||||
"integrity": "sha512-Vh1yZX3XmYjn9yYLkjU8DN6L0ceBtEcapqiyclHne8guG84IaTzqtvizZB1Yfxm3h6m7EIvjerLO5fvOZO6IIQ==",
|
||||
"version": "2.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.29.tgz",
|
||||
"integrity": "sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/language-core": "~2.1.3",
|
||||
"@volar/language-core": "~2.4.0-alpha.18",
|
||||
"@vue/compiler-dom": "^3.4.0",
|
||||
"@vue/compiler-vue2": "^2.7.16",
|
||||
"@vue/shared": "^3.4.0",
|
||||
"computeds": "^0.0.1",
|
||||
"minimatch": "^9.0.3",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vue-template-compiler": "^2.7.14"
|
||||
"muggle-string": "^0.4.1",
|
||||
"path-browserify": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
|
@ -1977,9 +1986,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/element-plus": {
|
||||
"version": "2.7.3",
|
||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.7.3.tgz",
|
||||
"integrity": "sha512-OaqY1kQ2xzNyRFyge3fzM7jqMwux+464RBEqd+ybRV9xPiGxtgnj/sVK4iEbnKnzQIa9XK03DOIFzoToUhu1DA==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.8.1.tgz",
|
||||
"integrity": "sha512-p11/6w/O0+hGvPhiN3jrcgh+XG+eg5jZlLdQVYvcPHZYhhCh3J3YeZWW1JO/REPES1vevkboT6VAi+9wHA8Dsg==",
|
||||
"dependencies": {
|
||||
"@ctrl/tinycolor": "^3.4.1",
|
||||
"@element-plus/icons-vue": "^2.3.1",
|
||||
|
@ -3249,9 +3258,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
||||
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
|
@ -5042,6 +5051,12 @@
|
|||
"vue": ">=3.2.13"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-uri": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz",
|
||||
"integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.4.21",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.21.tgz",
|
||||
|
@ -5132,31 +5147,21 @@
|
|||
"vue": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-template-compiler": {
|
||||
"version": "2.7.16",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz",
|
||||
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vue-tsc": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.7.tgz",
|
||||
"integrity": "sha512-LYa0nInkfcDBB7y8jQ9FQ4riJTRNTdh98zK/hzt4gEpBZQmf30dPhP+odzCa+cedGz6B/guvJEd0BavZaRptjg==",
|
||||
"version": "2.0.29",
|
||||
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.29.tgz",
|
||||
"integrity": "sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@volar/typescript": "~2.1.3",
|
||||
"@vue/language-core": "2.0.7",
|
||||
"@volar/typescript": "~2.4.0-alpha.18",
|
||||
"@vue/language-core": "2.0.29",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"bin": {
|
||||
"vue-tsc": "bin/vue-tsc.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
"typescript": ">=5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vuetify": {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"dependencies": {
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"ansi_up": "^6.0.2",
|
||||
"element-plus": "^2.7.3",
|
||||
"element-plus": "^2.8.1",
|
||||
"mitt": "^3.0.1",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.21",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"/></svg>
|
After Width: | Height: | Size: 411 B |
43
src/i18n.ts
43
src/i18n.ts
|
@ -1,19 +1,48 @@
|
|||
import { createI18n } from 'vue-i18n';
|
||||
import {createI18n} from 'vue-i18n';
|
||||
import zh from '@/locales/zh'
|
||||
import en from '@/locales/en'
|
||||
import fr from '@/locales/fr'
|
||||
|
||||
// const locale = localStorage.getItem('lang') || 'zh';
|
||||
export const locale = 'zh';
|
||||
const userLanguage = navigator.language || 'en';
|
||||
|
||||
// Get the language code (e.g., 'en' from 'en-US')
|
||||
export const locale = userLanguage.split('-')[0];
|
||||
const messages = {
|
||||
zh,
|
||||
en,
|
||||
fr,
|
||||
} as const;
|
||||
|
||||
type Locale = keyof typeof messages;
|
||||
|
||||
export const availableLanguages = Object.keys(messages);
|
||||
|
||||
// export const locale = 'zh';
|
||||
console.log(userLanguage, locale, availableLanguages)
|
||||
|
||||
const i18n = createI18n({
|
||||
globalInjection: true,
|
||||
legacy: false,
|
||||
locale: locale,
|
||||
fallbackLocale: 'zh',
|
||||
messages: {
|
||||
zh,
|
||||
// en,
|
||||
}
|
||||
messages: messages
|
||||
});
|
||||
|
||||
export function getFlagFromLang(lang: string) {
|
||||
if (lang === 'zh') {
|
||||
return '🇨🇳';
|
||||
} else if (lang === 'en') {
|
||||
return '🇺🇸';
|
||||
} else if (lang === 'fr') {
|
||||
return '🇫🇷';
|
||||
}
|
||||
return '🏳️';
|
||||
}
|
||||
|
||||
export function setLang(lang: string): void {
|
||||
if (availableLanguages.includes(lang)) {
|
||||
i18n.global.locale.value = lang as Locale;
|
||||
}
|
||||
}
|
||||
|
||||
export default i18n;
|
||||
|
|
|
@ -1,3 +1,127 @@
|
|||
export default {
|
||||
disconnected: "disconnected"
|
||||
emoji: {
|
||||
flag: "🇺🇸",
|
||||
},
|
||||
disconnected: "Disconnected",
|
||||
connected: "Connected",
|
||||
connecting: "Connecting",
|
||||
|
||||
ws: {
|
||||
disconnected: "Disconnected",
|
||||
connected: "Connected",
|
||||
connecting: "Connecting",
|
||||
},
|
||||
|
||||
page: {
|
||||
home: "Home",
|
||||
wifi: "Wi-Fi",
|
||||
about: "About",
|
||||
uart: "Uart",
|
||||
feedback: "Feedback",
|
||||
close: "Close",
|
||||
update: "Update",
|
||||
fullscreen: "Fullscreen",
|
||||
windowed: "Windowed"
|
||||
},
|
||||
|
||||
uart: {
|
||||
port: "Port",
|
||||
startCommunication: "Start Communication",
|
||||
stopCommunication: "Stop Communication",
|
||||
commonlyUsed: "Common",
|
||||
baudrate: "Baud Rate",
|
||||
customBaud: "Custom Baud",
|
||||
use: "Use",
|
||||
actual: "Actual",
|
||||
dataBits: "Data Bits",
|
||||
stopBits: "Stop Bits",
|
||||
parity: "Parity",
|
||||
parityNone: "None",
|
||||
parityOdd: "Odd",
|
||||
parityEven: "Even",
|
||||
flowControl: "Flow Control",
|
||||
send: "Send",
|
||||
clear: "Clear",
|
||||
clearTooltip: "Only clears the display area, can be restored with refresh.",
|
||||
updateTooltip: "Sync with cache + filter",
|
||||
autoUpdateTooltip: "Only stop refreshing the display area; the background continues to receive data.",
|
||||
receive: "Receive",
|
||||
|
||||
displayOptions: "Display Options",
|
||||
display: "Display",
|
||||
show: "Show",
|
||||
text: "Text",
|
||||
timestamp: "Timestamp",
|
||||
enable: "Enable",
|
||||
lineWrap: "Line Wrap",
|
||||
highlight: "Highlight",
|
||||
|
||||
frameBreakStrategy: "Frame Break Strategy",
|
||||
priority: "Priority",
|
||||
rule: "Rule",
|
||||
ruleTips:
|
||||
"<p>Timeout=-1: Disable timeout frame break</p>" +
|
||||
"<p>Timeout=0: Immediate break, any received data is considered complete</p>" +
|
||||
"<p>Match after break: Typical \\n scenario</p>" +
|
||||
"<p>Match before break: For scenarios with special frame headers</p>" +
|
||||
"<p>Fixed byte frame break: Useful for large data transfer, e.g., break frame every 1024 bytes for easy data viewing</p>",
|
||||
value: "Value",
|
||||
timeout: "Timeout",
|
||||
match: "Match",
|
||||
byte: "Byte",
|
||||
begin: "b",
|
||||
end: "b",
|
||||
|
||||
other: "Other",
|
||||
decodeAnsiEscapeCodes: "Decode ANSI Escape Codes",
|
||||
ansiTooltips:
|
||||
"<p>ANSI escape codes have many uses for terminals and text, such as changing text colors, among other effects.</p>\n" +
|
||||
"<p>\n Learn more ->\n <a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/ANSI_escape_code\">" +
|
||||
"https://en.wikipedia.org/wiki/ANSI_escape_code\n </a></p>",
|
||||
filter: "Filter",
|
||||
textAndEscape: "Text with \\n\\x support",
|
||||
autoUpdateNewData: "Auto-refresh new data",
|
||||
updateFrequency: "Data Display Update Interval (ms)",
|
||||
updateFrequencyTooltip: "Increasing the interval can reduce CPU usage.",
|
||||
|
||||
addHeader: "Add Header",
|
||||
addFooter: "Add Footer",
|
||||
|
||||
passthrough: "Passthrough",
|
||||
proxy: "Proxy",
|
||||
serverPort: "Server Port",
|
||||
connectedClient: "Connected Client",
|
||||
refresh: "Refresh",
|
||||
interface: "Interface",
|
||||
noClientConnected: "No Client Connected",
|
||||
|
||||
import: "Import",
|
||||
export: "Export",
|
||||
reset: "Reset",
|
||||
resetTooltip: "Takes effect after refreshing the page.",
|
||||
saveToLocal: "Save to Local",
|
||||
saveToLocalTooltip: "If multiple pages exist, they will overwrite each other.",
|
||||
add: "Add",
|
||||
edit: "Edit",
|
||||
drag: "Drag",
|
||||
ipChangeAlert: "Changing the IP address will cause the configuration to be lost.",
|
||||
|
||||
layout: "Layout",
|
||||
landscape: "Landscape",
|
||||
portrait: "Portrait",
|
||||
responsive: "Responsive",
|
||||
configPannel: "Config",
|
||||
displayPannel: "Display",
|
||||
macroPannel: "Quick Send",
|
||||
autoScrollToBottom: "Auto Scroll",
|
||||
clearScreen: "Clear",
|
||||
autoUpdate: "Auto Update",
|
||||
tempDisplayTooltip: "Data that does not meet the frame-break rules (e.g., not timed out) is temporarily displayed in real-time in this area. If it exceeds 8192 bytes, it will automatically break frames.",
|
||||
loopSend: "Loop Send",
|
||||
loopSendTooltip: "The actual frequency is affected by the interface refresh rate. For more accuracy, you can try turning off 'auto-refresh'.",
|
||||
sendFormat: "Send Format",
|
||||
cachedFrame: "Cached",
|
||||
format: "Format",
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,128 @@
|
|||
export default {
|
||||
emoji: {
|
||||
flag: "🇫🇷",
|
||||
},
|
||||
disconnected: "Déconnecté",
|
||||
connected: "Connecté",
|
||||
connecting: "Connexion..",
|
||||
|
||||
ws: {
|
||||
disconnected: "Déconnecté",
|
||||
connected: "Connecté",
|
||||
connecting: "Connexion..",
|
||||
},
|
||||
|
||||
page: {
|
||||
home: "Accueil",
|
||||
wifi: "Wi-Fi",
|
||||
about: "À propos",
|
||||
uart: "Uart",
|
||||
feedback: "Feedback",
|
||||
close: "Fermer",
|
||||
update: "Mise à jour",
|
||||
fullscreen: "Plein écran",
|
||||
windowed: "Fenêtré",
|
||||
},
|
||||
|
||||
uart: {
|
||||
port: "Port",
|
||||
startCommunication: "Démarrer la communication",
|
||||
stopCommunication: "Arrêter la communication",
|
||||
commonlyUsed: "Fréquemment utilisé",
|
||||
baudrate: "Taux de Baud",
|
||||
customBaud: "Baud",
|
||||
use: "Utiliser",
|
||||
actual: "Actuel",
|
||||
dataBits: "Bits de Données",
|
||||
stopBits: "Bits d'Arrêt",
|
||||
parity: "Parité",
|
||||
parityNone: "Aucune",
|
||||
parityOdd: "Impair(Odd)",
|
||||
parityEven: "Pair(Even)",
|
||||
flowControl: "Contrôle de Flux",
|
||||
send: "Envoyer",
|
||||
clear: "Effacer",
|
||||
clearTooltip: "Ne supprime que la zone d'affichage, peut être restaurée en actualisant.",
|
||||
updateTooltip: "Synchroniser avec le cache + filtrer",
|
||||
autoUpdateTooltip: "Arrête uniquement le rafraîchissement de la zone d'affichage ; l'arrière-plan continue de recevoir des données.",
|
||||
receive: "Recevoir",
|
||||
|
||||
displayOptions: "Options d'Affichage",
|
||||
display: "Affichage",
|
||||
show: "Afficher",
|
||||
text: "Texte",
|
||||
timestamp: "Horodatage",
|
||||
enable: "Activer",
|
||||
lineWrap: "Retour à la Ligne",
|
||||
highlight: "Surligner",
|
||||
|
||||
frameBreakStrategy: "Stratégie de Coupure de Trame",
|
||||
priority: "Priorité",
|
||||
rule: "Règle",
|
||||
ruleTips:
|
||||
"<p>Délai d'expiration=-1 : Désactiver la coupure de trame par délai d'expiration</p>" +
|
||||
"<p>Délai d'expiration=0 : Coupure immédiate, toutes données reçues sont considérées complètes</p>" +
|
||||
"<p>Match après coupure : Scénario typique \\n</p>" +
|
||||
"<p>Match avant coupure : Pour des scénarios avec en-têtes de trame spécifiques</p>" +
|
||||
"<p>Coupure de trame par octets fixes : Utile pour le transfert de grandes quantités de données, par exemple, couper la trame tous les 1024 octets pour faciliter la visualisation des données</p>",
|
||||
value: "Valeur",
|
||||
timeout: "Timeout",
|
||||
match: "Match",
|
||||
byte: "Byte",
|
||||
begin: "b",
|
||||
end: "b",
|
||||
|
||||
other: "Autres",
|
||||
decodeAnsiEscapeCodes: "Décode Échappement ANSI",
|
||||
ansiTooltips:
|
||||
"<p>Les codes d'échappement ANSI ont de nombreuses utilisations pour les terminaux et le texte, comme changer les couleurs du texte, entre autres effets.</p>" +
|
||||
"<p>\n En savoir plus ->\n " +
|
||||
"<a target=\"_blank\" href=\"https://en.wikipedia.org/wiki/ANSI_escape_code\">\n" +
|
||||
"https://en.wikipedia.org/wiki/ANSI_escape_code\n </a>\n</p>",
|
||||
filter: "Filtrer",
|
||||
textAndEscape: "Texte;supporte\\n\\x",
|
||||
autoUpdateNewData: "Auto-update nouvelles données",
|
||||
updateFrequency: "Délais rafraîchissement des Données (ms)",
|
||||
updateFrequencyTooltip: "Augmenter l'intervalle peut réduire l'utilisation des ressources CPU.",
|
||||
|
||||
addHeader: "Ajouter un En-tête",
|
||||
addFooter: "Ajouter un Pied de page",
|
||||
|
||||
passthrough: "Passage Direct",
|
||||
proxy: "Proxy",
|
||||
serverPort: "Port Serveur",
|
||||
connectedClient: "Client Connecté",
|
||||
refresh: "Rafraîchir",
|
||||
interface: "Interface",
|
||||
noClientConnected: "Aucun Client Connecté",
|
||||
|
||||
import: "Importer",
|
||||
export: "Exporter",
|
||||
reset: "Réinitialiser",
|
||||
resetTooltip: "Prend effet après le rafraîchissement de la page.",
|
||||
saveToLocal: "Enregistrer Localement",
|
||||
saveToLocalTooltip: "S'il existe plusieurs pages, elles se chevaucheront mutuellement.",
|
||||
add: "Ajouter",
|
||||
edit: "Éditer",
|
||||
drag: "Glisser",
|
||||
ipChangeAlert: "Le changement d'adresse IP entraînera la perte de la configuration.",
|
||||
|
||||
layout: "Disposition",
|
||||
landscape: "Paysage",
|
||||
portrait: "Portrait",
|
||||
responsive: "Résponsive",
|
||||
configPannel: "Configuration",
|
||||
displayPannel: "Données",
|
||||
macroPannel: "Envoie Rapide",
|
||||
autoScrollToBottom: "Auto Scroll",
|
||||
clearScreen: "Effacer",
|
||||
autoUpdate: "Auto Update",
|
||||
tempDisplayTooltip: "es données qui ne respectent pas les règles de rupture de trame (par exemple : non expirées) s'affichent temporairement en temps réel dans cette zone. Au-delà de 8192 octets, une rupture de trame est automatique.",
|
||||
loopSend: "Envoi en Boucle",
|
||||
loopSendTooltip: "La fréquence réelle est influencée par le taux de rafraîchissement de l'interface. Pour plus de précision, vous pouvez essayer de désactiver 'l'actualisation automatique'.",
|
||||
sendFormat: "Format d'Envoi",
|
||||
cachedFrame: "Cache",
|
||||
format: "Format",
|
||||
}
|
||||
|
||||
};
|
|
@ -7,8 +7,8 @@ type NestedKeyOf<ObjectType extends object> = {
|
|||
: `${Key}`
|
||||
}[keyof ObjectType & (string | number)];
|
||||
|
||||
type TranslationKeys = NestedKeyOf<typeof zh>;
|
||||
export type TranslationKeys = NestedKeyOf<typeof zh>;
|
||||
|
||||
export function translate<K extends TranslationKeys>(key: K | string): string {
|
||||
return i18n.global.t(key.toLowerCase());
|
||||
export function translate(key: TranslationKeys | string): string {
|
||||
return i18n.global.t(key);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
export default {
|
||||
emoji: {
|
||||
flag: "🇨🇳",
|
||||
},
|
||||
disconnected: "未连接",
|
||||
connected: "已连接",
|
||||
connecting: "连接中",
|
||||
use: "使用",
|
||||
|
||||
ws: {
|
||||
disconnected: "未连接",
|
||||
|
@ -13,9 +17,115 @@ export default {
|
|||
home: "主页",
|
||||
wifi: "Wi-Fi",
|
||||
about: "关于",
|
||||
uart: "UART透传",
|
||||
uart: "UART",
|
||||
feedback: "反馈",
|
||||
close: "关闭",
|
||||
update: "更新",
|
||||
fullscreen: "全屏",
|
||||
windowed: "窗口",
|
||||
},
|
||||
|
||||
uart: {
|
||||
port: "接口",
|
||||
startCommunication: "开始数据收发",
|
||||
stopCommunication: "停止数据收发",
|
||||
commonlyUsed: "常用",
|
||||
baudrate: "波特率",
|
||||
customBaud: "自定义波特率",
|
||||
use: "使用",
|
||||
actual: "实际",
|
||||
dataBits: "数据位",
|
||||
stopBits: "停止位",
|
||||
parity: "校验位",
|
||||
parityNone: "无(None)",
|
||||
parityOdd: "奇(Odd)",
|
||||
parityEven: "偶(Even)",
|
||||
flowControl: "流控制",
|
||||
send: "发送",
|
||||
clear: "清空",
|
||||
clearTooltip: "仅清除显示区域,可用刷新恢复",
|
||||
updateTooltip: "与缓存同步+过滤",
|
||||
autoUpdateTooltip: "仅停止刷新显示区,后台继续接收数据",
|
||||
receive: "接收",
|
||||
|
||||
displayOptions: "显示选项",
|
||||
display: "显示框",
|
||||
show: "显示",
|
||||
text: "文本",
|
||||
timestamp: "时间戳",
|
||||
enable: "启用",
|
||||
lineWrap: "换行",
|
||||
highlight: "高亮",
|
||||
|
||||
frameBreakStrategy: "断帧策略",
|
||||
priority: "优先级",
|
||||
rule: "规则",
|
||||
ruleTips:
|
||||
"<p>超时=-1: 禁用超时断帧</p>" +
|
||||
"<p>超时=0: 当机立断,收到任何数据都视为完整数据</p>" +
|
||||
"<p>匹配断后:典型\\n的场景</p>" +
|
||||
"<p>匹配断前:用于有特殊帧头的场景</p>" +
|
||||
"<p>固定字节断帧:传输大量数据,比如可以每隔1024字节断帧,方便查看数据</p>",
|
||||
value: "值",
|
||||
timeout: "超时",
|
||||
match: "匹配",
|
||||
byte: "字节",
|
||||
begin: "断",
|
||||
end: "断",
|
||||
|
||||
other: "其他",
|
||||
decodeAnsiEscapeCodes: "解码ANSI转义码",
|
||||
ansiTooltips:
|
||||
"<p>ANSI转义码对终端和文本有很多作用,比如改变文本颜色等。</p>\n" +
|
||||
"<p>\n" +
|
||||
" 简单了解->\n" +
|
||||
" <a target=\"_blank\" href=\"https://yunsi.studio/wireless-debugger/docs/uart-webhost/ansi-escape-code\">\n" +
|
||||
" https://yunsi.studio/wireless-debugger/docs/uart-webhost/ansi-escape-code\n" +
|
||||
" </a>\n" +
|
||||
"</p>",
|
||||
filter: "过滤",
|
||||
textAndEscape: "文本,支持\\n\\x",
|
||||
autoUpdateNewData: "新数据自动刷新",
|
||||
updateFrequency: "数据显示刷新间隔(ms)",
|
||||
updateFrequencyTooltip: "提高间隔可减少CPU资源的使用",
|
||||
|
||||
addHeader: "增加帧头",
|
||||
addFooter: "增加帧尾",
|
||||
|
||||
passthrough: "透传",
|
||||
proxy: "透传",
|
||||
serverPort: "服务器端口",
|
||||
connectedClient: "已连接的客户端",
|
||||
refresh: "刷新",
|
||||
interface: "接口",
|
||||
noClientConnected: "无客户端连接",
|
||||
|
||||
import: "导入",
|
||||
export: "导出",
|
||||
reset: "重置",
|
||||
resetTooltip: "刷新页面后生效",
|
||||
saveToLocal: "保存到本地",
|
||||
saveToLocalTooltip: "若存在多个页面,会相互覆盖",
|
||||
add: "添加",
|
||||
edit: "编辑",
|
||||
drag: "拖拽",
|
||||
ipChangeAlert: "IP地址改变会导致配置丢失",
|
||||
|
||||
layout: "布局",
|
||||
landscape: "横/行",
|
||||
portrait: "竖/列",
|
||||
responsive: "自适应",
|
||||
configPannel: "设置窗",
|
||||
displayPannel: "数据窗",
|
||||
macroPannel: "快捷窗",
|
||||
autoScrollToBottom: "自动滚动到底部",
|
||||
clearScreen: "清屏",
|
||||
autoUpdate: "自动刷新",
|
||||
tempDisplayTooltip: "未满足断帧规则的数据(如:未超时),暂时实时显示在此区域。超过8192字节,自动断帧;",
|
||||
loopSend: "循环发送",
|
||||
loopSendTooltip: "实际频率受界面刷新率影响,如需要更精确,可以尝试关闭‘自动刷新’",
|
||||
sendFormat: "发送格式",
|
||||
cachedFrame: "缓存帧数",
|
||||
format: "格式化",
|
||||
}
|
||||
}
|
|
@ -364,18 +364,18 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
|
|||
|
||||
const frameBreakSize = ref(0);
|
||||
const frameBreakRules = ref([{
|
||||
name: '超时(ms)',
|
||||
name: 'timeout',
|
||||
type: 'number',
|
||||
min: -1,
|
||||
draggable: false,
|
||||
transformData: breakDelay,
|
||||
}, {
|
||||
name: '匹配',
|
||||
name: 'match',
|
||||
type: 'text',
|
||||
draggable: true,
|
||||
transformData: breakSequence,
|
||||
}, {
|
||||
name: '字节(B)',
|
||||
name: 'byte',
|
||||
type: 'number',
|
||||
min: 0,
|
||||
draggable: true,
|
||||
|
@ -437,9 +437,9 @@ export const useDataViewerStore = defineStore('text-viewer', () => {
|
|||
function reloadFrameBreak() {
|
||||
/* function and ref can not be stored in localStorage */
|
||||
for (let i = 0; i < frameBreakRules.value.length; i++) {
|
||||
if (frameBreakRules.value[i].name === "超时(ms)") {
|
||||
if (frameBreakRules.value[i].name === "timeout") {
|
||||
frameBreakRules.value[i].transformData = breakDelay;
|
||||
} else if (frameBreakRules.value[i].name === "匹配") {
|
||||
} else if (frameBreakRules.value[i].name === "match") {
|
||||
frameBreakRules.value[i].transformData = breakSequence;
|
||||
} else {
|
||||
frameBreakRules.value[i].transformData = breakSize;
|
||||
|
|
|
@ -38,15 +38,24 @@
|
|||
<div class="custom-style flex justify-center">
|
||||
<el-segmented v-model="store.winLayoutMode" :options="layoutOptions" size="small"/>
|
||||
</div>
|
||||
<el-checkbox label="自适应" v-model="store.winAutoLayout" border size="small"
|
||||
:disabled="store.winLayoutMode==='col'"/>
|
||||
<el-checkbox label="设置窗" v-model="store.winLeft.show" border size="small" :disabled="store.winAutoLayout"/>
|
||||
<el-checkbox label="数据窗" v-model="winDataView.show" border size="small" :disabled="store.winAutoLayout"/>
|
||||
<el-checkbox label="快捷窗" v-model="store.winRight.show" border size="small" :disabled="store.winAutoLayout"/>
|
||||
<el-checkbox v-model="store.winAutoLayout" border size="small"
|
||||
:disabled="store.winLayoutMode==='col'">
|
||||
{{ $t('uart.responsive') }}
|
||||
</el-checkbox>
|
||||
<el-checkbox v-model="store.winLeft.show" border size="small" :disabled="store.winAutoLayout">
|
||||
{{ $t("uart.configPannel") }}
|
||||
</el-checkbox>
|
||||
<el-checkbox v-model="winDataView.show" border size="small" :disabled="store.winAutoLayout">
|
||||
{{ $t('uart.displayPannel') }}
|
||||
</el-checkbox>
|
||||
<el-checkbox v-model="store.winRight.show" border size="small" :disabled="store.winAutoLayout">
|
||||
{{ $t('uart.macroPannel') }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
|
||||
<template #reference>
|
||||
<el-button class="min-h-full" type="primary" :size="layoutConf.isMedium ? 'small' : 'default'">布局
|
||||
<el-button class="min-h-full" type="primary" :size="layoutConf.isMedium ? 'small' : 'default'">
|
||||
{{ $t('uart.layout') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-popover>
|
||||
|
@ -56,7 +65,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {onMounted, onUnmounted, reactive, type Ref, ref, type UnwrapRef, watch} from "vue";
|
||||
import {computed, onMounted, onUnmounted, reactive, type Ref, ref, type UnwrapRef, watch} from "vue";
|
||||
import {breakpointsTailwind, useBreakpoints} from '@vueuse/core'
|
||||
import {useDataViewerStore} from '@/stores/dataViewerStore';
|
||||
import * as api from '@/api';
|
||||
|
@ -83,6 +92,7 @@ import {isDevMode} from "@/composables/buildMode";
|
|||
import {useWsStore} from "@/stores/websocket";
|
||||
import {useUartStore} from "@/stores/useUartStore";
|
||||
import TextDataMacro from "@/views/text-data-viewer/textDataMacro.vue";
|
||||
import {translate} from "@/locales";
|
||||
|
||||
const store = useDataViewerStore()
|
||||
const wsStore = useWsStore()
|
||||
|
@ -100,13 +110,13 @@ const layoutConf = reactive({
|
|||
isMedium: breakpoints.smaller("lg"),
|
||||
});
|
||||
|
||||
const layoutOptions = [{
|
||||
label: '横/行',
|
||||
const layoutOptions = computed(() => [{
|
||||
label: translate("uart.landscape"),
|
||||
value: 'row'
|
||||
}, {
|
||||
label: '竖/列',
|
||||
label: translate("uart.portrait"),
|
||||
value: 'col'
|
||||
}]
|
||||
}]);
|
||||
|
||||
interface WinProperty {
|
||||
show: boolean;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<nav class="relative px-2 py-0.5 sm:py-1 flex justify-between items-center border-b h-full">
|
||||
<div class="flex">
|
||||
<button @click.prevent="sideMenuOpen=true" class="flex items-center hover:text-blue-600 pl-1 mx-4">
|
||||
<button @click.prevent="sideMenuOpen=true" class="flex items-center hover:text-blue-600 pl-1 mx-2 sm:mx-4">
|
||||
<svg class="block h-3 lg:h-4 lg:w-4 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>导航侧栏</title>
|
||||
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
|
||||
|
@ -20,7 +20,7 @@
|
|||
<!-- <router-link to="/" class="flex items-center text-sm text-blue-600 font-bold">主页</router-link>-->
|
||||
<!-- <a class="flex items-center text-sm text-blue-600 font-bold" href="/">主页6</a>-->
|
||||
|
||||
<div class="flex pt-0.5 sm:pt-1 ml-4 text-sm items-center sm:hidden">
|
||||
<div class="flex pt-0.5 sm:pt-1 ml-4 text-xs items-center sm:hidden">
|
||||
<router-link :to="route.fullPath">{{ route.meta.title }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,6 +36,20 @@
|
|||
<!-- <a class="md:ml-auto md:mr-3"></a>-->
|
||||
<div class="flex h-full">
|
||||
<div id="page-spec-slot" class="content-center h-full flex flex-row"></div>
|
||||
<div class="mr-2">
|
||||
<el-select v-model="language" class="min-w-20 h-full" @change="handleLanguageChange">
|
||||
<el-option value="en">🇺🇸 English</el-option>
|
||||
<el-option value="zh">🇨🇳 简体中文</el-option>
|
||||
<el-option value="fr">🇫🇷 Français</el-option>
|
||||
<template #label>
|
||||
<div class="flex">
|
||||
<InlineSvg name="translate" class="w-4 mr-1"></InlineSvg>
|
||||
{{ languageFlag }}
|
||||
</div>
|
||||
</template>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="lg:hidden">
|
||||
<el-button :type="wsColor" size="small" class="transition duration-1000 min-h-full">
|
||||
<InlineSvg v-show="wsColor!=='success'" name="link-off" class="mr-2" width="20"></InlineSvg>
|
||||
|
@ -81,9 +95,9 @@
|
|||
<div>
|
||||
<el-button @click="toggle">
|
||||
<InlineSvg v-if="!isFullscreen" name="open-in-full" width="16px" fill="#000000"></InlineSvg>
|
||||
<p v-if="!isFullscreen">全屏</p>
|
||||
<p v-if="!isFullscreen">{{ translate('page.fullscreen') }}</p>
|
||||
<InlineSvg v-if="isFullscreen" name="close-fullscreen" width="16px" fill="#000000"></InlineSvg>
|
||||
<p v-if="isFullscreen">缩小</p>
|
||||
<p v-if="isFullscreen">{{ translate('page.windowed') }}</p>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -109,7 +123,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import InlineSvg from "@/components/InlineSvg.vue";
|
||||
import {computed, type Ref, ref} from "vue";
|
||||
import {computed, type ComputedRef, type Ref, ref} from "vue";
|
||||
import {useWsStore} from "@/stores/websocket";
|
||||
import {translate} from "@/locales";
|
||||
import {ControlEvent} from "@/api";
|
||||
|
@ -117,11 +131,21 @@ import {useRoute} from "vue-router";
|
|||
import { useFullscreen } from '@vueuse/core'
|
||||
import {useUpdateStore} from "@/stores/useUpdateStore";
|
||||
import {isOTAEnabled} from "@/composables/buildMode";
|
||||
import {getFlagFromLang, locale, setLang} from "@/i18n"
|
||||
|
||||
const wsStore = useWsStore();
|
||||
const updateStore = useUpdateStore();
|
||||
const {isFullscreen, toggle} = useFullscreen();
|
||||
const route = useRoute();
|
||||
const language = ref(locale);
|
||||
|
||||
const languageFlag = computed(() => {
|
||||
return getFlagFromLang(language.value);
|
||||
});
|
||||
|
||||
function handleLanguageChange(lang: string) {
|
||||
setLang(lang);
|
||||
}
|
||||
|
||||
const sideMenuItemClass = "block p-4 text-sm font-semibold hover:bg-blue-50 hover:text-blue-600 rounded flex"
|
||||
const sideMenuOpen = ref(false);
|
||||
|
@ -144,7 +168,7 @@ const wsColor = computed(() => {
|
|||
});
|
||||
|
||||
const wsState = computed(() => {
|
||||
return translate(wsStore.state);
|
||||
return translate(wsStore.state.toLocaleLowerCase());
|
||||
});
|
||||
|
||||
type Item = {
|
||||
|
@ -154,7 +178,7 @@ type Item = {
|
|||
badge?: Ref<boolean>;
|
||||
};
|
||||
|
||||
const menuItems: Item[] = ([
|
||||
const menuItems: ComputedRef<Item[]> = computed(() => ([
|
||||
{
|
||||
name: translate("page.uart"),
|
||||
href: "/uart",
|
||||
|
@ -165,31 +189,35 @@ const menuItems: Item[] = ([
|
|||
name: translate("page.feedback"),
|
||||
href: "/feedback",
|
||||
},
|
||||
]);
|
||||
]));
|
||||
|
||||
const sideBarItems: ComputedRef<Item[]> = computed(() => {
|
||||
const items: Item[] = [
|
||||
{
|
||||
name: translate("page.uart"),
|
||||
href: "/uart",
|
||||
}, {
|
||||
name: translate("page.wifi"),
|
||||
href: "/wifi",
|
||||
}, {
|
||||
name: translate("page.about"),
|
||||
href: "/about",
|
||||
}, {
|
||||
name: translate("page.feedback"),
|
||||
href: "/feedback",
|
||||
},
|
||||
];
|
||||
if (isOTAEnabled()) {
|
||||
items.push({
|
||||
name: translate("page.update"),
|
||||
href: "/update",
|
||||
badge: computed(() => updateStore.canUpdate),
|
||||
})
|
||||
}
|
||||
return items;
|
||||
});
|
||||
|
||||
const sideBarItems: Item[] = ([
|
||||
{
|
||||
name: translate("page.uart"),
|
||||
href: "/uart",
|
||||
}, {
|
||||
name: translate("page.wifi"),
|
||||
href: "/wifi",
|
||||
}, {
|
||||
name: translate("page.about"),
|
||||
href: "/about",
|
||||
}, {
|
||||
name: translate("page.feedback"),
|
||||
href: "/feedback",
|
||||
},
|
||||
]);
|
||||
|
||||
if (isOTAEnabled()) {
|
||||
sideBarItems.push({
|
||||
name: translate("page.update"),
|
||||
href: "/update",
|
||||
badge: computed(() => updateStore.canUpdate),
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -217,5 +245,9 @@ if (isOTAEnabled()) {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.el-select :deep(.el-select__wrapper) {
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-tabs v-model="store.configPanelTab" class="mx-2 custom-tabs fit">
|
||||
<el-tab-pane label="接口" name="first" class="min-h-80">
|
||||
|
||||
<el-tab-pane name="first" class="min-h-80">
|
||||
<template #label>{{ $t("uart.port") }}</template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<el-form :size="store.winLeft.show ? '' : 'small'">
|
||||
<el-form-item
|
||||
label="波特率"
|
||||
class="mb-2"
|
||||
>
|
||||
<template #label>{{ $t("uart.baudrate") }}</template>
|
||||
<div class="flex w-full">
|
||||
<el-select v-model="store.uartBaud" :teleported="false" @change="onUartBaudChange">
|
||||
<template #header>
|
||||
|
@ -16,17 +16,17 @@
|
|||
<div class="flex gap-0">
|
||||
<el-input-number
|
||||
v-model="uartCustomBaud"
|
||||
placeholder="自定义波特率"
|
||||
:placeholder="translate('uart.customBaud')"
|
||||
size="small"
|
||||
:controls="false"
|
||||
:min="110"
|
||||
class="flex-grow"
|
||||
></el-input-number>
|
||||
<el-button size="small" @click="onUseCustomUartBaud">使用</el-button>
|
||||
<el-button size="small" @click="onUseCustomUartBaud">{{ $t('uart.use') }}</el-button>
|
||||
<!-- <el-button size="small" @click="onConfirm" class="ml-0">增加</el-button>-->
|
||||
</div>
|
||||
|
||||
<el-option-group label="常用">
|
||||
<el-option-group :label="translate('uart.commonlyUsed')">
|
||||
<el-option
|
||||
v-for="item in store.predefinedUartBaudFrequent"
|
||||
:key="item.baud"
|
||||
|
@ -35,7 +35,7 @@
|
|||
/>
|
||||
</el-option-group>
|
||||
|
||||
<el-option-group label="其他">
|
||||
<el-option-group :label="translate('uart.other')">
|
||||
<el-option
|
||||
v-for="item in store.uartBaudList"
|
||||
:key="item.baud"
|
||||
|
@ -48,9 +48,9 @@
|
|||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<p class="text-xs">实际波特率:{{ store.uartBaudReal }}</p>
|
||||
<p class="text-xs">{{ $t('uart.actual') }} {{ $t('uart.baudrate') }}:{{ store.uartBaudReal }}</p>
|
||||
|
||||
<el-form-item label="数据位" class="mb-2">
|
||||
<el-form-item :label="translate('uart.dataBits')" class="mb-2">
|
||||
<el-select v-model="store.uartConfig.data_bits" :teleported="false"
|
||||
placeholder="Select" @change="onUartConfigChange">
|
||||
<el-option
|
||||
|
@ -62,7 +62,7 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="校验位" class="mb-2">
|
||||
<el-form-item :label="translate('uart.parity')" class="mb-2">
|
||||
<el-select v-model="store.uartConfig.parity" :teleported="false"
|
||||
placeholder="Select" @change="onUartConfigChange">
|
||||
<el-option
|
||||
|
@ -74,7 +74,7 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="停止位">
|
||||
<el-form-item :label="translate('uart.stopBits')">
|
||||
<el-select v-model="store.uartConfig.stop_bits" :teleported="false"
|
||||
placeholder="Select" @change="onUartConfigChange">
|
||||
<el-option
|
||||
|
@ -92,7 +92,7 @@
|
|||
:disabled="wsStore.state !== ControlEvent.CONNECTED"
|
||||
@click="store.acceptIncomingData = !store.acceptIncomingData"
|
||||
>
|
||||
{{ store.acceptIncomingData ? "停止数据收发" : "开始数据收发" }}
|
||||
{{ store.acceptIncomingData ? $t("uart.stopCommunication") : $t("uart.startCommunication") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
@ -102,39 +102,40 @@
|
|||
|
||||
</el-tab-pane>
|
||||
<!-- ///////////////////////////////////////////////////////////////// -->
|
||||
<el-tab-pane label="显示框" name="second">
|
||||
<el-tab-pane name="second">
|
||||
<template #label>{{ $t("uart.displayPannel") }}</template>
|
||||
<div class="flex flex-col">
|
||||
<el-collapse v-model="collapseActiveName">
|
||||
<el-collapse-item name="1">
|
||||
<template #title>
|
||||
显示选项
|
||||
{{ $t('uart.displayOptions') }}
|
||||
</template>
|
||||
<template #default>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col">
|
||||
<el-checkbox border v-model="store.showText" label="显示文本"/>
|
||||
<el-checkbox border v-model="store.showText" :label="translate('uart.text')"/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<el-checkbox border v-model="store.showHex" label="显示HEX"/>
|
||||
<el-checkbox border v-model="store.showHex" label="HEX"/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<el-checkbox border v-model="store.showHexdump" label="显示HEXDUMP"/>
|
||||
<el-checkbox border v-model="store.showHexdump" label="HEXDUMP"/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<el-checkbox border v-model="store.showTimestamp">显示时间戳</el-checkbox>
|
||||
<el-checkbox border v-model="store.showTimestamp" :label="translate('uart.timestamp')"/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<el-checkbox border v-model="store.enableLineWrap" label="启用换行"/>
|
||||
<el-checkbox border v-model="store.enableLineWrap" :label="translate('uart.lineWrap')"/>
|
||||
</div>
|
||||
|
||||
<el-tag type="success">
|
||||
<el-text type="success">RX HEXDUMP高亮选色</el-text>
|
||||
<el-text type="success">RX HEXDUMP {{ $t("uart.highlight") }}</el-text>
|
||||
<el-color-picker v-model="store.RxHexdumpColor" show-alpha :predefine="store.predefineColors"
|
||||
size="small"/>
|
||||
</el-tag>
|
||||
|
||||
<el-tag type="primary">
|
||||
<el-text type="primary">TX HEXDUMP高亮选色</el-text>
|
||||
<el-text type="primary">TX HEXDUMP {{ $t("uart.highlight") }}</el-text>
|
||||
<el-color-picker v-model="store.TxHexdumpColor" show-alpha :predefine="store.predefineColors"
|
||||
size="small"/>
|
||||
</el-tag>
|
||||
|
@ -142,33 +143,26 @@
|
|||
</template>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="2">
|
||||
<template #title>
|
||||
断帧策略
|
||||
</template>
|
||||
<el-collapse-item name="2" :title="translate('uart.frameBreakStrategy')">
|
||||
<VueDraggable v-model="store.frameBreakRules" target="tbody" handle=".sort-target"
|
||||
:animation="150"
|
||||
:on-move="checkMove">
|
||||
<table class="w-full bg-white">
|
||||
<thead>
|
||||
<tr class="text-sm h-7">
|
||||
<th>优先级</th>
|
||||
<th>{{ $t('uart.priority') }}</th>
|
||||
<th>
|
||||
<div class="flex justify-center">
|
||||
规则
|
||||
{{ translate('uart.rule' as TranslationKeys) }}
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<template #content>
|
||||
<p>超时=-1: 禁用超时断帧</p>
|
||||
<p>超时=0: 当机立断,收到任何数据都视为完整数据</p>
|
||||
<p>匹配断后:典型\n的场景</p>
|
||||
<p>匹配断前:用于有特殊帧头的场景</p>
|
||||
<p>固定字节断帧:传输大量数据,比如可以每隔1024字节断帧,方便查看数据</p>
|
||||
<div v-html="translate('uart.ruleTips')"></div>
|
||||
</template>
|
||||
<InlineSvg name="help" class="w-4 text-gray-500 cursor-help"></InlineSvg>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</th>
|
||||
<th>值</th>
|
||||
<th>{{ translate('uart.value' as TranslationKeys) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-xs text-center">
|
||||
|
@ -176,20 +170,22 @@
|
|||
<td :class="item.draggable ? 'sort-target' : ''">
|
||||
{{ item.draggable ? index : 'NaN' }}
|
||||
</td>
|
||||
<td :class="item.draggable ? 'sort-target' : ''">{{ item.name }}</td>
|
||||
<td :class="item.draggable ? 'sort-target' : ''">
|
||||
{{ translate("uart." + item.name) }}
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="item.type === 'number'">
|
||||
<el-input-number v-if="item.name === '超时(ms)'" v-model="store.frameBreakDelay" :min="item.min || 0" size="small" style="width: 100px"/>
|
||||
<el-input-number v-if="item.name === 'timeout'" v-model="store.frameBreakDelay" :min="item.min || 0" size="small" style="width: 100px"/>
|
||||
<el-input-number v-else v-model="store.frameBreakSize" :min="item.min || 0" size="small" style="width: 100px"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-input class="break-input" v-model="store.frameBreakSequence" placeholder="文本;支持\n\x" size="small"
|
||||
<el-input class="break-input" v-model="store.frameBreakSequence" :placeholder="translate('uart.textAndEscape')" size="small"
|
||||
style="width: 100px">
|
||||
<template #prepend>
|
||||
<el-button size="small" @click="store.frameBreakAfterSequence = false">
|
||||
<span
|
||||
:class="store.frameBreakAfterSequence ? 'text-gray-400' : 'text-blue-400 font-bold'">
|
||||
断
|
||||
{{ translate("uart.begin") }}
|
||||
</span>
|
||||
</el-button>
|
||||
</template>
|
||||
|
@ -197,7 +193,7 @@
|
|||
<el-button size="small" @click="store.frameBreakAfterSequence = true">
|
||||
<span
|
||||
:class="store.frameBreakAfterSequence ? 'text-blue-400 font-bold' : 'text-gray-300'">
|
||||
断
|
||||
{{ translate("uart.end") }}
|
||||
</span>
|
||||
</el-button>
|
||||
</template>
|
||||
|
@ -210,10 +206,7 @@
|
|||
</VueDraggable>
|
||||
</el-collapse-item>
|
||||
|
||||
<el-collapse-item name="3">
|
||||
<template #title>
|
||||
其他
|
||||
</template>
|
||||
<el-collapse-item name="3" :title="translate('uart.other')">
|
||||
<template #default>
|
||||
<div class="flex flex-col gap-2">
|
||||
<el-tooltip
|
||||
|
@ -222,30 +215,24 @@
|
|||
placement="right-start"
|
||||
>
|
||||
<template #content>
|
||||
<p>ANSI转义码对终端和文本有很多作用,比如改变文本颜色等。</p>
|
||||
<p>
|
||||
简单了解->
|
||||
<el-link target="_blank" href="https://zhuanlan.zhihu.com/p/390666800">
|
||||
https://zhuanlan.zhihu.com/p/390666800
|
||||
</el-link>
|
||||
</p>
|
||||
<div v-html="translate('uart.ansiTooltips')"></div>
|
||||
</template>
|
||||
<el-checkbox border v-model="store.enableAnsiDecode">解析ANSI转义码</el-checkbox>
|
||||
<el-checkbox border v-model="store.enableAnsiDecode">{{ translate('uart.decodeAnsiEscapeCodes') }}</el-checkbox>
|
||||
</el-tooltip>
|
||||
<el-input v-model="store.filterValue" placeholder="文本;支持\n\x" clearable>
|
||||
<el-input v-model="store.filterValue" :placeholder="translate('uart.textAndEscape')" clearable>
|
||||
<template #prepend>
|
||||
过滤
|
||||
{{ translate("uart.filter") }}
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<div class="border rounded flex flex-col">
|
||||
|
||||
<el-checkbox border v-model="store.dataFilterAutoUpdate">新数据自动刷新</el-checkbox>
|
||||
<el-checkbox border v-model="store.dataFilterAutoUpdate">{{ translate('uart.autoUpdateNewData') }}</el-checkbox>
|
||||
|
||||
<el-tooltip content="提高间隔可减少CPU资源的使用" placement="right" effect="light"
|
||||
<el-tooltip :content="translate('uart.updateFrequencyTooltip')" placement="right" effect="light"
|
||||
:show-after="500">
|
||||
<div class="flex gap-4 p-2">
|
||||
<el-text>数据显示刷新间隔(ms)</el-text>
|
||||
<el-text>{{ translate('uart.updateFrequency') }}</el-text>
|
||||
<el-input-number
|
||||
:step="10"
|
||||
:min="10"
|
||||
|
@ -300,34 +287,36 @@
|
|||
</el-tab-pane>
|
||||
|
||||
<!-- ///////////////////////////////////////////////////////////// -->
|
||||
<el-tab-pane label="发送" name="third">
|
||||
<el-tab-pane :label="translate('uart.send')" name="third">
|
||||
<template #label>{{ $t("uart.send") }}</template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<el-input v-model="store.textPrefixValue" placeholder="支持\n\x" clearable>
|
||||
<el-input v-model="store.textPrefixValue" :placeholder="translate('uart.textAndEscape')" clearable>
|
||||
<template #prepend>
|
||||
{{ `添加帧头►` }}
|
||||
{{ translate('uart.addHeader') }}►
|
||||
</template>
|
||||
</el-input>
|
||||
<el-input v-model="store.textSuffixValue" placeholder="支持\n\x" clearable>
|
||||
<el-input v-model="store.textSuffixValue" :placeholder="translate('uart.textAndEscape')" clearable>
|
||||
<template #append>
|
||||
◄添加帧尾
|
||||
◄{{ translate('uart.addFooter') }}
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
|
||||
<el-tab-pane label="透传" name="fourth" class="min-h-80">
|
||||
<el-tab-pane :label="translate('uart.proxy')" name="fourth" class="min-h-80">
|
||||
<template #label>{{ $t("uart.passthrough") }}</template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="border rounded bg-white p-2">
|
||||
<span class="border-r px-2">TCP服务器端口</span>
|
||||
<span class="border-r px-2">TCP {{ translate('uart.serverPort') }}</span>
|
||||
<span class="px-2 cursor-not-allowed">1346</span>
|
||||
</div>
|
||||
<div>
|
||||
<p><el-button @click="refreshTCPClientList" size="small" type="primary" :plain="true">刷新</el-button> 已连接的客户端:</p>
|
||||
<p><el-button @click="refreshTCPClientList" size="small" type="primary" :plain="true">{{ translate('uart.refresh') }}</el-button> {{ translate('uart.connectedClient') }}</p>
|
||||
|
||||
<el-table :data="dfStore.instanceList.filter((item) => (item.port_info as ISocketInfo).local_port === 1346)" empty-text="无客户端连接">
|
||||
<el-table :data="dfStore.instanceList.filter((item) => (item.port_info as ISocketInfo).local_port === 1346)" :empty-text="translate('uart.noClientConnected')">
|
||||
<el-table-column label="IP" prop="port_info.foreign_ip" />
|
||||
<el-table-column label="端口" prop="port_info.foreign_port"/>
|
||||
<el-table-column :label="translate('uart.port')" prop="port_info.foreign_port"/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -338,7 +327,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import {VueDraggable} from 'vue-draggable-plus'
|
||||
import {ref} from "vue";
|
||||
import {computed, ref} from "vue";
|
||||
import {useDataViewerStore} from "@/stores/dataViewerStore";
|
||||
import {useWsStore} from "@/stores/websocket";
|
||||
import {globalNotify} from "@/composables/notification";
|
||||
|
@ -349,6 +338,7 @@ import {useDataFlowStore} from "@/stores/useDataFlowStore";
|
|||
import {wt_data_flow_get_instance_list, type ISocketInfo} from "@/api/apiDataFlow";
|
||||
import {uart_set_baud, uart_set_config} from "@/api/apiUart";
|
||||
import {useUartStore} from "@/stores/useUartStore";
|
||||
import {translate, type TranslationKeys} from "@/locales";
|
||||
|
||||
const store = useDataViewerStore()
|
||||
const uartStore = useUartStore()
|
||||
|
@ -375,18 +365,18 @@ const uartDataBitsOptions = [
|
|||
}
|
||||
]
|
||||
|
||||
const uartParityOptions = [
|
||||
const uartParityOptions = computed(() => [
|
||||
{
|
||||
key: 0,
|
||||
label: "无(none)",
|
||||
label: translate("uart.parityNone"),
|
||||
}, {
|
||||
key: 1,
|
||||
label: "奇(odd)",
|
||||
label: translate("uart.parityOdd"),
|
||||
}, {
|
||||
key: 2,
|
||||
label: "偶(even)",
|
||||
label: translate("uart.parityEven"),
|
||||
}
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
const uartStopBitsOptions = [
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
<template>
|
||||
<div class="flex items-center mb-2 flex-wrap gap-2">
|
||||
<el-button type="primary" @click="importSettings">导入</el-button>
|
||||
<el-button type="warning" @click="exportSettings">导出</el-button>
|
||||
<el-button type="primary" @click="importSettings">{{ translate('uart.import') }}</el-button>
|
||||
<el-button type="warning" @click="exportSettings">{{ translate('uart.export') }}</el-button>
|
||||
|
||||
<el-tooltip
|
||||
effect="light"
|
||||
placement="top"
|
||||
:show-after="500"
|
||||
>
|
||||
<template #content>
|
||||
<p>刷新页面后生效</p>
|
||||
<p>{{ translate('uart.resetTooltip') }}</p>
|
||||
</template>
|
||||
<el-button type="info" @click="resetSettings">重置</el-button>
|
||||
<el-button type="info" @click="resetSettings">{{ translate('uart.reset') }}</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
effect="light"
|
||||
placement="top"
|
||||
:show-after="500"
|
||||
>
|
||||
<template #content>
|
||||
<p>若存在多个页面,会相互覆盖</p>
|
||||
<p>{{ translate('uart.saveToLocalTooltip') }}</p>
|
||||
</template>
|
||||
<el-checkbox border v-model="store.autoSaveSettings">保存至本地</el-checkbox>
|
||||
<el-checkbox border v-model="store.autoSaveSettings">{{ translate('uart.saveToLocal') }}</el-checkbox>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
|
@ -27,17 +29,17 @@
|
|||
<el-button type="primary" @click="() => {
|
||||
store.macroData.push({
|
||||
value: '',
|
||||
label: '发送',
|
||||
label: translate('uart.send'),
|
||||
id: store.macroId,
|
||||
})
|
||||
store.macroId++;
|
||||
}">添加
|
||||
}">{{ translate('uart.add') }}
|
||||
</el-button>
|
||||
<el-checkbox v-model="editMode" border>编辑</el-checkbox>
|
||||
<el-checkbox v-model="draggableEnabled" border>拖拽</el-checkbox>
|
||||
<el-checkbox v-model="editMode" border>{{ translate('uart.edit') }}</el-checkbox>
|
||||
<el-checkbox v-model="draggableEnabled" border>{{ translate('uart.drag') }}</el-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<el-alert v-if="store.ipChangeAlert" @close="store.ipChangeAlert=false">IP地址改变会导致配置丢失</el-alert>
|
||||
<el-alert v-if="store.ipChangeAlert" @close="store.ipChangeAlert=false">{{ translate('uart.ipChangeAlert') }}</el-alert>
|
||||
</div>
|
||||
|
||||
<VueDraggable v-model="store.macroData" handle=".sort-target"
|
||||
|
@ -67,6 +69,7 @@ import {VueDraggable} from "vue-draggable-plus";
|
|||
import {onMounted, ref} from "vue";
|
||||
import {globalNotify, globalNotifyRightSide} from "@/composables/notification";
|
||||
import {useDataViewerStore} from "@/stores/dataViewerStore";
|
||||
import {translate} from "../../locales";
|
||||
|
||||
const editMode = ref(false);
|
||||
const draggableEnabled = ref(true);
|
||||
|
|
|
@ -18,18 +18,18 @@
|
|||
</el-popover>
|
||||
|
||||
<div class="flex">
|
||||
<el-checkbox size="small" v-model="store.forceToBottom" label="自动滚动至底部" border/>
|
||||
<el-checkbox size="small" v-model="store.forceToBottom" :label="translate('uart.autoScrollToBottom')" border/>
|
||||
<el-tooltip
|
||||
class="box-item"
|
||||
effect="light"
|
||||
placement="top"
|
||||
>
|
||||
<template #content>
|
||||
<p>仅清除显示区域,可用刷新恢复</p>
|
||||
<p>{{ translate('uart.clearTooltip') }}</p>
|
||||
</template>
|
||||
<el-button size="small" @click="store.clearFilteredBuff">
|
||||
<InlineSvg class="h-5" name="trash"></InlineSvg>
|
||||
清屏 ⇩
|
||||
{{ $t('uart.clearScreen') }} ⇩
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
|
||||
|
@ -39,10 +39,10 @@
|
|||
placement="top"
|
||||
>
|
||||
<template #content>
|
||||
<p>与缓存同步+过滤</p>
|
||||
<p>{{ translate('uart.clearTooltip') }}</p>
|
||||
</template>
|
||||
<el-button size="small" @click="store.refreshFilteredBuff">
|
||||
刷新
|
||||
{{ $t('page.update') }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
|
@ -51,10 +51,10 @@
|
|||
placement="top"
|
||||
>
|
||||
<template #content>
|
||||
<p>仅停止刷新显示区,后台继续接收数据</p>
|
||||
<p>{{ translate('uart.autoUpdateTooltip') }}</p>
|
||||
</template>
|
||||
<el-checkbox size="small" border v-model="store.dataFilterAutoUpdate">
|
||||
自动刷新
|
||||
{{ $t('uart.autoUpdate') }}
|
||||
</el-checkbox>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -77,7 +77,7 @@
|
|||
<p class="text-nowrap text-sm text-sky-500" v-else-if="item.type === 0" type="primary" v-show="store.showTimestamp">
|
||||
<span>{{ item.time }}</span>TX-►|</p>
|
||||
<p class="text-nowrap text-sm text-amber-800" v-else type="primary" v-show="store.showTimestamp">
|
||||
<span>{{ item.time }}</span>未发送►|</p>
|
||||
<span>{{ item.time }}</span>NS-►|</p>
|
||||
|
||||
<p v-show="store.showText"
|
||||
v-html="item.str"></p>
|
||||
|
@ -111,7 +111,7 @@
|
|||
<p class="text-nowrap text-sm text-sky-500" v-else-if="item.type === 0" type="primary" v-show="store.showTimestamp">
|
||||
<span>{{ item.time }}</span>TX-►|</p>
|
||||
<p class="text-nowrap text-sm text-amber-800" v-else type="primary" v-show="store.showTimestamp">
|
||||
<span>{{ item.time }}</span>未发送►|</p>
|
||||
<span>{{ item.time }}</span>NS-►|</p>
|
||||
<p v-show="store.showText"
|
||||
v-html="item.str"></p>
|
||||
</div>
|
||||
|
@ -132,7 +132,7 @@
|
|||
|
||||
<div class="shrink-0 flex h-8 mt-0.5 text-xs">
|
||||
<div class="flex shrink-0">
|
||||
<el-tooltip content="未满足断帧规则的数据(如:未超时),暂时实时显示在此区域。超过8192字节,自动断帧;" effect="light">
|
||||
<el-tooltip :content="translate('uart.tempDisplayTooltip')" effect="light">
|
||||
<InlineSvg name="help" class="w-3.5 h-3.5 text-gray-500 cursor-help"></InlineSvg>
|
||||
</el-tooltip>
|
||||
<p>►</p>
|
||||
|
@ -153,10 +153,10 @@
|
|||
</el-tag>
|
||||
</el-link>
|
||||
|
||||
<el-tooltip content="实际频率受界面刷新率影响,如需要更精确,可以尝试关闭‘自动刷新’" placement="right" effect="light" :show-after="1000">
|
||||
<el-tooltip :content="translate('uart.loopSendTooltip')" placement="right" effect="light" :show-after="1000">
|
||||
<div class="flex align-center">
|
||||
<el-checkbox v-model="store.enableLoopSend" class="font-mono font-bold max-h-5" size="small" border>
|
||||
循环发送(ms)
|
||||
{{ translate('uart.loopSend') }}(ms)
|
||||
</el-checkbox>
|
||||
<el-input-number
|
||||
v-model="store.loopSendFreq"
|
||||
|
@ -170,7 +170,7 @@
|
|||
</el-tooltip>
|
||||
|
||||
<el-link @click="store.isSendTextFormat = !store.isSendTextFormat">
|
||||
<el-tag class="font-mono font-bold" size="small">发送格式:{{ store.isSendTextFormat ? "文本" : "HEX" }}</el-tag>
|
||||
<el-tag class="font-mono font-bold" size="small">{{ translate('uart.sendFormat') }}:{{ store.isSendTextFormat ? translate("uart.text") : "HEX" }}</el-tag>
|
||||
</el-link>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
|
@ -189,7 +189,7 @@
|
|||
<el-link class="flex" @click="store.clearDataBuff" type="warning">
|
||||
<InlineSvg class="h-5" name="trash"></InlineSvg>
|
||||
</el-link>
|
||||
<span class="align-text-bottom">缓存帧数: {{ store.dataBufLength }}/30000</span>
|
||||
<span class="align-text-bottom">{{ translate('uart.cachedFrame') }}: {{ store.dataBufLength }}/30000</span>
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -197,14 +197,14 @@
|
|||
<div class="flex flex-row font-mono">
|
||||
<el-input type="textarea" :autosize="{ minRows: 1, maxRows: 6}" v-model="store.uartInputTextBox" clearable
|
||||
:placeholder="store.isSendTextFormat ?
|
||||
'输入文本,支持\\n\\x转义' :
|
||||
'输入HEX格式'"
|
||||
translate('uart.textAndEscape') :
|
||||
'HEX'"
|
||||
@keydown="handleTextboxKeydown"
|
||||
></el-input>
|
||||
<el-tooltip content="Ctrl+回车" placement="top" :auto-close="500">
|
||||
<el-tooltip content="Ctrl+Enter" placement="top" :auto-close="500">
|
||||
<el-button type="primary"
|
||||
@click="onSendClick">
|
||||
{{ (store.isSendTextFormat || store.isHexStringValid) ? "发送" : "格式化" }}
|
||||
{{ (store.isSendTextFormat || store.isHexStringValid) ? translate("uart.send") : translate("格式化") }}
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
@ -217,6 +217,7 @@ import InlineSvg from "@/components/InlineSvg.vue";
|
|||
import TextDataConfig from "@/views/text-data-viewer/textDataConfig.vue";
|
||||
import {debouncedWatch} from "@vueuse/core";
|
||||
import {globalNotify} from "@/composables/notification";
|
||||
import {translate} from "../../locales";
|
||||
|
||||
const count = ref(0);
|
||||
const vuetifyVirtualScrollBarRef = ref(document.body);
|
||||
|
|
Loading…
Reference in New Issue