mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 12:34:22 +08:00
feat: 间隔时间加分可以按照多少天、月、分钟后加分
fix: 修复若干问题 下雨了好害怕我靠
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use parking_lot::RwLock;
|
||||
use serde::Deserialize;
|
||||
use sea_orm::{ConnectionTrait, DatabaseConnection, Statement};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Map, Value as JsonValue};
|
||||
use sqlx::{Column, Row, SqlitePool};
|
||||
use std::collections::HashSet;
|
||||
@@ -155,7 +155,10 @@ async fn get_board_configs_raw(conn: &DatabaseConnection) -> Result<Option<Strin
|
||||
}
|
||||
}
|
||||
|
||||
async fn upsert_board_configs_raw(conn: &DatabaseConnection, config_json: &str) -> Result<(), String> {
|
||||
async fn upsert_board_configs_raw(
|
||||
conn: &DatabaseConnection,
|
||||
config_json: &str,
|
||||
) -> Result<(), String> {
|
||||
let config_escaped = escape_sql(config_json);
|
||||
let now_escaped = escape_sql(&now_iso());
|
||||
let sql = format!(
|
||||
|
||||
@@ -1150,7 +1150,10 @@ pub async fn db_switch_connection(
|
||||
let logger = state_guard.logger.read();
|
||||
logger.log(
|
||||
LogLevel::Info,
|
||||
&format!("Database switch requested, connection_string length: {}", connection_string.len()),
|
||||
&format!(
|
||||
"Database switch requested, connection_string length: {}",
|
||||
connection_string.len()
|
||||
),
|
||||
Some("database"),
|
||||
None,
|
||||
);
|
||||
@@ -1225,17 +1228,15 @@ pub async fn db_switch_connection(
|
||||
connection_string
|
||||
};
|
||||
|
||||
let conn = create_sqlite_connection(&path)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
logger.log(
|
||||
LogLevel::Error,
|
||||
&format!("SQLite connection failed: {}", e),
|
||||
Some("database"),
|
||||
None,
|
||||
);
|
||||
e.to_string()
|
||||
})?;
|
||||
let conn = create_sqlite_connection(&path).await.map_err(|e| {
|
||||
logger.log(
|
||||
LogLevel::Error,
|
||||
&format!("SQLite connection failed: {}", e),
|
||||
Some("database"),
|
||||
None,
|
||||
);
|
||||
e.to_string()
|
||||
})?;
|
||||
run_migration(&conn, DatabaseType::SQLite)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
|
||||
@@ -313,7 +313,9 @@ async fn post_banyou_action<T: DeserializeOwned>(
|
||||
params: serde_json::Value,
|
||||
) -> Result<T, String> {
|
||||
let timestamp = chrono::Utc::now().timestamp_millis();
|
||||
let url = format!("https://care.seewo.com/app/apis.json?action={action}×tamp={timestamp}&isAjax=1");
|
||||
let url = format!(
|
||||
"https://care.seewo.com/app/apis.json?action={action}×tamp={timestamp}&isAjax=1"
|
||||
);
|
||||
let payload = serde_json::json!({
|
||||
"action": action,
|
||||
"params": params,
|
||||
@@ -371,7 +373,11 @@ async fn post_banyou_action<T: DeserializeOwned>(
|
||||
"body_preview": first_n_chars(&body, 500),
|
||||
})),
|
||||
);
|
||||
return Err(format!("班优接口请求失败({} HTTP {})", action, status.as_u16()));
|
||||
return Err(format!(
|
||||
"班优接口请求失败({} HTTP {})",
|
||||
action,
|
||||
status.as_u16()
|
||||
));
|
||||
}
|
||||
|
||||
let parsed: BanYouApiResponse<T> = serde_json::from_str(&body).map_err(|e| {
|
||||
@@ -993,7 +999,9 @@ pub async fn student_fetch_banyou_classroom_detail(
|
||||
(Vec::new(), None)
|
||||
};
|
||||
|
||||
let final_team_plan_id = params.team_plan_id.or_else(|| team_plans.first().map(|p| p.team_plan_id));
|
||||
let final_team_plan_id = params
|
||||
.team_plan_id
|
||||
.or_else(|| team_plans.first().map(|p| p.team_plan_id));
|
||||
|
||||
let group_data = if let Some(team_plan_id) = final_team_plan_id {
|
||||
match post_banyou_action::<BanYouGroupFetchData>(
|
||||
@@ -1032,7 +1040,10 @@ pub async fn student_fetch_banyou_classroom_detail(
|
||||
let detail = BanYouClassroomDetailData {
|
||||
medals,
|
||||
students: students_data.students,
|
||||
teams: group_data.as_ref().map(|d| d.teams.clone()).unwrap_or_default(),
|
||||
teams: group_data
|
||||
.as_ref()
|
||||
.map(|d| d.teams.clone())
|
||||
.unwrap_or_default(),
|
||||
ungrouped_students: group_data
|
||||
.as_ref()
|
||||
.map(|d| d.students.clone())
|
||||
|
||||
@@ -292,9 +292,10 @@ fn setup_database(app: &mut App) -> Result<(), Box<dyn std::error::Error>> {
|
||||
*db_guard = Some(active_conn);
|
||||
}
|
||||
|
||||
state_guard.initialize().await.map_err(|e| {
|
||||
format!("Failed to initialize app state: {}", e)
|
||||
})?;
|
||||
state_guard
|
||||
.initialize()
|
||||
.await
|
||||
.map_err(|e| format!("Failed to initialize app state: {}", e))?;
|
||||
|
||||
Ok::<_, Box<dyn std::error::Error>>(())
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::{DateTime, Months, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use tauri::{AppHandle, Emitter};
|
||||
@@ -15,6 +15,20 @@ pub struct AutoScoreAction {
|
||||
pub value: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
enum IntervalUnit {
|
||||
Minute,
|
||||
Day,
|
||||
Month,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct IntervalTriggerValue {
|
||||
amount: i64,
|
||||
unit: IntervalUnit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AutoScoreRule {
|
||||
pub id: i32,
|
||||
@@ -171,23 +185,17 @@ impl AutoScoreService {
|
||||
|
||||
for trigger in &rule.triggers {
|
||||
if trigger.event == "interval_time_passed" {
|
||||
let minutes = trigger
|
||||
.value
|
||||
let interval = parse_interval_trigger_value(trigger.value.as_ref());
|
||||
let base_time = rule
|
||||
.last_executed
|
||||
.as_ref()
|
||||
.and_then(|v| v.parse::<i64>().ok())
|
||||
.unwrap_or(30);
|
||||
let interval_ms = minutes * 60 * 1000;
|
||||
.and_then(|value| DateTime::parse_from_rfc3339(value).ok())
|
||||
.map(|value| value.with_timezone(&Utc))
|
||||
.unwrap_or(now);
|
||||
|
||||
if let Some(last_executed_str) = &rule.last_executed {
|
||||
if let Ok(last_executed) = DateTime::parse_from_rfc3339(last_executed_str) {
|
||||
let last_executed_utc: DateTime<Utc> = last_executed.with_timezone(&Utc);
|
||||
let next_execute_time =
|
||||
last_executed_utc + chrono::Duration::milliseconds(interval_ms);
|
||||
let delay_ms = (next_execute_time - now).num_milliseconds();
|
||||
return Some(delay_ms.max(0));
|
||||
}
|
||||
}
|
||||
return Some(interval_ms);
|
||||
let next_execute_time = add_interval_to_time(base_time, &interval)?;
|
||||
let delay_ms = (next_execute_time - now).num_milliseconds();
|
||||
return Some(delay_ms.max(0));
|
||||
}
|
||||
}
|
||||
None
|
||||
@@ -197,3 +205,43 @@ impl AutoScoreService {
|
||||
let _ = app_handle.emit("auto-score:rulesChanged", &self.rules);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_interval_trigger_value(value: Option<&String>) -> IntervalTriggerValue {
|
||||
if let Some(raw_value) = value {
|
||||
if let Ok(minutes) = raw_value.parse::<i64>() {
|
||||
if minutes > 0 {
|
||||
return IntervalTriggerValue {
|
||||
amount: minutes,
|
||||
unit: IntervalUnit::Minute,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(parsed_value) = serde_json::from_str::<IntervalTriggerValue>(raw_value) {
|
||||
if parsed_value.amount > 0 {
|
||||
return parsed_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IntervalTriggerValue {
|
||||
amount: 30,
|
||||
unit: IntervalUnit::Minute,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_interval_to_time(
|
||||
base_time: DateTime<Utc>,
|
||||
interval: &IntervalTriggerValue,
|
||||
) -> Option<DateTime<Utc>> {
|
||||
match interval.unit {
|
||||
IntervalUnit::Minute => {
|
||||
base_time.checked_add_signed(chrono::Duration::minutes(interval.amount))
|
||||
}
|
||||
IntervalUnit::Day => base_time.checked_add_signed(chrono::Duration::days(interval.amount)),
|
||||
IntervalUnit::Month => {
|
||||
let months = u32::try_from(interval.amount).ok()?;
|
||||
base_time.checked_add_months(Months::new(months))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,9 +431,7 @@ impl SettingsService {
|
||||
"settings",
|
||||
];
|
||||
return items.iter().all(|item| {
|
||||
item.as_str()
|
||||
.map(|s| allowed.contains(&s))
|
||||
.unwrap_or(false)
|
||||
item.as_str().map(|s| allowed.contains(&s)).unwrap_or(false)
|
||||
});
|
||||
}
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user