mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-21 18:19:03 +08:00
修你妈的
This commit is contained in:
@@ -42,10 +42,6 @@ interface ActionItem {
|
||||
value: string
|
||||
reason: string
|
||||
}
|
||||
interface TagItem {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
interface AutoScoreRuleFormValues {
|
||||
name: string
|
||||
@@ -65,7 +61,6 @@ const ACTION_DEFINITIONS = [
|
||||
export const AutoScoreManager: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const [rules, setRules] = useState<AutoScoreRule[]>([])
|
||||
const [allTags, setAllTags] = useState<TagItem[]>([])
|
||||
const [students, setStudents] = useState<{ id: number; name: string }[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
@@ -85,19 +80,6 @@ export const AutoScoreManager: React.FC = () => {
|
||||
return def ? t(def.labelKey) : eventName
|
||||
}
|
||||
|
||||
async function fetchAllTags() {
|
||||
if (!(window as any).api) return
|
||||
try {
|
||||
const res = await (window as any).api.tagsGetAll()
|
||||
if (res.success && res.data) {
|
||||
setAllTags(res.data)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch tags:', e)
|
||||
messageApi.error(t('tags.fetchFailed'))
|
||||
}
|
||||
}
|
||||
|
||||
const fetchRules = async () => {
|
||||
if (!(window as any).api) return
|
||||
|
||||
@@ -333,20 +315,6 @@ export const AutoScoreManager: React.FC = () => {
|
||||
])
|
||||
}
|
||||
|
||||
const handleRemoveTrigger = (id: number) => {
|
||||
setTriggerList((prev) => prev.filter((t) => t.id !== id))
|
||||
}
|
||||
|
||||
const handleTriggerChange = (
|
||||
id: number,
|
||||
field: keyof TriggerItem,
|
||||
value: string | number | 'AND' | 'OR'
|
||||
) => {
|
||||
setTriggerList((prev) =>
|
||||
prev.map((t) => (t.id === id ? { ...t, [field]: value } : t))
|
||||
)
|
||||
}
|
||||
|
||||
const handleAddAction = () => {
|
||||
const nextId = actionList.length ? Math.max(...actionList.map((a) => a.id)) + 1 : 1
|
||||
const defaultAction = ACTION_DEFINITIONS[0]
|
||||
@@ -369,14 +337,8 @@ export const AutoScoreManager: React.FC = () => {
|
||||
setActionList((prev) => prev.filter((a) => a.id !== id))
|
||||
}
|
||||
|
||||
const handleActionChange = (
|
||||
id: number,
|
||||
field: keyof ActionItem,
|
||||
value: string | number
|
||||
) => {
|
||||
setActionList((prev) =>
|
||||
prev.map((a) => (a.id === id ? { ...a, [field]: value } : a))
|
||||
)
|
||||
const handleActionChange = (id: number, field: keyof ActionItem, value: string | number) => {
|
||||
setActionList((prev) => prev.map((a) => (a.id === id ? { ...a, [field]: value } : a)))
|
||||
}
|
||||
|
||||
const columns: ColumnsType<AutoScoreRule> = [
|
||||
@@ -481,72 +443,6 @@ export const AutoScoreManager: React.FC = () => {
|
||||
}
|
||||
]
|
||||
|
||||
const renderTriggerItem = (trigger: TriggerItem, index: number) => (
|
||||
<div
|
||||
key={trigger.id}
|
||||
style={{
|
||||
padding: '12px',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: '6px',
|
||||
backgroundColor: 'var(--ss-card-bg)',
|
||||
marginBottom: '8px'
|
||||
}}
|
||||
>
|
||||
<Space wrap>
|
||||
{index > 0 && (
|
||||
<Select
|
||||
value={trigger.relation}
|
||||
onChange={(value) => handleTriggerChange(trigger.id, 'relation', value)}
|
||||
style={{ width: 80 }}
|
||||
options={[
|
||||
{ label: 'AND', value: 'AND' },
|
||||
{ label: 'OR', value: 'OR' }
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<Select
|
||||
value={trigger.eventName}
|
||||
onChange={(value) => handleTriggerChange(trigger.id, 'eventName', value)}
|
||||
style={{ width: 150 }}
|
||||
options={TRIGGER_DEFINITIONS.map((d) => ({
|
||||
label: t(d.labelKey),
|
||||
value: d.eventName
|
||||
}))}
|
||||
/>
|
||||
{trigger.eventName === 'interval_time_passed' && (
|
||||
<InputNumber
|
||||
value={trigger.value ? parseInt(trigger.value) : undefined}
|
||||
onChange={(value) => handleTriggerChange(trigger.id, 'value', String(value || 0))}
|
||||
placeholder={t('autoScore.minutesPlaceholder')}
|
||||
min={1}
|
||||
style={{ width: 120 }}
|
||||
addonAfter={t('autoScore.minutes')}
|
||||
/>
|
||||
)}
|
||||
{trigger.eventName === 'student_has_tag' && (
|
||||
<Select
|
||||
mode="multiple"
|
||||
allowClear
|
||||
value={trigger.value}
|
||||
onChange={(value) => handleTriggerChange(trigger.id, 'value', value)}
|
||||
onClick={fetchAllTags}
|
||||
style={{ width: 380 }}
|
||||
options={allTags.map((tag) => ({
|
||||
label: tag.name,
|
||||
value: tag.name
|
||||
}))}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
type="text"
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleRemoveTrigger(trigger.id)}
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
)
|
||||
|
||||
const renderActionItem = (action: ActionItem) => (
|
||||
<div
|
||||
key={action.id}
|
||||
@@ -635,9 +531,10 @@ export const AutoScoreManager: React.FC = () => {
|
||||
title={t('autoScore.whenTriggered')}
|
||||
>
|
||||
<Space orientation="vertical" style={{ width: '100%' }}>
|
||||
{/* {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))}
|
||||
*/} <RuleComponent />
|
||||
<Button
|
||||
{/* {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))}
|
||||
*/}{' '}
|
||||
<RuleComponent />
|
||||
<Button
|
||||
type="dashed"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAddTrigger}
|
||||
@@ -652,7 +549,7 @@ export const AutoScoreManager: React.FC = () => {
|
||||
style={{ marginBottom: '24px', backgroundColor: 'var(--ss-card-bg)' }}
|
||||
title={t('autoScore.triggeredActions')}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Space orientation="vertical" style={{ width: '100%' }}>
|
||||
{actionList.map((action) => renderActionItem(action))}
|
||||
<Button
|
||||
type="dashed"
|
||||
@@ -667,9 +564,7 @@ export const AutoScoreManager: React.FC = () => {
|
||||
|
||||
<div style={{ marginBottom: '24px', display: 'flex', gap: '12px' }}>
|
||||
<Button type="primary" onClick={handleSubmit}>
|
||||
{editingRuleId !== null
|
||||
? t('autoScore.updateAutomation')
|
||||
: t('autoScore.addAutomation')}
|
||||
{editingRuleId !== null ? t('autoScore.updateAutomation') : t('autoScore.addAutomation')}
|
||||
</Button>
|
||||
<Button onClick={handleResetForm}>
|
||||
{editingRuleId !== null ? t('autoScore.cancelEdit') : t('autoScore.resetForm')}
|
||||
@@ -701,4 +596,4 @@ export const AutoScoreManager: React.FC = () => {
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { Suspense, lazy } from 'react'
|
||||
import { Layout, Space, Button, Tag } from 'antd'
|
||||
import { Layout, Space, Button, Tag, Spin } from 'antd'
|
||||
import { Routes, Route, Navigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
@@ -104,19 +104,12 @@ export function ContentArea({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
height: '100%'
|
||||
height: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: 16
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
border: '3px solid var(--ss-border-color)',
|
||||
borderTopColor: 'var(--ant-color-primary)',
|
||||
borderRadius: '50%',
|
||||
animation: 'spin 1s linear infinite'
|
||||
}}
|
||||
/>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -598,7 +598,9 @@ export const OOBE: React.FC<oobeProps> = ({ visible, onComplete }) => {
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#52c41a' }}>✓</span>
|
||||
<span>{t('oobe.steps.start.features.score')}</span>
|
||||
<span style={{ color: isDark ? '#fff' : 'rgba(0, 0, 0, 0.88)' }}>
|
||||
{t('oobe.steps.start.features.score')}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@@ -611,7 +613,9 @@ export const OOBE: React.FC<oobeProps> = ({ visible, onComplete }) => {
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#52c41a' }}>✓</span>
|
||||
<span>{t('oobe.steps.start.features.history')}</span>
|
||||
<span style={{ color: isDark ? '#fff' : 'rgba(0, 0, 0, 0.88)' }}>
|
||||
{t('oobe.steps.start.features.history')}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@@ -624,7 +628,9 @@ export const OOBE: React.FC<oobeProps> = ({ visible, onComplete }) => {
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#52c41a' }}>✓</span>
|
||||
<span>{t('oobe.steps.start.features.settlement')}</span>
|
||||
<span style={{ color: isDark ? '#fff' : 'rgba(0, 0, 0, 0.88)' }}>
|
||||
{t('oobe.steps.start.features.settlement')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -659,7 +665,9 @@ export const OOBE: React.FC<oobeProps> = ({ visible, onComplete }) => {
|
||||
width: 480,
|
||||
maxWidth: '90vw',
|
||||
boxShadow: isDark ? '0 8px 32px rgba(0, 0, 0, 0.3)' : '0 8px 32px rgba(0, 0, 0, 0.1)',
|
||||
border: isDark ? '1px solid rgba(255, 255, 255, 0.08)' : '1px solid rgba(0, 0, 0, 0.06)'
|
||||
border: isDark ? '1px solid rgba(255, 255, 255, 0.08)' : '1px solid rgba(0, 0, 0, 0.06)',
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", sans-serif, "Apple Color Emoji", "Segoe UI Emoji"'
|
||||
}}
|
||||
>
|
||||
{contextHolder}
|
||||
|
||||
@@ -226,7 +226,7 @@ export function Sidebar({ activeMenu, permission, onMenuChange }: SidebarProps):
|
||||
backgroundColor: 'var(--ss-card-bg)',
|
||||
border: '1px solid var(--ss-border-color)'
|
||||
}}
|
||||
bodyStyle={{ padding: '12px' }}
|
||||
styles={{ body: { padding: '12px' } }}
|
||||
>
|
||||
{contextHolder}
|
||||
<Space orientation="vertical" size={4} style={{ width: '100%' }}>
|
||||
|
||||
@@ -477,7 +477,7 @@ export const StudentManager: React.FC<{ canEdit: boolean }> = ({ canEdit }) => {
|
||||
footer={null}
|
||||
destroyOnHidden
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Space orientation="vertical" style={{ width: '100%' }}>
|
||||
<Button
|
||||
loading={xlsxLoading}
|
||||
disabled={!canEdit}
|
||||
|
||||
@@ -96,4 +96,4 @@ export const ActionComponent: React.FC<ActionComponentProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
export default ActionComponent
|
||||
export default ActionComponent
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
.queryBuilder {
|
||||
--querybuilder-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
|
||||
--querybuilder-font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans',
|
||||
sans-serif;
|
||||
--querybuilder-background: var(--ss-card-bg, #ffffff);
|
||||
--querybuilder-color: var(--ss-text-main, rgba(0, 0, 0, 0.85));
|
||||
--querybuilder-border-radius: 6px;
|
||||
|
||||
@@ -42,15 +42,15 @@ export const ACTION_TYPE_KEYS = {
|
||||
|
||||
// Function to get fields with i18n support
|
||||
export const getFields = (t: (key: string) => string): Field[] => [
|
||||
{
|
||||
name: 'interval_time_passed',
|
||||
label: t('autoScore.triggerIntervalTime'),
|
||||
placeholder: t('autoScore.intervalMinutesPlaceholder')
|
||||
{
|
||||
name: 'interval_time_passed',
|
||||
label: t('autoScore.triggerIntervalTime'),
|
||||
placeholder: t('autoScore.intervalMinutesPlaceholder')
|
||||
},
|
||||
{
|
||||
name: 'student_has_tag',
|
||||
label: t('autoScore.triggerStudentTag'),
|
||||
placeholder: t('autoScore.tagNamesPlaceholder')
|
||||
{
|
||||
name: 'student_has_tag',
|
||||
label: t('autoScore.triggerStudentTag'),
|
||||
placeholder: t('autoScore.tagNamesPlaceholder')
|
||||
}
|
||||
]
|
||||
|
||||
@@ -116,4 +116,4 @@ export function autoScoreRuleToQuery(ruleData: AutoScoreRuleData): RuleGroupType
|
||||
combinator: currentCombinator,
|
||||
rules: rules.length > 0 ? rules : defaultQuery.rules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,4 +81,4 @@ export const RuleComponent: React.FC<RuleComponentProps> = ({ initialData, onCha
|
||||
)
|
||||
}
|
||||
|
||||
export default RuleComponent
|
||||
export default RuleComponent
|
||||
|
||||
Reference in New Issue
Block a user