feat(auth): add org/dept/position management, user page, and Phase 2 completion

Complete Phase 2 identity & authentication module:
- Organization CRUD with tree structure (parent_id + materialized path)
- Department CRUD nested under organizations with tree support
- Position CRUD nested under departments
- User management page with table, create/edit modal, role assignment
- Organization architecture page with 3-panel tree layout
- Frontend API layer for orgs/depts/positions
- Sidebar navigation updated with organization menu item
- Fix parse_ttl edge case for strings ending in 'd' (e.g. "invalid")
This commit is contained in:
iven
2026-04-11 04:00:32 +08:00
parent 6fd0288e7c
commit 8a012f6c6a
15 changed files with 2409 additions and 10 deletions

View File

@@ -28,14 +28,14 @@ pub struct AuthState {
/// Falls back to parsing the raw string as seconds if no unit suffix is recognized.
pub fn parse_ttl(ttl: &str) -> i64 {
let ttl = ttl.trim();
if ttl.ends_with('s') {
ttl.trim_end_matches('s').parse::<i64>().unwrap_or(900)
} else if ttl.ends_with('m') {
ttl.trim_end_matches('m').parse::<i64>().unwrap_or(15) * 60
} else if ttl.ends_with('h') {
ttl.trim_end_matches('h').parse::<i64>().unwrap_or(1) * 3600
} else if ttl.ends_with('d') {
ttl.trim_end_matches('d').parse::<i64>().unwrap_or(1) * 86400
if let Some(num) = ttl.strip_suffix('s') {
num.parse::<i64>().unwrap_or(900)
} else if let Some(num) = ttl.strip_suffix('m') {
num.parse::<i64>().map(|n| n * 60).unwrap_or(900)
} else if let Some(num) = ttl.strip_suffix('h') {
num.parse::<i64>().map(|n| n * 3600).unwrap_or(900)
} else if let Some(num) = ttl.strip_suffix('d') {
num.parse::<i64>().map(|n| n * 86400).unwrap_or(900)
} else {
ttl.parse::<i64>().unwrap_or(900)
}