好的, 我们可以使用 Tauri 框架将这个计算器应用改写成桌面应用。以下是步骤和代码示例:

  1. 首先, 安装 Tauri CLI:
npm init tauri-app calculator-app
cd calculator-app
  1. src-tauri/src/main.rs 中设置后端 API:
#![cfg_attr(
  all(not(debug_assertions), target_os = "windows"),
  windows_subsystem = "windows"
)]
 
use tauri::Manager;
use serde::{Deserialize, Serialize};
 
#[derive(Serialize, Deserialize)]
struct CalculationResult {
    result: f64,
}
 
#[tauri::command]
fn calculate(operation: String, values: Vec<f64>) -> CalculationResult {
    let result = match operation.as_str() {
        "sin" => values[0].sin(),
        "cos" => values[0].cos(),
        "tan" => values[0].tan(),
        "mean" => values.iter().sum::<f64>() / values.len() as f64,
        "median" => {
            let mut sorted = values.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
            let mid = sorted.len() / 2;
            if sorted.len() % 2 == 0 {
                (sorted[mid - 1] + sorted[mid]) / 2.0
            } else {
                sorted[mid]
            }
        },
        _ => 0.0,
    };
 
    CalculationResult { result }
}
 
fn main() {
    tauri::Builder::default()
        .setup(|app| {
            #[cfg(debug_assertions)]
            {
                let window = app.get_window("main").unwrap();
                window.open_devtools();
            }
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![calculate])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
  1. 修改 src/App.tsx:
import React, { useState } from 'react';
import { invoke } from '@tauri-apps/api/tauri';
 
const themes = {
  light: 'bg-white text-black',
  dark: 'bg-gray-800 text-white',
  colorful: 'bg-gradient-to-r from-purple-400 via-pink-500 to-red-500 text-white',
};
 
function App() {
  const [operation, setOperation] = useState('');
  const [values, setValues] = useState('');
  const [result, setResult] = useState<number | null>(null);
  const [theme, setTheme] = useState('light');
  const [layout, setLayout] = useState('vertical');
 
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      const res: { result: number } = await invoke('calculate', {
        operation,
        values: values.split(',').map(Number),
      });
      setResult(res.result);
    } catch (error) {
      console.error('Calculation error:', error);
    }
  };
 
  const handleNumberClick = (num: number) => {
    setValues(prev => prev + (prev ? ',' : '') + num);
  };
 
  const handleClear = () => {
    setValues('');
    setResult(null);
  };
 
  return (
    <div className={`p-4 ${themes[theme as keyof typeof themes]} ${layout === 'vertical' ? 'flex flex-col' : 'flex flex-row'}`}>
      <div className="flex-1">
        <h1 className="text-2xl font-bold mb-4">Complex Calculator</h1>
        <form onSubmit={handleSubmit} className="mb-4">
          <select 
            value={operation} 
            onChange={(e) => setOperation(e.target.value)}
            className="w-full p-2 mb-2 border rounded"
          >
            <option value="">Select operation</option>
            <option value="sin">Sin</option>
            <option value="cos">Cos</option>
            <option value="tan">Tan</option>
            <option value="mean">Mean</option>
            <option value="median">Median</option>
          </select>
          <input
            Type="text"
            value={values}
            onChange={(e) => setValues(e.target.value)}
            placeholder="Enter values (comma-separated)"
            className="w-full p-2 mb-2 border rounded"
          />
          <button type="submit" className="w-full p-2 bg-blue-500 text-white rounded hover:bg-blue-600">Calculate</button>
        </form>
        {result !== null && <p className="text-xl">Result: {result}</p>}
        
        <div className="grid grid-cols-3 gap-2 mt-4">
          {[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((num) => (
            <button
              key={num}
              onClick={() => handleNumberClick(num)}
              className="p-2 bg-gray-200 rounded hover:bg-gray-300"
            >
              {num}
            </button>
          ))}
          <button
            onClick={handleClear}
            className="p-2 bg-red-500 text-white rounded hover:bg-red-600 col-span-3"
          >
            Clear
          </button>
        </div>
      </div>
      
      <div className={`${layout === 'vertical' ? 'mt-4' : 'ml-4'}`}>
        <h2 className="text-xl font-bold mb-2">Customize</h2>
        <select 
          Value={theme} 
          onChange={(e) => setTheme(e.target.value)}
          className="w-full p-2 mb-2 border rounded"
        >
          <option value="light">Light Theme</option>
          <option value="dark">Dark Theme</option>
          <option value="colorful">Colorful Theme</option>
        </select>
        <select 
          value={layout} 
          onChange={(e) => setLayout(e.target.value)}
          className="w-full p-2 mb-2 border rounded"
        >
          <option value="vertical">Vertical Layout</option>
          <option value="horizontal">Horizontal Layout</option>
        </select>
      </div>
    </div>
  );
}
 
export default App;
  1. 配置 UnoCSS:

src/main.tsx 中添加:

import 'virtual:uno.css'

创建 uno.config.ts:

import { defineConfig } from 'unocss'
import presetUno from '@unocss/preset-uno'
 
export default defineConfig({
  presets: [presetUno()],
})
  1. 更新 package.json:
{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "tauri": "tauri"
  },
  "dependencies": {
    "@tauri-apps/api": "^1.0.0",
    "react": "^17.0.0",
    "react-dom": "^17.0.0"
  },
  "devDependencies": {
    "@types/react": "^17.0.0",
    "@types/react-dom": "^17.0.0",
    "@vitejs/plugin-react": "^1.0.0",
    "typescript": "^4.3.2",
    "vite": "^2.9.0",
    "@tauri-apps/cli": "^1.0.0",
    "unocss": "^0.53.0"
  }
}
  1. 更新 vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import UnoCSS from 'unocss/vite'
 
export default defineConfig({
  plugins: [UnoCSS(), react()],
})
  1. 运行应用:
npm run tauri dev

这个版本将计算器应用改写成了一个 Tauri 桌面应用。主要变化包括:

  1. 使用 Rust 编写后端逻辑, 替代了原来的 Node. Js 服务器。
  2. 前端代码改用 React 和 Vite, 适配 Tauri 的结构。
  3. 使用 Tauri 的 API 进行前后端通信, 替代了原来的 HTTP 请求。
  4. UnoCSS 集成到了 Vite 构建流程中。

现在你可以使用 npm run tauri build 来构建一个可执行的桌面应用程序。