Commit 6c77f9e8 by Sweet Zhang

新单跟进修改

parent 590d2904
......@@ -256,3 +256,48 @@ export function getProductList(data) {
data: data
})
}
// 新单跟进产品计划查询
export function getProductPlan(policyBizId) {
return request({
url: `/csf/api/policy_follow/product_plan?policyBizId=${policyBizId}`,
method: 'get'
})
}
// 新单跟进投保人查询
export function getPolicyholder(policyBizId) {
return request({
url: `/csf/api/policy_follow/policyholder?policyBizId=${policyBizId}`,
method: 'get'
})
}
// 新单跟进受保人查询
export function getInsurant(policyBizId) {
return request({
url: `/csf/api/policy_follow/insurant?policyBizId=${policyBizId}`,
method: 'get'
})
}
// 新单跟进 受益人(列表)查询
export function getBeneficiary(policyBizId) {
return request({
url: `/csf/api/policy_follow/beneficiary?policyBizId=${policyBizId}`,
method: 'get'
})
}
// 新单跟进第二持有人查询
export function getSecondHolder(policyBizId) {
return request({
url: `/csf/api/policy_follow/second_holder?policyBizId=${policyBizId}`,
method: 'get'
})
}
// 新单跟进 预约附件查询
export function getAppointmentFiles(policyBizId) {
return request({
url: `/csf/api/policy_follow/appointment_files?policyBizId=${policyBizId}`,
method: 'get'
})
}
\ No newline at end of file
......@@ -2,70 +2,137 @@
<template>
<div class="form-page">
<el-form ref="formRef" :model="localData" label-width="120px" size="default">
<!-- Tabs -->
<!-- 完整Tab列表:通用Tab + 自定义Tab -->
<el-tabs v-model="activeTab" @tab-click="handleTabClick" :before-leave="handleBeforeLeave">
<el-tab-pane label="基础信息" name="basic"></el-tab-pane>
<el-tab-pane label="产品计划" name="productPlan"></el-tab-pane>
<el-tab-pane label="投保人" name="policyholder"></el-tab-pane>
<el-tab-pane label="受保人" name="insured"></el-tab-pane>
<el-tab-pane label="受益人" name="beneficiary"></el-tab-pane>
<el-tab-pane label="第二持有人" name="secondHolder"></el-tab-pane>
<el-tab-pane label="预约附件" name="appointmentAttachment"></el-tab-pane>
<el-tab-pane label="介绍人" name="introducer"></el-tab-pane>
<el-tab-pane label="邮寄信息" name="postal"></el-tab-pane>
<el-tab-pane label="关联记录" name="relatedRecords"></el-tab-pane>
<el-tab-pane label="新单附件" name="policyAttachment"></el-tab-pane>
<!-- 自定义已实现的Tab -->
<el-tab-pane label="基础信息" name="basic"></el-tab-pane>
<!-- 复用预约页面的通用Tab -->
<el-tab-pane label="产品计划" name="productPlan"></el-tab-pane>
<el-tab-pane label="投保人" name="policyholder"></el-tab-pane>
<el-tab-pane label="受保人" name="insured"></el-tab-pane>
<el-tab-pane label="受益人" name="beneficiary"></el-tab-pane>
<el-tab-pane label="第二持有人" name="secondHolder"></el-tab-pane>
<el-tab-pane label="预约附件" name="appointmentAttachment"></el-tab-pane>
<!-- 自定义已实现的Tab -->
<el-tab-pane label="介绍人" name="introducer"></el-tab-pane>
<el-tab-pane label="邮寄信息" name="postal"></el-tab-pane>
<el-tab-pane label="关联记录" name="relatedRecords"></el-tab-pane>
<el-tab-pane label="新单附件" name="policyAttachment"></el-tab-pane>
</el-tabs>
<!-- 基础信息 Tab 内容 -->
<!-- 1. 基础信息 Tab(你已实现的部分) -->
<div v-if="activeTab === 'basic'" class="tab-content">
<!-- 签单信息 -->
<div class="section">
<h3 class="sectionTitle">基础信息</h3>
<SearchForm
ref="basicInfoFormRef"
:config="basicInfoFormConfig"
v-model="basicInfoFormData"
:disabled="props.mode === 'viewDetail'"
/>
</div>
<!-- 保单信息 -->
<div class="section">
<h3 class="sectionTitle">保单信息</h3>
<SearchForm
ref="policyInfoFormRef"
:config="policyInfoFormConfig"
v-model="policyInfoFormData"
:disabled="props.mode === 'viewDetail'"
/>
</div>
</div>
<!-- 产品计划 Tab 内容 -->
<div v-else-if="activeTab === 'productPlan'" class="tab-content">
<!-- 2. 产品计划 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'productPlan'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">产品计划</h3>
<!-- 复用预约页面的ProductPlan组件 -->
<ProductPlan
ref="productPlanRef"
:api-product-plan-info-dto="policyProductData"
:edit-status="!isEditing"
active-name="productPlan"
:ids-obj="{ appointmentBizId: null }"
page-source="policyList"
:father-tab-name="activeTab"
anchor-container=".el-tabs__content"
:affix-offset="60"
:tab-index="1"
:formData="productPlanFormData"
:disabled="props.mode === 'viewDetail'"
@form-change="handleProductPlanChange"
@save="handleProductPlanSave"
/>
</div>
</div>
<!-- 3. 投保人 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'policyholder'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">投保人信息</h3>
<!-- 复用预约页面的Customer组件(投保人) -->
<Customer
ref="policyholderRef"
type="policyholder"
:formData="policyholderFormData"
:disabled="props.mode === 'viewDetail'"
@form-change="handlePolicyholderChange"
/>
</div>
</div>
<!-- 4. 受保人 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'insured'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">受保人信息</h3>
<!-- 复用预约页面的Customer组件(受保人) -->
<Customer
ref="insuredRef"
type="insured"
:formData="insuredFormData"
:disabled="props.mode === 'viewDetail'"
@form-change="handleInsuredChange"
/>
</div>
</div>
<!-- 5. 受益人 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'beneficiary'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">受益人信息</h3>
<!-- 复用预约页面的Beneficiary组件 -->
<Beneficiary
ref="beneficiaryRef"
:formData="beneficiaryFormData"
:disabled="props.mode === 'viewDetail'"
@form-change="handleBeneficiaryChange"
/>
</div>
</div>
<!-- 6. 第二持有人 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'secondHolder'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">第二持有人信息</h3>
<!-- 复用预约页面的SecondHolder组件 -->
<SecondHolder
ref="secondHolderRef"
:formData="secondHolderFormData"
:disabled="props.mode === 'viewDetail'"
@form-change="handleSecondHolderChange"
/>
</div>
</div>
<!-- 7. 预约附件 Tab(复用预约页面组件) -->
<div v-else-if="activeTab === 'appointmentAttachment'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">预约附件</h3>
<!-- 复用预约页面的FileUpload组件 -->
<FileUpload
ref="appointmentAttachmentRef"
type="appointment"
:bizId="props.policyBizId"
:disabled="props.mode === 'viewDetail'"
@upload-success="handleAppointmentAttachmentUpload"
/>
</div>
</div>
<!-- 投保人 Tab 内容 -->
<div v-else-if="activeTab === 'policyholder'" class="tab-content"> </div>
<!-- 受保人 Tab 内容 -->
<div v-else-if="activeTab === 'insured'" class="tab-content"> </div>
<!-- 受益人 Tab 内容 -->
<div v-else-if="activeTab === 'beneficiary'" class="tab-content"> </div>
<!-- 第二持有人 Tab 内容 -->
<div v-else-if="activeTab === 'secondHolder'" class="tab-content"> </div>
<!-- 预约附件 Tab 内容 -->
<div v-else-if="activeTab === 'appointmentAttachment'" class="tab-content"> </div>
<!-- 介绍人 Tab 内容 -->
<!-- 8. 介绍人 Tab(你已实现的部分) -->
<div v-else-if="activeTab === 'introducer'" class="tab-content">
<!-- 签单信息 -->
<div class="section">
<h3 class="sectionTitle">介绍人信息</h3>
<h5>
......@@ -79,14 +146,21 @@
/>
</div>
</div>
<!-- 邮寄信息 Tab 内容 -->
<!-- 9. 邮寄信息 Tab(你已实现的部分) -->
<div v-else-if="activeTab === 'postal'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">邮寄信息</h3>
<SearchForm ref="postalFormRef" :config="postalFormConfig" v-model="postalFormData" />
<SearchForm
ref="postalFormRef"
:config="postalFormConfig"
v-model="postalFormData"
:disabled="props.mode === 'viewDetail'"
/>
</div>
</div>
<!-- 关联记录 Tab 内容 -->
<!-- 10. 关联记录 Tab(你已实现的部分) -->
<div v-else-if="activeTab === 'relatedRecords'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">关联记录</h3>
......@@ -110,7 +184,8 @@
</el-table>
</div>
</div>
<!-- 附件 Tab 内容 -->
<!-- 11. 新单附件 Tab(你已实现的部分) -->
<div v-else-if="activeTab === 'policyAttachment'" class="tab-content">
<div class="section">
<h3 class="sectionTitle">附件</h3>
......@@ -140,8 +215,9 @@
@click="handleClick"
:disabled="props.mode === 'viewDetail'"
>
修改 </el-button
><el-button
修改
</el-button>
<el-button
link
type="danger"
size="small"
......@@ -155,10 +231,7 @@
</el-table>
</div>
</div>
<!-- 其他 Tab 占位(你可以按需填充) -->
<div v-else class="tab-placeholder">
<el-empty description="该 Tab 内容待开发" />
</div>
<!-- 底部按钮 -->
<div class="form-footer">
<el-button size="default" @click="handleCancel">取消</el-button>
......@@ -166,6 +239,7 @@
</div>
</el-form>
<!-- 文件上传弹窗(新单附件) -->
<CommonDialog
dialogTitle="文件导入"
dialogWidth="80%"
......@@ -191,25 +265,35 @@
<script setup>
import { ref, reactive, watch, nextTick, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Upload } from '@element-plus/icons-vue'
// ========== 1. 导入你已实现的组件 ==========
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import CommonDialog from '@/components/commonDialog'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Delete, Edit, Search, Share, Upload } from '@element-plus/icons-vue'
import { getPolicyfollow, getProductList } from '@/api/sign/underwritingMain'
import EditableTable from '@/components/csf-common/EditableTable.vue'
// ========== 2. 导入预约页面的通用组件 ==========
import ProductPlan from '@/views/sign/appointment/components/productPlan.vue'
import Customer from '@/views/sign/FnaList/components/customer' // 投保人/受保人通用
import Beneficiary from '@/views/sign/appointment/components/beneficiaryInfo.vue'
import SecondHolder from '@/views/sign/appointment/components/secondHolderInfo.vue'
import FileUpload from '@/views/sign/appointment/components/fileUpload.vue' // 预约附件上传
// ========== 3. 导入API和工具函数 ==========
import { getPolicyfollow, getProductPlan, getPolicyholder,getInsurant,getBeneficiary,getSecondHolder,getAppointmentFiles,updatePolicyfollow } from '@/api/sign/underwritingMain'
import { uploadOssFileList } from '@/api/common'
import { getProcessDetail } from '@/api/sign/fna'
import { premiumReconciliationList } from '@/api/sign/policy'
import { loadDicts, getDictLabel } from '@/utils/useDict'
import { getNowTime, formatToDate, formatToDateTime } from '@/utils/date'
import EditableTable from '@/components/csf-common/EditableTable.vue'
import { formatToDate } from '@/utils/date'
import useUserStore from '@/store/modules/user'
// 引用预约界面的产品计划
import ProductPlan from '@/views/sign/appointment/components/productPlan.vue'
const productPlanRef = ref(null)
const policyProductData = ref({}) // 从 API 获取的保单产品计划数据
const isEditing = ref(false) // 控制整个页面编辑状态
// ========== 4. 核心变量定义 ==========
const { proxy } = getCurrentInstance()
const router = useRouter()
const userStore = useUserStore()
// 加载字典(复用预约页面的字典)
proxy.useDictLists([
'sys_no_yes',
'csf_ap_frequency',
......@@ -220,20 +304,25 @@ proxy.useDictLists([
'csf_ap_mailing_method',
'receipt_status'
])
const router = useRouter()
const userStore = useUserStore()
// 响应式数据
const files = ref('')
const fileUploadDialogFlag = ref(false)
// 记录每个 tab 是否有未保存的修改(dirty 状态)
const tabDirty = ref({
basic: false,
productPlan: false,
policyholder: false,
insured: false,
beneficiary: false,
secondHolder: false,
appointmentAttachment: false,
introducer: false,
postal: false,
related: false,
attachment: false
relatedRecords: false,
policyAttachment: false
})
// ===== Props & Emits =====
// ========== 5. Props & Emits ==========
const props = defineProps({
modelValue: {
type: Object,
......@@ -241,7 +330,7 @@ const props = defineProps({
},
mode: {
type: String,
default: 'viewDetail'
default: 'viewDetail' // viewDetail=查看,edit=编辑
},
policyBizId: {
type: String,
......@@ -249,10 +338,31 @@ const props = defineProps({
}
})
const emit = defineEmits(['update:modelValue', 'submit', 'cancel', 'saveRow'])
const emit = defineEmits(['update:modelValue', 'submit', 'cancel', 'saveSuccess'])
// ========== 6. 通用Tab表单数据(复用预约页面结构) ==========
// 产品计划
const productPlanRef = ref(null)
const productPlanFormData = ref({})
// 投保人
const policyholderRef = ref(null)
const policyholderFormData = ref({})
// 受保人
const insuredRef = ref(null)
const insuredFormData = ref({})
// 受益人
const beneficiaryRef = ref(null)
const beneficiaryFormData = ref({})
// 第二持有人
const secondHolderRef = ref(null)
const secondHolderFormData = ref({})
// 预约附件
const appointmentAttachmentRef = ref(null)
// ========== 7. 你已实现的变量(保留不变) ==========
// 介绍人配置
const introducerTableData = ref([])
const introducerConfig = [
const introducerConfig = ref([
{
type: 'select',
prop: 'brokerName',
......@@ -261,7 +371,7 @@ const introducerConfig = [
keywordField: 'realName',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入转介人名称搜索',
debounceWait: 500, // 自定义防抖时间
debounceWait: 500,
onChangeExtraFields: {
internalCode: 'code',
team: 'teamName',
......@@ -276,17 +386,6 @@ const introducerConfig = [
}))
}
},
// {
// type: 'select',
// prop: 'gender',
// label: '性别',
// span: 4,
// options: [
// { value: 'male', label: '男' },
// { value: 'female', label: '女' }
// ]
// },
{
type: 'input',
prop: 'phone',
......@@ -331,91 +430,13 @@ const introducerConfig = [
label: '备注',
span: 4
}
]
// 附加计划表格
const additionalPlansConfig = [
{
type: 'input',
prop: 'product',
label: '产品名称',
span: 4
},
{
type: 'input',
prop: 'frequency',
label: '付款频率',
span: 4
},
{
type: 'input',
prop: 'term',
label: '保障期限',
span: 4
},
{
type: 'input',
prop: 'phone',
label: '付款频率',
span: 4
},
{
type: 'input',
prop: 'periods',
label: '供款期数',
span: 4
},
{
type: 'input',
prop: 'currency',
label: '保单币种',
span: 4
},
{
type: 'input',
prop: 'premium',
label: '每期保费',
span: 4
},
{
type: 'input',
prop: 'fee',
label: '保单征费',
span: 4
}
]
function handleBatchSave(validRows) {
console.log('批量提交:', validRows)
// 调用 API
introducerTableData.value = validRows
}
function applyViewMode(fields, mode) {
if (mode === 'viewDetail') {
return fields.map(item => ({
...item,
disabled: true
}))
}
// 非查看模式:保留原对象,可选择性移除 disabled
return fields.map(item => {
// 如果你希望编辑模式下完全不禁用,可以删除 disabled 属性
const newItem = { ...item }
delete newItem.disabled
return newItem
})
}
])
const newOrderData = ref({})
// 基础信息(你已实现)
const basicInfoFormRef = ref()
const basicInfoFormData = ref({})
const basicInfoFormConfig = ref([
{
type: 'date',
prop: 'signDate',
label: '签单日'
},
{ type: 'date', prop: 'signDate', label: '签单日' },
{
type: 'select',
prop: 'signer',
......@@ -424,41 +445,24 @@ const basicInfoFormConfig = ref([
keywordField: 'realName',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入签单员姓名搜索',
debounceWait: 500, // 自定义防抖时间
onChangeExtraFields: {
signerBizId: 'userSignBizId',
practiceCode: 'practiceCode'
},
debounceWait: 500,
onChangeExtraFields: { signerBizId: 'userSignBizId', practiceCode: 'practiceCode' },
valueKey: 'realName',
labelKey: 'realName',
transform: res => {
return res?.data.records || []
},
transform: res => res?.data.records || [],
rules: [{ required: true, message: '请选择签单员', trigger: 'blur' }]
},
{
type: 'input',
prop: 'practiceCode',
label: '签单员执业编号'
},
{
type: 'select',
prop: 'signLocation',
label: '签单地点',
dictType: 'csf_ap_meeting_point'
}
{ type: 'input', prop: 'practiceCode', label: '签单员执业编号' },
{ type: 'select', prop: 'signLocation', label: '签单地点', dictType: 'csf_ap_meeting_point' }
])
// 保单信息
// 保单信息(你已实现)
const policyInfoFormRef = ref()
const policyInfoFormData = ref({})
const policyInfoFormConfig = ref([
{ type: 'input', prop: 'policyNo', label: '保单号' },
{
type: 'input',
prop: 'policyNo',
label: '保单号'
}, {
type: 'input',
prop: 'coolingOffDays',
label: '冷静期(天)',
inputType: 'decimal',
......@@ -467,61 +471,21 @@ const policyInfoFormConfig = ref([
{ required: true, message: '请填写冷静期', trigger: 'blur' }
]
},
{
{
type: 'date',
prop: 'coolingOffEndDate',
label: '冷静期到期日',
rules: [
{ required: true, message: '请填写冷静期到期日', trigger: 'blur' }
]
},
{
type: 'date',
prop: 'effectiveDate',
label: '保单生效日'
},
{
type: 'date',
prop: 'policyExpirationDate',
label: '保单截止日'
},
{
type: 'date',
prop: 'underwritingDate',
label: '保单核保日'
},
{
type: 'date',
prop: 'receiptDate',
label: '保单回执日'
},
{
type: 'select',
prop: 'receiptStatus',
label: '回执状态',
dictType: 'receipt_status'
},
{
type: 'select',
prop: 'directPaymentEnabled',
label: '是否开通直接支付',
dictType: 'sys_no_yes'
},
{
type: 'input',
prop: 'policyHolder',
label: '保单持有人'
},
{
type: 'input',
prop: 'insured',
label: '保单受保人'
},
{
type: 'input',
prop: 'insuredAge',
label: '受保人年龄'
},
rules: [{ required: true, message: '请填写冷静期到期日', trigger: 'blur' }]
},
{ type: 'date', prop: 'effectiveDate', label: '保单生效日' },
{ type: 'date', prop: 'policyExpirationDate', label: '保单截止日' },
{ type: 'date', prop: 'underwritingDate', label: '保单核保日' },
{ type: 'date', prop: 'receiptDate', label: '保单回执日' },
{ type: 'select', prop: 'receiptStatus', label: '回执状态', dictType: 'receipt_status' },
{ type: 'select', prop: 'directPaymentEnabled', label: '是否开通直接支付', dictType: 'sys_no_yes' },
{ type: 'input', prop: 'policyHolder', label: '保单持有人' },
{ type: 'input', prop: 'insured', label: '保单受保人' },
{ type: 'input', prop: 'insuredAge', label: '受保人年龄' },
{
type: 'input',
prop: 'gracePeriod',
......@@ -529,49 +493,23 @@ const policyInfoFormConfig = ref([
inputType: 'decimal',
rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
},
{
type: 'date',
prop: 'latestPaymentDate',
label: '最晚缴费日'
},
{ type: 'date', prop: 'latestPaymentDate', label: '最晚缴费日' },
{ type: 'select', prop: 'isJoin', label: '是否参加递增保障权益', dictType: 'sys_no_yes' },
{
type: 'select',
prop: 'isJoin',
label: '是否参加递增保障权益',
dictType: 'sys_no_yes'
},{
type: 'select',
prop: 'policyType',
label: '保单类型',
options:[
{label:'纸质保单',value:2},
{label:'电子保单',value:1},
]
},
options: [{ label: '纸质保单', value: 2 }, { label: '电子保单', value: 1 }]
}
])
// 邮寄信息
// 邮寄信息(你已实现)
const postalFormRef = ref(null)
const postalFormData = ref({})
const postalFormConfig = ref([
{
type: 'select',
prop: 'mailingMethod',
label: '寄送方式',
dictType: 'csf_mailing_method'
},
{
type: 'input',
prop: 'deliveryNo',
label: '快递单号',
visible: formData => formData.mailingMethod == '2'
},{
type: 'input',
prop: 'mailingItem',
label: '邮寄物品',
visible: formData => formData.mailingMethod == '2'
},
{ type: 'select', prop: 'mailingMethod', label: '寄送方式', dictType: 'csf_mailing_method' },
{ type: 'input', prop: 'deliveryNo', label: '快递单号', visible: formData => formData.mailingMethod == '2' },
{ type: 'input', prop: 'mailingItem', label: '邮寄物品', visible: formData => formData.mailingMethod == '2' },
{
type: 'date',
prop: 'brokerSignDate',
......@@ -586,101 +524,73 @@ const postalFormConfig = ref([
}
])
// 关联记录
// 关联记录 & 新单附件(你已实现)
const relatedTableData = ref([])
const attachmentTableData = ref([])
const attachmentTableColumns = ref([
{
prop: 'originalName',
label: '文件名',
sortable: true,
width: '150',
formatter: row => row.originalName || '-'
},
{
prop: 'fileType',
label: '文件类型',
sortable: true,
width: '150',
formatter: row => row.fileType || '-'
},
{
prop: 'createTime',
label: '上传时间',
sortable: true,
width: '150',
formatter: row => row.createTime || '-'
},
{
prop: 'creatorName',
label: '上传人',
sortable: true,
width: '150',
formatter: row => row.creatorName || '-'
}
{ prop: 'originalName', label: '文件名', sortable: true, width: '150', formatter: row => row.originalName || '-' },
{ prop: 'fileType', label: '文件类型', sortable: true, width: '150', formatter: row => row.fileType || '-' },
{ prop: 'createTime', label: '上传时间', sortable: true, width: '150', formatter: row => row.createTime || '-' },
{ prop: 'creatorName', label: '上传人', sortable: true, width: '150', formatter: row => row.creatorName || '-' }
])
// ===== 本地响应式数据 =====
// 本地表单数据
const defaultFormData = () => ({})
// ✅ 使用 ref 而不是 reactive
const localData = ref(defaultFormData())
// ✅ 只在挂载时初始化一次(避免 watch 形成闭环)
onMounted(async () => {
if (props.modelValue) {
console.log('🚀 父组件 props.modelValue 挂载时:', props.modelValue)
// 深拷贝 + 合并默认值,防止缺失字段
localData.value = { ...defaultFormData(), ...props.modelValue }
}
try {
getPolicyfollowDetail()
} catch (error) {
console.error('字典加载失败', error)
} finally {
}
// 应用查看模式到基本信息表格
basicInfoFormConfig.value = basicInfoFormConfig
? applyViewMode(basicInfoFormConfig.value, props.mode)
: []
policyInfoFormConfig.value = policyInfoFormConfig
? applyViewMode(policyInfoFormConfig.value, props.mode)
: []
})
// 监听基本信息(basic)
watch(
[basicInfoFormData, policyInfoFormData],
() => {
tabDirty.value.basic = true
},
{ deep: true }
)
// 监听邮寄信息
watch(
postalFormData,
() => {
tabDirty.value.postal = true
},
{ deep: true }
)
// ✅ 监听 localData 变化,emit 出去(用于 v-model)
watch(
() => localData.value,
newVal => {
console.log('========父组件监测的localData:', newVal)
emit('update:modelValue', newVal)
},
{ deep: true }
)
// ===== 表单引用 & 验证规则 =====
const formRef = ref()
const activeTab = ref('basic')
// ========================
// ✅ 新增:切换前确认
// ========================
// ========== 8. 通用Tab事件处理(复用预约页面逻辑) ==========
// 产品计划数据变更
const handleProductPlanChange = (data) => {
productPlanFormData.value = data
tabDirty.value.productPlan = true
}
// 产品计划保存
const handleProductPlanSave = async () => {
if (productPlanRef.value) {
const validData = await productPlanRef.value.validate()
if (validData) {
tabDirty.value.productPlan = false
ElMessage.success('产品计划保存成功')
}
}
}
// 投保人数据变更
const handlePolicyholderChange = (data) => {
policyholderFormData.value = data
tabDirty.value.policyholder = true
}
// 受保人数据变更
const handleInsuredChange = (data) => {
insuredFormData.value = data
tabDirty.value.insured = true
}
// 受益人数据变更
const handleBeneficiaryChange = (data) => {
beneficiaryFormData.value = data
tabDirty.value.beneficiary = true
}
// 第二持有人数据变更
const handleSecondHolderChange = (data) => {
secondHolderFormData.value = data
tabDirty.value.secondHolder = true
}
// 预约附件上传成功
const handleAppointmentAttachmentUpload = () => {
tabDirty.value.appointmentAttachment = true
ElMessage.success('预约附件上传成功')
}
// ========== 9. 原有方法(保留+适配通用Tab) ==========
// Tab切换前确认
const handleBeforeLeave = async (newTabName, oldTabName) => {
console.log('切换前确认-----------------------', newTabName, oldTabName)
if (tabDirty.value[oldTabName]) {
try {
await ElMessageBox.confirm(`“${getTabLabel(oldTabName)}” 未提交,确定要切换吗?`, '提示', {
......@@ -688,14 +598,16 @@ const handleBeforeLeave = async (newTabName, oldTabName) => {
cancelButtonText: '取消',
type: 'warning'
})
return true // 允许切换
return true
} catch {
return false // 阻止切换
return false
}
}
return true // 无未保存内容,允许切换
return true
}
const getTabLabel = name => {
// 获取Tab标签名
const getTabLabel = (name) => {
const labels = {
basic: '基础信息',
productPlan: '产品计划',
......@@ -711,195 +623,254 @@ const getTabLabel = name => {
}
return labels[name] || name
}
const handleTabClick = tab => {
if (tab.props.name === 'postal') {
postalFormConfig.value = postalFormConfig
? applyViewMode(postalFormConfig.value, props.mode)
: []
} else if (tab.props.name === 'relatedRecords') {
getRelationRecord(newOrderData.value.fnaBizId)
} else if (tab.props.name === 'policyAttachment') {
getAttachmentListDetail(newOrderData.value.policyBizId)
} else if (tab.props.name === 'introducer') {
// introducerConfig.value = introducerConfig ? applyViewMode(introducerConfig.value, props.mode) : []
} else if (tab.props.name === 'basic') {
basicInfoFormConfig.value = basicInfoFormConfig
? applyViewMode(basicInfoFormConfig.value, props.mode)
: []
// Tab点击事件(适配通用Tab)
const handleTabClick = (tab) => {
const tabName = tab.props.name
// 通用Tab加载逻辑
if (tabName === 'productPlan') {
loadProductPlanData() // 加载产品计划数据
} else if (tabName === 'policyholder') {
loadPolicyholderData() // 加载投保人数据
} else if (tabName === 'insured') {
loadInsuredData() // 加载受保人数据
} else if (tabName === 'beneficiary') {
loadBeneficiaryData() // 加载受益人数据
} else if (tabName === 'secondHolder') {
loadSecondHolderData() // 加载第二持有人数据
} else if (tabName === 'appointmentAttachment') {
loadAppointmentAttachmentData() // 加载预约附件数据
}
// 你已实现的Tab逻辑
else if (tabName === 'postal') {
postalFormConfig.value = postalFormConfig.value.map(item => ({
...item,
disabled: props.mode === 'viewDetail'
}))
} else if (tabName === 'relatedRecords') {
getRelationRecord(localData.value.fnaBizId || props.modelValue.fnaBizId)
} else if (tabName === 'policyAttachment') {
getAttachmentListDetail(props.policyBizId)
} else if (tabName === 'basic') {
// 基础信息逻辑
}
}
// ========== 10. 通用Tab数据加载(复用预约页面API) ==========
// 加载产品计划数据
const loadProductPlanData = () => {
if (!props.policyBizId) return
getProductPlan({ policyBizId: props.policyBizId }).then(res => {
if (res.code === 200) {
productPlanFormData.value = res.data || {}
}
})
}
// 加载投保人数据
const loadPolicyholderData = () => {
if (!props.policyBizId) return
// 复用预约页面的投保人查询API
getPolicyholder(props.policyBizId).then(res => {
if (res.code === 200) {
policyholderFormData.value = res.data || {}
}
})
}
// 加载受保人数据
const loadInsuredData = () => {
if (!props.policyBizId) return
// 复用预约页面的受保人查询API
getInsurant(props.policyBizId).then(res => {
if (res.code === 200) {
insuredFormData.value = res.data || {}
}
})
}
// 加载受益人数据
const loadBeneficiaryData = () => {
if (!props.policyBizId) return
// 复用预约页面的受益人查询API
getBeneficiary(props.policyBizId).then(res => {
if (res.code === 200) {
beneficiaryFormData.value = res.data || {}
}
})
}
// 加载第二持有人数据
const loadSecondHolderData = () => {
if (!props.policyBizId) return
// 复用预约页面的第二持有人查询API
getSecondHolder(props.policyBizId).then(res => {
if (res.code === 200) {
secondHolderFormData.value = res.data || {}
}
})
}
// 加载预约附件数据
const loadAppointmentAttachmentData = () => {
if (!props.policyBizId) return
// 复用预约页面的附件查询API
getAppointmentFiles({ policyBizId: props.policyBizId }).then(res => {
if (res.code === 200) {
appointmentAttachmentRef.value?.setFileList(res.data || [])
}
})
}
// ========== 11. 原有方法(保留不变) ==========
const handleBatchSave = (validRows) => {
console.log('批量提交:', validRows)
introducerTableData.value = validRows
tabDirty.value.introducer = true
}
const handleSubmit = () => {
formRef.value?.validate((valid) => {
if (valid) {
console.log('提交数据', introducerTableData.value)
if (activeTab.value === 'postal') {
emit('submit', { ...postalFormData.value, activeTab: activeTab.value })
tabDirty.value.postal = false
} else if (activeTab.value === 'policyAttachment') {
emit('submit', { activeTab: activeTab.value })
tabDirty.value.attachment = false
} else if (activeTab.value === 'introducer') {
emit('submit', { ...introducerTableData.value, activeTab: activeTab.value })
tabDirty.value.introducer = false
} else if (activeTab.value === 'basic') {
emit('submit', { ...basicInfoFormData.value, activeTab: activeTab.value, ...policyInfoFormData.value })
tabDirty.value.basic = false
} else if (activeTab.value === 'productPlan') {
emit('submit', { ...basicInfoFormData.value, activeTab: activeTab.value, ...policyInfoFormData.value })
tabDirty.value.basic = false
}
formRef.value?.validate(async (valid) => {
if (!valid) return
// 收集所有数据(通用Tab + 自定义Tab)
const submitData = {
policyBizId: props.policyBizId,
// 自定义Tab数据
...basicInfoFormData.value,
...policyInfoFormData.value,
...postalFormData.value,
brokerList: introducerTableData.value,
// 通用Tab数据
...productPlanFormData.value,
policyholder: policyholderFormData.value,
insured: insuredFormData.value,
beneficiary: beneficiaryFormData.value,
secondHolder: secondHolderFormData.value
}
}
})
try {
// 调用新单跟进保存接口
const res = await updatePolicyfollow(submitData)
if (res.code === 200) {
ElMessage.success('保存成功')
emit('saveSuccess', res.data)
// 重置dirty状态
Object.keys(tabDirty.value).forEach(key => tabDirty.value[key] = false)
}
} catch (error) {
ElMessage.error(`保存失败:${error.message || '服务器错误'}`)
}
})
}
const handleCancel = () => {
emit('cancel')
}
const handleClick = tab => {
activeTab.value = tab.name
const handleClick = () => {
ElMessage.info('附件操作功能待完善')
}
// 如果外部 modelValue 更新(比如重新加载数据),同步到 localData
watch(
() => props.modelValue,
newVal => {
if (newVal) {
Object.assign(localData, defaultFormData(), newVal)
}
},
{ deep: true }
)
// 查询新单跟进详情
const getPolicyfollowDetail = () => {
if (!props.policyBizId) {
return
}
if (!props.policyBizId) return
getPolicyfollow(props.policyBizId).then(res => {
if (res.code === 200) {
newOrderData.value = res.data
policyInfoFormData.value = { ...transformToFormData(res.data, policyInfoFormConfig.value) }
basicInfoFormData.value = { ...transformToFormData(res.data, basicInfoFormConfig.value) }
introducerTableData.value = res.data.brokerList || []
const data = res.data
localData.value = { ...localData.value, ...data }
basicInfoFormData.value = { ...transformToFormData(data, basicInfoFormConfig.value) }
policyInfoFormData.value = { ...transformToFormData(data, policyInfoFormConfig.value) }
postalFormData.value = { ...transformToFormData(data, postalFormConfig.value) }
introducerTableData.value = data.brokerList || []
}
})
}
// 查询产品计划详情
const loadPolicyDetail = async () => {
policyProductData.value = {
policyBizId: 'POL_123',
productPlan: {
apiProductPlanMainInfoDto: { },
apiProductPlanAdditionalInfoDtoList: [ ]
},
}
// const res = await getPolicyFollowDetail(policyBizId)
// policyProductData.value = res.data.productPlan || {}
}
// 查询附件列表
const getAttachmentListDetail = policyBizId => {
if (!policyBizId) {
return
}
const params = {
objectBizId: policyBizId,
pageNo: 1,
pageSize: 100
}
const getAttachmentListDetail = (policyBizId) => {
if (!policyBizId) return
const params = { objectBizId: policyBizId, pageNo: 1, pageSize: 100 }
uploadOssFileList(params).then(res => {
if (res.code === 200) {
attachmentTableData.value = res.data || []
console.log('attachmentTableData', res.data)
}
})
}
// 附件上传方法
const handleUploadEnd = code => {
const handleUploadEnd = (code) => {
if (code === 200) {
ElMessage.success('上传文件成功')
fileUploadDialogFlag.value = false
files.value = ''
getAttachmentListDetail(props.policyBizId)
tabDirty.value.policyAttachment = true
} else {
ElMessage.error('上传文件失败')
}
}
// 组装表单数据
const transformToFormData = (apiData, formConfig) => {
const formData = {}
formConfig.forEach(item => {
const { prop, dictType } = item
let value = null
// 特殊映射(按需添加)
switch (prop) {
case 'signLocation':
value = apiData.signLocation
break
default:
value = apiData[prop]
}
// 处理字典字段:如果配置了 dictType,且值是 number,转为 string
let value = apiData[prop] ?? null
if (dictType && typeof value === 'number') {
value = String(value)
}
formData[prop] = value ?? null
formData[prop] = value
})
return formData
}
// 获取关联流程记录
const getRelationRecord = fnaBizId => {
const getRelationRecord = (fnaBizId) => {
getProcessDetail(fnaBizId).then(res => {
if (res.code === 200) {
relatedTableData.value = [res.data] || []
console.log('relationRecordData', res.data)
}
})
}
const viewRecordDetail = e => {
const viewRecordDetail = (e) => {
router.push({
path: '/sign/FnaList/edit',
query: {
fnaBizId: newOrderData.value.fnaBizId,
fnaBizId: localData.value.fnaBizId,
type: 'edit',
status: newOrderData.value.status,
status: localData.value.status,
source: 'newOrder',
appointmentBizId: newOrderData.value.appointmentBizId
appointmentBizId: localData.value.appointmentBizId
}
})
}
const handleSelectChange = async (prop, value, item, type) => {
await nextTick()
// console.log('======子组件选择选项后,父组件接收的值 :', basicPlanFormData.value)
}
// ========== 12. 初始化 ==========
onMounted(async () => {
if (props.modelValue) {
localData.value = { ...defaultFormData(), ...props.modelValue }
}
// 加载新单跟进基础数据
getPolicyfollowDetail()
// 初始化通用Tab禁用状态
if (props.mode === 'viewDetail') {
// 通用Tab组件禁用
productPlanFormData.value.disabled = true
policyholderFormData.value.disabled = true
insuredFormData.value.disabled = true
beneficiaryFormData.value.disabled = true
secondHolderFormData.value.disabled = true
}
})
// 获取产品列表
const getProductLists = params => {
getProductList(params).then(res => {
if (res.code === 200) {
console.log('productList', res.data.records || [])
// productList.value = res.data.records || []
}
})
}
// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
if (newVal) {
Object.assign(localData, defaultFormData(), newVal)
}
}, { deep: true })
defineExpose({
getPolicyfollowDetail
})
// 监听localData变化,同步到父组件
watch(() => localData.value, (newVal) => {
emit('update:modelValue', newVal)
}, { deep: true })
</script>
<style scoped>
......@@ -949,4 +920,4 @@ defineExpose({
padding: 15px 10px;
border-radius: 4px;
}
</style>
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment