refactor: 移除WebSocket同步功能及相关代码

feat(theme): 增强侧边栏选中项样式配置
style: 优化主题变量和样式覆盖逻辑
chore: 清理未使用的依赖和配置文件
This commit is contained in:
Fox_block
2026-01-18 11:44:50 +08:00
parent b41139b941
commit e83f17af56
70 changed files with 4199 additions and 2173 deletions
+136 -66
View File
@@ -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) }))
}
}
}