- Update @tauri-apps/api and @tauri-apps/cli to v2.1.0 - Fix API imports: @tauri-apps/api/core (instead of tauri) - Add Emitter trait import for event emission - Export ClassifierConfig from ai module - Fix private field access: use data_dir() instead of config_dir - Add serde::Deserialize to AiResult struct - Fix base64 encoding: use BASE64 Engine API - Simplify tauri.conf.json for v2 compatibility - Fix Shortcut::new() call for hotkey module Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
380 lines
8.8 KiB
JavaScript
380 lines
8.8 KiB
JavaScript
// CutThink Lite - 主入口文件
|
|
|
|
import { invoke } from '@tauri-apps/api/core'
|
|
import { listen } from '@tauri-apps/api/event'
|
|
|
|
// 应用状态管理
|
|
const store = {
|
|
currentView: 'screenshot',
|
|
screenshots: [],
|
|
settings: {
|
|
theme: 'system',
|
|
language: 'zh-CN',
|
|
format: 'png',
|
|
hideWindow: true,
|
|
soundEffect: true,
|
|
},
|
|
}
|
|
|
|
// DOM 元素引用
|
|
const elements = {
|
|
navItems: null,
|
|
views: null,
|
|
btnCapture: null,
|
|
btnCaptureArea: null,
|
|
btnCaptureWindow: null,
|
|
galleryGrid: null,
|
|
uploadArea: null,
|
|
}
|
|
|
|
// 初始化应用
|
|
async function init() {
|
|
console.log('CutThink Lite 初始化中...')
|
|
|
|
// 获取 DOM 元素
|
|
cacheElements()
|
|
|
|
// 绑定事件
|
|
bindEvents()
|
|
|
|
// 加载设置
|
|
await loadSettings()
|
|
|
|
// 加载截图列表
|
|
await loadScreenshots()
|
|
|
|
// 设置默认视图
|
|
switchView('screenshot')
|
|
|
|
console.log('CutThink Lite 初始化完成')
|
|
}
|
|
|
|
// 缓存 DOM 元素
|
|
function cacheElements() {
|
|
elements.navItems = document.querySelectorAll('.nav-item')
|
|
elements.views = document.querySelectorAll('.view')
|
|
elements.btnCapture = document.getElementById('btn-capture')
|
|
elements.btnCaptureArea = document.getElementById('btn-capture-area')
|
|
elements.btnCaptureWindow = document.getElementById('btn-capture-window')
|
|
elements.galleryGrid = document.getElementById('gallery-grid')
|
|
elements.uploadArea = document.getElementById('upload-area')
|
|
}
|
|
|
|
// 绑定事件
|
|
function bindEvents() {
|
|
// 导航切换
|
|
elements.navItems.forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const view = item.dataset.view
|
|
switchView(view)
|
|
})
|
|
})
|
|
|
|
// 截图按钮
|
|
if (elements.btnCapture) {
|
|
elements.btnCapture.addEventListener('click', () => {
|
|
console.log('触发全屏截图')
|
|
handleCapture('full')
|
|
})
|
|
}
|
|
|
|
if (elements.btnCaptureArea) {
|
|
elements.btnCaptureArea.addEventListener('click', () => {
|
|
console.log('触发区域截图')
|
|
handleCapture('area')
|
|
})
|
|
}
|
|
|
|
if (elements.btnCaptureWindow) {
|
|
elements.btnCaptureWindow.addEventListener('click', () => {
|
|
console.log('触发窗口截图')
|
|
handleCapture('window')
|
|
})
|
|
}
|
|
|
|
// 上传区域拖拽
|
|
if (elements.uploadArea) {
|
|
setupDragAndDrop()
|
|
}
|
|
|
|
// 监听 Tauri 事件
|
|
setupTauriListeners()
|
|
}
|
|
|
|
// 视图切换
|
|
function switchView(viewName) {
|
|
console.log('切换视图:', viewName)
|
|
|
|
// 更新导航状态
|
|
elements.navItems.forEach(item => {
|
|
if (item.dataset.view === viewName) {
|
|
item.classList.add('active')
|
|
} else {
|
|
item.classList.remove('active')
|
|
}
|
|
})
|
|
|
|
// 更新视图显示
|
|
elements.views.forEach(view => {
|
|
if (view.id === `view-${viewName}`) {
|
|
view.classList.add('active')
|
|
} else {
|
|
view.classList.remove('active')
|
|
}
|
|
})
|
|
|
|
store.currentView = viewName
|
|
}
|
|
|
|
// 处理截图
|
|
async function handleCapture(type) {
|
|
try {
|
|
console.log('开始截图:', type)
|
|
|
|
// 调用 Tauri 后端截图功能
|
|
// 注意: 这需要在 Tauri 后端实现相应的命令
|
|
const result = await invoke('capture_screenshot', {
|
|
type,
|
|
})
|
|
|
|
console.log('截图成功:', result)
|
|
|
|
// 刷新截图列表
|
|
await loadScreenshots()
|
|
|
|
// 显示成功提示
|
|
showNotification('截图成功', 'success')
|
|
} catch (error) {
|
|
console.error('截图失败:', error)
|
|
showNotification('截图失败: ' + error.message, 'error')
|
|
}
|
|
}
|
|
|
|
// 加载截图列表
|
|
async function loadScreenshots() {
|
|
try {
|
|
console.log('加载截图列表...')
|
|
|
|
// 调用 Tauri 后端获取截图列表
|
|
// 注意: 这需要在 Tauri 后端实现相应的命令
|
|
const screenshots = await invoke('get_screenshots', {})
|
|
|
|
store.screenshots = screenshots
|
|
renderGallery()
|
|
} catch (error) {
|
|
console.error('加载截图失败:', error)
|
|
store.screenshots = []
|
|
renderGallery()
|
|
}
|
|
}
|
|
|
|
// 渲染画廊
|
|
function renderGallery() {
|
|
if (!elements.galleryGrid) return
|
|
|
|
if (store.screenshots.length === 0) {
|
|
elements.galleryGrid.innerHTML = `
|
|
<div class="placeholder">
|
|
<p>暂无截图</p>
|
|
<small>截图后会自动显示在这里</small>
|
|
</div>
|
|
`
|
|
return
|
|
}
|
|
|
|
elements.galleryGrid.innerHTML = store.screenshots
|
|
.map(
|
|
screenshot => `
|
|
<div class="gallery-item">
|
|
<img src="${screenshot.path}" alt="${screenshot.name}">
|
|
<div class="gallery-item-info">
|
|
<span class="gallery-item-name">${screenshot.name}</span>
|
|
<span class="gallery-item-date">${formatDate(screenshot.date)}</span>
|
|
</div>
|
|
</div>
|
|
`
|
|
)
|
|
.join('')
|
|
}
|
|
|
|
// 设置拖拽上传
|
|
function setupDragAndDrop() {
|
|
const area = elements.uploadArea
|
|
|
|
area.addEventListener('dragover', e => {
|
|
e.preventDefault()
|
|
area.classList.add('dragover')
|
|
})
|
|
|
|
area.addEventListener('dragleave', () => {
|
|
area.classList.remove('dragover')
|
|
})
|
|
|
|
area.addEventListener('drop', e => {
|
|
e.preventDefault()
|
|
area.classList.remove('dragover')
|
|
|
|
const files = Array.from(e.dataTransfer.files)
|
|
handleFileUpload(files)
|
|
})
|
|
|
|
area.addEventListener('click', () => {
|
|
const input = document.createElement('input')
|
|
input.type = 'file'
|
|
input.accept = 'image/png,image/jpeg,image/jpg'
|
|
input.multiple = true
|
|
|
|
input.addEventListener('change', e => {
|
|
const files = Array.from(e.target.files)
|
|
handleFileUpload(files)
|
|
})
|
|
|
|
input.click()
|
|
})
|
|
}
|
|
|
|
// 处理文件上传
|
|
async function handleFileUpload(files) {
|
|
console.log('上传文件:', files)
|
|
|
|
for (const file of files) {
|
|
try {
|
|
// 调用 Tauri 后端上传文件
|
|
// 注意: 这需要在 Tauri 后端实现相应的命令
|
|
const result = await invoke('upload_screenshot', {
|
|
path: file.path,
|
|
})
|
|
|
|
console.log('上传成功:', result)
|
|
showNotification('上传成功', 'success')
|
|
} catch (error) {
|
|
console.error('上传失败:', error)
|
|
showNotification('上传失败: ' + error.message, 'error')
|
|
}
|
|
}
|
|
}
|
|
|
|
// 加载设置
|
|
async function loadSettings() {
|
|
try {
|
|
// 调用 Tauri 后端加载设置
|
|
// 注意: 这需要在 Tauri 后端实现相应的命令
|
|
const settings = await invoke('get_settings', {})
|
|
|
|
store.settings = { ...store.settings, ...settings }
|
|
applySettings()
|
|
} catch (error) {
|
|
console.error('加载设置失败:', error)
|
|
}
|
|
}
|
|
|
|
// 应用设置
|
|
function applySettings() {
|
|
// 应用主题
|
|
document.documentElement.setAttribute('data-theme', store.settings.theme)
|
|
|
|
// 应用其他设置
|
|
console.log('应用设置:', store.settings)
|
|
}
|
|
|
|
// 设置 Tauri 事件监听
|
|
function setupTauriListeners() {
|
|
// 监听截图完成事件
|
|
listen('screenshot-taken', event => {
|
|
console.log('收到截图事件:', event.payload)
|
|
loadScreenshots()
|
|
})
|
|
|
|
// 监听上传完成事件
|
|
listen('upload-complete', event => {
|
|
console.log('收到上传完成事件:', event.payload)
|
|
showNotification('上传成功', 'success')
|
|
})
|
|
}
|
|
|
|
// 显示通知
|
|
function showNotification(message, type = 'info') {
|
|
console.log(`[${type}] ${message}`)
|
|
|
|
// TODO: 实现更完善的通知 UI
|
|
const notification = document.createElement('div')
|
|
notification.className = `notification notification-${type}`
|
|
notification.textContent = message
|
|
notification.style.cssText = `
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
padding: 12px 24px;
|
|
background: ${type === 'success' ? 'var(--success-color)' : type === 'error' ? 'var(--danger-color)' : 'var(--primary-color)'};
|
|
color: white;
|
|
border-radius: var(--radius-md);
|
|
box-shadow: var(--shadow-lg);
|
|
z-index: 1000;
|
|
animation: slideIn 0.3s ease-out;
|
|
`
|
|
|
|
document.body.appendChild(notification)
|
|
|
|
setTimeout(() => {
|
|
notification.style.animation = 'slideOut 0.3s ease-out'
|
|
setTimeout(() => {
|
|
document.body.removeChild(notification)
|
|
}, 300)
|
|
}, 3000)
|
|
}
|
|
|
|
// 格式化日期
|
|
function formatDate(dateString) {
|
|
const date = new Date(dateString)
|
|
const now = new Date()
|
|
const diff = now - date
|
|
|
|
if (diff < 60000) {
|
|
return '刚刚'
|
|
} else if (diff < 3600000) {
|
|
return `${Math.floor(diff / 60000)} 分钟前`
|
|
} else if (diff < 86400000) {
|
|
return `${Math.floor(diff / 3600000)} 小时前`
|
|
} else {
|
|
return date.toLocaleDateString('zh-CN')
|
|
}
|
|
}
|
|
|
|
// 添加动画样式
|
|
const style = document.createElement('style')
|
|
style.textContent = `
|
|
@keyframes slideIn {
|
|
from {
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
@keyframes slideOut {
|
|
from {
|
|
transform: translateX(0);
|
|
opacity: 1;
|
|
}
|
|
to {
|
|
transform: translateX(100%);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
.upload-area.dragover {
|
|
border-color: var(--primary-color);
|
|
background: var(--bg-tertiary);
|
|
}
|
|
`
|
|
document.head.appendChild(style)
|
|
|
|
// 初始化应用
|
|
document.addEventListener('DOMContentLoaded', init)
|
|
|
|
// 导出 API 供其他模块使用
|
|
export { store, switchView, handleCapture, loadScreenshots, showNotification }
|