修你妈的

This commit is contained in:
Fox_block
2026-03-08 20:54:44 +08:00
parent 7100a30f1b
commit f47b6d483c
18 changed files with 124 additions and 190 deletions
-3
View File
@@ -1,3 +0,0 @@
该项目使用pnpm作为包管理器
每次写完代码后请务必跑一遍格式化和lint,typecheck,一个warning都不可以有
每次完成任务请详细告知用户“你干了什么”和要确认的问题(如有)。
+19
View File
@@ -0,0 +1,19 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':capacitor-preferences')
}
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}
+6
View File
@@ -0,0 +1,6 @@
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@capacitor+android@8.1.0_@capacitor+core@8.1.0/node_modules/@capacitor/android/capacitor')
include ':capacitor-preferences'
project(':capacitor-preferences').projectDir = new File('../node_modules/.pnpm/@capacitor+preferences@8.0.1_@capacitor+core@8.1.0/node_modules/@capacitor/preferences/android')
+1
View File
@@ -77,6 +77,7 @@
"prettier": "^3.7.4",
"react": "^19.2.1",
"react-dom": "^19.2.1",
"terser": "^5.46.0",
"typescript": "^5.9.3",
"vite": "^7.2.6"
},
+37 -21
View File
@@ -120,7 +120,7 @@ importers:
version: 11.0.0
'@vitejs/plugin-react':
specifier: ^5.1.1
version: 5.1.2(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1))
version: 5.1.2(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0))
electron:
specifier: ^39.2.6
version: 39.2.7
@@ -129,7 +129,7 @@ importers:
version: 26.4.0(electron-builder-squirrel-windows@26.4.0)
electron-vite:
specifier: ^5.0.0
version: 5.0.0(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1))
version: 5.0.0(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0))
eslint:
specifier: ^9.39.1
version: 9.39.2(jiti@2.6.1)
@@ -151,12 +151,15 @@ importers:
react-dom:
specifier: ^19.2.1
version: 19.2.3(react@19.2.3)
terser:
specifier: ^5.46.0
version: 5.46.0
typescript:
specifier: ^5.9.3
version: 5.9.3
vite:
specifier: ^7.2.6
version: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)
version: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0)
packages:
@@ -825,6 +828,9 @@ packages:
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
'@jridgewell/source-map@0.3.11':
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
@@ -1243,79 +1249,66 @@ packages:
resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.55.1':
resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.55.1':
resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.55.1':
resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-loong64-musl@4.55.1':
resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
cpu: [loong64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-musl@4.55.1':
resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
cpu: [ppc64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.55.1':
resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.55.1':
resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.55.1':
resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.55.1':
resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openbsd-x64@4.55.1':
resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
@@ -1905,6 +1898,9 @@ packages:
resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
engines: {node: '>=18'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
commander@5.1.0:
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
engines: {node: '>= 6'}
@@ -3885,6 +3881,11 @@ packages:
resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==}
engines: {node: '>=6.0.0'}
terser@5.46.0:
resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==}
engines: {node: '>=10'}
hasBin: true
text-hex@1.0.0:
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
@@ -4941,6 +4942,11 @@ snapshots:
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/source-map@0.3.11':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/sourcemap-codec@1.5.5': {}
'@jridgewell/trace-mapping@0.3.31':
@@ -5696,7 +5702,7 @@ snapshots:
'@use-gesture/core': 10.3.0
react: 19.2.3
'@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1))':
'@vitejs/plugin-react@5.1.2(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
@@ -5704,7 +5710,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.53
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
vite: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)
vite: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0)
transitivePeerDependencies:
- supports-color
@@ -6220,6 +6226,8 @@ snapshots:
commander@12.1.0: {}
commander@2.20.3: {}
commander@5.1.0: {}
commander@9.5.0:
@@ -6421,7 +6429,7 @@ snapshots:
electron-to-chromium@1.5.267: {}
electron-vite@5.0.0(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)):
electron-vite@5.0.0(vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0)):
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5)
@@ -6429,7 +6437,7 @@ snapshots:
esbuild: 0.25.12
magic-string: 0.30.21
picocolors: 1.1.1
vite: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)
vite: 7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0)
transitivePeerDependencies:
- supports-color
@@ -8529,6 +8537,13 @@ snapshots:
mkdirp: 0.5.6
rimraf: 2.6.3
terser@5.46.0:
dependencies:
'@jridgewell/source-map': 0.3.11
acorn: 8.15.0
commander: 2.20.3
source-map-support: 0.5.21
text-hex@1.0.0: {}
throttle-debounce@5.0.2: {}
@@ -8717,7 +8732,7 @@ snapshots:
extsprintf: 1.4.1
optional: true
vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1):
vite@7.3.1(@types/node@22.19.5)(jiti@2.6.1)(terser@5.46.0):
dependencies:
esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -8729,6 +8744,7 @@ snapshots:
'@types/node': 22.19.5
fsevents: 2.3.3
jiti: 2.6.1
terser: 5.46.0
void-elements@3.1.0: {}
+1 -3
View File
@@ -225,9 +225,7 @@ export class EventRepository extends Service {
return { startTime, rows }
}
async getLastScoreTimeByStudents(
studentNames: string[]
): Promise<Map<string, Date>> {
async getLastScoreTimeByStudents(studentNames: string[]): Promise<Map<string, Date>> {
if (studentNames.length === 0) return new Map()
const repo = this.ctx.db.dataSource.getRepository(ScoreEventEntity)
+6 -2
View File
@@ -1,6 +1,10 @@
import { Service } from '../../shared/kernel'
import { MainContext } from '../context'
import { AutoScoreRuleEngine, type RuleConfig, type AutoScoreContext } from '../../shared/autoScore/AutoScoreRuleEngine'
import {
AutoScoreRuleEngine,
type RuleConfig,
type AutoScoreContext
} from '../../shared/autoScore/AutoScoreRuleEngine'
interface AutoScoreRule extends RuleConfig {
id: number
@@ -385,7 +389,7 @@ export class AutoScoreService extends Service {
id: s.id,
name: s.name,
tags: s.tags || [],
lastScoreTime: lastScoreTimeMap.get(s.name) || new Date(0),
lastScoreTime: lastScoreTimeMap.get(s.name) || new Date(0)
})),
events: [],
rule: {
+5 -7
View File
@@ -1,5 +1,5 @@
import { Outlet, useLocation, useNavigate } from 'react-router-dom'
import { Layout, TabBar } from 'antd-mobile'
import { TabBar } from 'antd-mobile'
import {
HomeOutlined,
PlusCircleOutlined,
@@ -8,8 +8,6 @@ import {
} from '@ant-design/icons'
import { useTheme } from '../App'
const { Content } = Layout
const tabs = [
{ key: '/', title: '主页', icon: <HomeOutlined /> },
{ key: '/score', title: '积分', icon: <PlusCircleOutlined /> },
@@ -23,15 +21,15 @@ export function MobileLayout(): React.JSX.Element {
const { isDark } = useTheme()
return (
<Layout
<div
style={{
minHeight: '100vh',
backgroundColor: isDark ? '#1a1a1a' : '#f5f5f5'
}}
>
<Content style={{ paddingBottom: '50px' }}>
<div style={{ paddingBottom: '50px' }}>
<Outlet />
</Content>
</div>
<div
style={{
position: 'fixed',
@@ -57,6 +55,6 @@ export function MobileLayout(): React.JSX.Element {
}}
/>
</div>
</Layout>
</div>
)
}
@@ -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,8 +531,9 @@ export const AutoScoreManager: React.FC = () => {
title={t('autoScore.whenTriggered')}
>
<Space orientation="vertical" style={{ width: '100%' }}>
{/* {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))}
*/} <RuleComponent />
{/* {triggerList.map((trigger, index) => renderTriggerItem(trigger, index))}
*/}{' '}
<RuleComponent />
<Button
type="dashed"
icon={<PlusOutlined />}
@@ -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')}
+5 -12
View File
@@ -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>
}
>
+12 -4
View File
@@ -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}
+1 -1
View File
@@ -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}
@@ -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;
+3 -6
View File
@@ -90,7 +90,8 @@ export class AutoScoreRuleEngine {
students: AutoScoreContext['students'],
value: string | undefined
): Set<number> {
const requiredTags = value
const requiredTags =
value
?.split(',')
.map((t) => t.trim())
.filter(Boolean) || []
@@ -136,11 +137,7 @@ export class AutoScoreRuleEngine {
switch (trigger.event) {
case 'interval_time_passed':
matchedIds = this.checkIntervalTimeTrigger(
context.students,
trigger.value,
context.now
)
matchedIds = this.checkIntervalTimeTrigger(context.students, trigger.value, context.now)
break
case 'student_has_tag':
matchedIds = this.checkStudentTagTrigger(context.students, trigger.value)