import React, { useState, useEffect } from 'react' import { AddIcon, Delete1Icon, MoveIcon } from 'tdesign-icons-react' import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter' import { prism } from 'react-syntax-highlighter/dist/esm/styles/prism' import { Card, Form, Input, InputNumber, Button, MessagePlugin, Table, PrimaryTableCol, Tag, Space, Switch, Popconfirm, Radio, Select, TooltipLite } from 'tdesign-react' interface AutoScoreRule { id: number enabled: boolean name: string intervalMinutes: number studentNames: string[] scoreValue: number reason: string lastExecuted?: string } interface AutoScoreRuleFormValues { name: string intervalMinutes: number studentNames: string scoreValue: number reason: string } export const AutoScoreManager: React.FC = () => { const [rules, setRules] = useState([]) const [students, setStudents] = useState<{ id: number; name: string }[]>([]) const [loading, setLoading] = useState(false) const [currentPage, setCurrentPage] = useState(1) const [pageSize, setPageSize] = useState(50) const [form] = Form.useForm() const [editingRuleId, setEditingRuleId] = useState(null) const fetchRules = async () => { if (!(window as any).api) return setLoading(true) try { // 权限检查:确保当前为 admin try { const authRes = await (window as any).api.authGetStatus() if (!authRes || !authRes.success || authRes.data?.permission !== 'admin') { MessagePlugin.error('需要管理员权限以查看自动加分自动化,请先登录管理员账号') setLoading(false) return } } catch (e) { // 如果权限检查失败,继续让后端返回更明确的错误 console.warn('Auth check failed', e) } const [rulesRes, studentsRes] = await Promise.all([ (window as any).api.invoke('auto-score:getRules', {}), (window as any).api.queryStudents({}) ]) if (rulesRes.success) { setRules(rulesRes.data) } else { MessagePlugin.error(rulesRes.message || '获取自动化失败') } if (studentsRes.success) { setStudents(studentsRes.data) } } catch (error) { console.error('Failed to fetch auto score rules:', error) MessagePlugin.error('获取自动化失败') } finally { setLoading(false) } } useEffect(() => { fetchRules() }, []) const handleSubmit = async () => { if (!(window as any).api) return const values = form.getFieldsValue(true) as unknown as AutoScoreRuleFormValues & { timeUnit: string } if (!values.name || values.intervalMinutes == null || values.scoreValue == null) { MessagePlugin.warning('请填写完整信息') return } // 根据单位转换间隔时间 const intervalMinutes = values.timeUnit === 'days' ? values.intervalMinutes * 1440 : values.intervalMinutes // 确保 studentNames 是数组类型 const studentNames = Array.isArray(values.studentNames) ? values.studentNames : [] const ruleData = { enabled: true, name: values.name, intervalMinutes, studentNames, scoreValue: values.scoreValue, reason: values.reason || `自动化加分 - ${values.name}` } // 权限检查:仅管理员可创建/更新自动化 try { const authRes = await (window as any).api.authGetStatus() if (!authRes || !authRes.success || authRes.data?.permission !== 'admin') { MessagePlugin.error('需要管理员权限以创建或更新自动加分自动化') return } } catch (e) { console.warn('Auth check failed', e) } try { let res if (editingRuleId !== null) { // 更新现有自动化 res = await (window as any).api.invoke('auto-score:updateRule', { id: editingRuleId, ...ruleData }) } else { // 创建新自动化 res = await (window as any).api.invoke('auto-score:addRule', ruleData) } if (res.success) { MessagePlugin.success(editingRuleId !== null ? '自动化更新成功' : '自动化创建成功') // 手动清空表单字段,避免 form.reset() 导致的栈溢出 form.setFieldsValue({ name: '', intervalMinutes: undefined, studentNames: '', scoreValue: undefined, reason: '', timeUnit: 'minutes' }) setEditingRuleId(null) fetchRules() // 刷新自动化列表 } else { MessagePlugin.error( res.message || (editingRuleId !== null ? '更新自动化失败' : '创建自动化失败') ) } } catch (error) { console.error('Failed to submit auto score rule:', error) MessagePlugin.error(editingRuleId !== null ? '更新自动化失败' : '创建自动化失败') } } const handleEdit = (rule: AutoScoreRule) => { setEditingRuleId(rule.id) form.setFieldsValue({ name: rule.name, intervalMinutes: rule.intervalMinutes, studentNames: rule.studentNames.join(', '), scoreValue: rule.scoreValue, reason: rule.reason }) } const handleDelete = async (ruleId: number) => { if (!(window as any).api) return // 权限检查 try { const authRes = await (window as any).api.authGetStatus() if (!authRes || !authRes.success || authRes.data?.permission !== 'admin') { MessagePlugin.error('需要管理员权限以删除自动加分自动化') return } } catch (e) { console.warn('Auth check failed', e) } try { const res = await (window as any).api.invoke('auto-score:deleteRule', ruleId) if (res.success) { MessagePlugin.success('自动化删除成功') fetchRules() // 刷新自动化列表 } else { MessagePlugin.error(res.message || '删除自动化失败') } } catch (error) { console.error('Failed to delete auto score rule:', error) MessagePlugin.error('删除自动化失败') } } const handleToggle = async (ruleId: number, enabled: boolean) => { if (!(window as any).api) return // 权限检查 try { const authRes = await (window as any).api.authGetStatus() if (!authRes || !authRes.success || authRes.data?.permission !== 'admin') { MessagePlugin.error('需要管理员权限以启用/禁用自动加分自动化') return } } catch (e) { console.warn('Auth check failed', e) } try { const res = await (window as any).api.invoke('auto-score:toggleRule', { ruleId, enabled }) if (res.success) { MessagePlugin.success(enabled ? '自动化已启用' : '自动化已禁用') fetchRules() // 刷新自动化列表 } else { MessagePlugin.error(res.message || (enabled ? '启用自动化失败' : '禁用自动化失败')) } } catch (error) { console.error('Failed to toggle auto score rule:', error) MessagePlugin.error(enabled ? '启用自动化失败' : '禁用自动化失败') } } const handleResetForm = () => { // 手动清空表单字段,避免 form.reset() 导致的栈溢出 form.setFieldsValue({ name: '', intervalMinutes: undefined, studentNames: '', scoreValue: undefined, reason: '' }) setEditingRuleId(null) } const columns: PrimaryTableCol[] = [ { colKey: 'drag', title: '排序', cell: () => , width: 60 }, { colKey: 'enabled', title: '状态', width: 80, cell: ({ row }) => ( handleToggle(row.id, value)} size="small" /> ) }, { colKey: 'name', title: '自动化名称', width: 150 }, { colKey: 'intervalMinutes', title: '间隔', width: 100, cell: ({ row }) => { const isDays = row.intervalMinutes >= 1440 const value = isDays ? row.intervalMinutes / 1440 : row.intervalMinutes const unit = isDays ? '天' : '分钟' return `${value} ${unit}` } }, { colKey: 'scoreValue', title: '分值', width: 80, cell: ({ row }) => ( 0 ? 'success' : 'danger'} variant="light"> {row.scoreValue > 0 ? `+${row.scoreValue}` : row.scoreValue} ) }, { colKey: 'studentNames', title: '适用学生', width: 130, cell: ({ row }) => { if (row.studentNames.length === 0) { return 所有学生 } const studentList = row.studentNames.join(',\n') return ( {row.studentNames.length} 名学生 ) } }, { colKey: 'reason', title: '理由', width: 130, ellipsis: true }, { colKey: 'lastExecuted', title: '最后执行', width: 180, cell: ({ row }) => { if (!row.lastExecuted) return 未执行 try { const date = new Date(row.lastExecuted) return date.toLocaleString() } catch { return 无效时间 } } }, { colKey: 'operation', title: '操作', width: 150, cell: ({ row }) => ( handleDelete(row.id)}> ) } ] const onDragSort = (params: any) => setRules(params.newData) // 定义触发规则选项 const triggerOptions = [ { label: '学生注册', value: 'student_registered' }, { label: '学生登录', value: 'student_logged_in' }, { label: '完成作业', value: 'homework_completed' }, { label: '考试通过', value: 'exam_passed' }, { label: '参与活动', value: 'event_participated' }, { label: '签到', value: 'check_in' }, { label: '其他自定义事件', value: 'custom_event' } ] const initialTriggers = [ { id: 1, triggerEvent: triggerOptions[1], description: '当学生登录时触发自动化', haveValue: true, value: 1 }, { id: 2, triggerEvent: triggerOptions[2], description: '当学生完成作业时触发自动化', haveValue: true, value: '12' }, { id: 3, triggerEvent: triggerOptions[3], description: '当学生考试通过时触发自动化', haveValue: false, value: null } ] const [triggerList, setTriggerList] = useState(initialTriggers) const handleTriggerChange = (id: number, value: string) => { setTriggerList((prev) => prev.map((t) => t.id === id ? { ...t, triggerEvent: triggerOptions.find((o) => o.value === value) || t.triggerEvent } : t ) ) } const handleValueChange = (id: number, val: string) => { setTriggerList((prev) => prev.map((t) => (t.id === id ? { ...t, value: val } : t))) } const handleDeleteTrigger = (id: number) => { setTriggerList((prev) => prev.filter((t) => t.id !== id)) } const handleAddTrigger = () => { const nextId = triggerList.length ? Math.max(...triggerList.map((t) => t.id)) + 1 : 1 setTriggerList((prev) => [ ...prev, { id: nextId, triggerEvent: triggerOptions[0], description: '', haveValue: false, value: '' } ]) } const triggerItems = triggerList .filter((t) => t.description !== null) .map((triggerTest) => (
)) return (

自动化加分管理

分钟
setCurrentPage(pageInfo.current), onPageSizeChange: (size) => setPageSize(size) }} style={{ color: 'var(--ss-text-main)' }} /> {triggerItems} println("这是一个示例代码块,展示如何使用自动化加分功能的API接口") {/*

使用说明

  • 自动化加分功能会按照设定的时间间隔自动为学生加分
  • 间隔时间以分钟为单位,例如1440表示每24小时(一天)执行一次
  • 如果"适用学生"字段为空,则自动化适用于所有学生
  • 可以随时启用/禁用自动化,不会影响已保存的自动化配置
*/} ) }