From 3c56fc45d3b37be6025162f3b065551ec97c856b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com>
Date: Wed, 17 Jun 2026 00:24:38 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20WiFi/vCard/Email/=E7=94=B5=E8=AF=9D/SMS?=
=?UTF-8?q?=20=E5=85=A8=E6=A8=A1=E5=BC=8F=E8=A1=A8=E5=8D=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
gui/src-frontend/src/App.tsx | 16 ++++++---
gui/src-frontend/src/modes/EmailMode.tsx | 28 +++++++++++++++
gui/src-frontend/src/modes/PhoneMode.tsx | 18 ++++++++++
gui/src-frontend/src/modes/SmsMode.tsx | 24 +++++++++++++
gui/src-frontend/src/modes/VCardMode.tsx | 33 ++++++++++++++++++
gui/src-frontend/src/modes/WifiMode.tsx | 44 ++++++++++++++++++++++++
6 files changed, 158 insertions(+), 5 deletions(-)
create mode 100644 gui/src-frontend/src/modes/EmailMode.tsx
create mode 100644 gui/src-frontend/src/modes/PhoneMode.tsx
create mode 100644 gui/src-frontend/src/modes/SmsMode.tsx
create mode 100644 gui/src-frontend/src/modes/VCardMode.tsx
create mode 100644 gui/src-frontend/src/modes/WifiMode.tsx
diff --git a/gui/src-frontend/src/App.tsx b/gui/src-frontend/src/App.tsx
index 21bb161..f8c293b 100644
--- a/gui/src-frontend/src/App.tsx
+++ b/gui/src-frontend/src/App.tsx
@@ -5,6 +5,11 @@ import ExportPanel from './components/ExportPanel';
import HistoryList from './components/HistoryList';
import TextMode from './modes/TextMode';
import UrlMode from './modes/UrlMode';
+import WifiMode from './modes/WifiMode';
+import VCardMode from './modes/VCardMode';
+import EmailMode from './modes/EmailMode';
+import PhoneMode from './modes/PhoneMode';
+import SmsMode from './modes/SmsMode';
function AppLayout() {
return (
@@ -44,11 +49,12 @@ function BottomInput() {
switch (state.mode) {
case 'text': return ;
case 'url': return ;
- default: return (
-
- 更多模式即将推出...
-
- );
+ case 'wifi': return ;
+ case 'vcard': return ;
+ case 'email': return ;
+ case 'phone': return ;
+ case 'sms': return ;
+ default: return ;
}
}
diff --git a/gui/src-frontend/src/modes/EmailMode.tsx b/gui/src-frontend/src/modes/EmailMode.tsx
new file mode 100644
index 0000000..ef66f88
--- /dev/null
+++ b/gui/src-frontend/src/modes/EmailMode.tsx
@@ -0,0 +1,28 @@
+import { useQrState } from '../store/qrContext';
+import { useQrEncode } from '../hooks/useQrEncode';
+
+export default function EmailMode() {
+ const { state, dispatch } = useQrState();
+ const { encode } = useQrEncode();
+
+ const update = (field: string, value: string) => {
+ const data = { ...state.formData, [field]: value };
+ dispatch({ type: 'SET_FORM_DATA', payload: data });
+ const mailto = `mailto:${data.to || ''}?subject=${encodeURIComponent(data.subject || '')}&body=${encodeURIComponent(data.body || '')}`;
+ encode(mailto);
+ };
+
+ return (
+
+ update('to', e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+ update('subject', e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+ update('body', e.target.value)}
+ className="flex-[2] px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+
+ );
+}
diff --git a/gui/src-frontend/src/modes/PhoneMode.tsx b/gui/src-frontend/src/modes/PhoneMode.tsx
new file mode 100644
index 0000000..91dca0a
--- /dev/null
+++ b/gui/src-frontend/src/modes/PhoneMode.tsx
@@ -0,0 +1,18 @@
+import { useQrState } from '../store/qrContext';
+import { useQrEncode } from '../hooks/useQrEncode';
+
+export default function PhoneMode() {
+ const { state, dispatch } = useQrState();
+ const { encode } = useQrEncode();
+
+ const update = (number: string) => {
+ dispatch({ type: 'SET_FORM_DATA', payload: { number } });
+ encode(`tel:${number}`);
+ };
+
+ return (
+ update(e.target.value)}
+ className="w-full h-full px-4 text-sm bg-transparent outline-none placeholder-gray-400 dark:placeholder-gray-600 focus:ring-2 focus:ring-blue-500/30" />
+ );
+}
diff --git a/gui/src-frontend/src/modes/SmsMode.tsx b/gui/src-frontend/src/modes/SmsMode.tsx
new file mode 100644
index 0000000..9775c0f
--- /dev/null
+++ b/gui/src-frontend/src/modes/SmsMode.tsx
@@ -0,0 +1,24 @@
+import { useQrState } from '../store/qrContext';
+import { useQrEncode } from '../hooks/useQrEncode';
+
+export default function SmsMode() {
+ const { state, dispatch } = useQrState();
+ const { encode } = useQrEncode();
+
+ const update = (field: string, value: string) => {
+ const data = { ...state.formData, [field]: value };
+ dispatch({ type: 'SET_FORM_DATA', payload: data });
+ encode(`smsto:${data.number || ''}:${data.message || ''}`);
+ };
+
+ return (
+
+ update('number', e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+ update('message', e.target.value)}
+ className="flex-[2] px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+
+ );
+}
diff --git a/gui/src-frontend/src/modes/VCardMode.tsx b/gui/src-frontend/src/modes/VCardMode.tsx
new file mode 100644
index 0000000..e09ab14
--- /dev/null
+++ b/gui/src-frontend/src/modes/VCardMode.tsx
@@ -0,0 +1,33 @@
+import { useQrState } from '../store/qrContext';
+import { useQrEncode } from '../hooks/useQrEncode';
+
+const FIELDS = [
+ { key: 'name', placeholder: '姓名' },
+ { key: 'phone', placeholder: '电话' },
+ { key: 'email', placeholder: '邮箱' },
+ { key: 'company', placeholder: '公司' },
+ { key: 'address', placeholder: '地址' },
+];
+
+export default function VCardMode() {
+ const { state, dispatch } = useQrState();
+ const { encode } = useQrEncode();
+
+ const update = (field: string, value: string) => {
+ const data = { ...state.formData, [field]: value };
+ dispatch({ type: 'SET_FORM_DATA', payload: data });
+ const vcard = `BEGIN:VCARD\nVERSION:3.0\nFN:${data.name || ''}\nTEL:${data.phone || ''}\nEMAIL:${data.email || ''}\nORG:${data.company || ''}\nADR:${data.address || ''}\nEND:VCARD`;
+ encode(vcard);
+ };
+
+ return (
+
+ {FIELDS.map(f => (
+ update(f.key, e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+ ))}
+
+ );
+}
diff --git a/gui/src-frontend/src/modes/WifiMode.tsx b/gui/src-frontend/src/modes/WifiMode.tsx
new file mode 100644
index 0000000..82efda5
--- /dev/null
+++ b/gui/src-frontend/src/modes/WifiMode.tsx
@@ -0,0 +1,44 @@
+import { useQrState } from '../store/qrContext';
+import { useQrEncode } from '../hooks/useQrEncode';
+
+export default function WifiMode() {
+ const { state, dispatch } = useQrState();
+ const { encode } = useQrEncode();
+
+ const buildWifiText = (ssid: string, password: string, encryption: string, hidden: boolean) => {
+ if (!ssid) return '';
+ return `WIFI:T:${encryption};S:${ssid};P:${password};${hidden ? 'H:true;' : ''};`;
+ };
+
+ const update = (field: string, value: string | boolean) => {
+ const data = { ...state.formData, [field]: String(value) };
+ dispatch({ type: 'SET_FORM_DATA', payload: data });
+ const wifiText = buildWifiText(
+ data.ssid || '', data.password || '', data.encryption || 'WPA', data.hidden === 'true'
+ );
+ encode(wifiText);
+ };
+
+ return (
+
+ update('ssid', e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+ update('password', e.target.value)}
+ className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30" />
+
+
+
+ );
+}