mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-21 18:19:03 +08:00
refactor: 移除WebSocket同步功能及相关代码
feat(theme): 增强侧边栏选中项样式配置 style: 优化主题变量和样式覆盖逻辑 chore: 清理未使用的依赖和配置文件
This commit is contained in:
@@ -1,102 +1,172 @@
|
||||
import { Database } from 'better-sqlite3'
|
||||
import { Service } from '../../shared/kernel'
|
||||
import { MainContext } from '../context'
|
||||
import { IsNull } from 'typeorm'
|
||||
import { ScoreEventEntity, SettlementEntity, StudentEntity } from '../db/entities'
|
||||
|
||||
export interface SettlementSummary {
|
||||
export interface settlementSummary {
|
||||
id: number
|
||||
start_time: string
|
||||
end_time: string
|
||||
event_count: number
|
||||
}
|
||||
|
||||
export interface SettlementLeaderboardRow {
|
||||
export interface settlementLeaderboardRow {
|
||||
name: string
|
||||
score: number
|
||||
}
|
||||
|
||||
export class SettlementRepository {
|
||||
constructor(private db: Database) {}
|
||||
declare module '../../shared/kernel' {
|
||||
interface Context {
|
||||
settlements: SettlementRepository
|
||||
}
|
||||
}
|
||||
|
||||
findAll(): SettlementSummary[] {
|
||||
const rows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
s.id as id,
|
||||
s.start_time as start_time,
|
||||
s.end_time as end_time,
|
||||
(
|
||||
SELECT COUNT(1)
|
||||
FROM score_events e
|
||||
WHERE e.settlement_id = s.id
|
||||
) as event_count
|
||||
FROM settlements s
|
||||
ORDER BY julianday(s.end_time) DESC
|
||||
`
|
||||
)
|
||||
.all() as SettlementSummary[]
|
||||
return rows
|
||||
export class SettlementRepository extends Service {
|
||||
constructor(ctx: MainContext) {
|
||||
super(ctx, 'settlements')
|
||||
this.registerIpc()
|
||||
}
|
||||
|
||||
settleNow() {
|
||||
return this.db.transaction(() => {
|
||||
const unassigned = this.db
|
||||
.prepare(`SELECT COUNT(1) as count FROM score_events WHERE settlement_id IS NULL`)
|
||||
.get() as { count: number }
|
||||
private get mainCtx() {
|
||||
return this.ctx as MainContext
|
||||
}
|
||||
|
||||
const eventCount = Number(unassigned?.count ?? 0)
|
||||
private registerIpc() {
|
||||
this.mainCtx.handle('db:settlement:query', async () => {
|
||||
try {
|
||||
return { success: true, data: await this.findAll() }
|
||||
} catch (err: any) {
|
||||
return { success: false, message: err.message }
|
||||
}
|
||||
})
|
||||
|
||||
this.mainCtx.handle('db:settlement:create', async (event) => {
|
||||
try {
|
||||
if (!this.mainCtx.permissions.requirePermission(event, 'admin'))
|
||||
return { success: false, message: 'Permission denied' }
|
||||
const data = await this.settleNow()
|
||||
return { success: true, data }
|
||||
} catch (err: any) {
|
||||
return { success: false, message: err.message }
|
||||
}
|
||||
})
|
||||
|
||||
this.mainCtx.handle('db:settlement:leaderboard', async (_, params) => {
|
||||
try {
|
||||
const settlementId = Number(params?.settlement_id)
|
||||
if (!Number.isFinite(settlementId))
|
||||
return { success: false, message: 'Invalid settlement_id' }
|
||||
return { success: true, data: await this.getLeaderboard(settlementId) }
|
||||
} catch (err: any) {
|
||||
return { success: false, message: err.message }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async findAll(): Promise<settlementSummary[]> {
|
||||
const qb = this.ctx.db.dataSource
|
||||
.getRepository(SettlementEntity)
|
||||
.createQueryBuilder('s')
|
||||
.select('s.id', 'id')
|
||||
.addSelect('s.start_time', 'start_time')
|
||||
.addSelect('s.end_time', 'end_time')
|
||||
.addSelect((subQb) => {
|
||||
return subQb
|
||||
.select('COUNT(1)', 'cnt')
|
||||
.from(ScoreEventEntity, 'e')
|
||||
.where('e.settlement_id = s.id')
|
||||
}, 'event_count')
|
||||
.orderBy('julianday(s.end_time)', 'DESC')
|
||||
|
||||
const rows = await qb.getRawMany()
|
||||
return rows.map((r: any) => ({
|
||||
id: Number(r.id),
|
||||
start_time: String(r.start_time),
|
||||
end_time: String(r.end_time),
|
||||
event_count: Number(r.event_count ?? 0)
|
||||
}))
|
||||
}
|
||||
|
||||
async settleNow() {
|
||||
const ds = this.ctx.db.dataSource
|
||||
return await ds.transaction(async (manager) => {
|
||||
const eventsRepo = manager.getRepository(ScoreEventEntity)
|
||||
const unassignedCount = await eventsRepo.count({ where: { settlement_id: IsNull() } })
|
||||
const eventCount = Number(unassignedCount ?? 0)
|
||||
if (eventCount <= 0) {
|
||||
throw new Error('暂无可结算记录')
|
||||
}
|
||||
|
||||
const endTime = new Date().toISOString()
|
||||
const lastSettlement = this.db
|
||||
.prepare(`SELECT end_time FROM settlements ORDER BY julianday(end_time) DESC LIMIT 1`)
|
||||
.get() as { end_time: string } | undefined
|
||||
|
||||
const minEvent = this.db
|
||||
.prepare(`SELECT MIN(event_time) as min_time FROM score_events WHERE settlement_id IS NULL`)
|
||||
.get() as { min_time: string } | undefined
|
||||
const settlementsRepo = manager.getRepository(SettlementEntity)
|
||||
const lastSettlement = await settlementsRepo
|
||||
.createQueryBuilder('s')
|
||||
.select('s.end_time', 'end_time')
|
||||
.orderBy('julianday(s.end_time)', 'DESC')
|
||||
.limit(1)
|
||||
.getRawOne<{ end_time?: string }>()
|
||||
|
||||
const startTime = lastSettlement?.end_time || minEvent?.min_time || endTime
|
||||
const minEvent = await eventsRepo
|
||||
.createQueryBuilder('e')
|
||||
.select('MIN(e.event_time)', 'min_time')
|
||||
.where('e.settlement_id IS NULL')
|
||||
.getRawOne<{ min_time?: string }>()
|
||||
|
||||
const info = this.db
|
||||
.prepare(`INSERT INTO settlements (start_time, end_time) VALUES (?, ?)`)
|
||||
.run(startTime, endTime)
|
||||
const settlementId = info.lastInsertRowid as number
|
||||
const startTime = String(lastSettlement?.end_time || minEvent?.min_time || endTime)
|
||||
|
||||
this.db
|
||||
.prepare(`UPDATE score_events SET settlement_id = ? WHERE settlement_id IS NULL`)
|
||||
.run(settlementId)
|
||||
const created = await settlementsRepo.save(
|
||||
settlementsRepo.create({
|
||||
start_time: startTime,
|
||||
end_time: endTime,
|
||||
created_at: new Date().toISOString()
|
||||
})
|
||||
)
|
||||
const settlementId = created.id
|
||||
|
||||
this.db.prepare(`UPDATE students SET score = 0, updated_at = CURRENT_TIMESTAMP`).run()
|
||||
await eventsRepo
|
||||
.createQueryBuilder()
|
||||
.update(ScoreEventEntity)
|
||||
.set({ settlement_id: settlementId })
|
||||
.where('settlement_id IS NULL')
|
||||
.execute()
|
||||
|
||||
await manager
|
||||
.getRepository(StudentEntity)
|
||||
.createQueryBuilder()
|
||||
.update(StudentEntity)
|
||||
.set({ score: 0, updated_at: new Date().toISOString() })
|
||||
.execute()
|
||||
|
||||
return { settlementId, startTime, endTime, eventCount }
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
getLeaderboard(settlementId: number) {
|
||||
const settlement = this.db
|
||||
.prepare(`SELECT id, start_time, end_time FROM settlements WHERE id = ?`)
|
||||
.get(settlementId) as { id: number; start_time: string; end_time: string } | undefined
|
||||
|
||||
async getLeaderboard(settlementId: number) {
|
||||
const settlementsRepo = this.ctx.db.dataSource.getRepository(SettlementEntity)
|
||||
const settlement = await settlementsRepo.findOne({ where: { id: settlementId } })
|
||||
if (!settlement) {
|
||||
throw new Error('结算记录不存在')
|
||||
}
|
||||
|
||||
const rows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT
|
||||
e.student_name as name,
|
||||
COALESCE(SUM(e.delta), 0) as score
|
||||
FROM score_events e
|
||||
WHERE e.settlement_id = ?
|
||||
GROUP BY e.student_name
|
||||
ORDER BY score DESC, name ASC
|
||||
`
|
||||
)
|
||||
.all(settlementId) as SettlementLeaderboardRow[]
|
||||
const rows = await this.ctx.db.dataSource
|
||||
.getRepository(ScoreEventEntity)
|
||||
.createQueryBuilder('e')
|
||||
.select('e.student_name', 'name')
|
||||
.addSelect('COALESCE(SUM(e.delta), 0)', 'score')
|
||||
.where('e.settlement_id = :settlementId', { settlementId })
|
||||
.groupBy('e.student_name')
|
||||
.orderBy('score', 'DESC')
|
||||
.addOrderBy('name', 'ASC')
|
||||
.getRawMany<settlementLeaderboardRow>()
|
||||
|
||||
return { settlement, rows }
|
||||
return {
|
||||
settlement: {
|
||||
id: settlement.id,
|
||||
start_time: settlement.start_time,
|
||||
end_time: settlement.end_time
|
||||
},
|
||||
rows: rows.map((r: any) => ({ name: String(r.name), score: Number(r.score ?? 0) }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user