feat: 评分标准保存为模板功能
This commit is contained in:
+51
-5
@@ -72,8 +72,10 @@ function getDb() {
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT,
|
||||
course TEXT,
|
||||
questions_json TEXT DEFAULT '',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`).run()
|
||||
try { db.prepare(`ALTER TABLE exam ADD COLUMN questions_json TEXT DEFAULT ''`).run() } catch (_) {}
|
||||
db.prepare(`CREATE TABLE IF NOT EXISTS question (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
exam_id INTEGER,
|
||||
@@ -161,7 +163,12 @@ export function setupIpc(win: BrowserWindow): void {
|
||||
return result
|
||||
} catch (err: any) {
|
||||
log.error('AI grade failed:', err)
|
||||
throw new Error(err.message || 'AI grading failed')
|
||||
const apiMsg = err?.response?.data?.error?.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 等)')
|
||||
}
|
||||
throw new Error(apiMsg || err.message || 'AI grading failed')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -258,17 +265,24 @@ export function setupIpc(win: BrowserWindow): void {
|
||||
ipcMain.handle('template:list', () => {
|
||||
try {
|
||||
const db = getDb()
|
||||
const exams = db.prepare('SELECT * FROM exam ORDER BY created_at DESC').all()
|
||||
return exams
|
||||
const exams = db.prepare('SELECT * FROM exam ORDER BY created_at DESC').all() as any[]
|
||||
const result = exams.map((e: any) => {
|
||||
const questions = e.questions_json ? JSON.parse(e.questions_json) : []
|
||||
log.info('template:list item', { id: e.id, name: e.name, jsonLen: (e.questions_json || '').length, questionCount: questions.length })
|
||||
return { ...e, questions }
|
||||
})
|
||||
return result
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('template:save', (_event, data: { name: string; course: string }) => {
|
||||
ipcMain.handle('template:save', (_event, data: { name: string; course: string; questions?: any[] }) => {
|
||||
try {
|
||||
const db = getDb()
|
||||
const result = db.prepare('INSERT INTO exam (name, course) VALUES (?, ?)').run(data.name, data.course)
|
||||
const questionsJson = JSON.stringify(data.questions || [])
|
||||
log.info('template:save', { name: data.name, course: data.course, questionCount: data.questions?.length ?? 0, jsonLen: questionsJson.length })
|
||||
const result = db.prepare('INSERT INTO exam (name, course, questions_json) VALUES (?, ?, ?)').run(data.name, data.course, questionsJson)
|
||||
return result.lastInsertRowid
|
||||
} catch (err) {
|
||||
log.error('template:save error:', err)
|
||||
@@ -276,6 +290,38 @@ export function setupIpc(win: BrowserWindow): void {
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('template:delete', (_event, id: number) => {
|
||||
try {
|
||||
getDb().prepare('DELETE FROM exam WHERE id = ?').run(id)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('template:apply', (_event, id: number) => {
|
||||
try {
|
||||
const db = getDb()
|
||||
const row = db.prepare('SELECT * FROM exam WHERE id = ?').get(id) as any
|
||||
if (!row) throw new Error('模板不存在')
|
||||
const questions = row.questions_json ? JSON.parse(row.questions_json) : []
|
||||
if (!questions.length) throw new Error('模板中没有题目')
|
||||
db.prepare('DELETE FROM rubric').run()
|
||||
const insert = db.prepare(
|
||||
'INSERT INTO rubric (question_title, max_score, reference_answer, rubric, sort_order, reference_answer_image) VALUES (?, ?, ?, ?, ?, ?)'
|
||||
)
|
||||
for (let i = 0; i < questions.length; i++) {
|
||||
const q = questions[i]
|
||||
insert.run(q.questionTitle || '', q.maxScore ?? 100, q.referenceAnswer || '', q.rubric || '', i, q.referenceAnswerImage || '')
|
||||
}
|
||||
rubricNextIndex = 0
|
||||
return true
|
||||
} catch (err) {
|
||||
log.error('template:apply error:', err)
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
// --- Dialog child windows ---
|
||||
ipcMain.handle('dialog:open', (_event, { type, data }: { type: string; data?: any }) => {
|
||||
log.info('IPC: dialog:open', type)
|
||||
|
||||
@@ -62,7 +62,9 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
|
||||
template: {
|
||||
list: () => ipcRenderer.invoke('template:list'),
|
||||
save: (data: { name: string; course: string }) => ipcRenderer.invoke('template:save', data)
|
||||
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)
|
||||
},
|
||||
|
||||
dialog: {
|
||||
|
||||
Reference in New Issue
Block a user