diff --git a/frontend/lib/api/approval.ts b/frontend/lib/api/approval.ts index fcde00de..00b7ea84 100644 --- a/frontend/lib/api/approval.ts +++ b/frontend/lib/api/approval.ts @@ -90,6 +90,7 @@ export interface ApprovalLineTemplateStep { step_id: number; template_id: number; step_order: number; + step_type?: "approval" | "consensus" | "notification"; approver_type: "user" | "position" | "dept"; approver_user_id?: string; approver_position?: string; @@ -98,6 +99,23 @@ export interface ApprovalLineTemplateStep { company_code: string; } +export interface ApprovalProxySetting { + id: number; + original_user_id: string; + original_user_name?: string; + original_dept_name?: string; + proxy_user_id: string; + proxy_user_name?: string; + proxy_dept_name?: string; + start_date: string; + end_date: string; + reason?: string; + is_active: string; + company_code: string; + created_at: string; + updated_at: string; +} + export interface ApprovalRequest { request_id: number; title: string; @@ -157,12 +175,15 @@ export interface CreateApprovalRequestInput { screen_id?: number; button_component_id?: string; approval_mode?: "sequential" | "parallel"; + approval_type?: "self" | "escalation" | "consensus" | "post"; approvers: { approver_id: string; approver_name?: string; approver_position?: string; approver_dept?: string; approver_label?: string; + step_type?: "approval" | "consensus" | "notification"; + step_order?: number; }[]; } @@ -451,3 +472,175 @@ export async function processApprovalLine( return { success: false, error: error.message }; } } + +// ============================================================ +// 대결 위임 설정 (Proxy Settings) API +// ============================================================ + +export async function getProxySettings(): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/proxy-settings`, { + headers: getAuthHeaders(), + credentials: "include", + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function createProxySetting(data: { + original_user_id: string; + proxy_user_id: string; + start_date: string; + end_date: string; + reason?: string; +}): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/proxy-settings`, { + method: "POST", + headers: getAuthHeaders(), + credentials: "include", + body: JSON.stringify(data), + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function updateProxySetting( + id: number, + data: { + proxy_user_id?: string; + start_date?: string; + end_date?: string; + reason?: string; + is_active?: string; + } +): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/proxy-settings/${id}`, { + method: "PUT", + headers: getAuthHeaders(), + credentials: "include", + body: JSON.stringify(data), + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function deleteProxySetting(id: number): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/proxy-settings/${id}`, { + method: "DELETE", + headers: getAuthHeaders(), + credentials: "include", + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function checkActiveProxy( + userId: string +): Promise> { + try { + const response = await fetch( + `${API_BASE}/approval/proxy-settings/check/${encodeURIComponent(userId)}`, + { headers: getAuthHeaders(), credentials: "include" } + ); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +// ============================================================ +// 후결 승인 API +// ============================================================ + +export async function postApproveRequest(requestId: number): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/requests/${requestId}/post-approve`, { + method: "POST", + headers: getAuthHeaders(), + credentials: "include", + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +// ============================================================ +// 결재선 템플릿 단계 (Template Steps) API +// ============================================================ + +export async function getTemplateSteps( + templateId: number +): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/templates/${templateId}/steps`, { + headers: getAuthHeaders(), + credentials: "include", + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function createTemplateStep( + templateId: number, + data: Omit +): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/templates/${templateId}/steps`, { + method: "POST", + headers: getAuthHeaders(), + credentials: "include", + body: JSON.stringify(data), + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function updateTemplateStep( + templateId: number, + stepId: number, + data: Partial> +): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/templates/${templateId}/steps/${stepId}`, { + method: "PUT", + headers: getAuthHeaders(), + credentials: "include", + body: JSON.stringify(data), + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} + +export async function deleteTemplateStep( + templateId: number, + stepId: number +): Promise> { + try { + const response = await fetch(`${API_BASE}/approval/templates/${templateId}/steps/${stepId}`, { + method: "DELETE", + headers: getAuthHeaders(), + credentials: "include", + }); + return await response.json(); + } catch (error: any) { + return { success: false, error: error.message }; + } +} diff --git a/test-results/e2e-browser-test-177271836-4651c-접속-후-로그인-wace-qlalfqjsgh11-/error-context.md b/test-results/e2e-browser-test-177271836-4651c-접속-후-로그인-wace-qlalfqjsgh11-/error-context.md new file mode 100644 index 00000000..565e275b --- /dev/null +++ b/test-results/e2e-browser-test-177271836-4651c-접속-후-로그인-wace-qlalfqjsgh11-/error-context.md @@ -0,0 +1,62 @@ +# Page snapshot + +```yaml +- generic [active] [ref=e1]: + - generic [ref=e2]: + - generic [ref=e4]: + - complementary [ref=e5]: + - img "WACE 솔루션 로고" [ref=e9] + - generic [ref=e11]: + - img [ref=e12] + - generic [ref=e16]: + - paragraph [ref=e17]: 현재 관리 회사 + - paragraph [ref=e18]: WACE (최고 관리자) + - generic [ref=e19]: + - button "관리자 메뉴로 전환" [ref=e20] [cursor=pointer]: + - img + - text: 관리자 메뉴로 전환 + - button "회사 선택" [ref=e21] [cursor=pointer]: + - img + - text: 회사 선택 + - navigation [ref=e23]: + - generic [ref=e25] [cursor=pointer]: + - generic [ref=e26]: + - img [ref=e27] + - generic "DTG 이력관리" [ref=e29] + - img [ref=e31] + - generic [ref=e34] [cursor=pointer]: + - generic [ref=e35]: + - img [ref=e36] + - generic "물류 통합관제" [ref=e39] + - img [ref=e41] + - generic [ref=e45] [cursor=pointer]: + - img [ref=e46] + - generic "카테고리" [ref=e49] + - generic [ref=e52] [cursor=pointer]: + - img [ref=e53] + - generic "견적관리 테스트" [ref=e56] + - generic [ref=e59] [cursor=pointer]: + - img [ref=e60] + - generic "피벗테스트" [ref=e63] + - button "관리자 관리자 해외영업부" [ref=e65] [cursor=pointer]: + - img "관리자" [ref=e67] + - generic [ref=e68]: + - paragraph [ref=e69]: 관리자 + - paragraph [ref=e70]: 해외영업부 + - main [ref=e71]: + - generic [ref=e75]: + - heading "Vexplor에 오신 것을 환영합니다!" [level=3] [ref=e76] + - paragraph [ref=e77]: 제품 수명 주기 관리 시스템을 통해 효율적인 업무를 시작하세요. + - generic [ref=e78]: + - generic [ref=e79]: Node.js + - generic [ref=e80]: Next.js + - generic [ref=e81]: Shadcn/ui + - region "Notifications alt+T" + - generic [ref=e82]: + - img [ref=e84] + - button "Open Tanstack query devtools" [ref=e132] [cursor=pointer]: + - img [ref=e133] + - button "Open Next.js Dev Tools" [ref=e186] [cursor=pointer]: + - img [ref=e187] + - alert [ref=e190] +``` \ No newline at end of file