feat: implement P-WAR system analysis and inquiries sorting functionality
This commit is contained in:
93
server.py
93
server.py
@@ -76,6 +76,10 @@ async def get_mail_test(request: Request):
|
||||
async def get_inquiries_page(request: Request):
|
||||
return templates.TemplateResponse("inquiries.html", {"request": request})
|
||||
|
||||
@app.get("/analysis")
|
||||
async def get_analysis_page(request: Request):
|
||||
return templates.TemplateResponse("analysis.html", {"request": request})
|
||||
|
||||
class InquiryReplyRequest(BaseModel):
|
||||
reply: str
|
||||
status: str
|
||||
@@ -251,6 +255,95 @@ async def stop_sync():
|
||||
crawl_stop_event.set()
|
||||
return {"success": True}
|
||||
|
||||
@app.get("/api/analysis/p-war")
|
||||
async def get_p_war_analysis():
|
||||
"""P-WAR(Project Performance Above Replacement) 분석 API - 실제 평균 기반"""
|
||||
try:
|
||||
with get_db_connection() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
cursor.execute(DashboardQueries.GET_LAST_CRAWL_DATE)
|
||||
last_date = cursor.fetchone()['last_date']
|
||||
|
||||
cursor.execute(DashboardQueries.GET_PROJECT_LIST, (last_date,))
|
||||
projects = cursor.fetchall()
|
||||
|
||||
cursor.execute("SELECT project_nm, COUNT(*) as cnt FROM inquiries WHERE status != '완료' GROUP BY project_nm")
|
||||
inquiry_risks = {row['project_nm']: row['cnt'] for row in cursor.fetchall()}
|
||||
|
||||
import math
|
||||
temp_data = []
|
||||
total_files = 0
|
||||
total_stagnant = 0
|
||||
total_risk = 0
|
||||
count = len(projects)
|
||||
|
||||
if count == 0: return []
|
||||
|
||||
# 1. 1차 순회: 전체 합계 계산 (평균 산출용)
|
||||
for p in projects:
|
||||
file_count = int(p['file_count']) if p['file_count'] else 0
|
||||
log = p['recent_log']
|
||||
|
||||
days_stagnant = 10
|
||||
if log and log != "데이터 없음":
|
||||
match = re.search(r'(\d{4})\.(\d{2})\.(\d{2})', log)
|
||||
if match:
|
||||
log_date = datetime.strptime(match.group(0), "%Y.%m.%d").date()
|
||||
days_stagnant = (last_date - log_date).days
|
||||
|
||||
risk_count = inquiry_risks.get(p['project_nm'], 0)
|
||||
|
||||
total_files += file_count
|
||||
total_stagnant += days_stagnant
|
||||
total_risk += risk_count
|
||||
temp_data.append((p, file_count, days_stagnant, risk_count))
|
||||
|
||||
# 2. 시스템 실제 평균(Mean) 산출
|
||||
avg_files = total_files / count
|
||||
avg_stagnant = 5 # 사용자 요청에 따라 방치 기준을 5일로 강제 고정 (엄격한 판정)
|
||||
avg_risk = total_risk / count
|
||||
|
||||
# 3. 평균 수준의 프로젝트 가치(V_avg) 정의
|
||||
v_rep = ( (1 / (1 + avg_stagnant)) * math.log10(avg_files + 1) ) - (avg_risk * 0.5)
|
||||
|
||||
results = []
|
||||
# 4. 2차 순회: P-WAR 산출 (개별 가치 - 평균 가치)
|
||||
for p, f_cnt, d_stg, r_cnt in temp_data:
|
||||
name = p['short_nm'] or p['project_nm']
|
||||
log = p['recent_log'] or ""
|
||||
is_auto_delete = "폴더자동삭제" in log.replace(" ", "")
|
||||
|
||||
activity_factor = 1 / (1 + d_stg)
|
||||
scale_factor = math.log10(f_cnt + 1)
|
||||
v_project = (activity_factor * scale_factor) - (r_cnt * 0.5)
|
||||
|
||||
# [추가] 폴더 자동 삭제 페널티 부여 (실질적 관리 부재)
|
||||
if is_auto_delete:
|
||||
v_project -= 1.5
|
||||
|
||||
p_war = v_project - v_rep
|
||||
|
||||
results.append({
|
||||
"project_nm": name,
|
||||
"file_count": f_cnt,
|
||||
"days_stagnant": d_stg,
|
||||
"risk_count": r_cnt,
|
||||
"p_war": round(p_war, 3),
|
||||
"is_auto_delete": is_auto_delete,
|
||||
"master": p['master'],
|
||||
"dept": p['department'],
|
||||
"avg_info": {
|
||||
"avg_files": round(avg_files, 1),
|
||||
"avg_stagnant": round(avg_stagnant, 1),
|
||||
"avg_risk": round(avg_risk, 2)
|
||||
}
|
||||
})
|
||||
|
||||
results.sort(key=lambda x: x['p_war'])
|
||||
return results
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
@app.get("/attachments")
|
||||
async def get_attachments():
|
||||
path = "sample"
|
||||
|
||||
Reference in New Issue
Block a user