A 增加跨平台通信桥接实现(CSharp/Tauri/WebMock)
A 新增全局类型定义文件(global.d.ts) A 新增 WebPanel 组件及其集成到 Shell UI A 新增 BridgeFactory 工厂类用于动态创建桥接实例 U 优化 CommandManager 组件使用新通信桥接逻辑 D 移除未使用的旧代码和配置(e.g., 命令相关的 JS 文件)
This commit is contained in:
1 parent
709ca30f12
commit
71fb7e2db1
22 files changed
+641
-199
No files matched your search
@@ -1,4 +1,3 @@
|
||||
VITE_MODE='development'
|
||||
VITE_APP_API_URL='http://192.****:8008/api/'
|
||||
VITE_TAURI_DEV_HOST="0.0.0.0"
|
||||
VITE_API_URL=http://localhost:3000/api
|
||||
@@ -1,21 +0,0 @@
|
||||
/**
|
||||
* Time:2025/5/3 19:12 15
|
||||
* Name:index.ts
|
||||
* Path:src/commands
|
||||
* ProjectName:net-src
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { greetCommand } from '@/constants/command'
|
||||
|
||||
/**
|
||||
* 问候
|
||||
* @param name
|
||||
*/
|
||||
export function greet(name: string) {
|
||||
return invoke<string>(greetCommand, { name })
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { type Ref, ref } from 'vue'
|
||||
import { baseInvoke } from '@/utils/commandUtil.ts'
|
||||
import type { CommandType } from '@/types/command'
|
||||
import { logN } from '@/utils/logHelper/logUtils.ts'
|
||||
import CSharpBridgeV2 from '@/correspond/CSharpBridgeV2'
|
||||
|
||||
// 传递参数
|
||||
const props = defineProps({
|
||||
@@ -10,6 +10,7 @@ const props = defineProps({
|
||||
})
|
||||
// 使用 ref 使数据变成响应式数据
|
||||
const modules: Ref<CommandType[]> = ref([...(props.pro || [])])
|
||||
const bridge = CSharpBridgeV2.getBridge()
|
||||
|
||||
/**
|
||||
* 指令触发
|
||||
@@ -20,13 +21,9 @@ const invokeCommand = async (module: CommandType) => {
|
||||
logN.success('前端发送的参数', module.name, params)
|
||||
|
||||
try {
|
||||
const s = baseInvoke(module.name, params)
|
||||
s.then((res) => {
|
||||
logN.warning('后端返回的参数', module.name, res)
|
||||
module.result = JSON.stringify(res, null, 2)
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
module.result = `Error: ${err.message}`
|
||||
bridge.send(module.name, params, (data) => {
|
||||
logN.warning('后端返回的参数', module.name, data)
|
||||
module.result = JSON.stringify(data, null, 2)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(err)
|
||||
@@ -35,7 +32,6 @@ const invokeCommand = async (module: CommandType) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="modules-grid">
|
||||
@@ -44,11 +40,7 @@ const invokeCommand = async (module: CommandType) => {
|
||||
<p class="module-description">{{ module.description }}</p>
|
||||
|
||||
<div class="params-container">
|
||||
<div
|
||||
v-for="(param, paramIndex) in module.params"
|
||||
:key="paramIndex"
|
||||
class="param-item"
|
||||
>
|
||||
<div v-for="(param, paramIndex) in module.params" :key="paramIndex" class="param-item">
|
||||
<label :for="`${module.name}-${param.name}`" class="param-label">
|
||||
{{ param.label }}
|
||||
</label>
|
||||
@@ -70,12 +62,7 @@ const invokeCommand = async (module: CommandType) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@click="invokeCommand(module)"
|
||||
class="action-button"
|
||||
>
|
||||
触发 {{ module.name }}
|
||||
</button>
|
||||
<button @click="invokeCommand(module)" class="action-button">触发 {{ module.name }}</button>
|
||||
|
||||
<div v-if="module.result" class="result-container">
|
||||
<h3 class="result-title">结果</h3>
|
||||
@@ -108,9 +95,8 @@ const invokeCommand = async (module: CommandType) => {
|
||||
font-size: 1.125rem; // text-lg
|
||||
font-weight: 600; // font-semibold
|
||||
margin-bottom: 0.5rem; // mb-2
|
||||
user-select: text; /* 允许选中 */
|
||||
pointer-events: auto; /* 确保可以响应鼠标操作 */
|
||||
|
||||
user-select: text; /* 允许选中 */
|
||||
pointer-events: auto; /* 确保可以响应鼠标操作 */
|
||||
}
|
||||
|
||||
.module-description {
|
||||
@@ -189,8 +175,8 @@ const invokeCommand = async (module: CommandType) => {
|
||||
.result-content {
|
||||
font-size: 0.875rem; // text-sm
|
||||
white-space: pre-wrap;
|
||||
user-select: text; /* 允许选中 */
|
||||
pointer-events: auto; /* 确保可以响应鼠标操作 */
|
||||
user-select: text; /* 允许选中 */
|
||||
pointer-events: auto; /* 确保可以响应鼠标操作 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import IBridge from "./IBridge";
|
||||
/**
|
||||
* 业务层类型定义
|
||||
*/
|
||||
export interface UserInfo {
|
||||
id: string;
|
||||
name: string;
|
||||
email?: string;
|
||||
role: string;
|
||||
permissions: string[];
|
||||
}
|
||||
|
||||
export interface Notification {
|
||||
id: string;
|
||||
title: string;
|
||||
message: string;
|
||||
type: 'info' | 'warning' | 'error' | 'success';
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
||||
|
||||
export interface LogPayload {
|
||||
level: LogLevel;
|
||||
message: string;
|
||||
context?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务功能层 - 提供更高级的通信功能
|
||||
*/
|
||||
export class AppBridge {
|
||||
private bridge: IBridge;
|
||||
|
||||
constructor() {
|
||||
this.bridge = BridgeFactory.create();
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
async getUserInfo(): Promise<UserInfo> {
|
||||
return this.bridge.send<UserInfo>('user.getInfo');
|
||||
}
|
||||
|
||||
// 监听系统通知
|
||||
onNotification(listener: (notification: Notification) => void): () => void {
|
||||
return this.bridge.on<Notification>('system.notification', listener);
|
||||
}
|
||||
|
||||
// 发送日志
|
||||
async sendLog(payload: LogPayload): Promise<void> {
|
||||
return this.bridge.send<void, LogPayload>('system.log', payload);
|
||||
}
|
||||
|
||||
// 获取系统配置
|
||||
async getConfig<T extends Record<string, unknown>>(key: string): Promise<T> {
|
||||
return this.bridge.send<T, { key: string }>('system.getConfig', { key });
|
||||
}
|
||||
|
||||
// 保存系统配置
|
||||
async saveConfig<T extends Record<string, unknown>>(key: string, value: T): Promise<void> {
|
||||
return this.bridge.send<void, { key: string; value: T }>('system.saveConfig', { key, value });
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
export const appBridge = new AppBridge();
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Time:2025/5/10 13:42 55
|
||||
* Name:BaseBridge.ts
|
||||
* Path:src/correspond
|
||||
* ProjectName:ClientApp
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
import type MessagePayload from "./IBridge"
|
||||
import { IBridge } from '@/correspond/IBridge'
|
||||
|
||||
/**
|
||||
* 平台适配层基类
|
||||
*/
|
||||
abstract class BaseBridge implements IBridge {
|
||||
protected listeners: Map<string, Set<(data: unknown) => void>> = new Map();
|
||||
|
||||
abstract send<TResponse = void, TRequest extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data?: TRequest
|
||||
): Promise<TResponse>;
|
||||
|
||||
on<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): () => void {
|
||||
if (!this.listeners.has(channel)) {
|
||||
this.listeners.set(channel, new Set());
|
||||
}
|
||||
|
||||
// TypeScript 不允许将具体类型的函数分配给更通用的类型,因此这里需要类型转换
|
||||
const typedListener = listener as (data: unknown) => void;
|
||||
this.listeners.get(channel)!.add(typedListener);
|
||||
|
||||
return () => this.removeListener(channel, listener);
|
||||
}
|
||||
|
||||
once<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): () => void {
|
||||
// 创建一个一次性监听器
|
||||
const onceListener = ((data: TData) => {
|
||||
listener(data);
|
||||
this.removeListener(channel, onceListener);
|
||||
});
|
||||
|
||||
return this.on(channel, onceListener);
|
||||
}
|
||||
|
||||
off(channel: string): void {
|
||||
this.listeners.delete(channel);
|
||||
}
|
||||
|
||||
removeListener<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): void {
|
||||
const channelListeners = this.listeners.get(channel);
|
||||
if (channelListeners) {
|
||||
// 需要类型转换以匹配存储的监听器类型
|
||||
const typedListener = listener as (data: unknown) => void;
|
||||
channelListeners.delete(typedListener);
|
||||
if (channelListeners.size === 0) {
|
||||
this.listeners.delete(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected dispatchEvent<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data: TData
|
||||
): void {
|
||||
const listeners = this.listeners.get(channel);
|
||||
if (listeners) {
|
||||
listeners.forEach(listener => {
|
||||
try {
|
||||
listener(data);
|
||||
} catch (error) {
|
||||
console.error(`Error in listener for channel ${channel}:`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import CSharpBridge from "./CSharpBridge";
|
||||
import TauriBridge from "./TauriBridge";
|
||||
/**
|
||||
* 桥梁工厂 - 根据运行环境创建适当的桥梁实例
|
||||
*/
|
||||
export class BridgeFactory {
|
||||
static create(): IBridge {
|
||||
if (typeof window !== 'undefined') {
|
||||
// 根据环境判断使用哪个桥接实现
|
||||
if (window.csharpApp) {
|
||||
return new CSharpBridge();
|
||||
} else if (window.__TAURI__) {
|
||||
return new TauriBridge();
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回一个Web模拟实现
|
||||
return new WebMockBridge();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import BaseBridge from "./BaseBridge"
|
||||
/**
|
||||
* C#套壳浏览器的适配器
|
||||
*/
|
||||
class CSharpBridge extends BaseBridge {
|
||||
constructor() {
|
||||
super();
|
||||
// 假设C#注入了window.csharpApp对象
|
||||
if (typeof window !== 'undefined' && window.csharpApp) {
|
||||
// 监听C#发来的消息
|
||||
window.receiveCSharpMessage = (channel: string, dataJson: string) => {
|
||||
try {
|
||||
const data = JSON.parse(dataJson) as MessagePayload;
|
||||
this.dispatchEvent(channel, data);
|
||||
} catch (error) {
|
||||
console.error('Failed to parse message from C#:', error);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async send<TResponse = void, TRequest extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data?: TRequest
|
||||
): Promise<TResponse> {
|
||||
if (typeof window === 'undefined' || !window.csharpApp) {
|
||||
throw new BridgeError('CSharp bridge not available', 'BRIDGE_UNAVAILABLE');
|
||||
}
|
||||
|
||||
try {
|
||||
// 假设C#提供了sendToCSharp方法
|
||||
const responseJson = window.csharpApp.sendToCSharp(
|
||||
channel,
|
||||
JSON.stringify(data || {})
|
||||
);
|
||||
return JSON.parse(responseJson) as TResponse;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new BridgeError(`Failed to send message to C#: ${error.message}`, 'SEND_FAILED');
|
||||
}
|
||||
throw new BridgeError('Unknown error when sending message to C#', 'UNKNOWN_ERROR');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { MessagePayload } from '@/correspond/IBridge'
|
||||
import CSharpBridge from '@/correspond/CSharpBridge'
|
||||
import TauriBridge from '@/correspond/TauriBridge'
|
||||
|
||||
type MessagePayload<T> = {
|
||||
channel: string
|
||||
payload: T
|
||||
}
|
||||
|
||||
class CSharpBridgeV2 {
|
||||
private static CSBridge: CSharpBridgeV2 | null = null
|
||||
|
||||
static getBridge(): CSharpBridgeV2 | null {
|
||||
if (CSharpBridgeV2.CSBridge === null || CSharpBridgeV2.CSBridge.CSBridge === undefined) {
|
||||
if (window.chrome && window.chrome.webview) {
|
||||
// window.chrome.webview.postMessage("hello");
|
||||
CSharpBridgeV2.CSBridge = new CSharpBridgeV2()
|
||||
window.externalFunctions.__BRIDGE_LISTEN__ = CSharpBridgeV2.CSBridge.bridgeInvoke
|
||||
window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__ = new Map()
|
||||
} else {
|
||||
console.error('Not running in WebView2 environment')
|
||||
}
|
||||
}
|
||||
return CSharpBridgeV2.CSBridge
|
||||
}
|
||||
|
||||
bridgeInvoke(channel: string, json: string) {
|
||||
const bridgeListenFunctions = window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__
|
||||
const listeners = bridgeListenFunctions.get(channel)
|
||||
if (listeners) {
|
||||
listeners.forEach((listener) => {
|
||||
try {
|
||||
listener.callback(json)
|
||||
if (listener.once && CSharpBridgeV2.CSBridge) {
|
||||
CSharpBridgeV2.CSBridge.removeListen(channel, listener)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error in listener for channel ${channel}:`, error)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息到后端
|
||||
send<T, V>(channel: string, data?: T | null = null, callback: ((data: V) => void) | null = null) {
|
||||
const obj: MessagePayload = {
|
||||
channel,
|
||||
payload: data,
|
||||
}
|
||||
if (callback !== null && callback !== undefined) {
|
||||
this.listen(channel, callback, true)
|
||||
}
|
||||
window.chrome.webview.postMessage(obj)
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听后端消息
|
||||
*/
|
||||
listen<V>(channel: string, callback: (data: V) => void, once: boolean = false) {
|
||||
const bridgeListenFunctions = window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__
|
||||
if (!bridgeListenFunctions.has(channel)) {
|
||||
bridgeListenFunctions.set(channel, new Set())
|
||||
}
|
||||
|
||||
bridgeListenFunctions.get(channel)!.add({
|
||||
callback: callback,
|
||||
once: once,
|
||||
})
|
||||
}
|
||||
|
||||
// 移除指定通道的所有监听器
|
||||
off(channel: string) {
|
||||
window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__.delete(channel)
|
||||
}
|
||||
|
||||
// 移除特定监听器
|
||||
removeListen(channel: string, listener: unknown) {
|
||||
const bridgeListenFunctions = window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__
|
||||
const channelListeners = bridgeListenFunctions.get(channel)
|
||||
if (channelListeners) {
|
||||
// 需要类型转换以匹配存储的监听器类型
|
||||
channelListeners.delete(listener)
|
||||
if (channelListeners.size === 0) {
|
||||
bridgeListenFunctions.delete(channel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CSharpBridgeV2
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Time:2025/5/10 13:31 41
|
||||
* Name:IBridge.ts
|
||||
* Path:src/correspond
|
||||
* ProjectName:ClientApp
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
/**
|
||||
* 消息类型定义 - 用于类型安全的通信
|
||||
*/
|
||||
export type MessagePayload = Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* 核心接口层 - 定义与后端通信的基本能力
|
||||
*/
|
||||
export interface IBridge {
|
||||
// 发送消息到后端
|
||||
send<TResponse = void, TRequest extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data?: TRequest
|
||||
): Promise<TResponse>;
|
||||
|
||||
// 监听后端消息
|
||||
on<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): () => void;
|
||||
|
||||
// 只监听一次后端消息
|
||||
once<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): () => void;
|
||||
|
||||
// 移除指定通道的所有监听器
|
||||
off(channel: string): void;
|
||||
|
||||
// 移除特定监听器
|
||||
removeListener<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义Window扩展,用于与原生平台交互
|
||||
*/
|
||||
interface CSharpAppInterface {
|
||||
sendToCSharp(channel: string, dataJson: string): string;
|
||||
}
|
||||
|
||||
interface TauriInterface {
|
||||
invoke<T>(cmd: string, args?: unknown): Promise<T>;
|
||||
event: {
|
||||
listen(event: string, handler: (event: { payload: unknown }) => void): Promise<() => void>;
|
||||
once(event: string, handler: (event: { payload: unknown }) => void): Promise<void>;
|
||||
unlisten(event: string): Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
interface WindowWithNative extends Window {
|
||||
csharpApp?: CSharpAppInterface;
|
||||
receiveCSharpMessage?: (channel: string, dataJson: string) => void;
|
||||
__TAURI__?: TauriInterface;
|
||||
}
|
||||
|
||||
declare let window: WindowWithNative;
|
||||
|
||||
/**
|
||||
* 异常类型定义
|
||||
*/
|
||||
export class BridgeError extends Error {
|
||||
constructor(message: string, public readonly code?: string) {
|
||||
super(message);
|
||||
this.name = 'BridgeError';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import BaseBridge from "./BaseBridge";
|
||||
/**
|
||||
* Tauri适配器
|
||||
*/
|
||||
class TauriBridge extends BaseBridge {
|
||||
constructor() {
|
||||
super();
|
||||
// Tauri初始化代码
|
||||
if (typeof window !== 'undefined' && window.__TAURI__) {
|
||||
// 设置Tauri事件监听
|
||||
window.__TAURI__.event.listen('tauri://event', (event: { payload: unknown }) => {
|
||||
const eventData = event.payload as { channel: string; payload: MessagePayload };
|
||||
if (eventData.channel) {
|
||||
this.dispatchEvent(eventData.channel, eventData.payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async send<TResponse = void, TRequest extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data?: TRequest
|
||||
): Promise<TResponse> {
|
||||
if (typeof window === 'undefined' || !window.__TAURI__) {
|
||||
throw new BridgeError('Tauri bridge not available', 'BRIDGE_UNAVAILABLE');
|
||||
}
|
||||
|
||||
try {
|
||||
// 使用Tauri的invoke函数
|
||||
return await window.__TAURI__.invoke<TResponse>(channel, data || {});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new BridgeError(`Failed to invoke Tauri command: ${error.message}`, 'INVOKE_FAILED');
|
||||
}
|
||||
throw new BridgeError('Unknown error when invoking Tauri command', 'UNKNOWN_ERROR');
|
||||
}
|
||||
}
|
||||
|
||||
override on<TData extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
listener: (data: TData) => void
|
||||
): () => void {
|
||||
const unsubscribe = super.on(channel, listener);
|
||||
|
||||
// 向Tauri注册事件监听
|
||||
if (typeof window !== 'undefined' && window.__TAURI__) {
|
||||
window.__TAURI__.event.listen(channel, (event: { payload: unknown }) => {
|
||||
listener(event.payload as TData);
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
override off(channel: string): void {
|
||||
super.off(channel);
|
||||
// Tauri的事件注销需要特殊处理
|
||||
if (typeof window !== 'undefined' && window.__TAURI__) {
|
||||
window.__TAURI__.event.unlisten(channel).catch(console.error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import BaseBridge from "./BaseBridge";
|
||||
/**
|
||||
* Web环境的模拟实现 - 用于开发调试
|
||||
*/
|
||||
class WebMockBridge extends BaseBridge {
|
||||
async send<TResponse = void, TRequest extends MessagePayload = MessagePayload>(
|
||||
channel: string,
|
||||
data?: TRequest
|
||||
): Promise<TResponse> {
|
||||
console.log(`[WebMock] Send to channel ${channel}:`, data);
|
||||
// 模拟异步响应
|
||||
return new Promise<TResponse>(resolve => {
|
||||
setTimeout(() => {
|
||||
// 默认的模拟响应
|
||||
const mockResponse = { success: true, mock: true } as unknown as TResponse;
|
||||
resolve(mockResponse);
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
// 用于测试 - 模拟后端发送消息
|
||||
mockReceive<TData extends MessagePayload = MessagePayload>(channel: string, data: TData): void {
|
||||
this.dispatchEvent(channel, data);
|
||||
}
|
||||
}
|
||||
@@ -24,3 +24,6 @@ app.use(router)
|
||||
app.use(vuetify)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
// 注册 C# 函数
|
||||
window.externalFunctions = {};
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Time:2025/5/10 13:08 02
|
||||
* Name:global.d.ts
|
||||
* Path:src/types
|
||||
* ProjectName:ClientApp
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
|
||||
|
||||
// global.d.ts
|
||||
interface WebView2 {
|
||||
postMessage: (message: string) => void;
|
||||
addEventListener: <T>(type: "message", handler: (event: T) => void) => void;
|
||||
}
|
||||
|
||||
interface ChromeWithWebView {
|
||||
webview: WebView2;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
chrome?: ChromeWithWebView;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
/**
|
||||
* Time:2024/12/14 12:21 30
|
||||
* Name:commandUtil.ts
|
||||
* Path:src/utils
|
||||
* ProjectName:argus-src
|
||||
* Author:charlatans
|
||||
*
|
||||
* Il n'ya qu'un héroïsme au monde :
|
||||
* c'est de voir le monde tel qu'il est et de l'aimer.
|
||||
*/
|
||||
export function baseInvoke<T>(command: string, args: boolean | string | number | object) {
|
||||
return invoke<T>(command, args)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import CommandManager from '@/components/CommandManager.vue'
|
||||
import type { CommandType } from '@/types/command'
|
||||
|
||||
const commands: CommandType[] = [
|
||||
{
|
||||
name: 'greet',
|
||||
description: '查询exif信息',
|
||||
params: [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'name',
|
||||
type: 'text',
|
||||
value: 'Vue',
|
||||
placeholder: 'string'
|
||||
}
|
||||
],
|
||||
result: null
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommandManager :pro="commands"></CommandManager>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,25 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import CommandManager from '@/components/CommandManager.vue'
|
||||
import type { CommandType } from '@/types/command'
|
||||
|
||||
const commands: CommandType[] = [
|
||||
{
|
||||
name: 'is_elevated_command',
|
||||
description: '是否有管理员权限',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'get_exe_directory_command',
|
||||
description: '获取程序所在目录',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CommandManager :pro="commands"></CommandManager>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,53 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import CommandManager from '@/components/CommandManager.vue'
|
||||
import type { CommandType } from '@/types/command'
|
||||
import {onMounted,onUnmounted} from 'vue'
|
||||
import CSharpBridgeV2 from "@/correspond/CSharpBridgeV2"
|
||||
|
||||
|
||||
const bridge = CSharpBridgeV2.getBridge()
|
||||
bridge.listen("showMessage",(data) => {
|
||||
console.log('11111111',data);
|
||||
})
|
||||
|
||||
function func() {
|
||||
console.log('点击anniu')
|
||||
|
||||
bridge.send('showMessage',{
|
||||
title: "来自前端的问候",
|
||||
content: "Hello C#!"
|
||||
},(data) => {
|
||||
console.log(data,'======');
|
||||
console.log(window.externalFunctions.__BRIDGE_LISTEN__FUNCTIONS__);
|
||||
})
|
||||
}
|
||||
|
||||
const commands: CommandType[] = [
|
||||
{
|
||||
name: 'win_divert_command',
|
||||
description: '显示所有网络连接信息',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'monitor_network_with_windivert_command',
|
||||
description: '使用WinDivert监控网络数据包',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'recv_packet_command',
|
||||
description: '安全接收数据包的辅助函数',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'recv_packet_command1',
|
||||
description: '外部包接口!',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'get_all_tcp_info',
|
||||
description: '获取所有 TCP 信息!',
|
||||
params: [],
|
||||
result: null,
|
||||
},
|
||||
{
|
||||
name: 'get_more_info',
|
||||
description: 'get_more_info',
|
||||
name: 'showMessage',
|
||||
description: '获取信息!!',
|
||||
params: [
|
||||
{
|
||||
name: 'id',
|
||||
label: 'id',
|
||||
name: 'title',
|
||||
label: '标题',
|
||||
type: 'text',
|
||||
value: 'Vue',
|
||||
placeholder: 'text'
|
||||
}
|
||||
},{
|
||||
name: 'content',
|
||||
label: '标题',
|
||||
type: 'text',
|
||||
value: 'Hello C#!',
|
||||
placeholder: 'text'
|
||||
},
|
||||
],
|
||||
result: null,
|
||||
},
|
||||
]
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -8,8 +8,7 @@ import vueDevTools from 'vite-plugin-vue-devtools'
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
const host = env.VITE_TAURI_DEV_HOST;
|
||||
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
@@ -20,35 +19,12 @@ export default defineConfig(({ mode }) => {
|
||||
clearScreen: false,
|
||||
server: {
|
||||
port: 3000,
|
||||
// Tauri 需要一个固定端口,如果该端口不可用,则失败
|
||||
strictPort: true,
|
||||
// 如果设置了 Tauri 期望的主机,请使用它
|
||||
host: host || false,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: 'ws',
|
||||
host,
|
||||
port: 3000,
|
||||
}
|
||||
: undefined,
|
||||
|
||||
host: "0.0.0.0",
|
||||
watch: {
|
||||
// 告诉 Vite 忽略关注 'src-tauri'
|
||||
ignored: ['**/src-tauri/**'],
|
||||
},
|
||||
},
|
||||
// 以 'envPrefix' 项开头的 env 变量将通过 'import.meta.env' 暴露在 tauri 的源代码中。
|
||||
envPrefix: ['VITE_', 'TAURI_ENV_*'],
|
||||
build: {
|
||||
// Tauri 在 Windows 上使用 Chromium,在 macOS 和 Linux 上使用 WebKit
|
||||
target:
|
||||
process.env.TAURI_ENV_PLATFORM == 'windows'
|
||||
? 'chrome105'
|
||||
: 'safari13',
|
||||
// 不要缩小调试版本
|
||||
minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false,
|
||||
// 生成用于调试版本的 SourceMap
|
||||
sourcemap: !!process.env.TAURI_ENV_DEBUG,
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
Reference in new issue
Block a user