feat: 模板导出导入 + 模板应用自动刷新主窗口 + 窗口放大 + 状态栏可拖拽
This commit is contained in:
+55
-2
@@ -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)
|
||||
|
||||
@@ -62,11 +62,11 @@ export function openDialogWindow(type: string): BrowserWindow | null {
|
||||
}
|
||||
|
||||
const sizes: Record<string, { width: number; height: number }> = {
|
||||
settings: { width: 520, height: 560 },
|
||||
history: { width: 800, height: 600 },
|
||||
templates: { width: 640, height: 520 },
|
||||
rubric: { width: 640, height: 700 },
|
||||
result: { width: 520, height: 700 }
|
||||
settings: { width: 640, height: 680 },
|
||||
history: { width: 1000, height: 750 },
|
||||
templates: { width: 720, height: 600 },
|
||||
rubric: { width: 750, height: 800 },
|
||||
result: { width: 600, height: 780 }
|
||||
}
|
||||
const size = sizes[type] || { width: 500, height: 500 }
|
||||
|
||||
|
||||
@@ -57,14 +57,21 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
importJson: () => ipcRenderer.invoke('rubric:importJson'),
|
||||
getNextIndex: () => ipcRenderer.invoke('rubric:getNextIndex'),
|
||||
setNextIndex: (idx: number) => ipcRenderer.invoke('rubric:setNextIndex', idx),
|
||||
resetNextIndex: () => ipcRenderer.invoke('rubric:resetNextIndex')
|
||||
resetNextIndex: () => ipcRenderer.invoke('rubric:resetNextIndex'),
|
||||
onUpdated: (callback: () => void) => {
|
||||
const handler = () => callback()
|
||||
ipcRenderer.on('rubric:updated', handler)
|
||||
return () => ipcRenderer.removeListener('rubric:updated', handler)
|
||||
}
|
||||
},
|
||||
|
||||
template: {
|
||||
list: () => ipcRenderer.invoke('template:list'),
|
||||
save: (data: { name: string; course: string; questions?: any[] }) => ipcRenderer.invoke('template:save', data),
|
||||
delete: (id: number) => ipcRenderer.invoke('template:delete', id),
|
||||
apply: (id: number) => ipcRenderer.invoke('template:apply', id)
|
||||
apply: (id: number) => ipcRenderer.invoke('template:apply', id),
|
||||
exportJson: () => ipcRenderer.invoke('template:exportJson'),
|
||||
importJson: () => ipcRenderer.invoke('template:importJson')
|
||||
},
|
||||
|
||||
dialog: {
|
||||
|
||||
Reference in New Issue
Block a user