Files
sam-manage/resources/views/rd/ai-quotation/create.blade.php
김보곤 2803e4a53a fix: [rd] API 호출 URL /admin → /api/admin 수정
- index, create, show 뷰의 fetch URL을 /api/admin/rd/... 로 수정
- api.php 라우트는 api/ prefix가 자동 적용됨
2026-03-02 18:03:08 +09:00

175 lines
8.0 KiB
PHP

@extends('layouts.app')
@section('title', 'AI 견적서 생성')
@section('content')
<!-- 페이지 헤더 -->
<div class="flex justify-between items-center mb-6">
<h1 class="text-2xl font-bold text-gray-800 flex items-center gap-2">
<i class="ri-robot-line text-purple-600"></i>
AI 견적서 생성
</h1>
<a href="{{ route('rd.ai-quotation.index') }}" class="bg-white hover:bg-gray-100 text-gray-700 px-4 py-2 rounded-lg border transition">
<i class="ri-arrow-left-line"></i> 목록으로
</a>
</div>
<!-- 생성 -->
<div class="bg-white rounded-lg shadow-sm">
<div class="px-6 py-4 border-b border-gray-100">
<h2 class="text-lg font-semibold text-gray-800">인터뷰 내용 입력</h2>
<p class="text-sm text-gray-500 mt-1">고객사 인터뷰 내용을 입력하면 AI가 업무를 분석하고 맞춤형 견적서를 자동 생성합니다.</p>
</div>
<form id="quotationForm" class="p-6 space-y-6">
<!-- 제목 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">견적 제목 <span class="text-red-500">*</span></label>
<input type="text" name="title" id="inputTitle" required maxlength="200"
placeholder="예: (주)대한기계 ERP 도입 견적"
class="w-full px-4 py-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500">
</div>
<!-- 입력 유형 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">입력 유형</label>
<div class="flex gap-3">
<label class="flex items-center gap-2 px-4 py-2.5 border border-purple-500 bg-purple-50 text-purple-700 rounded-lg cursor-pointer">
<input type="radio" name="input_type" value="text" checked class="text-purple-600">
<i class="ri-file-text-line"></i> 텍스트 입력
</label>
<label class="flex items-center gap-2 px-4 py-2.5 border border-gray-300 bg-gray-50 text-gray-400 rounded-lg cursor-not-allowed" title="Phase 2 예정">
<input type="radio" name="input_type" value="voice" disabled>
<i class="ri-mic-line"></i> 음성 파일 (Phase 2)
</label>
</div>
</div>
<!-- AI Provider -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">AI Provider</label>
<div class="flex gap-3">
<label class="flex items-center gap-2 px-4 py-2.5 border rounded-lg cursor-pointer transition hover:bg-blue-50"
id="providerGemini">
<input type="radio" name="ai_provider" value="gemini" checked class="text-blue-600"
onchange="updateProviderUI()">
<span class="font-medium">Gemini</span>
<span class="text-xs text-gray-400">(기본)</span>
</label>
<label class="flex items-center gap-2 px-4 py-2.5 border rounded-lg cursor-pointer transition hover:bg-orange-50"
id="providerClaude">
<input type="radio" name="ai_provider" value="claude" class="text-orange-600"
onchange="updateProviderUI()">
<span class="font-medium">Claude</span>
</label>
</div>
</div>
<!-- 인터뷰 내용 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">인터뷰 내용 <span class="text-red-500">*</span></label>
<textarea name="input_text" id="inputText" rows="12" required
placeholder="고객사 직원과의 인터뷰 내용을 입력하세요.&#10;&#10;예시:&#10;&quot;저희 회사는 블라인드 제조업체인데요. 직원이 30명 정도 되고, 현재 엑셀로 급여 관리를 하고 있어요. 생산 현황도 수기로 적고 있고, 재고 파악이 안돼요. 영업팀에서는 견적서를 한글 프로그램으로 만들어서 이메일로 보내는데, 이력 관리가 안 돼요...&quot;"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-purple-500 resize-y"></textarea>
<p class="text-xs text-gray-400 mt-1">인터뷰 내용이 구체적일수록 정확한 견적이 생성됩니다.</p>
</div>
<!-- 제출 -->
<div class="flex justify-end gap-3 pt-4 border-t border-gray-100">
<a href="{{ route('rd.ai-quotation.index') }}" class="px-6 py-2.5 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition">
취소
</a>
<button type="submit" id="submitBtn"
class="px-6 py-2.5 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition flex items-center gap-2">
<i class="ri-robot-line"></i> AI 분석 실행
</button>
</div>
</form>
</div>
<!-- 결과 영역 (숨김) -->
<div id="resultArea" class="mt-6 hidden">
<div id="resultContent"></div>
</div>
@endsection
@push('scripts')
<script>
function updateProviderUI() {
const gemini = document.getElementById('providerGemini');
const claude = document.getElementById('providerClaude');
const selected = document.querySelector('input[name="ai_provider"]:checked').value;
gemini.classList.toggle('border-blue-500', selected === 'gemini');
gemini.classList.toggle('bg-blue-50', selected === 'gemini');
gemini.classList.toggle('border-gray-300', selected !== 'gemini');
claude.classList.toggle('border-orange-500', selected === 'claude');
claude.classList.toggle('bg-orange-50', selected === 'claude');
claude.classList.toggle('border-gray-300', selected !== 'claude');
}
document.getElementById('quotationForm').addEventListener('submit', async function(e) {
e.preventDefault();
const btn = document.getElementById('submitBtn');
const originalHtml = btn.innerHTML;
// 유효성 검사
const title = document.getElementById('inputTitle').value.trim();
const text = document.getElementById('inputText').value.trim();
if (!title || !text) {
alert('제목과 인터뷰 내용을 모두 입력하세요.');
return;
}
// 로딩 상태
btn.disabled = true;
btn.innerHTML = '<i class="ri-loader-4-line animate-spin"></i> AI 분석중... (30초~1분 소요)';
btn.classList.add('opacity-75');
try {
const formData = new FormData(this);
const data = Object.fromEntries(formData.entries());
const token = document.querySelector('meta[name="api-token"]')?.content
|| sessionStorage.getItem('api_token') || '';
const response = await fetch('{{ url("/api/admin/rd/ai-quotation") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content || '',
'Authorization': token ? `Bearer ${token}` : '',
},
credentials: 'same-origin',
body: JSON.stringify(data),
});
const result = await response.json();
if (result.success && result.data?.id) {
// 성공 — 상세 페이지로 이동
window.location.href = `{{ url('/rd/ai-quotation') }}/${result.data.id}`;
} else {
// 실패
alert(result.message || 'AI 분석에 실패했습니다.');
if (result.data?.id) {
window.location.href = `{{ url('/rd/ai-quotation') }}/${result.data.id}`;
}
}
} catch (err) {
console.error('AI 분석 요청 실패:', err);
alert('서버 통신 중 오류가 발생했습니다.');
} finally {
btn.disabled = false;
btn.innerHTML = originalHtml;
btn.classList.remove('opacity-75');
}
});
// 초기 Provider UI
updateProviderUI();
</script>
@endpush