feat: 模板导出导入 + 模板应用自动刷新主窗口 + 窗口放大 + 状态栏可拖拽

This commit is contained in:
2026-07-16 13:41:58 +08:00
parent e84b0705e5
commit 7d4551e7f2
6 changed files with 123 additions and 62 deletions
+55 -2
View File
@@ -111,7 +111,7 @@ export function setupIpc(win: BrowserWindow): void {
ipcMain.handle('window:resizeMain', (_event, width: number) => {
const [wx, wy] = win.getPosition()
win.setBounds({ x: wx, y: wy, width: Math.max(200, Math.min(width, 1200)), height: 64 })
win.setBounds({ x: wx, y: wy, width: Math.max(200, Math.min(width, 1200)), height: 76 })
})
ipcMain.handle('screenshot:start', () => {
@@ -163,7 +163,8 @@ export function setupIpc(win: BrowserWindow): void {
return result
} catch (err: any) {
log.error('AI grade failed:', err)
const apiMsg = err?.response?.data?.error?.message || ''
const res = err?.response?.data
const apiMsg = res?.error?.message || res?.error || res?.message || ''
const allMsg = (apiMsg + ' ' + (err.message || '')).toLowerCase()
if (allMsg.includes('does not support image') || allMsg.includes('image input') || allMsg.includes('not support image')) {
throw new Error('当前模型不支持图片输入,请在设置中更换为支持多模态的模型(如 gpt-4o、qwen-vl 等)')
@@ -277,6 +278,56 @@ export function setupIpc(win: BrowserWindow): void {
}
})
ipcMain.handle('template:exportJson', async () => {
try {
const d = getDb()
const rows: any[] = d.prepare('SELECT * FROM exam ORDER BY created_at DESC').all()
if (!rows.length) throw new Error('暂无模板可导出')
const templates = rows.map(r => ({
name: r.name,
course: r.course,
questions: r.questions_json ? JSON.parse(r.questions_json) : [],
created_at: r.created_at
}))
const result = await dialogBox.showSaveDialog({
defaultPath: '评分模板.json',
filters: [{ name: 'JSON', extensions: ['json'] }]
})
if (result.canceled || !result.filePath) return false
fs.writeFileSync(result.filePath, JSON.stringify(templates, null, 2), 'utf-8')
return true
} catch (err) {
log.error('template:exportJson error:', err)
return false
}
})
ipcMain.handle('template:importJson', async () => {
try {
const result = await dialogBox.showOpenDialog({
properties: ['openFile'],
filters: [{ name: 'JSON', extensions: ['json'] }]
})
if (result.canceled || result.filePaths.length === 0) return null
const content = fs.readFileSync(result.filePaths[0], 'utf-8')
const data = JSON.parse(content)
if (!Array.isArray(data)) throw new Error('JSON 格式错误:应为数组')
const db = getDb()
const insert = db.prepare('INSERT INTO exam (name, course, questions_json) VALUES (?, ?, ?)')
let count = 0
for (const tpl of data) {
if (tpl.name && tpl.course) {
insert.run(tpl.name, tpl.course, JSON.stringify(tpl.questions || []))
count++
}
}
return { count }
} catch (err) {
log.error('template:importJson error:', err)
return null
}
})
ipcMain.handle('template:save', (_event, data: { name: string; course: string; questions?: any[] }) => {
try {
const db = getDb()
@@ -315,6 +366,8 @@ export function setupIpc(win: BrowserWindow): void {
insert.run(q.questionTitle || '', q.maxScore ?? 100, q.referenceAnswer || '', q.rubric || '', i, q.referenceAnswerImage || '')
}
rubricNextIndex = 0
const mainWin = getMainWindow()
if (mainWin) mainWin.webContents.send('rubric:updated')
return true
} catch (err) {
log.error('template:apply error:', err)