174 lines
6.4 KiB
Vue
174 lines
6.4 KiB
Vue
<template>
|
||
<div v-if="quoteModal.isOpen" class="quote-modal-overlay" @click="handleClose">
|
||
<div class="quote-modal" @click.stop>
|
||
<div class="quote-modal-header">
|
||
<h2 class="quote-modal-title">获取报价</h2>
|
||
<button type="button" class="quote-modal-close" @click="handleClose" aria-label="关闭">×</button>
|
||
</div>
|
||
<div class="quote-modal-body">
|
||
<p class="quote-modal-desc">请填写或上传报价所需资料,生成报价后可向各保司获取精准报价。</p>
|
||
<section class="quote-section">
|
||
<h3 class="quote-section-title">1. 报价需提交的资料</h3>
|
||
<div class="quote-fill-mode">
|
||
<label class="quote-radio">
|
||
<input type="radio" name="fillMode" :checked="fillMode === 'manual'" @change="fillMode = 'manual'" />
|
||
<span>手动填写</span>
|
||
</label>
|
||
<label class="quote-radio">
|
||
<input type="radio" name="fillMode" :checked="fillMode === 'upload'" @change="fillMode = 'upload'" />
|
||
<span>上传项目方案(AI 识别填充)</span>
|
||
</label>
|
||
</div>
|
||
<div v-if="fillMode === 'upload'" class="form-group">
|
||
<label>上传项目方案</label>
|
||
<input type="file" accept=".pdf,.doc,.docx" @change="handleUploadChange" />
|
||
<p v-if="uploading" class="form-hint">AI 识别中…</p>
|
||
</div>
|
||
<div class="quote-form-grid">
|
||
<div class="form-group">
|
||
<label>项目方案编号</label>
|
||
<input v-model="formData.projectCode" type="text" placeholder="如:CT-2025-001" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>项目标题</label>
|
||
<input v-model="formData.projectTitle" type="text" placeholder="试验方案标题" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>申办者</label>
|
||
<input v-model="formData.sponsor" type="text" placeholder="申办者名称" />
|
||
</div>
|
||
<div class="form-group">
|
||
<label>项目分期</label>
|
||
<input v-model="formData.projectPhase" type="text" placeholder="如:I期、II期、III期" />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="quote-section">
|
||
<h3 class="quote-section-title">2. 生成报价</h3>
|
||
<button
|
||
type="button"
|
||
class="btn btn-primary"
|
||
:disabled="!canGenerateQuote || generatingQuote"
|
||
@click="handleGenerateQuote"
|
||
>
|
||
{{ generatingQuote ? 'AI 生成中…' : '生成报价' }}
|
||
</button>
|
||
<div v-if="aiQuote" class="quote-ai-result">
|
||
<pre>{{ aiQuote }}</pre>
|
||
</div>
|
||
</section>
|
||
<section class="quote-section">
|
||
<h3 class="quote-section-title">3. 获取精准报价</h3>
|
||
<p class="quote-section-desc">系统将把报价资料整合后以邮件发送至各保司,保司回复后将经临研安审核并回显到报价页面。</p>
|
||
<button
|
||
type="button"
|
||
class="btn btn-primary"
|
||
:disabled="!aiQuote || sendingPrecise"
|
||
@click="handleGetPreciseQuote"
|
||
>
|
||
{{ sendingPrecise ? '发送中…' : preciseSent ? '已发送至各保司' : '获取精准报价' }}
|
||
</button>
|
||
<div v-if="preciseSent" class="quote-precise-tip">
|
||
<p>已向各保司发送询价邮件,保司将回复至 rmo@vdano.com,审核通过后将展示在报价页面。</p>
|
||
<button
|
||
v-if="auth.isAuthenticated"
|
||
type="button"
|
||
class="btn btn-secondary btn-sm"
|
||
@click="goToQuotes"
|
||
>
|
||
前往报价页面查看
|
||
</button>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed } from 'vue'
|
||
import { useRouter } from 'vue-router'
|
||
import { useQuoteModalStore } from '@/stores/quoteModal'
|
||
import { useAuthStore } from '@/stores/auth'
|
||
|
||
const router = useRouter()
|
||
const quoteModal = useQuoteModalStore()
|
||
const auth = useAuthStore()
|
||
|
||
const fillMode = ref<'manual' | 'upload'>('manual')
|
||
const formData = ref({
|
||
projectCode: '',
|
||
projectTitle: '',
|
||
sponsor: '',
|
||
projectPhase: '',
|
||
})
|
||
const uploading = ref(false)
|
||
const aiQuote = ref<string | null>(null)
|
||
const generatingQuote = ref(false)
|
||
const preciseSent = ref(false)
|
||
const sendingPrecise = ref(false)
|
||
|
||
const canGenerateQuote = computed(() =>
|
||
formData.value.projectCode.trim() !== '' &&
|
||
formData.value.projectTitle.trim() !== '' &&
|
||
formData.value.sponsor.trim() !== '' &&
|
||
formData.value.projectPhase.trim() !== ''
|
||
)
|
||
|
||
function handleClose() {
|
||
quoteModal.closeQuoteModal()
|
||
formData.value = { projectCode: '', projectTitle: '', sponsor: '', projectPhase: '' }
|
||
aiQuote.value = null
|
||
preciseSent.value = false
|
||
}
|
||
|
||
async function handleUploadChange(e: Event) {
|
||
const input = e.target as HTMLInputElement
|
||
const file = input.files?.[0]
|
||
if (!file) return
|
||
uploading.value = true
|
||
await new Promise(r => setTimeout(r, 1200))
|
||
formData.value = {
|
||
projectCode: 'CT-2025-' + Math.floor(1000 + Math.random() * 9000),
|
||
projectTitle: file.name.replace(/\.[^.]+$/, '') || '临床试验方案',
|
||
sponsor: '示例申办者',
|
||
projectPhase: 'I期',
|
||
}
|
||
uploading.value = false
|
||
}
|
||
|
||
async function handleGenerateQuote() {
|
||
if (!canGenerateQuote.value) return
|
||
generatingQuote.value = true
|
||
await new Promise(r => setTimeout(r, 1500))
|
||
aiQuote.value =
|
||
`基于当前项目信息(${formData.value.projectTitle},${formData.value.projectPhase})的预估报价:\n` +
|
||
'· 建议每人保额:80–120 万\n· 每次事故限额:400–600 万\n· 预估年保费区间:约 1.1 万–1.4 万元\n(实际以各保司精准报价为准)'
|
||
generatingQuote.value = false
|
||
}
|
||
|
||
async function handleGetPreciseQuote() {
|
||
if (!auth.isAuthenticated) {
|
||
if (window.confirm('获取精准报价需先登录,是否前往登录?')) {
|
||
handleClose()
|
||
router.push({ path: '/login', query: { from: '/dashboard/project-quotes' } })
|
||
}
|
||
return
|
||
}
|
||
if (!aiQuote.value) return
|
||
sendingPrecise.value = true
|
||
await new Promise(r => setTimeout(r, 1000))
|
||
preciseSent.value = true
|
||
sendingPrecise.value = false
|
||
}
|
||
|
||
function goToQuotes() {
|
||
handleClose()
|
||
router.push('/dashboard/project-quotes')
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
@import './QuoteRequestModal.css';
|
||
</style>
|