Commit f4cb66d2 by Sweet Zhang

Merge branch 'test' of http://139.224.139.2:9091/yuzhenWang/yd-csf-front into test

parents a8bfbe34 bfe1b96c
...@@ -63,3 +63,19 @@ export function getMoreDicts(data) { ...@@ -63,3 +63,19 @@ export function getMoreDicts(data) {
data: data data: data
}) })
} }
// 查询保险产品列表
export function getInsuranceProductList(data) {
return request({
url: '/insurance/base/api/insuranceProduct/page',
method: 'post',
data: data
})
}
// 查询保险附加产品列表
export function getAdditionalProductList(data) {
return request({
url: '/insurance/base/api/insuranceAdditionalProduct/page',
method: 'post',
data: data
})
}
import request from '@/utils/request'
// 查询预约列表
export function getAppointmentList(data) {
return request({
url: '/csf/api/appointment/page',
method: 'post',
data: data
})
}
// 导出预约信息
export function getAppointmentExprot(appointmentBizId) {
return request({
url: `/csf/api/appointmentFile/excel/export/appointment?appointmentBizId=${appointmentBizId}`,
method: 'get'
})
}
// 导出行程单信息
export function getItineraryExprot(appointmentBizId) {
return request({
url: `/csf/api/appointmentFile/pdf/itinerary?appointmentBizId=${appointmentBizId}`,
method: 'get'
})
}
// 新增预约
export function addAppointment(data) {
return request({
url: '/csf/api/appointment/add',
method: 'post',
data: data
})
}
// 编辑预约
export function editAppointmentDetail(data) {
return request({
url: '/csf/api/appointment/edit',
method: 'put',
data: data
})
}
// 暂存预约
export function storageAppointment(data) {
return request({
url: '/csf/api/appointment/add/storage',
method: 'post',
data: data
})
}
// 获取预约详情
export function getAppointmentDetail(appointmentBizId) {
return request({
url: `/csf/api/appointment/detail?appointmentBizId=${appointmentBizId}`,
method: 'get'
})
}
// 获取预约健康信息数据
export function getQuestionnaires(appointmentBizId) {
return request({
url: `/question/api/questionnaires/detail?questionnaireBizId=questionnaires_1001&objectBizId=${appointmentBizId}`,
method: 'get'
})
}
// 预约-提交预约信息模块
export function editAppointmentInfo(data) {
return request({
url: '/csf/api/appointment/single/edit',
method: 'put',
data: data
})
}
// 预约-生成新单
export function newPolicy(data) {
return request({
url: '/csf/api/appointment/edit/confirm/time',
method: 'put',
data: data
})
}
// 预约-提交产品计划模块
export function editProductPlanInfo(data) {
return request({
url: '/csf/api/productPlan/edit/plan',
method: 'put',
data: data
})
}
// 删除附加险
export function delAdditional(additionalBizId) {
return request({
url: '/csf/api/additional/del?additionalBizId=' + additionalBizId,
method: 'delete'
})
}
// 预约-提交投保人模块
export function editPolicyholderInfo(data) {
return request({
url: '/csf/api/policyholder/edit',
method: 'put',
data: data
})
}
// 预约-提交受保人模块
export function editInsurantInfo(data) {
return request({
url: '/csf/api/insurant/edit',
method: 'put',
data: data
})
}
// 预约-提交第二持有人模块
export function editSecondHolderInfo(data) {
return request({
url: '/csf/api/secondHolder/edit',
method: 'put',
data: data
})
}
// 预约-提交受益人模块
export function editBeneficiaryInfo(data) {
return request({
url: '/csf/api/beneficiary/batch/edit',
method: 'put',
data: data
})
}
// 删除单个受益人
export function delBeneficiary(beneficiaryBizId) {
return request({
url: '/csf/api/beneficiary/del?beneficiaryBizId=' + beneficiaryBizId,
method: 'delete'
})
}
// 预约-编辑关联FNA
export function editFna(data) {
return request({
url: '/csf/api/appointment/edit/fna',
method: 'put',
data: data
})
}
// 预约-解除关联FNA
export function unlinkFna(data) {
return request({
url: '/csf/api/appointment/remove/fna',
method: 'put',
data: data
})
}
// 预约-编辑转保声明
export function editPolicytransfer(data) {
return request({
url: '/csf/api/appointment/edit/policy/transfer',
method: 'put',
data: data
})
}
// 新增附件
export function addFile(data) {
return request({
url: '/csf/api/appointmentFile/add',
method: 'post',
data: data
})
}
// 附件列表
export function getAppointmentFile(data) {
return request({
url: '/csf/api/appointmentFile/page',
method: 'post',
data: data
})
}
// 删除单个附件
export function delFile(appointmentFileBizId) {
return request({
url: '/csf/api/appointmentFile/del?appointmentFileBizId=' + appointmentFileBizId,
method: 'delete'
})
}
// 删除单个预约
export function delSigleAppointment(appointmentBizId) {
return request({
url: '/csf/api/appointment/del?appointmentBizId=' + appointmentBizId,
method: 'delete'
})
}
...@@ -42,6 +42,14 @@ export function updateProcess(data) { ...@@ -42,6 +42,14 @@ export function updateProcess(data) {
data: data data: data
}) })
} }
// 生成副本
export function subProcess(data) {
return request({
url: '/csf/api/Fna/copy',
method: 'post',
data: data
})
}
/* /*
流程接口结束 流程接口结束
*/ */
......
<template>
<div class="detail-panel">
<div v-for="(row, rowIndex) in processedData" :key="rowIndex" class="detail-row">
<div
v-for="(item, colIndex) in row"
:key="colIndex"
class="detail-col"
:class="getColClass(item)"
:style="{ width: getColWidth(item.span) }"
>
<!-- 每个列都有独立的边框 -->
<div class="col-container">
<!-- 左侧 Label -->
<div class="detail-label">
<el-tooltip
:content="item.label"
placement="top"
:disabled="!isTextOverflow(item.label, 'label', `${rowIndex}-${colIndex}`)"
>
<span class="label-text">{{ item.label }}</span>
</el-tooltip>
</div>
<!-- 右侧 Value -->
<div class="detail-value">
<el-tooltip
:content="item.value"
placement="top"
:disabled="!isTextOverflow(item.value, 'value', `${rowIndex}-${colIndex}`)"
>
<span class="value-text">{{ item.value || '-' }}</span>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, nextTick, watch } from 'vue'
const props = defineProps({
// 详情数据,支持两种格式:
// 1. 一维数组: [{ label: '标签', value: '值', span: 8 }, ...]
// 2. 二维数组: [[{ label: '标签1', value: '值1', span: 12 }, { label: '标签2', value: '值2', span: 12 }], ...]
data: {
type: [Array, Object],
default: () => []
},
// 每行总span数(类似Element Plus的24分栏)
rowSpan: {
type: Number,
default: 24
},
// 标签宽度,默认120px
labelWidth: {
type: String,
default: '120px'
},
// 行高
rowHeight: {
type: String,
default: '40px'
},
// 列间距
colGap: {
type: String,
default: '16px'
},
// 是否显示列边框
showColBorder: {
type: Boolean,
default: true
}
})
// 处理数据,确保是二维数组格式
const processedData = computed(() => {
if (!props.data || props.data.length === 0) return []
// 如果已经是二维数组,直接返回
if (Array.isArray(props.data[0]) && Array.isArray(props.data[0])) {
return props.data
}
// 一维数组转换为二维数组
const result = []
let currentRow = []
let currentSpan = 0
props.data.forEach(item => {
const span = item.span || Math.floor(props.rowSpan / 2) // 默认占一半
if (currentSpan + span > props.rowSpan) {
// 当前行已满,创建新行
result.push([...currentRow])
currentRow = [item]
currentSpan = span
} else {
// 添加到当前行
currentRow.push(item)
currentSpan += span
}
})
// 添加最后一行
if (currentRow.length > 0) {
result.push(currentRow)
}
return result
})
// 存储文本溢出状态
const overflowState = ref({})
// 检查文本是否溢出
const isTextOverflow = (text, type, key) => {
if (!text) return false
return overflowState.value[`${type}-${key}`] || false
}
// 获取列的宽度
const getColWidth = span => {
const percentage = (span / props.rowSpan) * 100
return `calc(${percentage}% - ${props.colGap})`
}
// 获取列的class
const getColClass = item => {
const classes = []
if (item.align) {
classes.push(`align-${item.align}`)
}
return classes
}
// 检测文本溢出
const checkTextOverflow = () => {
nextTick(() => {
const labelElements = document.querySelectorAll('.label-text')
const valueElements = document.querySelectorAll('.value-text')
// 重置溢出状态
overflowState.value = {}
// 检测label溢出
labelElements.forEach((el, index) => {
const parentCol = el.closest('.detail-col')
if (parentCol) {
const rowIndex = Array.from(parentCol.parentNode.children).indexOf(parentCol)
const colIndex = Array.from(parentCol.parentNode.parentNode.children).indexOf(
parentCol.parentNode
)
const key = `${colIndex}-${rowIndex}`
overflowState.value[`label-${key}`] = el.scrollWidth > el.clientWidth
}
})
// 检测value溢出
valueElements.forEach((el, index) => {
const parentCol = el.closest('.detail-col')
if (parentCol) {
const rowIndex = Array.from(parentCol.parentNode.children).indexOf(parentCol)
const colIndex = Array.from(parentCol.parentNode.parentNode.children).indexOf(
parentCol.parentNode
)
const key = `${colIndex}-${rowIndex}`
overflowState.value[`value-${key}`] = el.scrollWidth > el.clientWidth
}
})
})
}
onMounted(() => {
checkTextOverflow()
})
// 监听数据变化
watch(
() => props.data,
() => {
nextTick(() => {
checkTextOverflow()
})
},
{ deep: true }
)
</script>
<style lang="scss" scoped>
.detail-panel {
/* border: 1px solid #dcdfe6; */
border-radius: 4px;
background-color: #fff;
}
.detail-row {
display: flex;
flex-wrap: wrap;
min-height: v-bind(rowHeight);
/* border-bottom: 1px solid #ebeef5; */
gap: v-bind(colGap);
padding: 0 calc(v-bind(colGap) / 2);
&:last-child {
border-bottom: none;
}
}
.detail-col {
display: flex;
min-height: v-bind(rowHeight);
// 对齐方式
&.align-center {
.detail-label,
.detail-value {
justify-content: center;
text-align: center;
}
}
&.align-right {
.detail-label,
.detail-value {
justify-content: flex-end;
text-align: right;
}
}
}
// 每个列的容器,添加独立边框
.col-container {
display: flex;
width: 100%;
/* border: v-bind(showColBorder ? '1px solid #ebeef5' : 'none'); */
border: 1px solid #ebeef5;
border-radius: 4px;
overflow: hidden;
background-color: #fff;
margin-bottom: 15px;
// 鼠标悬停效果
/* .detail-row:hover & {
background-color: #f5f7fa;
.detail-label {
background-color: #e6f3ff;
}
} */
}
.detail-label {
width: v-bind(labelWidth);
min-width: v-bind(labelWidth);
padding: 8px 12px;
/* background-color: #f5f7fa; */
border-right: 1px solid #ebeef5;
display: flex;
align-items: center;
font-weight: 500;
color: #606266;
.label-text {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
font-size: 14px;
}
}
.detail-value {
flex: 1;
padding: 8px 12px;
display: flex;
align-items: center;
.value-text {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
color: #303133;
font-size: 14px;
}
}
// 响应式处理
@media (max-width: 768px) {
.detail-col {
width: 100% !important;
}
.col-container {
border: 1px solid #ebeef5;
margin-bottom: 8px;
}
}
</style>
// key: 'person',代表个人,key: 'company',代表公司
const applicant = [
// 客户信息 此模块始终展示
{
fatherTitle: '客户信息',
type: 'object',
key: 'customer',
showMoudle: true, //模块是否展示
data: [
{
label: '客户类型',
key: 'customerType',
customerKey: 'customerType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_customer_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '客户编号',
key: 'customerNo',
customerKey: 'customCode',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 200,
disabled: true,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 基础信息
{
fatherTitle: '基础信息',
type: 'object',
key: 'person',
labelPosition: 'top', //标签的位置
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '名字-英文',
key: 'nameEn',
customerKey: 'firstNamePinyin',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '名字',
key: 'name',
customerKey: 'name',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '性别',
key: 'gender',
customerKey: 'gender',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'sys_gender',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件类型',
key: 'documentType',
customerKey: 'idType',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_id_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件号码',
key: 'idNumber',
customerKey: 'idCard',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生日期',
key: 'birthday',
customerKey: 'birthdate',
domType: 'DatePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '年龄',
key: 'age',
customerKey: 'age',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '居住地址',
key: 'residenceAddress',
customerKey: 'residenceAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
residenceAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '通讯地址',
commonKey: true, //是否是公共字段
key: 'txAddress',
// customerKey: 'mailingAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
txAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '移动电话',
key: 'mobile',
customerKey: 'phone',
customerCode: 'areaCode',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
mobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'mobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '邮箱',
key: 'email',
customerKey: 'email',
domType: 'Input',
inputType: 'text',
maxLength: 30,
required: false,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司名称',
key: 'companyName',
customerKey: 'companyName',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司地址',
key: 'companyAddress',
customerKey: 'companyAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
companyAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '行业',
key: 'industry',
customerKey: 'companyType',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '职位',
key: 'position',
customerKey: 'position',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '风险偏好',
key: 'riskAppetite',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_risk',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: 'VIP',
key: 'isVip',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '备注',
key: 'vipRemark',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: false,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
},
// 个人信息
{
fatherTitle: '个人信息',
type: 'object',
key: 'person',
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '称谓',
key: 'appellation',
customerKey: 'title',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_customer_title',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否吸烟',
key: 'smokingAllowed',
customerKey: 'smoke',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '吸烟量(支/天)',
key: 'smokingVolume',
customerKey: 'smokeQuantity',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: false,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生地(省市)',
key: 'birthplace',
customerKey: 'birthplace',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '国籍',
key: 'nationality',
customerKey: 'countryName',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'country',
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '身高',
key: 'height',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入身高(cm)',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '体重',
key: 'weight',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入身高(kg)',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: 'BMI',
key: 'bmi',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '平均每月收入',
key: 'monthIncome',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月收入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '平均每月支出',
key: 'monthExpenditure',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月支出',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '受雇于现职年期',
key: 'currentTenure',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '总流动资产',
key: 'totalCurrentAssets',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月支出',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '总负债额',
key: 'totalDebt',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '受供养人数目',
key: 'dependentsNum',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '婚姻状况',
key: 'maritalStatus',
customerKey: 'marriage',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_marriage',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '教育程度',
key: 'educationLevel',
customerKey: 'education',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_education',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '现时每月收入',
key: 'currentMonthlyIncome',
customerKey: 'salary',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '总工作年期',
key: 'totalWorkingYears',
customerKey: 'workYear',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月支出',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司电话',
key: 'companyMobile',
commonKey: true,
customerKey: 'companyTelephone',
customerCode: 'companyAreaCode',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
companyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'companyMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '固定电话',
key: 'landline',
customerKey: 'fixedPhone',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '其他电话',
commonKey: true, //是否是公共字段
key: 'otherMobile',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '过往一年是否所属国家以外地区居住超过182日',
key: 'isExceed',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否拥有其他国家公民身份(如美国、日本等)',
key: 'isOtherCountry',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否接受推广信息',
commonKey: true, //是否是公共字段
key: 'isPromotion',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '投保人邮政编码',
key: 'postalCode',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月支出',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
//其他信息
{
fatherTitle: '其他信息',
type: 'object',
key: 'person',
showMoudle: true, //模块是否展示
data: [
{
label: '旅行',
key: 'travel',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '运动',
key: 'exercise',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_exercise',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '游戏',
key: 'game',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_game',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '电影/戏剧',
key: 'movieDrama',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_movie',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '美食',
key: 'delicacy',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 公司信息
{
fatherTitle: '公司信息',
type: 'object',
key: 'company',
labelPosition: 'top', //标签的位置
showMoudle: false, //模块是否展示
data: [
{
label: '公司名称',
key: 'companyName',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
commonKey: true, //是否是公共字段
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司名称(英文)',
key: 'companyNameEn',
customerKey: 'companyNameEn',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司商业登记号码',
key: 'companyBusinessNo',
customerKey: 'companyBusinessNo',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册日期',
key: 'companyRegisterTime',
customerKey: '',
domType: 'DatePicker',
required: true,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司电话',
commonKey: true, //是否是公共字段
key: 'companyMobile',
customerKey: '',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
companyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'companyMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册地区',
key: 'companyRegisterRegion',
customerKey: '',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_registration',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司邮箱',
key: 'companyEmail',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司登记地址',
key: 'companyEnterAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
companyEnterAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '通讯地址',
commonKey: true, //是否是公共字段
key: 'txAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
txAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名中文-名字',
key: 'authNameCn',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名英文-名字',
key: 'authNameEn',
customerKey: '',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表职称',
key: 'authProfessional',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表电话',
key: 'authMobile',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
authMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'authMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '其他电话',
commonKey: true, //是否是公共字段
key: 'otherMobile',
customerKey: '',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否接受推广信息',
commonKey: true, //是否是公共字段
key: 'isPromotion',
customerKey: '',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
}
]
export default applicant
const appointmentInfo = [
// 申请
{
fatherTitle: '',
type: 'object',
key: 'personInfo',
showMoudle: true, //模块是否展示
data: [
{
label: '申请类型',
key: 'applyType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_apply_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '预约时间',
key: 'confirmAppointmentTime',
domType: 'datetimePicker',
required: true,
disabled: true,
placeholder: '请选择',
show: false,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: ' ',
key: 'newPolicyButton',
domType: 'button',
buttonTxt: '生成新单跟进记录',
buttonType: 'primary',
required: false,
maxLength: 10,
disabled: false,
show: false,
// labelPosition: 'top', //标签的位置
labelWidth: '0px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 业务信息
{
fatherTitle: '业务信息',
type: 'object',
key: 'business',
labelPosition: 'top', //标签的位置
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '业务编号',
key: 'businessNo',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '业务代表账号',
key: 'businessRepresentAccount1',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '业务代表姓名',
key: 'businessRepresentName1',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '业务代表电话号码',
key: 'businessRepresentMobile1',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
businessRepresentMobile1: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'businessRepresentMobile1Code',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '业务代表邮箱',
key: 'businessRepresentEmail1',
domType: 'Input',
inputType: 'text',
maxLength: 30,
required: false,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 基础信息
{
fatherTitle: '基础信息',
type: 'object',
key: 'basic',
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '意向预约时间',
key: 'intentionAppointmentTime',
domType: 'datetimePicker',
required: true,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '顾问是否陪同',
key: 'isAccompany',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否有用车需求',
key: 'isUseCar',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 陪同顾问信息
{
fatherTitle: '陪同顾问信息',
type: 'object',
key: 'consult',
showMoudle: false, //模块是否展示
data: [
{
label: '姓名',
key: 'accompanyName',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '手机',
key: 'accompanyMobile',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
labelPosition: 'top', //标签的位置
drawerType: 'phone',
accompanyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'accompanyMobileCode',
maxLength: 20,
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '邮箱',
key: 'accompanyEmail',
domType: 'Input',
inputType: 'text',
maxLength: 30,
required: false,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 到港信息
{
fatherTitle: '到港信息',
type: 'object',
key: 'position',
showMoudle: true, //模块是否展示
data: [
{
label: '到港时间',
key: 'arrivalTime',
domType: 'datetimePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '离港时间',
key: 'departureTime',
domType: 'datetimePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '会面地点',
key: 'meetingPoint',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_meeting_point',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '签单地址',
key: 'signingAddress',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '客户在港期间联络电话',
key: 'hkMobile',
domType: 'arrowRight', //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
required: false,
disabled: false,
placeholder: '请填写',
show: true,
labelPosition: 'top', //标签的位置
drawerType: 'phone',
hkMobile: {},
code: 'hkMobileCode',
maxLength: 20,
labelWidth: '200px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 其他情况
{
fatherTitle: '其他情况',
type: 'object',
key: 'other',
showMoudle: true, //模块是否展示
data: [
{
label: '是否开户',
key: 'isOpenAccount',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 开户信息
{
fatherTitle: '开户信息',
type: 'object',
key: 'openAccount',
showMoudle: false, //模块是否展示
data: [
{
label: '开户行名称',
key: 'bankName',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '开户行支行',
key: 'bankBranchName',
domType: 'Input',
inputType: 'text',
maxLength: 300,
required: false,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '开户时间段(开始)',
key: 'openAccountStartTime',
domType: 'datetimePicker',
required: false,
disabled: true,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '开户时间段(结束)',
key: 'openAccountEndTime',
domType: 'datetimePicker',
required: false,
disabled: true,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '开户地点',
key: 'openAccountLocation',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否购买过香港保险',
key: 'isBuy',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否体检',
key: 'isTj',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 10, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '开户须知',
key: 'openAccountNotice',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
},
{
label: '',
title: '所需资料',
key: 'information',
domType: 'Div',
required: false,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
informationList: [
{ name: '1、身份证' },
{ name: '2、港澳通行证/护照' },
{ name: '3、出生证明(18岁以下受保人)' },
{ name: '4、结婚证(如夫妻为对方支付保费)' },
{ name: '5、通关小白条' }
],
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
}
]
export default appointmentInfo
const beneficiary = [
{
bigTitle: '受益人',
deleteIcon: true,
id: 1, //唯一标识,用于删除
children: [
// 客户信息 此模块始终展示
{
fatherTitle: '客户信息',
type: 'object',
key: 'customer',
showMoudle: true, //模块是否展示
data: [
{
label: '客户类型',
key: 'customerType',
customerKey: 'customerType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_customer_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '与受保人关系',
key: 'insurantRel',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_rel',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 基础信息
{
fatherTitle: '基础信息',
type: 'object',
key: 'person',
labelPosition: 'top', //标签的位置
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '名字',
key: 'name',
customerKey: 'name',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '名字-英文',
key: 'nameEn',
customerKey: 'firstNamePinyin',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '性别',
key: 'gender',
customerKey: 'gender',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'sys_gender',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件类型',
key: 'documentType',
customerKey: 'idType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_id_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件号码',
key: 'idNumber',
customerKey: 'idCard',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生日期',
key: 'birthTime',
customerKey: 'birthdate',
domType: 'DatePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 公司信息
{
fatherTitle: '公司信息',
type: 'object',
key: 'company',
labelPosition: 'top', //标签的位置
showMoudle: false, //模块是否展示
data: [
{
label: '公司名称',
key: 'companyName',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司名称(英文)',
key: 'companyNameEn',
customerKey: 'companyNameEn',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司商业登记号码',
key: 'companyBusinessNo',
customerKey: 'companyBusinessNo',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册日期',
key: 'companyRegisterTime',
customerKey: '',
domType: 'DatePicker',
required: true,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册地区',
key: 'companyRegisterRegion',
customerKey: '',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_registration',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司电话',
key: 'companyMobile',
customerKey: '',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
companyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'companyMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司邮箱',
key: 'companyEmail',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司登记地址',
key: 'companyEnterAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
companyEnterAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '通讯地址',
key: 'txAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
txAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名中文-名字',
key: 'authNameCn',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名英文-名字',
key: 'authNameEn',
customerKey: '',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表职称',
key: 'authProfessional',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表电话',
key: 'authMobile',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
authMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'authMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 其他信息
{
fatherTitle: '其他信息',
type: 'object',
key: 'customer',
showMoudle: true, //模块是否展示
data: [
{
label: '受益比列',
key: 'benefitRatio',
customerKey: 'idCard',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '备注',
key: 'remark',
customerKey: 'idCard',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
}
]
}
]
export default beneficiary
/**
* 1.普通模块得数据格式,无子级:
* {
一些页面用到得属性,比如个人资料模块得数据格式
data:[] data主要是这个模块对应得表单dom数据
}
2. 有子级得模块得数据格式:
{
一些页面用到得属性,比如家庭状况模块得数据格式
data:[ data主要父级模块对应得表单
{
比如家庭状况中有父亲,母亲,配偶,这个对象就代表这些人
children:[],代表得是这些人对应得表单dom
}
]
}
以上两种格式说明了fnaForm页面得dom数据格式,如果有子级得dom请参照2格式添加,否则可能有未知错误
*/
const fnaForm = [ const fnaForm = [
{ {
fatherTitle: '个人资料', fatherTitle: '个人资料',
...@@ -159,8 +179,6 @@ const fnaForm = [ ...@@ -159,8 +179,6 @@ const fnaForm = [
childTitle: '父亲', childTitle: '父亲',
id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识 id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
span: 24, //栅格布局份数 span: 24, //栅格布局份数
// age: '',
// needProvide: '',
children: [ children: [
{ {
label: '年龄', label: '年龄',
...@@ -197,8 +215,6 @@ const fnaForm = [ ...@@ -197,8 +215,6 @@ const fnaForm = [
childTitle: '母亲', childTitle: '母亲',
id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识 id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
span: 24, //栅格布局份数 span: 24, //栅格布局份数
// age: '',
// needProvide: '',
children: [ children: [
{ {
label: '年龄', label: '年龄',
...@@ -235,8 +251,6 @@ const fnaForm = [ ...@@ -235,8 +251,6 @@ const fnaForm = [
childTitle: '配偶', childTitle: '配偶',
id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识 id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
span: 24, //栅格布局份数 span: 24, //栅格布局份数
// age: '',
// needProvide: '',
children: [ children: [
{ {
label: '年龄', label: '年龄',
......
// key: 'person',代表个人,key: 'company',代表公司
const insured = [
// 客户信息 此模块始终展示
{
fatherTitle: '客户信息',
type: 'object',
key: 'customer',
showMoudle: true, //模块是否展示
data: [
{
label: '客户类型',
key: 'customerType',
customerKey: 'customerType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_customer_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '客户编号',
key: 'customerNo',
customerKey: 'customCode',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 200,
disabled: true,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '与投保人关系',
key: 'policyholderRel',
// customerKey: 'customerType',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_rel',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 基础信息
{
fatherTitle: '基础信息',
type: 'object',
key: 'person',
labelPosition: 'top', //标签的位置
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '名字-英文',
key: 'nameEn',
customerKey: 'firstNamePinyin',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '名字',
key: 'name',
customerKey: 'name',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '性别',
key: 'gender',
customerKey: 'gender',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'sys_gender',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件类型',
key: 'documentType',
customerKey: 'idType',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_id_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件号码',
key: 'idNumber',
customerKey: 'idCard',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生日期',
key: 'birthday',
customerKey: 'birthdate',
domType: 'DatePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '年龄',
key: 'age',
customerKey: 'age',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '居住地址',
key: 'residenceAddress',
customerKey: 'residenceAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
residenceAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '通讯地址',
commonKey: true, //是否是公共字段
key: 'txAddress',
// customerKey: 'mailingAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
txAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '移动电话',
key: 'mobile',
customerKey: 'phone',
customerCode: 'areaCode',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
mobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'mobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '邮箱',
key: 'email',
customerKey: 'email',
domType: 'Input',
inputType: 'text',
maxLength: 30,
required: false,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司名称',
key: 'companyName',
customerKey: 'companyName',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司地址',
key: 'companyAddress',
customerKey: 'companyAddress',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
companyAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '行业',
key: 'industry',
customerKey: 'companyType',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '职位',
key: 'position',
customerKey: 'position',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '风险偏好',
key: 'riskAppetite',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_risk',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: 'VIP',
key: 'isVip',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '备注',
key: 'vipRemark',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: false,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
},
// 个人信息
{
fatherTitle: '个人信息',
type: 'object',
key: 'person',
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '称谓',
key: 'appellation',
customerKey: 'title',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_customer_title',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否吸烟',
key: 'smokingAllowed',
customerKey: 'smoke',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '吸烟量(支/天)',
key: 'smokingVolume',
customerKey: 'smokeQuantity',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: false,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生地(省市)',
key: 'birthplace',
customerKey: 'birthplace',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '国籍',
key: 'nationality',
customerKey: 'countryName',
domType: 'arrowRight',
required: true,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'country',
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '身高',
key: 'height',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入身高(cm)',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '体重',
key: 'weight',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入身高(kg)',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: 'BMI',
key: 'bmi',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
// {
// label: '平均每月收入',
// key: 'monthIncome',
// domType: 'Input',
// inputType: 'number',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入平均每月收入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '平均每月支出',
// key: 'monthExpenditure',
// domType: 'Input',
// inputType: 'number',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入平均每月支出',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
{
label: '受雇于现职年期',
key: 'currentTenure',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
// {
// label: '总流动资产',
// key: 'totalCurrentAssets',
// domType: 'Input',
// inputType: 'number',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入平均每月支出',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
{
label: '总负债额',
key: 'totalDebt',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '受供养人数目',
key: 'dependentsNum',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '婚姻状况',
key: 'maritalStatus',
customerKey: 'marriage',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_marriage',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '教育程度',
key: 'educationLevel',
customerKey: 'education',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_education',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '现时每月收入',
key: 'currentMonthlyIncome',
customerKey: 'salary',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '总工作年期',
key: 'totalWorkingYears',
customerKey: 'workYear',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入平均每月支出',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司电话',
key: 'companyMobile',
commonKey: true,
customerKey: 'companyTelephone',
customerCode: 'companyAreaCode',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
companyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'companyMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '固定电话',
key: 'landline',
customerKey: 'fixedPhone',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '其他电话',
commonKey: true, //是否是公共字段
key: 'otherMobile',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '过往一年是否所属国家以外地区居住超过182日',
key: 'isExceed',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否拥有其他国家公民身份(如美国、日本等)',
key: 'isOtherCountry',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否接受推广信息',
commonKey: true, //是否是公共字段
key: 'isPromotion',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
// {
// label: '投保人邮政编码',
// key: 'postalCode',
// domType: 'Input',
// inputType: 'number',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入平均每月支出',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// }
]
},
//其他信息
{
fatherTitle: '其他信息',
type: 'object',
key: 'person',
showMoudle: true, //模块是否展示
data: [
{
label: '旅行',
key: 'travel',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '运动',
key: 'exercise',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_exercise',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '游戏',
key: 'game',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_game',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '电影/戏剧',
key: 'movieDrama',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_movie',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '美食',
key: 'delicacy',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
// 公司信息
{
fatherTitle: '公司信息',
type: 'object',
key: 'company',
labelPosition: 'top', //标签的位置
showMoudle: false, //模块是否展示
data: [
{
label: '公司名称',
key: 'companyName',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
commonKey: true, //是否是公共字段
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司名称(英文)',
key: 'companyNameEn',
customerKey: 'companyNameEn',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司商业登记号码',
key: 'companyBusinessNo',
customerKey: 'companyBusinessNo',
domType: 'Input',
inputType: 'text',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册日期',
key: 'companyRegisterTime',
customerKey: '',
domType: 'DatePicker',
required: true,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司电话',
commonKey: true, //是否是公共字段
key: 'companyMobile',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
companyMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'companyMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司注册地区',
key: 'companyRegisterRegion',
customerKey: '',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_registration',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司邮箱',
key: 'companyEmail',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '公司登记地址',
key: 'companyEnterAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
companyEnterAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '通讯地址',
commonKey: true, //是否是公共字段
key: 'txAddress',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'address',
txAddress: {},
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名中文-名字',
key: 'authNameCn',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表姓名英文-名字',
key: 'authNameEn',
customerKey: '',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表职称',
key: 'authProfessional',
customerKey: '',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '授权代表电话',
key: 'authMobile',
customerKey: '',
domType: 'arrowRight',
required: false,
disabled: false,
placeholder: '请填写',
show: true,
drawerType: 'phone',
authMobile: {}, //带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
code: 'authMobileCode',
maxLength: 20,
labelPosition: 'top', //标签的位置
labelWidth: '180px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '其他电话',
commonKey: true, //是否是公共字段
key: 'otherMobile',
customerKey: '',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否接受推广信息',
commonKey: true, //是否是公共字段
key: 'isPromotion',
customerKey: '',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
}
]
export default insured
const policyTransferInfo = [
{
fatherTitle: '',
type: 'object',
key: 'policyTransfer',
showMoudle: true, //模块是否展示
label: '',
title:
'阁下是否使用或打算使用现有人寿保险保单的部分或全部资金,或使用或打算使用通过减少现有人寿保险保单的应付保费而节省的金额,以资助阁下购买新的人寿保险保单?例如,此等资金或金额可能来自:',
domType: 'Div',
required: false,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
dictType: 'csf_ap_policy_transfer',
tip: '请在适当的方格内填上剔号(只可选择一项)',
informationList: [
{ name: 'a. 就 阁下现有人寿保险保单作出退保/部分退保的安排,以获得其退保价值' },
{ name: 'b. 从 阁下现有人寿保险保单中提取保单贷款(包括自动保费贷款)' },
{ name: 'c. 从 阁下现有人寿保险保单中提取保单价值(例如:套现红利或赎回基金单位等)' },
{ name: 'd. 容许 阁下现有人寿保险保单失效(例如:终止支付保费)' },
{ name: 'e. 行使 阁下现有人寿保险保单中「保费假期」的权利' }
],
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
export default policyTransferInfo
const productPlan = [
{
fatherTitle: '',
keyType: 'Object', //用于表单收集值时,判断是数组还是对象
key: 'apiProductPlanMainInfoDto',
child: 'no', //有子级dom,需要循环展示
showMoudle: true, //模块是否展示
fatherRequired: true, //父级必填,代表个人资料这个模块有必填项
data: [
{
label: '产品名称',
key: 'productName',
domType: 'SearchSelect',
required: true,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
labelPosition: 'top', //标签的位置
lg: 8 //栅格布局份数
},
{
label: '地区',
key: 'region',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: true,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '货币',
key: 'currency',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'bx_currency_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '供款年期',
key: 'paymentTerm',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'paymentTerm',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '付款频率',
key: 'paymentFrequency',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_frequency',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '每期保费',
key: 'eachIssuePremium',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保额',
key: 'sumInsured',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否预缴保费',
key: 'isPrepay',
domType: 'Select',
required: true,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '首期付款方式',
key: 'initialPaymentMethod',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_first_issue',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '续期付款方式',
key: 'renewalPaymentMethod',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_first_issue',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '红利分配方式',
key: 'dividendDistributionMethod',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_dividend',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保单日期回溯',
key: 'isBacktrack',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保单生效日',
key: 'policyEffectiveDate',
domType: 'DatePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '是否参加递增保障权益',
key: 'isJoin',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_no_yes',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
},
//附加险
{
showMoudle: true, //模块是否展示
fatherTitle: '附加险',
keyType: 'Array', //用于表单收集值时,判断是数组还是对象
key: 'apiProductPlanAdditionalInfoDtoList',
child: 'yes', //有子级dom,需要循环展示
fatherRequired: true, //父级必填,代表个人资料这个模块有必填项
addBtn: true,
emptySpan: 24, //空状态得span
data: [
// {
// id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
// span: 24, //栅格布局份数
// childTitle: '附加险',
// deleteBtn: true,
// children: [
// {
// label: '产品名称',
// key: 'addProductName',
// domType: 'SearchSelect',
// required: true,
// maxLength: 30,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// labelPosition: 'top', //标签的位置
// lg: 8 //栅格布局份数
// },
// {
// label: '保额',
// key: 'sumInsured',
// domType: 'Input',
// inputType: 'number',
// required: true,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '保费',
// key: 'premium',
// domType: 'Input',
// inputType: 'number',
// required: true,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '保障地区',
// key: 'guaranteeRegion',
// domType: 'Input',
// inputType: 'text',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '货币',
// key: 'currency',
// domType: 'Select',
// inputType: 'text',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// dictType: 'bx_currency_type',
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '等级',
// key: 'insuranceType',
// domType: 'Input',
// inputType: 'text',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '自付额',
// key: 'deductibles',
// domType: 'Input',
// inputType: 'number',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '附加保障',
// key: 'additionalSafeguards',
// domType: 'Input',
// inputType: 'textarea',
// required: false,
// maxLength: 300,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 24, //栅格布局份数
// lg: 24 //栅格布局份数
// }
// ]
// }
]
}
]
export default productPlan
const secondHolder = [
// 基础信息
{
fatherTitle: '',
type: 'object',
key: 'person',
labelPosition: 'top', //标签的位置
showMoudle: true, //模块是否展示
// description: '证件信息至少填写一项',
data: [
{
label: '与受保人关系',
key: 'insurantRel',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_ap_rel',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '名字',
key: 'name',
customerKey: 'name',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '名字-英文',
key: 'nameEn',
customerKey: 'firstNamePinyin',
showEn: true, //是否填写英文
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '性别',
key: 'gender',
customerKey: 'gender',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'sys_gender',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '出生日期',
key: 'birthTime',
customerKey: 'birthdate',
domType: 'DatePicker',
required: false,
disabled: false,
placeholder: '请选择',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '年龄',
key: 'age',
customerKey: 'age',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: true,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件类型',
key: 'documentType',
customerKey: 'idType',
domType: 'Select',
required: false,
disabled: false,
placeholder: '请选择',
dictType: 'csf_id_type',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '证件号码',
key: 'idNumber',
customerKey: 'idCard',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 20,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
}
]
}
]
export default secondHolder
const useDictStore = defineStore('dict', { const useDictStore = defineStore('dict', {
state: () => ({ state: () => ({
dict: new Array(), dict: new Array(),
tenantUserList: [], tenantUserList: [], //租户用户数据
insureProductList: [], //保险产品数据
additionalProductList: [], //附加险产品数据
dictTypeLists: [] //字典列表,根据请求得不同会变化,所以使用之前需要使用useDictLists请求数据 dictTypeLists: [] //字典列表,根据请求得不同会变化,所以使用之前需要使用useDictLists请求数据
}), }),
actions: { actions: {
...@@ -54,6 +56,14 @@ const useDictStore = defineStore('dict', { ...@@ -54,6 +56,14 @@ const useDictStore = defineStore('dict', {
setTenantUserList(user) { setTenantUserList(user) {
this.tenantUserList = user this.tenantUserList = user
}, },
// 设置保险产品列表
setInsureProductList(product) {
this.insureProductList = product
},
// 设置附加险产品列表
setAdditionalProductList(product) {
this.additionalProductList = product
},
// 设置字典列表 // 设置字典列表
setDictTypeLists(typeList) { setDictTypeLists(typeList) {
this.dictTypeLists = typeList this.dictTypeLists = typeList
......
{
"id": 587,
"fnaBizId": "fna_nJEdXVIhXsp8uaO0",
"fnaNo": "CSF-B-20250924-0587",
"userBizId": "user_dMnkKPIwemvY0zhk",
"customerName": "33",
"customerBizId": "customer_cdV0p5a86hqmMnDw",
"fnaFormBizId": "fna_form_0PjYRkZFt2oMJ62b",
"fnaFormStatus": "1",
"appointmentNo": "Y2509295725815",
"appointmentBizId": "appointment_2ImPDnPjXQLD2GOQ",
"policyBizId": null,
"policyNo": null,
"status": "UNCOMPLETED",
"productCode": null,
"productName": null,
"url": null,
"edit": null,
"remark": null,
"isDeleted": null,
"createTime": "2025-09-24T16:01:07.000+08:00"
}
...@@ -12,7 +12,7 @@ const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss' ...@@ -12,7 +12,7 @@ const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
const DATE_FORMAT = 'YYYY-MM-DD' const DATE_FORMAT = 'YYYY-MM-DD'
export function formatToDateTime(date, format = DATE_TIME_FORMAT) { export function formatToDateTime(date, format = DATE_TIME_FORMAT) {
if (!date) return '' if (!date) return ''
return dayjs(date).format(format) return dayjs(date).format(format)
} }
...@@ -21,10 +21,39 @@ export function formatToDate(date, format = DATE_FORMAT) { ...@@ -21,10 +21,39 @@ export function formatToDate(date, format = DATE_FORMAT) {
return dayjs(date).format(format) return dayjs(date).format(format)
} }
export const getNowTime = (format = DATE_TIME_FORMAT) => { export const getNowTime = (format = DATE_TIME_FORMAT) => {
if (!date) return '' if (!date) return ''
return dayjs().format(format) return dayjs().format(format)
} }
/**
* 更精确的年龄计算(精确到月日)
* @param {string|Date} birthDate - 出生日期
* @returns {number} 年龄
*/
export const calculateExactAge = birthDate => {
if (!birthDate) return 0
try {
const birth = dayjs(birthDate)
const today = dayjs()
if (!birth.isValid() || birth.isAfter(today)) {
return 0
}
let age = today.diff(birth, 'year')
const remainder = today.diff(birth.add(age, 'year'), 'month')
// 如果还没到今年的生日,年龄减1
if (remainder < 0) {
age--
}
return age > 0 ? age : 0
} catch (error) {
console.error('计算精确年龄时出错:', error)
return 0
}
}
export default { export default {
formatIsoToDateTime, formatIsoToDateTime,
formatToDateTime, formatToDateTime,
......
...@@ -11,14 +11,18 @@ export function useDict(...args) { ...@@ -11,14 +11,18 @@ export function useDict(...args) {
args.forEach((dictType, index) => { args.forEach((dictType, index) => {
res.value[dictType] = [] res.value[dictType] = []
const dicts = useDictStore().getDict(dictType) const dicts = useDictStore().getDict(dictType)
if (dicts) { // if (dicts) {
res.value[dictType] = dicts // res.value[dictType] = dicts
} else { // } else {
getDicts(dictType).then(resp => { // getDicts(dictType).then(resp => {
res.value[dictType] = resp.data.map(p => ({ label: p.itemLabel, value: p.itemValue })) // res.value[dictType] = resp.data.map(p => ({ label: p.itemLabel, value: p.itemValue }))
useDictStore().setDict(dictType, res.value[dictType]) // useDictStore().setDict(dictType, res.value[dictType])
}) // })
} // }
getDicts(dictType).then(resp => {
res.value[dictType] = resp.data.map(p => ({ label: p.itemLabel, value: p.itemValue }))
useDictStore().setDict(dictType, res.value[dictType])
})
}) })
return toRefs(res.value) return toRefs(res.value)
})() })()
...@@ -29,18 +33,20 @@ export function useDict(...args) { ...@@ -29,18 +33,20 @@ export function useDict(...args) {
export function useDictLists(typeLists) { export function useDictLists(typeLists) {
let params = { typeList: typeLists } let params = { typeList: typeLists }
let dictArray = [] let dictArray = []
getMoreDicts(params).then(resp => { return (() => {
if (resp.code === 200) { getMoreDicts(params).then(resp => {
dictArray = resp.data.map(item => { if (resp.code === 200) {
item.dictItemList.forEach(dict => { dictArray = resp.data.map(item => {
dict.label = dict.itemLabel item.dictItemList.forEach(dict => {
dict.value = dict.itemValue dict.label = dict.itemLabel
dict.value = dict.itemValue
})
return item
}) })
return item useDictStore().setDictTypeLists(dictArray)
}) }
useDictStore().setDictTypeLists(dictArray) })
} })()
})
} }
// /** // /**
// * 获取字典数据 // * 获取字典数据
......
...@@ -90,7 +90,7 @@ const menuList = ref([]) ...@@ -90,7 +90,7 @@ const menuList = ref([])
const quickList = ref([]) const quickList = ref([])
const confirmCountry = item => { const confirmCountry = item => {
menuList.value[0].value = item.areaCode menuList.value[0].value = item.areaCode
hanleCountryClose() hanleCountryClose()
} }
const openCountryDrawer = item => { const openCountryDrawer = item => {
...@@ -129,7 +129,6 @@ const confirmClick = () => { ...@@ -129,7 +129,6 @@ const confirmClick = () => {
info[key] = phone info[key] = phone
} }
} }
emit('confirmDrawer', info) emit('confirmDrawer', info)
drawer.value = false drawer.value = false
} }
......
...@@ -180,8 +180,8 @@ import Country from '@/views/components/country' ...@@ -180,8 +180,8 @@ import Country from '@/views/components/country'
import Phone from '@/views/components/phone' import Phone from '@/views/components/phone'
import Address from '@/views/components/address' import Address from '@/views/components/address'
import { getDicts } from '@/api/system/dict/data'
import { watch, nextTick } from 'vue' import { watch, } from 'vue'
import { addCustomer, getCustomerDetail, editCustomer, getCustomerList } from '@/api/sign/fna' import { addCustomer, getCustomerDetail, editCustomer, getCustomerList } from '@/api/sign/fna'
import useDictStore from '@/store/modules/dict' import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据 const dictStore = useDictStore() //获取字典数据
...@@ -373,6 +373,7 @@ const processFormData = async () => { ...@@ -373,6 +373,7 @@ const processFormData = async () => {
if (props.customerBizId) { if (props.customerBizId) {
getCustomerInfo(props.customerBizId, processedData) getCustomerInfo(props.customerBizId, processedData)
editStatus.value = true
} else { } else {
editStatus.value = false editStatus.value = false
processedCustomerData.value = oldCustomerData.value = processedData processedCustomerData.value = oldCustomerData.value = processedData
...@@ -768,6 +769,7 @@ watch( ...@@ -768,6 +769,7 @@ watch(
newVal => { newVal => {
if (newVal === 'customer') { if (newVal === 'customer') {
openList.value = false openList.value = false
processFormData() processFormData()
} }
} }
......
...@@ -190,13 +190,21 @@ ...@@ -190,13 +190,21 @@
<el-row> <el-row>
<el-col> <el-col>
<div class="tabButton"> <div class="tabButton">
<!-- :disabled="editStatus" --> <el-button
<el-button type="primary" icon="RefreshRight" size="large" @click="submitForm('temp')" type="primary"
icon="RefreshRight"
size="large"
@click="submitForm('temp')"
:disabled="editStatus"
>暂存</el-button >暂存</el-button
> >
<!-- :disabled="editStatus" --> <el-button
<el-button type="primary" icon="Check" @click="submitForm('save')" size="large" type="success"
>提交</el-button icon="Check"
@click="submitForm('save')"
size="large"
:disabled="editStatus"
>立即预约</el-button
> >
</div> </div>
</el-col> </el-col>
...@@ -366,8 +374,10 @@ const processFormData = async () => { ...@@ -366,8 +374,10 @@ const processFormData = async () => {
if (props.fnaFormBizId) { if (props.fnaFormBizId) {
getFanformInfo(props.fnaFormBizId, processedData) getFanformInfo(props.fnaFormBizId, processedData)
editStatus.value = true
} else { } else {
processedFanFormData.value = oldFanFormData.value = processedData processedFanFormData.value = oldFanFormData.value = processedData
editStatus.value = false
} }
} }
// 添加表单子级dom // 添加表单子级dom
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <!-- <div class="right">
<el-button <el-button
:disabled="!(processInfo.customerBizId && processInfo.fnaFormBizId)" :disabled="!(processInfo.customerBizId && processInfo.fnaFormBizId)"
type="success" type="success"
...@@ -38,12 +38,12 @@ ...@@ -38,12 +38,12 @@
plain plain
>生成副本</el-button >生成副本</el-button
> >
</div> </div> -->
</div> </div>
<div class="tabsBox"> <div class="tabsBox">
<el-tabs v-model="activeName" class="demo-tabs" :before-leave="beforeTabLeave"> <el-tabs v-model="activeName" class="demo-tabs" :before-leave="beforeTabLeave">
<el-tab-pane v-for="tab in tabsList" :key="tab.name" :label="tab.label" :name="tab.name"> <el-tab-pane v-for="tab in tabsList" :key="tab.name" :label="tab.label" :name="tab.name">
<div class="tabPaneBox"> <div :class="{ tabPaneBox: activeName !== 'appointment' }">
<div v-if="tab.name === 'overview'" class="overviewBox"> <div v-if="tab.name === 'overview'" class="overviewBox">
<div <div
class="oneItem" class="oneItem"
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
unFinishTitle: item.status == '0' unFinishTitle: item.status == '0'
}" }"
> >
{{ item.title }} {{ item.label }}
</div> </div>
<div <div
class="status" class="status"
...@@ -109,9 +109,16 @@ ...@@ -109,9 +109,16 @@
@handleSuccess="handleSuccess" @handleSuccess="handleSuccess"
/> />
</div> </div>
<div v-if="tab.name === 'appointment'">关联预约内容</div> <div v-if="tab.name === 'appointment'">
<AppointmentEdit
:embed="true"
editStatus="add"
:tabName="activeName"
:processDetail="processInfo"
@handleSuccess="handleSuccess"
/>
</div>
<div v-if="tab.name === 'newpolicy'">关联新单内容</div> <div v-if="tab.name === 'newpolicy'">关联新单内容</div>
<div v-if="tab.name === 'policy'">关联保单内容</div>
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
...@@ -120,12 +127,14 @@ ...@@ -120,12 +127,14 @@
</div> </div>
</template> </template>
<script setup name="FnaEdit"> <script setup name="FnaEdit">
import AppointmentEdit from '@/views/sign/appointment/appointmentEdit'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import useDictStore from '@/store/modules/dict' import useDictStore from '@/store/modules/dict'
import { addFna, getProcessDetail, updateProcess } from '@/api/sign/fna' import { addFna, getProcessDetail, updateProcess } from '@/api/sign/fna'
import { listTenantUser } from '@/api/common' import { listTenantUser, getInsuranceProductList, getAdditionalProductList } from '@/api/common'
import Customer from './components/customer' import Customer from './components/customer'
import FanForm from './components/fanForm' import FanForm from './components/fanForm'
import { Check } from '@element-plus/icons-vue' import { Check } from '@element-plus/icons-vue'
import { ref } from 'vue' import { ref } from 'vue'
const userStore = useUserStore() const userStore = useUserStore()
...@@ -135,10 +144,10 @@ const route = useRoute() ...@@ -135,10 +144,10 @@ const route = useRoute()
const router = useRouter() const router = useRouter()
const activeName = ref('overview') const activeName = ref('overview')
const processInfo = ref({ const processInfo = ref({
fnaNo: '暂无', // fnaNo: '暂无',
status: '未完成', // status: '未完成',
createTime: proxy.parseTime(new Date()), // createTime: proxy.parseTime(new Date()),
customerName: userStore.name // customerName: userStore.name
}) // 流程详情信息 }) // 流程详情信息
const updateStatus = ref(false) const updateStatus = ref(false)
const dictTypeLists = ref([]) const dictTypeLists = ref([])
...@@ -175,28 +184,61 @@ const tabsList = ref([ ...@@ -175,28 +184,61 @@ const tabsList = ref([
id: 4, id: 4,
status: '0', status: '0',
key: 'policyBizld' key: 'policyBizld'
},
{
label: '关联保单',
name: 'policy',
id: 5,
status: '0',
key: 'policyNo'
} }
// {
// label: '关联保单',
// name: 'policy',
// id: 5,
// status: '0',
// key: 'policyNo'
// }
]) ])
const { csf_fna_status } = proxy.useDict('csf_fna_status') const { csf_fna_status } = proxy.useDict('csf_fna_status')
// 获取各个流程所需要得字典数据 // 获取各个流程所需要得字典数据
const getDictsData = async () => { const getDictsData = async () => {
// 获取租户用户列表 // 获取租户用户列表
const params = { const params1 = {
tenantBizId: userStore.projectInfo.tenantBizId, tenantBizId: userStore.projectInfo.tenantBizId,
pageNo: 1, pageNo: 1,
pageSize: 10 pageSize: 10
} }
const response = await listTenantUser(params) const response1 = await listTenantUser(params1)
if (response.code == 200) { if (response1.code == 200) {
dictStore.setTenantUserList(response.data.records) dictStore.setTenantUserList(response1.data.records)
}
const params2 = {
loginTenantBizId: userStore.projectInfo.tenantBizId,
pageNo: 1,
pageSize: 10
}
const response2 = await getInsuranceProductList(params2)
if (response2.code == 200) {
response2.data.records = response2.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.productBizId
}
})
dictStore.setInsureProductList(response2.data.records)
}
const params3 = {
pageNo: 1,
pageSize: 10
}
const response3 = await getAdditionalProductList(params3)
if (response3.code == 200) {
response3.data.records = response3.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.additionalProductBizId
}
})
dictStore.setAdditionalProductList(response3.data.records)
} }
// 请求每个流程中所涉及到的字典值数据 // 请求每个流程中所涉及到的字典值数据
proxy.useDictLists([ proxy.useDictLists([
...@@ -210,7 +252,20 @@ const getDictsData = async () => { ...@@ -210,7 +252,20 @@ const getDictsData = async () => {
'sys_gender', 'sys_gender',
'csf_marriage', 'csf_marriage',
'csf_education', 'csf_education',
'csf_id_type' 'csf_id_type',
'csf_ap_apply_type',
'csf_ap_meeting_point',
'csf_ap_first_issue',
'csf_ap_dividend',
'csf_ap_frequency',
'csf_ap_rel',
'csf_ap_registration',
'csf_ap_exercise',
'csf_ap_risk',
'csf_ap_movie',
'csf_ap_game',
'wj_question_first_category',
'wj_question_second_category'
]) ])
} }
...@@ -246,7 +301,9 @@ function getProcessInfo(fnaBizId, changeTab) { ...@@ -246,7 +301,9 @@ function getProcessInfo(fnaBizId, changeTab) {
} }
}) })
csf_fna_status._object.csf_fna_status.forEach(item => { csf_fna_status._object.csf_fna_status.forEach(item => {
if (item.value == res.data.status) processInfo.value.status = item.label if (item.value == res.data.status) {
processInfo.value.status = item.label
}
}) })
if (changeTab) { if (changeTab) {
activeName.value = changeTab activeName.value = changeTab
...@@ -310,7 +367,9 @@ const handleBack = () => { ...@@ -310,7 +367,9 @@ const handleBack = () => {
if (route.query.type == 'add') { if (route.query.type == 'add') {
getAddInfo() getAddInfo()
} else if (route.query.type == 'edit') { } else if (route.query.type == 'edit') {
getProcessInfo(route.query.fnaBizId) setTimeout(() => {
getProcessInfo(route.query.fnaBizId)
}, 100)
} }
const handleSuccess = info => { const handleSuccess = info => {
switch (info.tab) { switch (info.tab) {
...@@ -345,6 +404,12 @@ const handleSuccess = info => { ...@@ -345,6 +404,12 @@ const handleSuccess = info => {
}) })
} }
break break
case 'appointment':
if (info.type == 'add') {
getProcessInfo(processInfo.value.fnaBizId, 'newpolicy')
} else {
}
break
case 'newpolicy': case 'newpolicy':
break break
case 'policy': case 'policy':
...@@ -354,10 +419,6 @@ const handleSuccess = info => { ...@@ -354,10 +419,6 @@ const handleSuccess = info => {
} }
} }
getDictsData() getDictsData()
// handleDomData()
// 1.通过新建流程进来的,要请求创建/csf/api/Fna/add拿到头部dom等信息
//2.每次进来要请求根据id获取/csf/api/Fna/get/vo,根据流程BizId获取进行到哪一步了,还可以拿到头部dom等信息
//3.每个模块保存完要重新请求/csf/api/Fna/get/vo,还要再请求/csf/api/Fna/update,更新后端数据库
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
::v-deep .el-card { ::v-deep .el-card {
......
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 步骤条 --> <!-- 步骤条 -->
<el-row style="margin-bottom: 30px"> <!-- <el-row style="margin-bottom: 30px">
<el-col :span="24"> <el-col :span="24">
<Step :stepList="stepList"></Step> <Step :stepList="stepList"></Step>
</el-col> </el-col>
</el-row> </el-row> -->
<!-- 条件查询 --> <!-- 条件查询 -->
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
...@@ -79,15 +79,15 @@ ...@@ -79,15 +79,15 @@
:data="tenantList" :data="tenantList"
@selection-change="tableSelect" @selection-change="tableSelect"
@sort-change="sortChange" @sort-change="sortChange"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column type="index" width="50" />
<el-table-column label="流程编号" align="center" prop="fnaNo" width="200" /> <el-table-column label="流程编号" align="center" prop="fnaNo" width="200" />
<el-table-column label="预约编号" align="center" prop="appointmentNo" width="150" /> <el-table-column label="预约编号" align="center" prop="appointmentNo" />
<el-table-column label="新单编号" align="center" prop="policyId" /> <el-table-column label="新单编号" align="center" prop="policyId" />
<el-table-column label="保单号" align="center" prop="policyNo" /> <el-table-column label="保单号" align="center" prop="policyNo" width="150" />
<el-table-column label="客户姓名" align="center" prop="customerName" /> <el-table-column label="客户姓名" align="center" prop="customerName" width="100" />
<el-table-column label="状态" align="center" width="150"> <el-table-column label="状态" align="center" width="150">
<template #default="scope"> <template #default="scope">
...@@ -102,8 +102,7 @@ ...@@ -102,8 +102,7 @@
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<!-- sortable 后端未做 --> <el-table-column label="创建时间" sortable align="center" prop="createTime" width="150">
<el-table-column label="创建时间" sortable align="center" prop="createTime">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
...@@ -111,13 +110,20 @@ ...@@ -111,13 +110,20 @@
<el-table-column <el-table-column
label="操作" label="操作"
align="center" align="center"
width="200" width="250"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
fixed="right"
> >
<template #default="scope"> <template #default="scope">
<el-button link type="primary" @click="handleUpdate(scope.row)">修改</el-button> <el-button type="primary" @click="handleUpdate(scope.row)">修改</el-button>
<el-button type="success" @click="handleCopy(scope.row)">生成副本</el-button>
<!-- v-if="scope.row.status == 'COMPLETED'" --> <!-- v-if="scope.row.status == 'COMPLETED'" -->
<el-button link type="primary" @click="handleDelete(scope.row)">删除</el-button> <el-button
v-if="scope.row.status == 'COMPLETED'"
type="danger"
@click="handleDelete(scope.row)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -137,7 +143,7 @@ ...@@ -137,7 +143,7 @@
<script setup name="FnaList"> <script setup name="FnaList">
import Step from '@/views/components/moduleStep' import Step from '@/views/components/moduleStep'
import { getFnaList, deleteFna } from '@/api/sign/fna' import { getFnaList, deleteFna, subProcess } from '@/api/sign/fna'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const stepList = ref([ const stepList = ref([
...@@ -148,11 +154,7 @@ const stepList = ref([ ...@@ -148,11 +154,7 @@ const stepList = ref([
const userStore = useUserStore() const userStore = useUserStore()
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { sys_status, csf_fna_status, sys_no_yes } = proxy.useDict( const { csf_fna_status } = proxy.useDict('csf_fna_status')
'sys_status',
'csf_fna_status',
'sys_no_yes'
)
const tenantList = ref([]) const tenantList = ref([])
const loading = ref(true) const loading = ref(true)
...@@ -174,6 +176,25 @@ const data = reactive({ ...@@ -174,6 +176,25 @@ const data = reactive({
}) })
const { queryParams, form, rules } = toRefs(data) const { queryParams, form, rules } = toRefs(data)
const handleCopy = row => {
// { fnaBizId: row.fnaBizId }
subProcess({ fnaBizId: row.fnaBizId }).then(response => {
if (response.code === 200) {
getList()
proxy.$modal.msgSuccess('生成副本成功')
}
})
// proxy.$modal
// .confirm('是否确认复用' + row.customerName + '的FNA流程?')
// .then(function () {
// return subProcess({ fnaBizId: row.fnaBizId })
// })
// .then(() => {
// getList()
// proxy.$modal.msgSuccess('生成副本成功')
// })
// .catch(() => {})
}
const sortChange = ({ prop, order }) => { const sortChange = ({ prop, order }) => {
if (order == 'ascending') { if (order == 'ascending') {
queryParams.value.sortOrder = 'ascend' queryParams.value.sortOrder = 'ascend'
...@@ -261,20 +282,15 @@ function handleAdd() { ...@@ -261,20 +282,15 @@ function handleAdd() {
/** 修改按钮操作 */ /** 修改按钮操作 */
function handleUpdate(row) { function handleUpdate(row) {
router.push({ path: '/sign/FnaList/edit', query: { fnaBizId: row.fnaBizId, type: 'edit' } }) router.push({
path: '/sign/FnaList/edit',
query: { fnaBizId: row.fnaBizId, type: 'edit', status: row.status }
})
} }
getList() getList()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* ::v-deep .el-step__head.is-success {
color: none !important;
background-color: #e8f3ff !important;
border: none !important;
} */
/* ::v-deep .el-step__icon {
background-color: #e8f3ff !important;
} */
.bottomBtn { .bottomBtn {
width: 100%; width: 100%;
text-align: right; text-align: right;
......
<template>
<div
class="appointment-container"
:class="{
'noembed-container': !embed,
'embed-container': embed
}"
>
<div v-if="!embed">
<el-button type="primary" icon="Back" @click="handleBack" style="margin-bottom: 10px"
>返回</el-button
>
</div>
<el-card shadow="never">
<div class="cardHeader" v-if="!embed">
<div class="left">
<img class="iconBox" src="@/assets/images/icon1.png" alt="" />
<div class="rightBox">
<div class="num">{{ processInfo.appointmentNo || '--' }}</div>
<div class="bottom">
<div class="status">
{{ processInfo.status || '--' }}
</div>
<div class="time">
<span class="iconfont icon-yanqiweiwancheng"></span>
<span
>{{ parseTime(processInfo.createTime) }}{{
processInfo.creatorName || '--'
}}创建</span
>
</div>
</div>
</div>
</div>
<div class="right">
<el-button type="success" :icon="Check" @click="handleSubmit('submit')">提交</el-button>
</div>
</div>
<div class="tabsBox">
<el-row v-if="embed">
<el-col>
<div class="topButtonBox">
<el-button type="success" :icon="Check" @click="handleSubmit('submit')"
>提交</el-button
>
<el-button type="primary" plain v-if="showStorage" @click="handleSubmit('storage')"
>暂存</el-button
>
</div>
</el-col>
</el-row>
<el-tabs v-model="activeName" type="card" class="demo-tabs" :before-leave="beforeTabLeave">
<el-tab-pane v-for="tab in tabsList" :key="tab.name" :label="tab.label" :name="tab.name">
<div
class="appointmentTabPaneBox"
:class="{ yesEmbedTabPaneBox: embed, noEmbedTabPaneBox: !embed }"
>
<div v-if="tab.name === 'appointmentInfo'">
<AppointmentInfo
v-if="tab.name === 'appointmentInfo'"
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiAppointmentInfoDto="appointmentSummeryInfo.apiAppointmentInfoDto"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="appointmentInfoRef"
/>
</div>
<div v-if="tab.name === 'productPlan'">
<ProductPlan
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiProductPlanInfoDto="appointmentSummeryInfo.apiProductPlanInfoDto"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="productPlanRef"
/>
</div>
<div v-if="tab.name === 'policyholder'">
<PolicyHolderInfo
:activeName="activeName"
:formStatus="formStatus"
:customerInfo="customerInfo"
:idsObj="idsObj"
:apiPolicyholderInfoDto="appointmentSummeryInfo.apiPolicyholderInfoDto"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="policyHolderInfoRef"
/>
</div>
<div v-if="tab.name === 'insurantInfo'">
<InsuredInfo
:activeName="activeName"
:formStatus="formStatus"
:customerInfo="customerInfo"
:idsObj="idsObj"
:apiInsurantInfoDto="appointmentSummeryInfo.apiInsurantInfoDto"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="insuredInfoRef"
/>
</div>
<div v-if="tab.name === 'secondHolder'">
<SecondHolderInfo
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiSecondHolderInfoDto="appointmentSummeryInfo.apiSecondHolderInfoDto"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="secondHolderInfoRef"
/>
</div>
<div v-if="tab.name === 'beneficiary'">
<BeneficiaryInfo
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiBeneficiaryInfoDtoList="appointmentSummeryInfo.apiBeneficiaryInfoDtoList"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="beneficiaryInfoRef"
/>
</div>
<div v-if="tab.name === 'questionnaires'">
<HealthInfo
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:appointmentStatus="appointmentSummeryInfo.status"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="questionnairesInfoRef"
/>
</div>
<div v-if="tab.name === 'fna'">
<FnaInfo
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
/>
</div>
<div v-if="tab.name === 'policyTransfer'">
<PolicyTransferInfo
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiAppointmentInfoDto="appointmentSummeryInfo.apiAppointmentInfoDto"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
ref="policyTransferRef"
/>
</div>
<div v-if="tab.name === 'accessories'">
<FileUpload
:activeName="activeName"
:formStatus="formStatus"
:idsObj="idsObj"
:apiAppointmentInfoDto="appointmentSummeryInfo.apiAppointmentInfoDto"
@handleSuccessEdit="getAppointmentInfo(idsObj.appointmentBizId)"
/>
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
</el-card>
</div>
</template>
<script setup name="AppointmentEdit">
import AppointmentInfo from './components/appointmentInfo.vue'
import ProductPlan from './components/productPlan.vue'
import PolicyHolderInfo from './components/policyHolderInfo.vue'
import InsuredInfo from './components/insuredInfo.vue'
import SecondHolderInfo from './components/secondHolderInfo.vue'
import BeneficiaryInfo from './components/beneficiaryInfo.vue'
import FnaInfo from './components/fnaInfo.vue'
import PolicyTransferInfo from './components/policyTransferInfo.vue'
import FileUpload from './components/fileUpload.vue'
import HealthInfo from './components/healthInfo.vue'
import useUserStore from '@/store/modules/user'
import useDictStore from '@/store/modules/dict'
import { getCustomerDetail } from '@/api/sign/fna'
import {
addAppointment,
getAppointmentDetail,
storageAppointment,
editAppointmentDetail
} from '@/api/sign/appointment'
import { listTenantUser, getInsuranceProductList, getAdditionalProductList } from '@/api/common'
import { Check } from '@element-plus/icons-vue'
import { ref, nextTick, onUnmounted } from 'vue'
const emit = defineEmits(['handleSuccess'])
const { proxy } = getCurrentInstance()
// const { csf_ap_status } = proxy.useDict('csf_ap_status')
const props = defineProps({
embed: { type: Boolean, default: false }, //作为组件嵌入别的地方
editStatus: { type: String, default: '' }, //作为组件嵌入别的地方
tabName: { type: String, default: '' }, //父组件的tab名称
processDetail: { type: Object, default: () => ({}) } //新增预约单时,传入的流程详情信息
})
const userStore = useUserStore()
const dictStore = useDictStore()
const showStorage = ref(false)
const route = useRoute()
const router = useRouter()
const activeName = ref('')
const formStatus = ref('')
const submitAppointmentObj = ref({})
const appointmentInfoRef = ref(null)
const productPlanRef = ref(null)
const policyHolderInfoRef = ref(null)
const insuredInfoRef = ref(null)
const secondHolderInfoRef = ref(null)
const beneficiaryInfoRef = ref(null)
const policyTransferRef = ref(null)
const questionnairesInfoRef = ref(null)
const customerInfo = ref({})
const idsObj = ref({}) //各个模块的bizId
// const appointmentSummeryInfo = ref({ apiAppointmentInfoDto: { appointmentBizId: '' } }) //预约详情总信息
const appointmentSummeryInfo = ref({}) //预约详情总信息
const processInfo = ref({
fnaNo: '暂无',
status: '未完成',
createTime: proxy.parseTime(new Date()),
customerName: userStore.name
})
const tabsList = ref([
{
label: '预约信息',
name: 'appointmentInfo',
id: 1,
key: 'appointmentBizId'
},
{
label: '产品计划',
name: 'productPlan',
id: 2,
status: '0',
key: 'planBizId'
},
{
label: '投保人',
name: 'policyholder',
id: 3,
status: '0',
key: 'policyholderBizId'
},
{
label: '受保人',
name: 'insurantInfo',
id: 4,
status: '0',
key: 'insurantBizId'
},
{
label: '受益人',
name: 'beneficiary',
id: 5,
status: '0',
key: 'beneficiaryBizId'
},
{
label: '第二持有人',
name: 'secondHolder',
id: 6,
status: '0',
key: 'secondHolderBizId'
},
{
label: '健康信息', //后端还没加这个字段
name: 'questionnaires',
id: 7,
status: '0',
key: 'questionnaireBizId'
},
{
label: '关联FNA',
name: 'fna',
id: 8,
status: '0',
key: 'fnaBizId'
},
{
label: '转保声明',
name: 'policyTransfer',
id: 9,
status: '0',
key: 'policyTransfer'
},
{
label: '附件', //大提交的时候不用提交了,因为上传文件的时候已经入库了
name: 'accessories',
id: 10,
status: '0',
key: 'fnaBizId'
}
//
// {
// label: '关联计划书', //关联计划书暂时先不做
// name: 'fna',
// id: 10,
// status: '0',
// key: 'fnaBizId'
// },
// {
// label: '其他', //先不做
// name: 'fna',
// id: 11,
// status: '0',
// key: 'fnaBizId'
// },
])
// 获取预约详情
function getAppointmentInfo(appointmentBizId, changeTab) {
getAppointmentDetail(appointmentBizId).then(res => {
if (res.code == 200) {
appointmentSummeryInfo.value = res.data
if (!appointmentSummeryInfo.value.apiAppointmentInfoDto.appointmentBizId) {
showStorage.value = true
}
idsObj.value.fnaNo = res.data.apiAppointmentInfoDto.fnaNo
idsObj.value.fnaBizId = res.data.apiAppointmentInfoDto.fnaBizId
// 从预约列表里的修改,改变状态
if (route.query.appointmentNo) {
formStatus.value = 'appointmentEdit'
if (changeTab) {
activeName.value = 'appointmentInfo'
}
}
}
})
}
// 获取客户详情,投保人模块回填用
function getCustomerInfo(customerBizId) {
getCustomerDetail(customerBizId).then(res => {
if (res.code == 200) {
customerInfo.value = res.data
}
})
}
// 获取各个流程所需要得字典数据
const getDictsData = async () => {
// 获取租户用户列表
const params1 = {
tenantBizId: userStore.projectInfo.tenantBizId,
pageNo: 1,
pageSize: 10
}
const response1 = await listTenantUser(params1)
if (response1.code == 200) {
dictStore.setTenantUserList(response1.data.records)
}
const params2 = {
loginTenantBizId: userStore.projectInfo.tenantBizId,
pageNo: 1,
pageSize: 10
}
const response2 = await getInsuranceProductList(params2)
if (response2.code == 200) {
response2.data.records = response2.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.productBizId
}
})
dictStore.setInsureProductList(response2.data.records)
}
const params3 = {
pageNo: 1,
pageSize: 10
}
const response3 = await getAdditionalProductList(params3)
if (response3.code == 200) {
response3.data.records = response3.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.additionalProductBizId
}
})
dictStore.setAdditionalProductList(response3.data.records)
}
proxy.useDictLists([
'csf_employment',
'sys_no_yes',
'bx_currency_type',
'csf_liquid_asset_type',
'csf_premium_funding_source',
'csf_customer_type',
'csf_customer_title',
'sys_gender',
'csf_marriage',
'csf_education',
'csf_id_type',
'csf_ap_apply_type',
'csf_ap_meeting_point',
'csf_ap_first_issue',
'csf_ap_dividend',
'csf_ap_frequency',
'csf_ap_rel',
'csf_ap_registration',
'csf_ap_exercise',
'csf_ap_risk',
'csf_ap_movie',
'csf_ap_game',
'csf_ap_policy_transfer',
'wj_question_first_category',
'wj_question_second_category'
])
}
// Tab切换前的验证
const beforeTabLeave = (activeTabName, oldTabName) => {
return true
}
const handleBack = () => {
// 先手动清理状态
submitAppointmentObj.value = {}
appointmentSummeryInfo.value = {}
router.go(-1)
}
// 判断是否为数组
const isArray = value => {
return Array.isArray(value)
}
// 判断是否为对象
const isObject = value => {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
const handleSubmit = type => {
// 提交得时候要拿到各个步骤得表单数据
if (appointmentInfoRef.value) {
submitAppointmentObj.value.apiAppointmentInfoDto =
appointmentInfoRef.value[0].handleFormValues()
}
if (productPlanRef.value) {
submitAppointmentObj.value.apiProductPlanInfoDto = productPlanRef.value[0].handleSubmitForm()
}
if (policyHolderInfoRef.value) {
submitAppointmentObj.value.apiPolicyholderInfoDto =
policyHolderInfoRef.value[0].handleFormValues()
}
if (insuredInfoRef.value) {
submitAppointmentObj.value.apiInsurantInfoDto = insuredInfoRef.value[0].handleFormValues()
}
if (secondHolderInfoRef.value) {
submitAppointmentObj.value.apiSecondHolderInfoDto =
secondHolderInfoRef.value[0].handleFormValues()
}
if (beneficiaryInfoRef.value) {
submitAppointmentObj.value.apiBeneficiaryInfoDtoList =
beneficiaryInfoRef.value[0].handleFormValues()
}
if (policyTransferRef.value) {
submitAppointmentObj.value.apiAppointmentInfoDto.policyTransfer =
policyTransferRef.value[0].form.policyTransfer
}
// 代表新增预约
if (formStatus.value == 'appointmentAdd' && !idsObj.value.appointmentBizId) {
submitAppointmentObj.value.apiAppointmentInfoDto.customerBizId =
props.processDetail.customerBizId
submitAppointmentObj.value.apiAppointmentInfoDto.fnaBizId = props.processDetail.fnaBizId
submitAppointmentObj.value.apiAppointmentInfoDto.fnaNo = props.processDetail.fnaNo
if (type == 'submit') {
// 新增预约单
addAppointment(submitAppointmentObj.value).then(res => {
if (res.code == 200) {
proxy.$message.success('预约成功')
emit('handleSuccess', {
tab: 'appointment',
type: 'add'
})
}
})
}
}
// 代表修改预约单
if (idsObj.value.appointmentBizId) {
// 与预约聚合详情做对比,如果拿到得个表单数据有为空得就使用聚合详情得数据
for (const key1 in appointmentSummeryInfo.value) {
for (const key2 in submitAppointmentObj.value) {
if (
key1 == key2 &&
isArray(submitAppointmentObj.value[key2]) &&
submitAppointmentObj.value[key2].length == 0
) {
submitAppointmentObj.value[key2] = appointmentSummeryInfo.value[key1]
}
if (
key1 == key2 &&
isObject(submitAppointmentObj.value[key2]) &&
Object.keys(submitAppointmentObj.value[key2]).length == 0
) {
submitAppointmentObj.value[key2] = appointmentSummeryInfo.value[key1]
}
}
}
// 新增预约单
editAppointmentDetail(submitAppointmentObj.value).then(res => {
if (res.code == 200) {
getAppointmentInfo(idsObj.value.appointmentBizId)
appointmentInfoRef.value[0].handleEditStatus()
productPlanRef.value[0].handleEditStatus()
policyHolderInfoRef.value[0].handleEditStatus()
insuredInfoRef.value[0].handleEditStatus()
secondHolderInfoRef.value[0].handleEditStatus()
beneficiaryInfoRef.value[0].handleEditStatus()
policyTransferRef.value[0].handleEditStatus()
questionnairesInfoRef.value[0].handleEditStatus()
proxy.$message.success('修改预约单成功')
}
})
}
if (type == 'storage') {
submitAppointmentObj.value.apiAppointmentInfoDto.customerBizId =
props.processDetail.customerBizId
submitAppointmentObj.value.apiAppointmentInfoDto.fnaBizId = props.processDetail.fnaBizId
submitAppointmentObj.value.apiAppointmentInfoDto.fnaNo = props.processDetail.fnaNo
// 暂存预约单
storageAppointment(submitAppointmentObj.value).then(res => {
if (res.code == 200) {
proxy.$message.success('预约暂存成功')
router.push({ path: '/sign/appointment' })
}
})
}
}
//修改预约数据
if (route.query.appointmentNo) {
processInfo.value = route.query
idsObj.value.appointmentBizId = route.query.appointmentBizId
getDictsData()
// 请求预约单聚合详情
getAppointmentInfo(idsObj.value.appointmentBizId, true)
}
// 预约作为组件在别的地放提交成功后processDetail会改变,所以需要监听
watch(
() => props.processDetail,
newVal => {
idsObj.value = { ...newVal }
}
)
watch(
() => props.tabName,
newVal => {
if (newVal === 'appointment') {
// 这个页面作为组件在别的地方使用,所以需要判断是新增还是编辑
//props.editStatus == 'add'
//代表是新增预约状态
if (!idsObj.value.appointmentBizId) {
formStatus.value = 'appointmentAdd'
getCustomerInfo(props.processDetail.customerBizId)
// if (idsObj.value.appointmentBizId) {
// getAppointmentInfo(idsObj.value.appointmentBizId)
// }
tabsList.value = [
{
label: '预约信息',
name: 'appointmentInfo',
id: 1,
key: 'appointmentBizId'
},
{
label: '产品计划',
name: 'productPlan',
id: 2,
status: '0',
key: 'planBizId'
},
{
label: '投保人',
name: 'policyholder',
id: 3,
status: '0',
key: 'policyholderBizId'
},
{
label: '受保人',
name: 'insurantInfo',
id: 4,
status: '0',
key: 'insurantBizId'
},
{
label: '受益人',
name: 'beneficiary',
id: 4,
status: '0',
key: 'beneficiaryBizId'
},
{
label: '第二持有人',
name: 'secondHolder',
id: 5,
status: '0',
key: 'secondHolderBizId'
}
]
nextTick(() => {
activeName.value = 'appointmentInfo'
})
} else {
getAppointmentInfo(idsObj.value.appointmentBizId)
tabsList.value = [
{
label: '预约信息',
name: 'appointmentInfo',
id: 1,
key: 'appointmentBizId'
},
{
label: '产品计划',
name: 'productPlan',
id: 2,
status: '0',
key: 'planBizId'
},
{
label: '投保人',
name: 'policyholder',
id: 3,
status: '0',
key: 'policyholderBizId'
},
{
label: '受保人',
name: 'insurantInfo',
id: 4,
status: '0',
key: 'insurantBizId'
},
{
label: '受益人',
name: 'beneficiary',
id: 5,
status: '0',
key: 'beneficiaryBizId'
},
{
label: '第二持有人',
name: 'secondHolder',
id: 6,
status: '0',
key: 'secondHolderBizId'
},
{
label: '健康信息', //后端还没加这个字段
name: 'questionnaires',
id: 7,
status: '0',
key: 'questionnaireBizId'
},
{
label: '关联FNA',
name: 'fna',
id: 8,
status: '0',
key: 'fnaBizId'
},
{
label: '转保声明',
name: 'policyTransfer',
id: 9,
status: '0',
key: 'policyTransfer'
},
{
label: '附件', //大提交的时候不用提交了,因为上传文件的时候已经入库了
name: 'accessories',
id: 10,
status: '0',
key: 'fnaBizId'
}
]
}
nextTick(() => {
activeName.value = 'appointmentInfo'
})
}
}
)
onUnmounted(() => {
console.log('预约编辑页面完全销毁')
// 彻底重置所有响应式数据
submitAppointmentObj.value = {}
appointmentSummeryInfo.value = {}
customerInfo.value = {}
idsObj.value = {}
activeName.value = ''
formStatus.value = ''
// 强制清理数组
tabsList.value = []
// 清理所有 ref 引用
appointmentInfoRef.value = null
productPlanRef.value = null
policyHolderInfoRef.value = null
insuredInfoRef.value = null
secondHolderInfoRef.value = null
beneficiaryInfoRef.value = null
policyTransferRef.value = null
questionnairesInfoRef.value = null
// 清理事件监听器(如果有的话)
// window.removeEventListener('resize', yourHandler)
})
</script>
<style lang="scss" scoped>
::v-deep .el-card {
border: none !important;
}
::v-deep .el-input-group__append,
.el-input-group__prepend {
background-color: #fff !important;
}
.noembed-container {
padding: 20px;
background-color: #f2f3f5;
min-height: calc(100vh - 84.5px);
}
.embed-container {
min-height: calc(100vh - 317px);
}
.appointment-container {
display: flex;
flex-direction: column;
.cardHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
.left {
display: flex;
justify-content: flex-start;
align-items: center;
.iconBox {
width: 40px;
height: 40px;
margin-right: 5px;
background-color: #e8f3ff;
border-radius: 3px;
text-align: center;
padding: 5px;
}
.rightBox {
margin-left: 10px;
display: flex;
flex-direction: column;
.num {
font-size: 14px;
}
.bottom {
display: flex;
align-items: center;
margin-top: 3px;
.status {
font-size: 11px;
color: #00b42a;
background-color: #e8ffea;
padding: 4px 6px;
border-radius: 2px;
margin-right: 10px;
}
.time {
font-size: 12px;
color: #86909c;
.icon-yanqiweiwancheng {
margin-right: 5px;
font-size: 12px;
}
}
}
}
}
}
.tabsBox {
.topButtonBox {
width: 100%;
display: flex;
justify-content: flex-end;
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 20px;
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
}
.noEmbedTabPaneBox {
height: calc(100vh - 317px);
}
.yesEmbedTabPaneBox {
height: calc(100vh - 439px);
}
.appointmentTabPaneBox {
overflow-y: auto;
padding-right: 10px;
}
.overviewBox {
display: flex;
align-items: center;
justify-content: space-between;
.oneItem {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.circle {
width: 35px;
height: 35px;
box-sizing: border-box;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 5px;
}
.el-icon {
font-size: 16px;
font-weight: 600;
}
}
.finfishCircle {
background-color: #e8f3ff;
color: #165dff;
}
.todoCircle {
background-color: #165dff;
color: #fff;
}
.unFinishCircle {
background-color: #f2f3f5;
color: #4e5969;
}
.title {
font-size: 14px;
margin-bottom: 5px;
}
.finfishTitle {
color: #1d2129;
font-size: 14px;
}
.unFinishTitle {
color: #4e5969;
font-size: 13px;
}
.status {
font-size: 12px;
margin-bottom: 8px;
color: #86909c;
}
.finfishStatus {
color: #165dff;
}
.unFinishStatus {
color: #4e5969;
}
.operation {
display: flex;
align-items: center;
font-size: 12px;
.editIcon {
margin-right: 3px;
color: #165dff;
font-size: 12px;
}
}
.finfishOperation {
color: #4e5969;
}
.unFinishOperation {
color: #165dff;
}
}
}
</style>
<template>
<div>
<div v-if="processedAppointmentData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="appointmentInfoFormRef" :model="form" :rules="rules" label-width="120px">
<div v-for="father in processedAppointmentData">
<el-row style="margin-bottom: 10px" v-if="father.showMoudle">
<div class="formBox">
<div class="fatherLable">{{ father.fatherTitle }}</div>
<div class="fatherDes">{{ father.description }}</div>
<el-row :gutter="20">
<template v-for="child in father.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItemBox" v-if="child.show">
<div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="child.key"
:key="child.key"
:label-position="child.labelPosition"
class="button-form-item"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form[child.key]"
style="width: 100%"
v-if="child.domType === 'datetimePicker'"
type="datetime"
:placeholder="child.placeholder"
:disabled="child.disabled"
@change="handleDateChange(child)"
format="YYYY-MM-DD HH:mm"
value-format="YYYY-MM-DD HH:mm:ss"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
<el-button
class="formBtn"
v-if="child.domType === 'button'"
:type="child.buttonType"
@click="handleButtonClick(child)"
>{{ child.buttonTxt }}</el-button
>
</el-form-item>
<div v-if="child.domType === 'Div'" class="divClass">
<div v-if="child.key == 'information'" class="desBox">
<div class="title">{{ child.title }}</div>
<div class="informationBox">
<div v-for="(item, index) in child.informationList" :key="index">
{{ item.name }}
</div>
</div>
</div>
</div>
</div>
</el-col>
</template>
</el-row>
</div>
</el-row>
</div>
<el-row v-if="props.idsObj.appointmentBizId">
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row>
</el-form>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="appointmentInfo">
import { ArrowRight } from '@element-plus/icons-vue'
import appointmentDomData from '@/formJson/appointmentInfo'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { getCustomerDetail } from '@/api/sign/fna'
import { editAppointmentInfo, newPolicy } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiAppointmentInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerBizId: { type: String, default: '' } //提交状态,新增、修改
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const consultKey = ref({})
const openAccountKey = ref({})
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress'
]) // 存储需要删除的key
const data = reactive({
form: {},
processedAppointmentData: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, processedAppointmentData, queryParams, oldAppointmentData } = toRefs(data)
const handleButtonClick = child => {
if (child.key == 'newPolicyButton') {
let obj = {
appointmentBizId: props.idsObj.appointmentBizId,
confirmAppointmentTime: form.value.confirmAppointmentTime
}
newPolicy(obj).then(response => {
if (response.code == 200) {
proxy.$modal.msgSuccess('新单已生成')
emit('handleSuccessEdit')
}
})
}
}
const handleDateChange = child => {
if (child.key === 'confirmAppointmentTime' && form.value[child.key]) {
resetShow({ type: 'child', key: 'newPolicyButton', status: true })
} else if (child.key === 'confirmAppointmentTime' && !form.value[child.key]) {
resetShow({ type: 'child', key: 'newPolicyButton', status: false })
}
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
// options = item.dictItemList
if (dictType == 'sys_no_yes') {
item.dictItemList.forEach(item1 => {
item1.value = Number(item1.value)
})
}
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
// 处理表单配置,添加字典数据
const processFormData = async () => {
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(appointmentDomData))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (section.key == 'openAccount') {
openAccountKey.value[field.key] = field.key
}
if (section.key == 'consult') {
consultKey.value[field.key] = field.key
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (field.required) {
if (field.key === 'firstNamePinyin') {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' },
{ validator: validateEnglish, trigger: 'change' }
]
} else {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' }
]
}
}
}
}
}
if (props.idsObj.appointmentBizId) {
editStatus.value = true
setFormValue(props.apiAppointmentInfoDto, processedData)
} else {
editStatus.value = false
processedAppointmentData.value = processedData
}
}
//弹出右侧抽屉
const handleFoucs = child => {
if (child.disabled) return
console.log('saveKey.value', saveKey.value)
drawerInfo.value = JSON.parse(JSON.stringify(child))
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showPhoneDrawer.value = true
break
case 'address':
addressMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
console.log('drawerInfo.value', drawerInfo.value)
let newObj = info[drawerInfo.value.key]
console.log('newObj', newObj)
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
newObj.objType = drawerInfo.value.drawerType
// 因为电话有多个,根据点击的电话类型在抽屉里回显,所以要用drawerInfo.value.code来控制
form.value[info.key] = `${newObj[drawerInfo.value.code]} ${newObj[drawerInfo.value.key]}`
saveKey.value[drawerInfo.value.key] = newObj
break
case 'address':
newObj.objType = drawerInfo.value.drawerType
newObj.type = drawerInfo.value.key
form.value[info.key] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
saveKey.value[info.key] = newObj
break
case 'country':
info.objType = drawerInfo.value.drawerType
form.value[drawerInfo.value.key] = info.name
saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of processedAppointmentData.value) {
if (obj.type == 'father' && section.key == obj.key) {
section.showMoudle = obj.status
// if (!obj.status) {
// if (section.data) {
// for (const field of section.data) {
// form.value[field.key] = ''
// }
// }
// }
} else if (obj.type == 'child') {
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
// if (!obj.status) {
// form.value[obj.key] = ''
// }
}
}
}
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'isAccompany':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'father', key: 'consult', status: true })
} else {
resetShow({ type: 'father', key: 'consult', status: false })
}
break
case 'isOpenAccount':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'father', key: 'openAccount', status: true })
} else {
resetShow({ type: 'father', key: 'openAccount', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedAppointmentData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
processedAppointmentData.value = processedData
}
//给表单赋值 方便表单回显 obj 为表单数据
const setFormValue = (obj, formData) => {
let tempPhoneList = []
let tempAddressList = []
addressQuickList.value = []
phoneQuickList.value = []
// 深拷贝原始数据
form.value = JSON.parse(JSON.stringify(obj))
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(formData))
for (const section of processedData) {
if (obj.isOpenAccount === 1 && section.key == 'openAccount') {
section.showMoudle = true
}
if (obj.isAccompany === 1 && section.key == 'consult') {
section.showMoudle = true
}
if (section.data) {
for (const field of section.data) {
if (field.key == 'confirmAppointmentTime' && props.appointmentStatus !== 0) {
field.show = true
}
if (obj.confirmAppointmentTime && field.key == 'newPolicyButton') {
field.show = true
}
if (props.apiAppointmentInfoDto.appointmentBizId) {
field.disabled = true
} else {
field.disabled = false
}
//要判断drawerType,因为抽屉要回显数据
switch (field.drawerType) {
case 'phone':
let phoneObj = {}
for (const key1 in field) {
for (const key2 in obj) {
if (key1 !== 'drawerType' && field[key1] == key2) {
if (key1 == 'code' && obj[key2]) {
phoneObj[field[key1]] = obj[key2].includes('+') ? obj[key2] : `+${obj[key2]}`
} else {
phoneObj[field[key1]] = obj[key2]
}
}
}
}
if (phoneObj[field.key]) {
phoneObj.phoneString = form.value[field.key] = `${phoneObj[field.code]} ${
phoneObj[field.key]
}`
tempPhoneList.push(phoneObj)
}
phoneObj.objType = field.drawerType
phoneObj.key = field.key
phoneObj.phoneCode = field.code
saveKey.value[field.key] = phoneObj
break
case 'address':
let addressObj = null
for (const key1 in field) {
if (obj.addressList && obj.addressList.length > 0) {
obj.addressList.forEach(item => {
if (key1 == item.type) {
addressObj = item
}
})
}
}
if (addressObj) {
form.value[
field.key
] = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.addressString = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.objType = field.drawerType
saveKey.value[field.key] = addressObj
if (tempAddressList.length > 0) {
tempAddressList.forEach(item => {
if (item.addressString !== addressObj.addressString) {
tempAddressList.push(addressObj)
}
})
} else {
tempAddressList.push(addressObj)
}
}
break
case 'country':
form.value[field.key] = obj.countryName
saveKey.value[field.key] = {
country: obj.country || '',
countryCode: obj.country || '',
countryName: obj.countryName || '',
name: obj.countryName || '',
objType: field.drawerType
}
break
default:
break
}
}
}
}
addressQuickList.value = tempAddressList
tempPhoneList.forEach(item => {
for (const key in saveKey.value) {
if (item.key == key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.mobile = saveKey.value[key][key2]
}
if (item.phoneCode == key2) {
item.code = saveKey.value[key][key2]
}
}
}
}
})
phoneQuickList.value = removeDuplicates(tempPhoneList, 'phoneString')
addressQuickList.value = removeDuplicates(tempAddressList, 'addressString')
processedAppointmentData.value = oldAppointmentData.value = processedData
oldObjInfo.value = JSON.parse(JSON.stringify(form.value))
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (!seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = { ...form.value }
const pattern = /Time$/ // 以Time结尾
//处理表单数据
for (const key1 in form.value) {
// 不开户去除开户相关信息
if (key1 == 'isOpenAccount' && form.value[key1] === 0) {
for (const key4 in openAccountKey.value) {
delete submitObj[key4]
}
}
// 没顾问去除顾问相关信息
if (key1 == 'isAccompany' && form.value[key1] === 0) {
for (const key5 in consultKey.value) {
delete submitObj[key5]
}
}
if (pattern.test(key1) && form.value[key1]) {
submitObj[key1] = proxy.formatToDateTime(form.value[key1])
}
for (const key2 in saveKey.value) {
//要判断drawerType
switch (saveKey.value[key2].objType) {
case 'phone':
if (key1 == key2) {
for (const key3 in saveKey.value[key2]) {
submitObj[key3] = saveKey.value[key2][key3]
}
}
break
case 'address':
if (key1 == key2) {
addressList.push(saveKey.value[key2])
}
break
case 'country':
if (key1 == key2) {
submitObj['country'] = saveKey.value[key2]['countryCode']
submitObj['countryName'] = saveKey.value[key2]['name']
}
break
default:
break
}
}
}
return submitObj
}
// 表单提交
const submitForm = () => {
// return
proxy.$refs['appointmentInfoFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
editAppointmentInfo(submitObj).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('预约信息修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
form.value = { ...oldObjInfo.value }
editStatus.value = true
processedAppointmentData.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
proxy.$refs['appointmentInfoFormRef'].resetFields()
})
.catch(() => {})
}
// 获取流程详情
function getCustomerInfo(customerBizId, formData) {
getCustomerDetail(customerBizId).then(async res => {
if (res.code == 200) {
// 回显值
setFormValue(res.data, formData)
}
})
}
watch(
() => props.activeName,
newVal => {
if (newVal === 'appointmentInfo') {
openList.value = false
setTimeout(() => {
processFormData()
}, 500)
}
}
)
watch(
() => props.formStatus,
newVal => {
if (newVal === 'appointmentEdit') {
openList.value = false
processFormData()
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
.title {
width: 120px;
font-size: 14px;
text-align: left;
margin-bottom: 10px;
color: #606266;
font-weight: 700;
}
.informationBox {
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
.infoItem {
display: flex;
align-items: center;
margin: 5px 0;
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
@media only screen and (min-width: 768px) {
.formBtn {
margin-top: 0 !important;
}
}
@media only screen and (min-width: 1200px) {
.formBtn {
margin-top: 30px !important;
}
}
</style>
<template>
<div>
<div v-if="processedBeneficiaryData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
type="warning"
icon="DocumentAdd"
@click="addBeneficiary"
:disabled="editStatus"
>新增受益人</el-button
>
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="beneficiaryInfoFormRef" :model="form" label-width="120px">
<div v-for="(level1, l1) in processedBeneficiaryData" :key="level1.id">
<el-row style="margin-bottom: 10px">
<div class="formBox">
<div class="level1Label">
<span>{{ level1.bigTitle }}-{{ l1 + 1 }}</span>
<el-icon
@click="deleteBeneficiary(l1, level1)"
v-if="level1.deleteIcon && processedBeneficiaryData.length > 1"
style="color: red; font-size: 18px; margin-left: 10px"
><Delete
/></el-icon>
</div>
<div v-for="(level2, l2) in level1.children" :key="level2.key">
<div class="fatherLable" v-if="level2.showMoudle">{{ level2.fatherTitle }}</div>
<el-row :gutter="20" v-if="level2.showMoudle">
<template v-for="child in level2.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItem" v-if="child.show">
<div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="`apiBeneficiaryInfoDtoList.${l1}.${child.key}`"
:key="child.key"
:label-position="child.labelPosition"
:rules="
child.required
? [
{
required: true,
message: `${child.label}不能为空`,
trigger: 'blur'
}
]
: []
"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form['apiBeneficiaryInfoDtoList'][l1][child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form['apiBeneficiaryInfoDtoList'][l1][child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(child, l1, l2)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form['apiBeneficiaryInfoDtoList'][l1][child.key]"
style="width: 100%"
v-if="child.domType === 'DatePicker'"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
:disabled-date="disabledDate"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form['apiBeneficiaryInfoDtoList'][l1][child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child, l1, level1)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
</el-form-item>
</div>
</el-col>
</template>
</el-row>
</div>
</div>
</el-row>
</div>
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<el-dialog title="联系人信息" v-model="openList" width="600px" append-to-body>
<div>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="85px">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" @input="customerList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" circle @click="customerList" />
<el-button type="info" icon="Refresh" circle @click="resetCustomerList" />
</el-form-item>
</el-form>
<div class="customerBox">
<div class="customerItem" v-for="item in tableData" :key="item.id">
<div class="top">
<div class="right">
<el-button type="primary" size="small" @click="handleExport(item)"
>导入联系人</el-button
>
</div>
</div>
<div class="bottom">
<div class="left">
<div class="infoItem">
<span>姓名:</span>
<span> {{ item.name || '暂无' }}</span>
</div>
<div class="infoItem">
<span>性别:</span>
<span>
<dict-tag :options="fetchDictData('sys_gender')" :value="item.gender"
/></span>
</div>
<div class="infoItem">
<span>年龄:</span>
<span> {{ item.age || '暂无' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="beneficiaryInfo">
import { ArrowRight } from '@element-plus/icons-vue'
import beneficiaryDomData from '@/formJson/beneficiary'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { addCustomer, getCustomerDetail, editCustomer, getCustomerList } from '@/api/sign/fna'
import { editBeneficiaryInfo, delBeneficiary } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiBeneficiaryInfoDtoList: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerInfo: { type: Object, default: () => ({}) } //客户详情回显表单用
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { sys_gender } = proxy.useDict('sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tempSaveKey = ref({}) // 用于tab切换的时候保存一份临时的值,防止切换的时候数据丢失
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const phoneOraddressKey = ref([]) // 存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tableLoading = ref(false)
const tableData = ref([])
const total = ref(0)
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const tempAddressQuickList = ref([])
const tempPhoneQuickList = ref([])
const personalObj = ref({}) //存储个人key
const companyObj = ref({}) //存储公司key
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress',
'txAddress',
'companyEnterAddress',
'phoneString',
'phoneCode'
]) // 存储需要删除的key
const data = reactive({
form: { apiBeneficiaryInfoDtoList: [] },
tempBeneficiaryForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
processedBeneficiaryData: [], // 处理后的表单数据
tempBeneficiaryDomData: [], //保存旧的表单Dom,便于撤销操作
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const {
form,
rules,
processedBeneficiaryData,
queryParams,
oldAppointmentData,
tempBeneficiaryForm,
tempBeneficiaryDomData
} = toRefs(data)
// 新增受益人
const addBeneficiary = () => {
let oneMoudle = JSON.parse(JSON.stringify(processedBeneficiaryData.value[0]))
oneMoudle.id = Date.now() + Math.floor(Math.random() * 1000) //唯一标识,用于删除
processedBeneficiaryData.value.push(oneMoudle)
form.value.apiBeneficiaryInfoDtoList.push({ id: oneMoudle.id })
}
// 删除受益人
const deleteBeneficiary = (l1, level1) => {
if (editStatus.value) {
proxy.$modal.confirm(`编辑状态下才能删除`, { showCancel: '0', title: '填写提示' })
return
}
if (processedBeneficiaryData.value.length == 1) {
proxy.$modal.confirm(`至少保留一个受益人`, { showCancel: '0', title: '填写提示' })
return
}
if (level1.beneficiaryBizId) {
delBeneficiary(level1.beneficiaryBizId).then(res => {
if (res.code == 200) {
proxy.$message.success('受益人删除成功')
processedBeneficiaryData.value.splice(l1, 1)
form.value.apiBeneficiaryInfoDtoList.splice(l1, 1)
}
})
} else {
proxy.$message.success('受益人删除成功')
processedBeneficiaryData.value.splice(l1, 1)
form.value.apiBeneficiaryInfoDtoList.splice(l1, 1)
}
}
const disabledDate = time => {
return time.getTime() > Date.now()
}
const exportInfo = () => {
if (props.customerBizId && editStatus.value) {
proxy.$modal.confirm(`请先点击编辑在导入客户信息`, { showCancel: '0', title: '填写提示' })
return
}
openList.value = true
customerList()
}
const customerList = () => {
console.log('触发了')
tableLoading.value = true
getCustomerList(queryParams.value).then(res => {
if (res.code == 200) {
tableData.value = res.data.records
total.value = res.data.total
tableLoading.value = false
}
})
}
const resetCustomerList = () => {
queryParams.value = {
pageNo: 1,
pageSize: 4,
name: undefined
}
customerList()
}
// 从客户列表中导入客户信息到当前表单
const handleExport = row => {
oldObjInfo.value = JSON.parse(JSON.stringify(form.value)) // 修改时存储原始数据,便于撤销操作
processFormData({
domdata: processedBeneficiaryData.value,
customerInfo: row,
exportValue: true
})
openList.value = false
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const item of processedData) {
if (tempBeneficiaryDomData.value.length == 0) {
form.value.apiBeneficiaryInfoDtoList.push({ id: item.id })
}
if (item.children) {
for (const section of item.children) {
if (section.data) {
for (const field of section.data) {
if (section.key == 'customer' || section.key == 'other') {
personalObj.value[field.key] = field.key
companyObj.value[field.key] = field.key
}
// 收集key,区分个人和企业
if (section.key == 'person') {
personalObj.value[field.key] = field.key
} else if (section.key == 'company') {
companyObj.value[field.key] = field.key
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
// if (props.idsObj.appointmentBizId) {
// field.disabled = true
// } else {
// field.disabled = false
// }
}
}
}
}
}
if (tempBeneficiaryDomData.value.length > 0 && !props.idsObj.appointmentBizId) {
form.value = { ...tempBeneficiaryForm.value }
saveKey.value = { ...tempSaveKey.value }
addressQuickList.value = JSON.parse(JSON.stringify(tempAddressQuickList.value))
phoneQuickList.value = JSON.parse(JSON.stringify(tempPhoneQuickList.value))
processedBeneficiaryData.value = JSON.parse(JSON.stringify(tempBeneficiaryDomData.value))
} else {
processedBeneficiaryData.value = oldAppointmentData.value = processedData
}
if (props.idsObj.appointmentBizId) {
editStatus.value = true
} else {
editStatus.value = false
processedBeneficiaryData.value = oldAppointmentData.value = processedData
}
}
//弹出右侧抽屉
const handleFoucs = (child, l1, level1) => {
if (child.disabled) return
child.l1 = l1
child.id = level1.id
drawerInfo.value = JSON.parse(JSON.stringify(child))
console.log('drawerInfo', drawerInfo.value)
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
item.value = ''
})
let phoneString = form.value.apiBeneficiaryInfoDtoList[l1][child.key]
if (phoneString) {
phoneMenuList.value[0].value = phoneString.split(' ')[0]
phoneMenuList.value[1].value = phoneString.split(' ')[1]
}
showPhoneDrawer.value = true
break
case 'address':
console.log('2222', phoneOraddressKey.value)
addressMenuList.value.forEach(item => {
item.value = ''
phoneOraddressKey.value.forEach(item1 => {
if (item1.id == level1.id && item1.type == child.key) {
for (const key in item1) {
if (item.key == key) {
item.value = item1[key]
}
}
}
})
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
let newObj = info[drawerInfo.value.key]
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
form.value.apiBeneficiaryInfoDtoList[drawerInfo.value.l1][drawerInfo.value.key] = `${
newObj[drawerInfo.value.code]
} ${newObj[drawerInfo.value.key]}`
break
case 'address':
//因为可以添加多个受益人,所以需要判断是哪个受益人,一定要有id
newObj.type = drawerInfo.value.key
newObj.id = drawerInfo.value.id
newObj.drawerType = drawerInfo.value.drawerType
form.value.apiBeneficiaryInfoDtoList[drawerInfo.value.l1][
drawerInfo.value.key
] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
// 检查数组中是否已存在相同ID的地址
const existingIndex = phoneOraddressKey.value.findIndex(
item => item.id === newObj.id && item.type === newObj.type
)
if (existingIndex !== -1) {
// 更新已存在的地址
phoneOraddressKey.value[existingIndex] = { ...newObj }
} else {
// 添加新地址
phoneOraddressKey.value.push({ ...newObj })
}
break
case 'country':
// info.objType = drawerInfo.value.drawerType
// form.value[drawerInfo.value.key] = info.name
// saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of processedBeneficiaryData.value) {
switch (obj.type) {
case 'father':
if (section.key == obj.key) {
section.showMoudle = obj.status
}
break
case 'child':
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
}
}
}
break
default:
break
}
}
}
const handleSelectChange = (child, l1, l2) => {
let customerType = form.value['apiBeneficiaryInfoDtoList'][l1]['customerType']
let insurantRel = form.value['apiBeneficiaryInfoDtoList'][l1]['insurantRel']
switch (child.key) {
case 'customerType':
const newDOM = JSON.parse(JSON.stringify(processedBeneficiaryData.value))
//这里存在一个对index得问题,暂不解决先放在这
for (const section of newDOM[l1].children) {
if (
(customerType == 'COMPANY' || customerType == 'INDIVIDUAL') &&
insurantRel &&
insurantRel == 'MYSELF' &&
section.key == 'customer'
) {
section.showMoudle = true
} else if (customerType == 'COMPANY' && insurantRel && insurantRel !== 'MYSELF') {
if (section.key == 'person') {
section.showMoudle = false
} else {
section.showMoudle = true
}
} else if (customerType == 'INDIVIDUAL' && insurantRel && insurantRel !== 'MYSELF') {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
} else if (customerType == 'COMPANY' && !insurantRel) {
if (section.key == 'company') {
section.showMoudle = true
} else if (section.key == 'person') {
section.showMoudle = false
}
} else if (customerType == 'INDIVIDUAL' && !insurantRel) {
if (section.key == 'company') {
section.showMoudle = false
} else if (section.key == 'person') {
section.showMoudle = true
}
}
}
processedBeneficiaryData.value = newDOM
break
case 'insurantRel':
const newDOM1 = JSON.parse(JSON.stringify(processedBeneficiaryData.value))
for (const child of newDOM1[l1].children) {
if (insurantRel == 'MYSELF') {
if (child.key == 'customer') {
child.showMoudle = true
} else {
child.showMoudle = false
}
} else {
if (customerType == 'COMPANY') {
if (child.key == 'company') {
child.showMoudle = true
} else if (child.key == 'person') {
child.showMoudle = false
}
} else {
if (child.key == 'company') {
child.showMoudle = false
} else {
child.showMoudle = true
}
}
}
}
processedBeneficiaryData.value = newDOM1
break
case 'smokingAllowed':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'smokingVolume', status: true })
} else {
resetShow({ type: 'child', key: 'smokingVolume', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedBeneficiaryData.value))
for (const section of processedData) {
for (const child of section.children) {
for (const field of child.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
processedBeneficiaryData.value = processedData
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (item[key] && !seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 修改状态下,处理表单数据
const setFormValue = () => {
personalObj.value = {}
companyObj.value = {}
processedBeneficiaryData.value = []
let quickMobile = []
let qucikAddress = []
// 深拷贝原始数据
const oldDom = JSON.parse(JSON.stringify(beneficiaryDomData))
// 先收集key,区分个人和企业
for (const item of oldDom) {
if (props.apiBeneficiaryInfoDtoList.length == 0) {
form.value.apiBeneficiaryInfoDtoList.push({ id: item.id })
}
if (item.children) {
for (const section of item.children) {
if (section.data) {
for (const field of section.data) {
if (section.key == 'customer' || section.key == 'other') {
personalObj.value[field.key] = field.key
companyObj.value[field.key] = field.key
}
// 收集key,区分个人和企业
if (section.key == 'person') {
personalObj.value[field.key] = field.key
} else if (section.key == 'company') {
companyObj.value[field.key] = field.key
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
}
}
}
}
}
}
let newInfoList = JSON.parse(JSON.stringify(props.apiBeneficiaryInfoDtoList))
// 详情中有数据,dom应该根据详情中的数据来渲染
if (newInfoList.length > 0) {
let newDOM1 = JSON.parse(JSON.stringify(oldDom))
newInfoList.forEach((info, index) => {
for (const item of newDOM1) {
if (item.children) {
for (const section of item.children) {
// 根据选择得客户类型和与受保人关系,展示对应的模块
if (
(info.customerType == 'COMPANY' || info.customerType == 'INDIVIDUAL') &&
info.insurantRel &&
info.insurantRel == 'MYSELF' &&
section.key == 'customer'
) {
section.showMoudle = true
} else if (
info.customerType == 'COMPANY' &&
info.insurantRel &&
info.insurantRel !== 'MYSELF'
) {
if (section.key == 'person') {
section.showMoudle = false
} else {
section.showMoudle = true
}
} else if (
info.customerType == 'INDIVIDUAL' &&
info.insurantRel &&
info.insurantRel !== 'MYSELF'
) {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
}
}
}
let phone = JSON.parse(JSON.stringify(info))
if (info.authMobile) {
quickMobile.push({
code: phone.authMobileCode,
mobile: phone.authMobile,
phoneString: `${phone.authMobileCode} ${phone.authMobile}`
})
info.authMobile = `${info.authMobileCode} ${info.authMobile}`
}
if (info.companyMobile) {
quickMobile.push({
code: phone.companyMobileCode,
mobile: phone.companyMobile,
phoneString: `${phone.companyMobileCode} ${phone.companyMobile}`
})
info.companyMobile = `${info.companyMobileCode} ${info.companyMobile}`
}
if (info.addressList && info.addressList.length > 0) {
info.addressList.forEach(address => {
if (address.type == 'companyEnterAddress') {
info.companyEnterAddress = `${address.region} ${address.city} ${address.street} ${address.location}`
}
if (address.type == 'txAddress') {
info.txAddress = `${address.region} ${address.city} ${address.street} ${address.location}`
}
qucikAddress.push({
...address,
id: info.id,
drawerType: 'address',
addressString: `${address.region} ${address.city} ${address.street} ${address.location}`
})
})
}
processedBeneficiaryData.value.push({
...newDOM1[0],
id: info.id,
beneficiaryBizId: info.beneficiaryBizId
})
})
form.value.apiBeneficiaryInfoDtoList = newInfoList
phoneQuickList.value = removeDuplicates(quickMobile, 'phoneString')
phoneOraddressKey.value = qucikAddress
addressQuickList.value = removeDuplicates(qucikAddress, 'addressString')
} else {
processedBeneficiaryData.value.push(oldDom[0]) // 详情中没有数据 ,dom应该根据默认数据来渲染
}
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
//提交的时候记得填写区号的电话,把相对应的区号字段加上
//地址相关的还没处理
let submitForm = []
let result = {}
if (props.activeName == 'beneficiary') {
result = JSON.parse(JSON.stringify(form.value))
} else {
result = JSON.parse(JSON.stringify(tempBeneficiaryForm.value))
}
const pattern = /Time$/ // 以Time结尾
for (const section of result['apiBeneficiaryInfoDtoList']) {
let submitObj = {}
if (phoneOraddressKey.value.length > 0) {
submitObj.addressList = []
}
for (const key in section) {
if (pattern.test(key) && section[key]) {
section[key] = proxy.formatToDateTime(section[key])
}
if (section['customerType'] == 'COMPANY') {
for (const key1 in companyObj.value) {
if (key == key1 && section[key]) {
submitObj[key1] = section[key]
}
if (key == 'companyMobile' && section[key]) {
submitObj[key] = section[key].split(' ')[1]
submitObj['companyMobileCode'] = section[key].split(' ')[0]
}
if (key == 'authMobile' && section[key]) {
submitObj[key] = section[key].split(' ')[1]
submitObj['authMobileCode'] = section[key].split(' ')[0]
}
}
}
if (section['customerType'] == 'INDIVIDUAL' && section[key]) {
for (const key1 in personalObj.value) {
if (key == key1) {
submitObj[key1] = section[key]
}
}
}
}
phoneOraddressKey.value.forEach(item => {
if (item.drawerType == 'address' && item.id === section.id) {
submitObj.addressList.push({
type: item.type,
location: item.location,
street: item.street,
city: item.city,
region: item.region
})
}
})
deleteKeyList.value.forEach(item => {
delete submitObj[item]
})
if (Object.keys(submitObj).length > 0) {
submitForm.push(submitObj)
}
}
console.log('====================================')
console.log('受益人', submitForm)
console.log('====================================')
// 删除多余字段
return submitForm
}
// 表单提交
const submitForm = () => {
console.log('form.value', form.value)
proxy.$refs['beneficiaryInfoFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
editBeneficiaryInfo({
appointmentBizId: props.idsObj.appointmentBizId,
apiBeneficiaryInfoDtoList: submitObj
}).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('受益人修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
if (props.customerBizId) {
form.value = { ...oldObjInfo.value }
editStatus.value = true
} else {
// resetShow('smokeQuantity', false)
proxy.$refs['beneficiaryInfoFormRef'].resetFields()
}
processedBeneficiaryData.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
})
.catch(() => {})
}
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
tempBeneficiaryForm.value = { ...form.value }
tempSaveKey.value = { ...saveKey.value }
tempAddressQuickList.value = JSON.parse(JSON.stringify(addressQuickList.value))
tempPhoneQuickList.value = JSON.parse(JSON.stringify(phoneQuickList.value))
tempBeneficiaryDomData.value = JSON.parse(JSON.stringify(processedBeneficiaryData.value))
if (newVal === 'beneficiary') {
openList.value = false
setTimeout(() => {
// 修改状态
if (props.idsObj.appointmentBizId) {
setFormValue()
} else {
// 新增状态
processFormData({
domdata: beneficiaryDomData,
exportValue: null
})
}
}, 500)
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.level1Label {
font-size: 18px;
margin: 15px 0;
display: flex;
align-items: center;
}
.fatherLable {
font-size: 15px;
border-left: 4px solid #165dff;
padding-left: 5px;
margin-bottom: 10px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
display: flex;
justify-content: flex-start;
.title {
width: 120px;
font-size: 14px;
text-align: right;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template>
<!-- :limit="limit" :on-exceed="handleExceed"-->
<div>
<div class="fileUploadBox">
<el-upload
:action="uploadImgUrl"
:headers="headers"
:show-file-list="false"
:on-success="uploadSuccess"
:before-upload="handleBeforeUpload"
>
<div class="uploadBox">
<el-icon size="20"><DocumentAdd /></el-icon>
<div class="file">选择文件</div>
</div>
</el-upload>
</div>
<div class="tip">(支持Word,Excel,PDF,图片格式)</div>
<el-table v-loading="loading" :data="fileTableList">
<!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="序号" type="index" width="50" />
<el-table-column label="文件名" align="center" prop="fileName" width="200" />
<!-- sortable -->
<el-table-column label="上传时间" align="center" prop="createTime" width="200">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="上传人" align="center" prop="creatorName" />
<el-table-column label="文件类型" align="center" prop="fileType" />
<el-table-column
label="操作"
align="left"
width="250"
class-name="small-padding fixed-width"
fixed="right"
>
<template #default="scope">
<el-button type="primary" link @click="downloadFile(scope.row)">下载</el-button>
<el-button
v-if="isImageFile(scope.row.fileName)"
type="primary"
link
@click="handleView(scope.row)"
>
查看
</el-button>
<el-button type="primary" link @click="handleUpdate(scope.row)">修改</el-button>
<el-button type="danger" link @click="handleDetele(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total >= 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getFileList"
/>
<!-- 图片查看器 -->
<el-dialog v-model="imageViewerVisible" title="图片预览" width="60%">
<div style="text-align: center">
<el-image :src="imageUrl" fit="contain" />
</div>
</el-dialog>
</div>
</template>
<script setup name="FileUpload">
import { getToken } from '@/utils/auth'
import { ElLoading } from 'element-plus'
import { addFile, getAppointmentFile, delFile } from '@/api/sign/appointment'
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiAppointmentInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number } //父组件传递过来的预约的状态
})
const { proxy } = getCurrentInstance()
const loading = ref(true)
const total = ref(0)
const fileTableList = ref([])
const limit = ref(2)
const fileSize = ref(10)
const headers = ref({ Authorization: 'Bearer ' + getToken() })
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + '/oss/api/oss/upload') // 上传的服务器地址
// 图片查看相关状态
const imageViewerVisible = ref(false)
const imageUrl = ref('')
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 4,
startTime: '',
endTime: '',
appointmentBizId: props.idsObj.appointmentBizId
}
})
const { queryParams, form } = toRefs(data)
const handleDetele = row => {
proxy.$modal
.confirm('是否确认删除名称为"' + row.fileName + '"的文件?')
.then(function () {
return delFile(row.appointmentFileBizId)
})
.then(res => {
if (res.code == 200) {
proxy.$modal.msgSuccess('删除成功')
getFileList()
}
})
.catch(() => {})
}
const isImageFile = fileName => {
return /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(fileName || '')
}
const handleUpdate = row => {}
const handleView = row => {
imageUrl.value = row.fileUrl
imageViewerVisible.value = true
}
const downloadFile = row => {
// 创建隐藏的下载链接
const link = document.createElement('a')
link.href = row.fileUrl
link.target = '_blank' // 新窗口打开
// 设置下载文件名(重要)
// 从URL中提取文件名,或者使用返回的文件名
const fileName = row.fileName
link.download = fileName
// 触发下载
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// const downloadFile = async row => {
// try {
// if (!row.fileUrl) {
// proxy.$modal.msgError('文件链接不存在')
// return
// }
// // 显示加载状态
// const loadingInstance = ElLoading.service({
// lock: true,
// text: '文件下载中...',
// background: 'rgba(0, 0, 0, 0.7)'
// })
// try {
// const response = await fetch(row.fileUrl)
// if (!response.ok) {
// throw new Error(`服务器响应错误: ${response.status}`)
// }
// const blob = await response.blob()
// const url = window.URL.createObjectURL(blob)
// const link = document.createElement('a')
// link.href = url
// link.download = row.fileName || extractFileName(row.fileUrl, row.fileName)
// link.style.display = 'none'
// document.body.appendChild(link)
// link.click()
// // 清理资源
// setTimeout(() => {
// document.body.removeChild(link)
// window.URL.revokeObjectURL(url)
// }, 100)
// proxy.$modal.msgSuccess('文件已开始下载')
// } finally {
// loadingInstance.close()
// }
// } catch (error) {
// console.error('下载失败:', error)
// // 如果fetch方式失败,尝试直接链接方式
// try {
// const link = document.createElement('a')
// link.href = row.fileUrl
// link.download = row.fileName || extractFileName(row.fileUrl, row.fileName)
// link.target = '_blank'
// link.style.display = 'none'
// document.body.appendChild(link)
// link.click()
// setTimeout(() => {
// document.body.removeChild(link)
// }, 100)
// proxy.$modal.msgSuccess('已尝试开始下载')
// } catch (fallbackError) {
// proxy.$modal.msgError('下载失败,请检查网络连接')
// }
// }
// }
// // 文件名处理函数
// const extractFileName = (url, fallbackName) => {
// if (fallbackName) return fallbackName
// try {
// const urlObj = new URL(url)
// const pathname = urlObj.pathname
// const filename = pathname.substring(pathname.lastIndexOf('/') + 1)
// return decodeURIComponent(filename) || `file_${Date.now()}`
// } catch {
// const parts = url.split('/')
// const lastPart = parts[parts.length - 1]
// return lastPart.split('?')[0] || `file_${Date.now()}`
// }
// }
// 上传前loading加载
function handleBeforeUpload(file) {
// if (file.name.includes(',')) {
// proxy.$modal.msgError('文件名不正确,不能包含英文逗号!')
// return false
// }
const isLt = file.size / 1024 / 1024 < fileSize.value
if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${fileSize.value} MB!`)
return false
}
// proxy.$modal.loading('正在上传文件,请稍候...')
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`一次只能上传${limit.value}个文件!`)
}
const uploadSuccess = res => {
console.log('上传成功', res)
if (res.code == 200) {
if (props.idsObj.appointmentBizId) {
let submitObj = {
appointmentBizId: props.idsObj.appointmentBizId,
fileUrl: res.data.url,
fileName: res.data.originalName,
ossFileBizId: res.data.fileBizId
}
addFile(submitObj).then(res => {
if (res.code == 200) {
proxy.$message.success('文件上传成功')
queryParams.value.pageNo = 1
getFileList()
// emit('handleSuccessEdit')
}
})
}
}
}
const getFileList = () => {
loading.value = true
try {
getAppointmentFile(queryParams.value).then(response => {
total.value = response.data.total
fileTableList.value = response.data.records
if (fileTableList.value.length > 0) {
for (const item of fileTableList.value) {
item.fileType = '预约文件'
}
}
loading.value = false
})
} catch (error) {
fileTableList.value = []
} finally {
loading.value = false
}
}
watch(
() => props.activeName,
newVal => {
if (newVal === 'accessories') {
queryParams.value.pageNo = 1
getFileList()
}
}
)
</script>
<style lang="scss" scoped>
.fileUploadBox {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
padding: 20px 0;
border: 1px dashed #dcdfe6;
}
.uploadBox {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.file {
font-size: 14px;
margin-top: 10px;
color: #409eff;
}
}
.tip {
font-size: 14px;
color: #909399;
margin: 10px 0 20px 0;
}
</style>
<template>
<div>
<el-table
v-loading="loading"
:data="tenantList"
@selection-change="tableSelect"
@sort-change="sortChange"
>
<!-- <el-table-column type="selection" width="55" /> -->
<el-table-column type="index" width="50" />
<el-table-column label="流程编号" align="center" prop="fnaNo" width="200" />
<el-table-column label="预约编号" align="center" prop="appointmentNo" />
<el-table-column label="新单编号" align="center" prop="policyId" />
<el-table-column label="保单号" align="center" prop="policyNo" width="150" />
<el-table-column label="客户姓名" align="center" prop="customerName" width="100" />
<el-table-column label="状态" align="center" width="150">
<template #default="scope">
<span v-if="scope.row.status == 'UNCOMPLETED'">
<span style="color: #ff7d00" class="iconfont icon-yanqiweiwancheng"></span> 未完成
</span>
<span v-if="scope.row.status == 'COMPLETED'"
><span style="color: #43cf7c" class="iconfont icon-yiwancheng"></span> 已完成
</span>
<span v-if="scope.row.status == 'DRAFT'"
><span style="color: #86909c" class="iconfont icon-genjinjilu"></span> 草稿
</span>
</template>
</el-table-column>
<el-table-column label="创建时间" sortable align="center" prop="createTime" width="150">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="250"
class-name="small-padding fixed-width"
fixed="right"
>
<template #default="scope">
<el-button type="primary" link @click="handleView(scope.row)">查看</el-button>
<el-button type="primary" link @click="handleLian">重新关联</el-button>
<el-button type="danger" link @click="handleUnlink(scope.row)">解除关联</el-button>
</template>
</el-table-column>
</el-table>
<div class="bottomBtn">
<el-button type="primary" @click="handleLian">关联FNA</el-button>
</div>
<el-dialog title="FNA列表" v-model="dialogVisible" width="70%">
<!-- 条件查询 -->
<el-row>
<el-col :span="24">
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="70px"
>
<el-form-item label="客户姓名" prop="customerName">
<el-input
v-model="queryParams.customerName"
placeholder="请输入姓名"
clearable
style="width: 140px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="fnaList"
@selection-change="tableSelect"
@sort-change="sortChange"
@row-click="rowClick"
>
<!-- <el-table-column type="selection" width="55" /> -->
<el-table-column type="index" width="50" />
<el-table-column label="流程编号" align="center" prop="fnaNo" width="200" />
<el-table-column label="预约编号" align="center" prop="appointmentNo" />
<el-table-column label="新单编号" align="center" prop="policyId" />
<el-table-column label="保单号" align="center" prop="policyNo" width="150" />
<el-table-column label="客户姓名" align="center" prop="customerName" width="100" />
<el-table-column label="状态" align="center" width="150">
<template #default="scope">
<span v-if="scope.row.status == 'UNCOMPLETED'">
<span style="color: #ff7d00" class="iconfont icon-yanqiweiwancheng"></span> 未完成
</span>
<span v-if="scope.row.status == 'COMPLETED'"
><span style="color: #43cf7c" class="iconfont icon-yiwancheng"></span> 已完成
</span>
<span v-if="scope.row.status == 'DRAFT'"
><span style="color: #86909c" class="iconfont icon-genjinjilu"></span> 草稿
</span>
</template>
</el-table-column>
<el-table-column label="创建时间" sortable align="center" prop="createTime" width="150">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total >= 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-dialog>
</div>
</template>
<script setup name="FnaList">
import { watch } from 'vue'
import { getFnaList, deleteFna, subProcess } from '@/api/sign/fna'
import { editFna, unlinkFna } from '@/api/sign/appointment'
import useUserStore from '@/store/modules/user'
const emit = defineEmits(['handleSuccessEdit'])
const userStore = useUserStore()
const router = useRouter()
const { proxy } = getCurrentInstance()
// const { sys_status, csf_fna_status, sys_no_yes } = proxy.useDict(
// 'sys_status',
// 'csf_fna_status',
// 'sys_no_yes'
// )
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) } //父组件传递过来的id对象
})
const tenantList = ref([])
const fnaList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const dialogVisible = ref(false)
const ids = ref([])
const total = ref(0)
const dateRange = ref([])
const selectIdsList = ref([])
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 5,
startTime: '',
endTime: '',
sortField: '',
sortOrder: ''
}
})
const { queryParams, form, rules } = toRefs(data)
const handleLian = () => {
dialogVisible.value = true
queryParams.value = {
pageNo: 1,
pageSize: 5,
startTime: '',
endTime: '',
sortField: '',
sortOrder: ''
}
getList()
}
const handleCopy = row => {
// { fnaBizId: row.fnaBizId }
subProcess({ fnaBizId: row.fnaBizId }).then(response => {
if (response.code === 200) {
getList()
proxy.$modal.msgSuccess('生成副本成功')
}
})
}
const rowClick = row => {
let data = {
fnaBizId: row.fnaBizId,
appointmentBizId: props.idsObj.appointmentBizId,
fnaNo: row.fnaNo
}
editFna(data).then(response => {
if (response.code === 200) {
queryParams.value.fnaBizId = row.fnaBizId
queryParams.value.pageNo = 1
getList()
emit('handleSuccessEdit')
dialogVisible.value = false
}
})
}
const sortChange = ({ prop, order }) => {
if (order == 'ascending') {
queryParams.value.sortOrder = 'ascend'
} else {
queryParams.value.sortOrder = 'descend'
}
if (prop) {
queryParams.value.sortField = prop
}
getList()
}
/** 多选框选中数据 */
function tableSelect(selection) {
// selectIdsList.value = selection.map(item => item.projectBizId)
}
/** 查询租户列表 */
function getList() {
if (dateRange.value.length > 0) {
queryParams.value.startTime = `${dateRange.value[0]} 00:00:00`
queryParams.value.endTime = `${dateRange.value[1]} 23:59:59`
}
loading.value = true
try {
getFnaList(queryParams.value).then(response => {
if (dialogVisible.value) {
total.value = response.data.total
fnaList.value = response.data.records
} else {
tenantList.value = response.data.records
}
loading.value = false
})
} catch (error) {
tenantList.value = []
fnaList.value = []
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNo = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
dateRange.value = []
proxy.resetForm('queryRef')
queryParams.value = {
pageNo: 1,
pageSize: 5,
startTime: '',
endTime: ''
}
handleQuery()
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.$modal
.confirm('是否确认删除' + row.customerName + '的FNA流程?')
.then(function () {
return deleteFna({ fnaBizId: row.fnaBizId })
})
.then(() => {
getList()
proxy.$modal.msgSuccess('删除成功')
})
.catch(() => {})
}
/** 重置操作表单 */
function reset() {
form.value = {
pageNo: 1,
pageSize: 8
}
proxy.resetForm('tenantRef')
}
/** 新增按钮操作 */
function handleAdd() {
router.push('/sign/FnaList/edit?type=add')
}
/** 修改按钮操作 */
function handleUpdate(row) {
router.push({ path: '/sign/FnaList/edit', query: { fnaBizId: row.fnaBizId, type: 'edit' } })
}
/** 查看按钮操作 */
function handleView(row) {
router.push({ path: '/sign/FnaList/edit', query: { fnaBizId: row.fnaBizId, type: 'edit' } })
}
/** 解除关联按钮操作 */
function handleUnlink(row) {
let data = {
appointmentBizId: props.idsObj.appointmentBizId
}
proxy.$modal
.confirm('是否确认解除关联?')
.then(function () {
return unlinkFna(data)
})
.then(response => {
if (response.code === 200) {
tenantList.value = []
emit('handleSuccessEdit')
}
proxy.$modal.msgSuccess('已解除关联')
})
.catch(() => {})
}
watch(
() => props.activeName,
newVal => {
if (newVal === 'fna') {
queryParams.value.fnaBizId = props.idsObj.fnaBizId
getList()
}
}
)
</script>
<style lang="scss" scoped>
.bottomBtn {
width: 100%;
text-align: center;
margin-top: 20px;
}
</style>
<template>
<div>
<div v-if="questionnairesDom.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<!-- <el-button type="warning" icon="DocumentAdd" @click="exportInfo" v-if="showContacts"
>导入联系人</el-button
> -->
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="heathFormRef" :model="form" :rules="rules">
<div v-for="(level1, l1) in questionnairesDom" :key="level1.firstCategory">
<el-row style="margin-bottom: 10px">
<div class="formBox">
<div class="fatherLable">{{ level1.firstCategoryName }}</div>
<!-- <div class="fatherDes">{{ father.description }}</div> -->
<el-row :gutter="20">
<template
v-for="(level2, l2) in level1.secondCategoryDtoList"
:key="level2.secondCategory"
>
<el-col :sm="level2.sm" :lg="level2.lg" class="formItem">
<div class="level2Title">{{ level2.secondCategoryName }}</div>
<div class="level2Content" v-for="(level3, l3) in level2.questionsDtoList">
<div class="level2Left">
{{ l3 + 1 }}/{{ level2.questionsDtoList.length }}
</div>
<div class="level2Right">
<div class="level3Title">{{ level3.text }}</div>
<!-- <el-form-item
:label-width="level3.labelWidth"
:key="level3.key"
:label-position="level3.labelPosition"
> -->
<div class="level3Content">
<el-radio-group
v-model="
form[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3][
'answerSessionsDto'
]['optionBizId']
"
@change="handleRadioChange(l1, l2, l3, level3)"
>
<el-radio
v-for="dict in level3.optionsDtoList"
:key="dict.optionBizId"
:value="dict.optionBizId"
>{{ dict.text }}</el-radio
>
</el-radio-group>
<div
v-if="
form[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3][
'answerSessionsDto'
]['optionBizId'] == 'option_1002'
"
style="width: 100%"
>
<div v-for="level4 in level3.addQuestionsDtoList">
<!-- -->
<el-form-item
label-position="top"
:key="level4.addQuestionsBizId"
:label="level4.text"
:rules="
level4.isRequired
? [
{
required: true,
message: `${level4.text}不能为空`,
trigger: 'blur'
}
]
: []
"
>
<div class="level4Content">
<el-input
v-if="level4.type === 'TEXT'"
:type="level4.type"
placeholder="请输入"
maxlength="30"
style="width: 50%"
@blur="inputBlur(l1, l2, l3, level4)"
/>
<!-- @change="handleDateChange(child)" -->
<el-date-picker
style="width: 50%"
v-if="level4.type === 'DATE'"
:type="level4.type"
placeholder="请输入"
:disabled-date="disabledDate"
/>
</div>
</el-form-item>
</div>
</div>
</div>
<!-- </el-form-item> -->
</div>
</div>
<!-- <div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="child.key"
:key="child.key"
:label-position="child.labelPosition"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form[child.key]"
style="width: 100%"
v-if="child.domType === 'DatePicker'"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
:disabled-date="disabledDate"
@change="handleDateChange(child)"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
<el-button v-if="child.domType === 'button'" :type="child.buttonType">{{
child.buttonTxt
}}</el-button>
</el-form-item>
</div> -->
</el-col>
</template>
</el-row>
</div>
</el-row>
</div>
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<el-dialog title="联系人信息" v-model="openList" width="600px" append-to-body>
<div>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="85px">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" @input="customerList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" circle @click="customerList" />
<el-button type="info" icon="Refresh" circle @click="resetCustomerList" />
</el-form-item>
</el-form>
<div class="customerBox">
<div class="customerItem" v-for="item in tableData" :key="item.id">
<div class="top">
<div class="right">
<el-button type="primary" size="small" @click="handleExport(item)"
>导入联系人</el-button
>
</div>
</div>
<div class="bottom">
<div class="left">
<div class="infoItem">
<span>姓名:</span>
<span> {{ item.name || '暂无' }}</span>
</div>
<div class="infoItem">
<span>性别:</span>
<span>
<dict-tag :options="fetchDictData('sys_gender')" :value="item.gender"
/></span>
</div>
<div class="infoItem">
<span>年龄:</span>
<span> {{ item.age || '暂无' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="secondHolderInfo">
import { calculateExactAge } from '@/utils/date'
import { ArrowRight } from '@element-plus/icons-vue'
import secondHolderDomData from '@/formJson/secondHolder'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { getCustomerList } from '@/api/sign/fna'
import { editSecondHolderInfo, getQuestionnaires } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiSecondHolderInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerInfo: { type: Object, default: () => ({}) } //客户详情回显表单用
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tempSaveKey = ref({}) // 用于tab切换的时候保存一份临时的值,防止切换的时候数据丢失
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const showContacts = ref(true)
const tableLoading = ref(false)
const tableData = ref([])
const total = ref(0)
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const personalObj = ref({}) //存储个人key
const companyObj = ref({}) //存储公司key
const commonObj = ref({}) //存储个人和公司的公共key
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress',
'txAddress',
'companyEnterAddress',
'phoneString',
'phoneCode'
]) // 存储需要删除的key
const data = reactive({
form: {},
tempSecondHolderForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
questionnairesDom: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, questionnairesDom, queryParams, oldAppointmentData, tempSecondHolderForm } =
toRefs(data)
const handleRadioChange = (l1, l2, l3, level3) => {
let answer = JSON.parse(
JSON.stringify(
form.value[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3]['answerSessionsDto']
)
)
let optionItem = level3.optionsDtoList.filter(item => item.optionBizId === answer.optionBizId)
if (optionItem[0].value == 'YES') {
let newObj = {
optionBizId: optionItem[0].optionBizId,
content: optionItem[0].value
}
// 检查数组中是否已存在相同ID的地址
const existingIndex = answer.optionJsonDtoList.findIndex(
item => item.optionBizId === optionItem[0].optionBizId
)
if (existingIndex !== -1) {
// 更新已存在的地址
answer.optionJsonDtoList[existingIndex] = { ...newObj }
} else {
// 添加新地址
answer.optionJsonDtoList.push({ ...newObj })
}
}
form.value[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3]['answerSessionsDto'] = answer
console.log('====================================')
console.log(
'改变',
form.value[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3]['answerSessionsDto']
)
console.log('====================================')
}
const inputBlur = (l1, l2, l3, level4) => {
// 写到这了
let answer = JSON.parse(
JSON.stringify(
form.value[l1]['secondCategoryDtoList'][l2]['questionsDtoList'][l3]['answerSessionsDto']
)
)
}
const handleDateChange = child => {
let age = null
if (child.key == 'birthTime') {
age = calculateExactAge(proxy.formatToDate(form.value.birthTime))
if (age >= 0) {
form.value.age = age
}
}
}
const disabledDate = time => {
return time.getTime() > Date.now()
}
const exportInfo = () => {
if (props.customerBizId && editStatus.value) {
proxy.$modal.confirm(`请先点击编辑在导入客户信息`, { showCancel: '0', title: '填写提示' })
return
}
openList.value = true
customerList()
}
const customerList = () => {
tableLoading.value = true
getCustomerList(queryParams.value).then(res => {
if (res.code == 200) {
tableData.value = res.data.records
total.value = res.data.total
tableLoading.value = false
}
})
}
const resetCustomerList = () => {
queryParams.value = {
pageNo: 1,
pageSize: 4,
name: undefined
}
customerList()
}
// 从客户列表中导入客户信息到当前表单
const handleExport = row => {
oldObjInfo.value = JSON.parse(JSON.stringify(form.value)) // 修改时存储原始数据,便于撤销操作
processFormData({
domdata: questionnairesDom.value,
customerInfo: row,
exportValue: true
})
openList.value = false
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
form.value = {}
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (field.required) {
if (field.showEn) {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' },
{ validator: validateEnglish, trigger: 'change' }
]
} else {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' }
]
}
}
if (obj.customerInfo) {
for (const key1 in obj.customerInfo) {
if (key1 == 'birthdate' && obj.customerInfo[key1]) {
obj.customerInfo[key1] = proxy.formatToDate(obj.customerInfo[key1])
}
// 对应客户和dom表单字段方便赋值
if (field.customerKey && key1 == field.customerKey) {
form.value[field.key] = obj.customerInfo[key1]
}
}
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
} else {
if (field.key == 'age') {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
}
//当tab切换走,在切换回来的时候,需要把之前保存的值赋值回来
if (JSON.stringify(tempSecondHolderForm.value) !== '{}' && !props.idsObj.appointmentBizId) {
form.value = { ...tempSecondHolderForm.value }
}
if (props.idsObj.appointmentBizId) {
form.value = { ...props.apiSecondHolderInfoDto }
editStatus.value = true
} else {
editStatus.value = false
}
questionnairesDom.value = oldAppointmentData.value = processedData
}
//弹出右侧抽屉
const handleFoucs = child => {
if (child.disabled) return
console.log('saveKey.value', saveKey.value)
console.log('child', child)
drawerInfo.value = JSON.parse(JSON.stringify(child))
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
item.value = ''
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showPhoneDrawer.value = true
break
case 'address':
addressMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
let newObj = info[drawerInfo.value.key]
if (form.value['customerType'] == 'COMPANY') {
newObj.fatherKey = 'company'
} else if (form.value['customerType'] == 'INDIVIDUAL') {
newObj.fatherKey = 'person'
}
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
newObj.objType = drawerInfo.value.drawerType
// 因为电话有多个,根据点击的电话类型在抽屉里回显,所以要用drawerInfo.value.code来控制
form.value[info.key] = `${newObj[drawerInfo.value.code]} ${newObj[drawerInfo.value.key]}`
saveKey.value[drawerInfo.value.key] = newObj
break
case 'address':
newObj.objType = drawerInfo.value.drawerType
newObj.type = drawerInfo.value.key
form.value[info.key] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
saveKey.value[info.key] = newObj
break
case 'country':
info.objType = drawerInfo.value.drawerType
form.value[drawerInfo.value.key] = info.name
saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of questionnairesDom.value) {
switch (obj.type) {
case 'father':
if (section.key == obj.key) {
section.showMoudle = obj.status
}
break
case 'child':
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
}
}
}
break
default:
break
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'customerType':
if (form.value[child.key] == 'COMPANY') {
showContacts.value = false
for (const section of questionnairesDom.value) {
if (section.key == 'company') {
for (const key1 in saveKey.value) {
for (const key2 in commonObj.value) {
if (key1 == key2) {
saveKey.value[key1]['fatherKey'] = section.key
}
}
}
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
}
} else {
showContacts.value = true
for (const section of questionnairesDom.value) {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
}
break
case 'smokingAllowed':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'smokingVolume', status: true })
} else {
resetShow({ type: 'child', key: 'smokingVolume', status: false })
}
break
case 'isVip':
// 选择vip,展示vip备注
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'vipRemark', status: true })
} else {
resetShow({ type: 'child', key: 'vipRemark', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(questionnairesDom.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
questionnairesDom.value = processedData
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (item[key] && !seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = {}
if (props.activeName == 'secondHolder') {
submitObj = JSON.parse(JSON.stringify(form.value))
} else {
submitObj = JSON.parse(JSON.stringify(tempSecondHolderForm.value))
}
//处理表单数据
for (const key1 in submitObj) {
if (key1 == 'birthTime') {
submitObj[key1] = proxy.formatToDateTime(submitObj[key1])
}
}
return submitObj
}
// 表单提交
const submitForm = () => {
proxy.$refs['heathFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
editSecondHolderInfo(submitObj).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('第二持有人修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
if (props.customerBizId) {
form.value = { ...oldObjInfo.value }
editStatus.value = true
} else {
// resetShow('smokeQuantity', false)
proxy.$refs['heathFormRef'].resetFields()
}
questionnairesDom.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
})
.catch(() => {})
}
const getQuestionnairesInfo = () => {
getQuestionnaires(props.idsObj.appointmentBizId).then(res => {
if (res.code == 200) {
let result = res.data.firstAndSecondCategoryDtoList
let first_category = fetchDictData('wj_question_first_category')
let second_category = fetchDictData('wj_question_second_category')
form.value = {}
result.forEach((level1, l1) => {
// form.value[level1.firstCategory] = {}
first_category.forEach((first, i) => {
if (level1.firstCategory == first.value) {
level1.firstCategoryName = first.label
}
})
level1.secondCategoryDtoList.forEach((level2, l2) => {
level2.sm = 24
level2.lg = 24
second_category.forEach((second, i) => {
if (level2.secondCategory == second.value) {
level2.secondCategoryName = second.label
}
})
level2.questionsDtoList.forEach((level3, l3) => {
level3.labelWidth = '100%'
level3.labelPosition = 'top'
level3.key = level3.id
if (!level3.answerSessionsDto) {
level3.answerSessionsDto = {}
if (!level3.answerSessionsDto.optionJsonDtoList) {
level3.answerSessionsDto.optionJsonDtoList = []
level3.answerSessionsDto.optionJsonDtoList.addQuestionsJsonDtoList = []
}
}
})
})
})
questionnairesDom.value = form.value = result
}
})
}
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
tempSecondHolderForm.value = { ...form.value }
if (newVal === 'questionnaires') {
getQuestionnairesInfo()
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.level2Title {
font-size: 16px;
margin: 10px 0;
}
.level2Content {
width: 100%;
display: flex;
justify-content: flex-start;
font-size: 14px;
margin-bottom: 10px;
.level2Left {
margin-right: 15px;
margin-top: 3px;
}
.level2Right {
width: calc(100% - 30px);
.level3Title {
font-size: 13px;
}
.level3Content {
display: flex;
flex-direction: column;
.level4Content {
width: 100%;
}
}
}
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
display: flex;
justify-content: flex-start;
.title {
width: 120px;
font-size: 14px;
text-align: right;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
/* display: flex;
align-items: center; */
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template>
<div>
<div v-if="processedinsuredData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
type="warning"
icon="DocumentAdd"
@click="exportInfo"
v-if="showContacts"
:disabled="editStatus"
>导入联系人</el-button
>
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="insuredInfoFormRef" :model="form" :rules="rules" label-width="120px">
<div v-for="father in processedinsuredData">
<el-row style="margin-bottom: 10px" v-if="father.showMoudle">
<div class="formBox">
<div class="fatherLable">{{ father.fatherTitle }}</div>
<div class="fatherDes">{{ father.description }}</div>
<el-row :gutter="20">
<template v-for="child in father.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItem" v-if="child.show">
<div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="child.key"
:key="child.key"
:label-position="child.labelPosition"
:rules="
child.required
? [
{
required: true,
message: `${child.label}不能为空`,
trigger: 'blur'
}
]
: []
"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form[child.key]"
style="width: 100%"
v-if="child.domType === 'DatePicker'"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
<el-button v-if="child.domType === 'button'" :type="child.buttonType">{{
child.buttonTxt
}}</el-button>
</el-form-item>
</div>
</el-col>
</template>
</el-row>
</div>
</el-row>
</div>
<!-- v-if="props.idObj.appointmentBizId" -->
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>保存</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<el-dialog title="联系人信息" v-model="openList" width="600px" append-to-body>
<div>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="85px">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" @input="customerList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" circle @click="customerList" />
<el-button type="info" icon="Refresh" circle @click="resetCustomerList" />
</el-form-item>
</el-form>
<div class="customerBox">
<div class="customerItem" v-for="item in tableData" :key="item.id">
<div class="top">
<div class="right">
<el-button type="primary" size="small" @click="handleExport(item)"
>导入联系人</el-button
>
</div>
</div>
<div class="bottom">
<div class="left">
<div class="infoItem">
<span>姓名:</span>
<span> {{ item.name || '暂无' }}</span>
</div>
<div class="infoItem">
<span>性别:</span>
<span>
<dict-tag :options="fetchDictData('sys_gender')" :value="item.gender"
/></span>
</div>
<div class="infoItem">
<span>年龄:</span>
<span> {{ item.age || '暂无' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="insuredInfo">
import { ArrowRight } from '@element-plus/icons-vue'
import policyDomData from '@/formJson/insured'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { getCustomerList } from '@/api/sign/fna'
import { editInsurantInfo } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiInsurantInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerInfo: { type: Object, default: () => ({}) } //客户详情回显表单用
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tempSaveKey = ref({}) // 用于tab切换的时候保存一份临时的值,防止切换的时候数据丢失
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const showContacts = ref(true)
const tableLoading = ref(false)
const tableData = ref([])
const total = ref(0)
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const tempAddressQuickList = ref([])
const tempPhoneQuickList = ref([])
const personalObj = ref({}) //存储个人key
const companyObj = ref({}) //存储公司key
const commonObj = ref({}) //存储个人和公司的公共key
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress',
'txAddress',
'companyEnterAddress',
'phoneString',
'phoneCode'
]) // 存储需要删除的key
const data = reactive({
form: {},
tempPolicyForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
processedinsuredData: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, processedinsuredData, queryParams, oldAppointmentData, tempPolicyForm } =
toRefs(data)
const exportInfo = () => {
if (props.customerBizId && editStatus.value) {
proxy.$modal.confirm(`请先点击编辑在导入客户信息`, { showCancel: '0', title: '填写提示' })
return
}
openList.value = true
customerList()
}
const customerList = () => {
console.log('触发了')
tableLoading.value = true
getCustomerList(queryParams.value).then(res => {
if (res.code == 200) {
tableData.value = res.data.records
total.value = res.data.total
tableLoading.value = false
}
})
}
const resetCustomerList = () => {
queryParams.value = {
pageNo: 1,
pageSize: 4,
name: undefined
}
customerList()
}
// 从客户列表中导入客户信息到当前表单
const handleExport = row => {
oldObjInfo.value = JSON.parse(JSON.stringify(form.value)) // 修改时存储原始数据,便于撤销操作
processFormData({
domdata: processedinsuredData.value,
customerInfo: row,
exportValue: true
})
openList.value = false
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
const mergeObjects = (obj1, obj2) => {
const result = Object.assign({}, obj1)
Object.keys(obj2).forEach(key => {
if (result[key] === undefined || !result.hasOwnProperty(key)) {
result[key] = obj2[key]
}
})
return result
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
form.value = {}
saveKey.value = {}
let tempPhoneList = []
let tempAddressList = []
addressQuickList.value = []
phoneQuickList.value = []
// 深拷贝原始数据
// const processedData = JSON.parse(JSON.stringify(policyDomData))
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (section.key == 'customer') {
personalObj.value[field.key] = field.key
companyObj.value[field.key] = field.key
}
// 收集key,区分个人和企业
if (section.key == 'person' && !field.commonKey) {
personalObj.value[field.key] = field.key
} else if (section.key == 'company' && !field.commonKey) {
companyObj.value[field.key] = field.key
} else if (field.commonKey) {
commonObj.value[field.key] = field.key
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (obj.customerInfo) {
for (const key1 in obj.customerInfo) {
if (key1 == 'birthdate' && obj.customerInfo[key1]) {
obj.customerInfo[key1] = proxy.formatToDateTime(obj.customerInfo[key1])
}
// 客户类型为公司时,隐藏非公司信息
if (key1 == 'customerType' && obj.customerInfo[key1] == 'COMPANY') {
showContacts.value = false
if (section.key == 'company') {
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
} else if (key1 == 'customerType' && obj.customerInfo[key1] !== 'COMPANY') {
showContacts.value = true
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
// 非公司信息时,给表单赋值客户信息
if (section.showMoudle && field.customerKey && key1 == field.customerKey) {
form.value[field.key] = obj.customerInfo[key1]
}
}
if (
(field.key == 'smokingVolume' && obj.customerInfo['smoke'] == '1') ||
obj.customerInfo['smokingAllowed'] == '1'
) {
field.show = true
} else if (field.key == 'smokingVolume') {
field.show = false
}
//要判断drawerType,因为抽屉要回显数据
if (
(section.key !== 'company' ||
(props.idsObj.appointmentBizId && section.key == 'company')) &&
field.drawerType
) {
switch (field.drawerType) {
//电话的code暂时没对上
case 'phone':
let phoneObj = {}
for (const key1 in field) {
for (const key2 in obj.customerInfo) {
//这样写的作用:和dom数据的key和code做对应,方便抽屉回显
if (key1 !== 'drawerType' && field[key1] == key2) {
if (
(key1 == 'customerCode' || field.code == key2) &&
obj.customerInfo[key2]
) {
phoneObj[field.code] = obj.customerInfo[key2].includes('+')
? obj.customerInfo[key2]
: `+${obj.customerInfo[key2]}`
}
if (
(key1 == 'customerKey' || field.key == key2) &&
field[key1] == key2 &&
obj.customerInfo[key2]
) {
phoneObj[field.key] = obj.customerInfo[key2]
}
}
}
}
if (phoneObj[field.key]) {
phoneObj.phoneString = form.value[field.key] = `${phoneObj[field.code]} ${
phoneObj[field.key]
}`
tempPhoneList.push(phoneObj)
phoneObj.objType = field.drawerType
phoneObj.key = field.key
phoneObj.phoneCode = field.code
phoneObj.fatherKey = section.key
saveKey.value[field.key] = phoneObj
}
break
case 'address':
let addressObj = null
for (const key1 in field) {
if (obj.customerInfo.addressList && obj.customerInfo.addressList.length > 0) {
obj.customerInfo.addressList.forEach(item => {
if (key1 == item.type) {
addressObj = item
}
})
}
}
if (addressObj) {
form.value[
field.key
] = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.addressString = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.objType = field.drawerType
addressObj.fatherKey = section.key
saveKey.value[field.key] = addressObj
if (tempAddressList.length > 0) {
tempAddressList.forEach(item => {
if (item.addressString !== addressObj.addressString) {
tempAddressList.push(addressObj)
}
})
} else {
tempAddressList.push(addressObj)
}
}
break
case 'country':
form.value[field.key] = obj.customerInfo.countryName
saveKey.value[field.key] = {
country: obj.customerInfo.country || '',
countryCode: obj.customerInfo.country || '',
countryName: obj.customerInfo.countryName || '',
name: obj.customerInfo.countryName || '',
objType: field.drawerType,
fatherKey: section.key
}
break
default:
break
}
}
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
addressQuickList.value = tempAddressList
tempPhoneList.forEach(item => {
for (const key in saveKey.value) {
if (item.key == key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.mobile = saveKey.value[key][key2]
}
if (item.phoneCode == key2) {
item.code = saveKey.value[key][key2]
}
}
}
}
})
phoneQuickList.value = removeDuplicates(tempPhoneList, 'phoneString')
addressQuickList.value = removeDuplicates(tempAddressList, 'addressString')
//当tab切换走,在切换回来的时候,需要把之前保存的值赋值回来
if (JSON.stringify(tempPolicyForm.value) !== '{}' && !props.idsObj.appointmentBizId) {
form.value = { ...tempPolicyForm.value }
saveKey.value = { ...tempSaveKey.value }
addressQuickList.value = JSON.parse(JSON.stringify(tempAddressQuickList.value))
phoneQuickList.value = JSON.parse(JSON.stringify(tempPhoneQuickList.value))
}
if (props.idsObj.appointmentBizId) {
form.value = mergeObjects(form.value, obj.customerInfo)
if (form.value.smokingAllowed) {
form.value.smokingAllowed = Number(form.value.smokingAllowed)
}
console.log('修改form', form.value)
editStatus.value = true
} else {
editStatus.value = false
}
processedinsuredData.value = oldAppointmentData.value = processedData
}
//弹出右侧抽屉
const handleFoucs = child => {
if (child.disabled) return
console.log('saveKey.value', saveKey.value)
console.log('child', child)
drawerInfo.value = JSON.parse(JSON.stringify(child))
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
item.value = ''
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showPhoneDrawer.value = true
break
case 'address':
addressMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
let newObj = info[drawerInfo.value.key]
// if (form.value['customerType'] == 'COMPANY') {
// newObj.fatherKey = 'company'
// } else if (form.value['customerType'] == 'INDIVIDUAL') {
// newObj.fatherKey = 'person'
// }
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
newObj.objType = drawerInfo.value.drawerType
// 因为电话有多个,根据点击的电话类型在抽屉里回显,所以要用drawerInfo.value.code来控制
form.value[info.key] = `${newObj[drawerInfo.value.code]} ${newObj[drawerInfo.value.key]}`
saveKey.value[drawerInfo.value.key] = newObj
break
case 'address':
newObj.objType = drawerInfo.value.drawerType
newObj.type = drawerInfo.value.key
form.value[info.key] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
saveKey.value[info.key] = newObj
break
case 'country':
info.objType = drawerInfo.value.drawerType
form.value[drawerInfo.value.key] = info.name
saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of processedinsuredData.value) {
switch (obj.type) {
case 'father':
if (section.key == obj.key) {
section.showMoudle = obj.status
}
break
case 'child':
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
}
}
}
break
default:
break
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'customerType':
if (form.value[child.key] == 'COMPANY') {
showContacts.value = false
console.log(' commonObj.value', commonObj.value)
for (const section of processedinsuredData.value) {
if (section.key == 'company') {
console.log(11111)
for (const key1 in saveKey.value) {
for (const key2 in commonObj.value) {
console.log(key1, key2)
if (key1 == key2) {
saveKey.value[key1]['fatherKey'] = section.key
}
}
}
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
}
} else {
showContacts.value = true
for (const section of processedinsuredData.value) {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
}
break
case 'smokingAllowed':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'smokingVolume', status: true })
} else {
resetShow({ type: 'child', key: 'smokingVolume', status: false })
}
break
case 'isVip':
// 选择vip,展示vip备注
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'vipRemark', status: true })
} else {
resetShow({ type: 'child', key: 'vipRemark', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedinsuredData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
processedinsuredData.value = processedData
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (item[key] && !seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = {}
let addressList = []
let result = {}
if (props.activeName == 'insurantInfo') {
result = JSON.parse(JSON.stringify(form.value))
} else {
result = JSON.parse(JSON.stringify(tempPolicyForm.value))
saveKey.value = JSON.parse(JSON.stringify(tempSaveKey.value))
}
let newSaveKey = {}
if (result.birthday) {
result.birthday = proxy.formatToDateTime(result.birthday)
}
if (result.companyRegisterTime) {
result.companyRegisterTime = proxy.formatToDateTime(result.companyRegisterTime)
}
//处理表单数据
for (const key1 in result) {
// if (key1 == 'birthday' || key1 == 'companyRegisterTime') {
// result[key1] = proxy.formatToDateTime(result[key1])
// }
// 根据选择的客户类型传值,公司和个人分开传值,因为电话和地址特殊所以也要处理
if (key1 == 'customerType' && result[key1] == 'COMPANY') {
for (const key4 in companyObj.value) {
submitObj[key4] = result[key4]
for (const key7 in saveKey.value) {
if (key4 == key7) {
newSaveKey[key4] = saveKey.value[key4]
}
}
}
} else if (key1 == 'customerType' && (!result[key1] || result[key1] == 'INDIVIDUAL')) {
for (const key5 in personalObj.value) {
submitObj[key5] = result[key5]
for (const key7 in saveKey.value) {
if (key5 == key7) {
newSaveKey[key5] = saveKey.value[key5]
}
}
}
}
for (const key6 in commonObj.value) {
submitObj[key6] = result[key6]
for (const key7 in saveKey.value) {
if (key6 == key7) {
newSaveKey[key6] = saveKey.value[key6]
}
}
}
for (const key2 in newSaveKey) {
//要判断drawerType
switch (newSaveKey[key2].objType) {
// case 'phone':
// if (key1 == key2) {
// for (const key3 in newSaveKey[key2]) {
// if (key3 == 'phoneCode') {
// submitObj[newSaveKey[key2][key3]] = newSaveKey[key2].phoneString.split(' ')[0]
// }
// if (key3 == 'phoneString') {
// submitObj[newSaveKey[key2].key] = newSaveKey[key2][key3].split(' ')[1]
// }
// }
// }
// break
case 'address':
if (key1 == key2) {
addressList.push(newSaveKey[key2])
}
break
case 'country':
if (key1 == key2 && key1 == 'customerType' && result[key1] == 'INDIVIDUAL') {
submitObj['country'] = newSaveKey[key2]['countryCode']
submitObj['countryName'] = newSaveKey[key2]['name']
}
break
default:
break
}
}
}
if (addressList.length > 0) {
submitObj['addressList'] = addressList
}
if (submitObj['companyMobile']) {
submitObj['companyMobileCode'] = submitObj['companyMobile'].split(' ')[0]
submitObj['companyMobile'] = submitObj['companyMobile'].split(' ')[1]
}
if (submitObj['mobile']) {
submitObj['mobileCode'] = submitObj['mobile'].split(' ')[0]
submitObj['mobile'] = submitObj['mobile'].split(' ')[1]
}
if (submitObj['authMobile']) {
submitObj['authMobileCode'] = submitObj['authMobile'].split(' ')[0]
submitObj['authMobile'] = submitObj['authMobile'].split(' ')[1]
}
console.log('====================================')
console.log('受保人submitObj', submitObj)
console.log('====================================')
// 删除多余字段
deleteKeyList.value.forEach(item => {
delete submitObj[item]
})
return submitObj
}
// 表单提交
const submitForm = () => {
// let submitObj = { ...form.value }
// let submitObj = handleFormValues()
// console.log('====================================')
// console.log('submitObj', submitObj)
// console.log('====================================')
// return
proxy.$refs['insuredInfoFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
submitObj['appointmentBizId'] = props.apiInsurantInfoDto.appointmentBizId
submitObj['id'] = props.apiInsurantInfoDto.id
submitObj['insurantBizId'] = props.apiInsurantInfoDto.insurantBizId
editInsurantInfo(submitObj).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('受保人修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
if (props.customerBizId) {
form.value = { ...oldObjInfo.value }
editStatus.value = true
} else {
// resetShow('smokeQuantity', false)
proxy.$refs['insuredInfoFormRef'].resetFields()
}
processedinsuredData.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
})
.catch(() => {})
}
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
tempPolicyForm.value = { ...form.value }
tempSaveKey.value = { ...saveKey.value }
tempAddressQuickList.value = JSON.parse(JSON.stringify(addressQuickList.value))
tempPhoneQuickList.value = JSON.parse(JSON.stringify(phoneQuickList.value))
if (newVal === 'insurantInfo') {
openList.value = false
setTimeout(() => {
if (props.idsObj.appointmentBizId) {
processFormData({
domdata: policyDomData,
customerInfo: props.apiInsurantInfoDto,
exportValue: null
})
} else {
processFormData({
domdata: policyDomData,
exportValue: null
})
}
}, 500)
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
display: flex;
justify-content: flex-start;
.title {
width: 120px;
font-size: 14px;
text-align: right;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
/* display: flex;
align-items: center; */
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template>
<div>
<div v-if="processedPolicyData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
type="warning"
icon="DocumentAdd"
@click="exportInfo"
v-if="showContacts"
:disabled="editStatus"
>导入联系人</el-button
>
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="policyholderInfoFormRef" :model="form" :rules="rules" label-width="120px">
<div v-for="father in processedPolicyData">
<el-row style="margin-bottom: 10px" v-if="father.showMoudle">
<div class="formBox">
<div class="fatherLable">{{ father.fatherTitle }}</div>
<div class="fatherDes">{{ father.description }}</div>
<el-row :gutter="20">
<template v-for="child in father.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItem" v-if="child.show">
<div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="child.key"
:key="child.key"
:label-position="child.labelPosition"
:rules="
child.required
? [
{
required: true,
message: `${child.label}不能为空`,
trigger: 'blur'
}
]
: []
"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form[child.key]"
style="width: 100%"
v-if="child.domType === 'DatePicker'"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
<el-button v-if="child.domType === 'button'" :type="child.buttonType">{{
child.buttonTxt
}}</el-button>
</el-form-item>
</div>
</el-col>
</template>
</el-row>
</div>
</el-row>
</div>
<!-- v-if="props.idObj.appointmentBizId" -->
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>保存</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<el-dialog title="联系人信息" v-model="openList" width="600px" append-to-body>
<div>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="85px">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" @input="customerList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" circle @click="customerList" />
<el-button type="info" icon="Refresh" circle @click="resetCustomerList" />
</el-form-item>
</el-form>
<div class="customerBox">
<div class="customerItem" v-for="item in tableData" :key="item.id">
<div class="top">
<div class="right">
<el-button type="primary" size="small" @click="handleExport(item)"
>导入联系人</el-button
>
</div>
</div>
<div class="bottom">
<div class="left">
<div class="infoItem">
<span>姓名:</span>
<span> {{ item.name || '暂无' }}</span>
</div>
<div class="infoItem">
<span>性别:</span>
<span>
<dict-tag :options="fetchDictData('sys_gender')" :value="item.gender"
/></span>
</div>
<div class="infoItem">
<span>年龄:</span>
<span> {{ item.age || '暂无' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="policyholderInfo">
import { ArrowRight } from '@element-plus/icons-vue'
import policyDomData from '@/formJson/applicant'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { addCustomer, getCustomerDetail, editCustomer, getCustomerList } from '@/api/sign/fna'
import { editPolicyholderInfo } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiPolicyholderInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerInfo: { type: Object, default: () => ({}) } //客户详情回显表单用
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tempSaveKey = ref({}) // 用于tab切换的时候保存一份临时的值,防止切换的时候数据丢失
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const showContacts = ref(true)
const tableLoading = ref(false)
const tableData = ref([])
const total = ref(0)
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const tempAddressQuickList = ref([])
const tempPhoneQuickList = ref([])
const personalObj = ref({}) //存储个人key
const companyObj = ref({}) //存储公司key
const commonObj = ref({}) //存储个人和公司的公共key
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress',
'txAddress',
'companyEnterAddress',
'phoneString',
'phoneCode'
]) // 存储需要删除的key
const data = reactive({
form: {},
tempPolicyForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
processedPolicyData: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, processedPolicyData, queryParams, oldAppointmentData, tempPolicyForm } =
toRefs(data)
const exportInfo = () => {
if (props.customerBizId && editStatus.value) {
proxy.$modal.confirm(`请先点击编辑在导入客户信息`, { showCancel: '0', title: '填写提示' })
return
}
openList.value = true
customerList()
}
const customerList = () => {
console.log('触发了')
tableLoading.value = true
getCustomerList(queryParams.value).then(res => {
if (res.code == 200) {
tableData.value = res.data.records
total.value = res.data.total
tableLoading.value = false
}
})
}
const resetCustomerList = () => {
queryParams.value = {
pageNo: 1,
pageSize: 4,
name: undefined
}
customerList()
}
// 从客户列表中导入客户信息到当前表单
const handleExport = row => {
oldObjInfo.value = JSON.parse(JSON.stringify(form.value)) // 修改时存储原始数据,便于撤销操作
processFormData({
domdata: processedPolicyData.value,
customerInfo: row,
exportValue: true
})
// setFormValue(row, processedPolicyData.value, true)
openList.value = false
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
const mergeObjects = (obj1, obj2) => {
const result = Object.assign({}, obj1)
Object.keys(obj2).forEach(key => {
if (result[key] === undefined || !result.hasOwnProperty(key)) {
result[key] = obj2[key]
}
})
return result
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
form.value = {}
saveKey.value = {}
let tempPhoneList = []
let tempAddressList = []
addressQuickList.value = []
phoneQuickList.value = []
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (section.key == 'customer') {
personalObj.value[field.key] = field.key
companyObj.value[field.key] = field.key
}
// 收集key,区分个人和企业
if (section.key == 'person' && !field.commonKey) {
personalObj.value[field.key] = field.key
} else if (section.key == 'company' && !field.commonKey) {
companyObj.value[field.key] = field.key
} else if (field.commonKey) {
commonObj.value[field.key] = field.key
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (obj.customerInfo) {
for (const key1 in obj.customerInfo) {
if (key1 == 'birthdate' && obj.customerInfo[key1]) {
obj.customerInfo[key1] = proxy.formatToDateTime(obj.customerInfo[key1])
}
// 客户类型为公司时,隐藏非公司信息
if (key1 == 'customerType' && obj.customerInfo[key1] == 'COMPANY') {
showContacts.value = false
if (section.key == 'company') {
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
} else if (key1 == 'customerType' && obj.customerInfo[key1] !== 'COMPANY') {
showContacts.value = true
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
// 非公司信息时,给表单赋值客户信息 方便导入客户信息的时候回显值
if (section.showMoudle && field.customerKey && key1 == field.customerKey) {
form.value[field.key] = obj.customerInfo[key1]
}
}
if (
field.key == 'smokingVolume' &&
(obj.customerInfo['smoke'] == '1' || obj.customerInfo['smokingAllowed'] == '1')
) {
field.show = true
} else if (field.key == 'smokingVolume') {
field.show = false
}
//要判断drawerType,因为抽屉要回显数据
if (
(section.key !== 'company' ||
(props.idsObj.appointmentBizId && section.key == 'company')) &&
field.drawerType
) {
switch (field.drawerType) {
case 'phone':
let phoneObj = {}
for (const key1 in field) {
for (const key2 in obj.customerInfo) {
//这样写的作用:和dom数据的key和code做对应,方便抽屉回显
if (key1 !== 'drawerType' && field[key1] == key2) {
if (
(key1 == 'customerCode' || field.code == key2) &&
obj.customerInfo[key2]
) {
phoneObj[field.code] = obj.customerInfo[key2].includes('+')
? obj.customerInfo[key2]
: `+${obj.customerInfo[key2]}`
}
if (
(key1 == 'customerKey' || field.key == key2) &&
field[key1] == key2 &&
obj.customerInfo[key2]
) {
phoneObj[field.key] = obj.customerInfo[key2]
}
}
}
}
if (phoneObj[field.key]) {
phoneObj.phoneString = form.value[field.key] = `${phoneObj[field.code]} ${
phoneObj[field.key]
}`
tempPhoneList.push(phoneObj)
phoneObj.objType = field.drawerType
phoneObj.key = field.key
phoneObj.phoneCode = field.code
phoneObj.fatherKey = section.key
saveKey.value[field.key] = phoneObj
}
break
case 'address':
let addressObj = null
for (const key1 in field) {
if (obj.customerInfo.addressList && obj.customerInfo.addressList.length > 0) {
obj.customerInfo.addressList.forEach(item => {
if (key1 == item.type) {
addressObj = item
}
})
}
}
if (addressObj) {
form.value[
field.key
] = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.addressString = `${addressObj.region} ${addressObj.city} ${addressObj.street} ${addressObj.location}`
addressObj.objType = field.drawerType
addressObj.fatherKey = section.key
saveKey.value[field.key] = addressObj
if (tempAddressList.length > 0) {
tempAddressList.forEach(item => {
if (item.addressString !== addressObj.addressString) {
tempAddressList.push(addressObj)
}
})
} else {
tempAddressList.push(addressObj)
}
}
break
case 'country':
form.value[field.key] = obj.customerInfo.countryName
saveKey.value[field.key] = {
country: obj.customerInfo.country || '',
countryCode: obj.customerInfo.country || '',
countryName: obj.customerInfo.countryName || '',
name: obj.customerInfo.countryName || '',
objType: field.drawerType,
fatherKey: section.key
}
break
default:
break
}
}
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
addressQuickList.value = tempAddressList
tempPhoneList.forEach(item => {
for (const key in saveKey.value) {
if (item.key == key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.mobile = saveKey.value[key][key2]
}
if (item.phoneCode == key2) {
item.code = saveKey.value[key][key2]
}
}
}
}
})
phoneQuickList.value = removeDuplicates(tempPhoneList, 'phoneString')
addressQuickList.value = removeDuplicates(tempAddressList, 'addressString')
//当tab切换走,在切换回来的时候,需要把之前保存的值赋值回来
if (JSON.stringify(tempPolicyForm.value) !== '{}' && !props.idsObj.appointmentBizId) {
form.value = { ...tempPolicyForm.value }
saveKey.value = { ...tempSaveKey.value }
addressQuickList.value = JSON.parse(JSON.stringify(tempAddressQuickList.value))
phoneQuickList.value = JSON.parse(JSON.stringify(tempPhoneQuickList.value))
}
if (props.idsObj.appointmentBizId) {
form.value = mergeObjects(form.value, obj.customerInfo)
if (form.value.smokingAllowed) {
form.value.smokingAllowed = Number(form.value.smokingAllowed)
}
console.log('修改form', form.value)
editStatus.value = true
} else {
editStatus.value = false
}
processedPolicyData.value = oldAppointmentData.value = processedData
}
//弹出右侧抽屉
const handleFoucs = child => {
if (child.disabled) return
console.log('saveKey.value', saveKey.value)
console.log('child', child)
drawerInfo.value = JSON.parse(JSON.stringify(child))
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
item.value = ''
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showPhoneDrawer.value = true
break
case 'address':
addressMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
let newObj = info[drawerInfo.value.key]
// if (form.value['customerType'] == 'COMPANY') {
// newObj.fatherKey = 'company'
// } else if (form.value['customerType'] == 'INDIVIDUAL') {
// newObj.fatherKey = 'person'
// }
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
newObj.objType = drawerInfo.value.drawerType
// 因为电话有多个,根据点击的电话类型在抽屉里回显,所以要用drawerInfo.value.code来控制
form.value[info.key] = `${newObj[drawerInfo.value.code]} ${newObj[drawerInfo.value.key]}`
saveKey.value[drawerInfo.value.key] = newObj
break
case 'address':
newObj.objType = drawerInfo.value.drawerType
newObj.type = drawerInfo.value.key
form.value[info.key] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
saveKey.value[info.key] = newObj
break
case 'country':
info.objType = drawerInfo.value.drawerType
form.value[drawerInfo.value.key] = info.name
saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of processedPolicyData.value) {
switch (obj.type) {
case 'father':
if (section.key == obj.key) {
section.showMoudle = obj.status
}
break
case 'child':
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
}
}
}
break
default:
break
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'customerType':
if (form.value[child.key] == 'COMPANY') {
showContacts.value = false
for (const section of processedPolicyData.value) {
if (section.key == 'company') {
for (const key1 in saveKey.value) {
for (const key2 in commonObj.value) {
if (key1 == key2) {
saveKey.value[key1]['fatherKey'] = section.key
}
}
}
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
}
} else {
showContacts.value = true
for (const section of processedPolicyData.value) {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
}
break
case 'smokingAllowed':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'smokingVolume', status: true })
} else {
resetShow({ type: 'child', key: 'smokingVolume', status: false })
}
break
case 'isVip':
// 选择vip,展示vip备注
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'vipRemark', status: true })
} else {
resetShow({ type: 'child', key: 'vipRemark', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedPolicyData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
processedPolicyData.value = processedData
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (item[key] && !seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = {}
let addressList = []
let result = {}
if (props.activeName == 'policyholder') {
result = JSON.parse(JSON.stringify(form.value))
} else {
result = JSON.parse(JSON.stringify(tempPolicyForm.value))
saveKey.value = JSON.parse(JSON.stringify(tempSaveKey.value))
}
console.log('====================================')
console.log('投保人result', result)
console.log('====================================')
let newSaveKey = {}
if (result.birthday) {
result.birthday = proxy.formatToDateTime(result.birthday)
}
if (result.companyRegisterTime) {
result.companyRegisterTime = proxy.formatToDateTime(result.companyRegisterTime)
}
//处理表单数据
for (const key1 in result) {
// 根据选择的客户类型传值,公司和个人分开传值,因为电话和地址特殊所以也要处理
if (key1 == 'customerType' && result[key1] == 'COMPANY') {
for (const key4 in companyObj.value) {
submitObj[key4] = result[key4]
for (const key7 in saveKey.value) {
if (key4 == key7) {
newSaveKey[key4] = saveKey.value[key4]
}
}
}
} else if (key1 == 'customerType' && (!result[key1] || result[key1] == 'INDIVIDUAL')) {
for (const key5 in personalObj.value) {
submitObj[key5] = result[key5]
for (const key7 in saveKey.value) {
if (key5 == key7) {
newSaveKey[key5] = saveKey.value[key5]
}
}
}
}
for (const key6 in commonObj.value) {
submitObj[key6] = result[key6]
for (const key7 in saveKey.value) {
if (key6 == key7) {
newSaveKey[key6] = saveKey.value[key6]
}
}
}
for (const key2 in newSaveKey) {
//要判断drawerType
switch (newSaveKey[key2].objType) {
// case 'phone':
// if (key1 == key2) {
// for (const key3 in newSaveKey[key2]) {
// if (key3 == 'phoneCode') {
// submitObj[newSaveKey[key2][key3]] = newSaveKey[key2].phoneString.split(' ')[0]
// }
// if (key3 == 'phoneString') {
// submitObj[newSaveKey[key2].key] = newSaveKey[key2][key3].split(' ')[1]
// }
// }
// }
// break
case 'address':
if (key1 == key2) {
addressList.push(newSaveKey[key2])
}
break
case 'country':
if (key1 == key2 && key1 == 'customerType' && result[key1] == 'INDIVIDUAL') {
submitObj['country'] = newSaveKey[key2]['countryCode']
submitObj['countryName'] = newSaveKey[key2]['name']
}
break
default:
break
}
}
}
if (addressList.length > 0) {
submitObj['addressList'] = addressList
}
if (submitObj['companyMobile']) {
submitObj['companyMobileCode'] = submitObj['companyMobile'].split(' ')[0]
submitObj['companyMobile'] = submitObj['companyMobile'].split(' ')[1]
}
if (submitObj['mobile']) {
submitObj['mobileCode'] = submitObj['mobile'].split(' ')[0]
submitObj['mobile'] = submitObj['mobile'].split(' ')[1]
}
if (submitObj['authMobile']) {
submitObj['authMobileCode'] = submitObj['authMobile'].split(' ')[0]
submitObj['authMobile'] = submitObj['authMobile'].split(' ')[1]
}
// 删除多余字段
deleteKeyList.value.forEach(item => {
delete submitObj[item]
})
return submitObj
}
// 表单提交
const submitForm = () => {
proxy.$refs['policyholderInfoFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
submitObj['appointmentBizId'] = props.apiPolicyholderInfoDto.appointmentBizId
submitObj['id'] = props.apiPolicyholderInfoDto.id
submitObj['policyholderBizId'] = props.apiPolicyholderInfoDto.policyholderBizId
editPolicyholderInfo(submitObj).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('投保人修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
if (props.customerBizId) {
form.value = { ...oldObjInfo.value }
editStatus.value = true
} else {
// resetShow('smokeQuantity', false)
proxy.$refs['policyholderInfoFormRef'].resetFields()
}
processedPolicyData.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
})
.catch(() => {})
}
// 获取流程详情
// function getCustomerInfo(customerBizId, formData) {
// getCustomerDetail(customerBizId).then(async res => {
// if (res.code == 200) {
// // 回显值
// setFormValue(res.data, formData)
// }
// })
// }
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
tempPolicyForm.value = { ...form.value }
tempSaveKey.value = { ...saveKey.value }
tempAddressQuickList.value = JSON.parse(JSON.stringify(addressQuickList.value))
tempPhoneQuickList.value = JSON.parse(JSON.stringify(phoneQuickList.value))
if (newVal === 'policyholder') {
openList.value = false
setTimeout(() => {
if (props.idsObj.appointmentBizId) {
processFormData({
domdata: policyDomData,
customerInfo: props.apiPolicyholderInfoDto,
exportValue: null
})
} else {
processFormData({
domdata: policyDomData,
exportValue: null
})
}
}, 500)
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
display: flex;
justify-content: flex-start;
.title {
width: 120px;
font-size: 14px;
text-align: right;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
/* display: flex;
align-items: center; */
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template>
<div>
<div v-if="policyTransferData.length > 0" class="content">
<!-- <el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row> -->
<el-form ref="policyTransferFormRef" :model="form" label-width="0px" class="formCon">
<div v-for="father in policyTransferData">
<div class="formBox">
<el-row :gutter="20">
<el-col :sm="father.sm" :lg="father.lg" class="formItem" v-if="father.show">
<div v-if="father.domType === 'Div'" class="divClass">
<div v-if="father.key == 'policyTransfer'" class="desBox">
<div class="title">{{ father.title }}</div>
<div class="informationBox">
<div
v-for="(item, index) in father.informationList"
:key="index"
style="margin-bottom: 10px"
>
{{ item.name }}
</div>
</div>
<el-form-item v-if="father.key == 'policyTransfer'" prop="policyTransfer">
<el-radio-group v-model="form[father.key]">
<el-radio
v-for="dict in father.options"
:key="dict.value"
:value="dict.value"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item>
<div class="tips" v-if="father.tip">{{ father.tip }}</div>
</div>
</div>
</el-col>
</el-row>
</div>
</div>
</el-form>
<el-row>
<el-col>
<div class="tabButton">
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row>
</div>
</div>
</template>
<script setup name="PolicyTransferInfo">
import policyTransferDomData from '@/formJson/policyTransferInfo'
import { watch } from 'vue'
import { editPolicytransfer } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiAppointmentInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number } //父组件传递过来的预约的状态
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const editStatus = ref(false) //编辑状态
const errorFields = ref([]) // 存储校验失败的字段信息
const data = reactive({
form: { policyTransfer: '' },
tempSecondHolderForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
policyTransferData: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, policyTransferData, tempSecondHolderForm } = toRefs(data)
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
form.value = {}
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const section of processedData) {
if (section.dictType) {
// 获取字典数据
section.options = fetchDictData(section.dictType)
}
}
if (props.idsObj.appointmentBizId) {
if (props.apiAppointmentInfoDto.policyTransfer) {
form.value.policyTransfer = props.apiAppointmentInfoDto.policyTransfer
}
}
policyTransferData.value = processedData
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(policyTransferData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
policyTransferData.value = processedData
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = {}
if (props.activeName == 'secondHolder') {
submitObj = JSON.parse(JSON.stringify(form.value))
} else {
submitObj = JSON.parse(JSON.stringify(tempSecondHolderForm.value))
}
//处理表单数据
for (const key1 in submitObj) {
if (key1 == 'birthTime') {
submitObj[key1] = proxy.formatToDateTime(submitObj[key1])
}
}
return submitObj
}
// 表单提交
const submitForm = () => {
proxy.$refs['policyTransferFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = JSON.parse(JSON.stringify(props.apiAppointmentInfoDto))
submitObj.policyTransfer = form.value.policyTransfer
submitObj.appointmentBizId = props.idsObj.appointmentBizId
if (props.idsObj.appointmentBizId) {
editPolicytransfer(submitObj).then(res => {
if (res.code == 200) {
// handleEditStatus()
proxy.$message.success('转保声明修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
// tempSecondHolderForm.value = { ...form.value }
if (newVal === 'policyTransfer') {
processFormData({
domdata: policyTransferDomData
})
}
}
)
// 暴露给父组件
defineExpose({
form,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.content {
display: flex;
flex-direction: column;
.formCon {
flex: 1;
}
}
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
padding: 10px;
.title {
width: 100%;
font-size: 14px;
margin-bottom: 15px;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
.tips {
width: 100%;
font-size: 13px;
margin-top: 5px;
}
}
}
.tabButton {
/* box-shadow: 0 -1px 14px #00000014; */
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 50px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
/* display: flex;
align-items: center; */
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template>
<div>
<div v-if="processedProductData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="productFormRef" :model="form" :rules="rules">
<el-row v-for="father in processedProductData" style="margin-bottom: 10px">
<div class="formBox formFna">
<div class="fatherLable">
<span>{{ father.fatherTitle }}</span>
<el-button
style="margin-left: 10px"
v-if="father.addBtn"
type="primary"
icon="Plus"
@click="addChildren(father)"
size="small"
:disabled="editStatus"
>新增</el-button
>
</div>
<div class="subTitle" v-if="father.subTitle">{{ father.subTitle }}</div>
<el-row v-if="father.child == 'no'" :gutter="20">
<template v-for="child in father.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItem" v-if="child.show">
<div>
<el-form-item
:label="child.label"
:prop="father.key + '.' + child.key"
:key="child.key"
:label-width="child.labelWidth"
:label-position="child.labelPosition"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[father.key][child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
:style="{ width: child.inputWidth ? child.inputWidth : '100%' }"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[father.key][child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
style="width: 100%"
v-if="child.domType === 'DatePicker'"
v-model="form[father.key][child.key]"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
/>
<el-checkbox-group
v-if="child.domType === 'Checkbox'"
v-model="form[father.key][child.key]"
:disabled="child.disabled"
>
<el-checkbox
v-for="item in child.options"
:key="item.value"
:label="item.value"
>
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
<el-select
v-model="form[father.key][child.key]"
v-if="child.domType === 'SearchSelect'"
filterable
remote
reserve-keyword
placeholder="请输入关键词搜索"
:remote-method="query => searchSelectList(query, child.key)"
:loading="searchLoadingStates[child.key]"
:disabled="child.disabled"
@change="handleSearchSelectChange(father, child)"
>
<el-option
v-for="item in searchOptions[child.key] || []"
:key="item.id"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</div>
</el-col>
</template>
</el-row>
<!-- 有子孙的dom -->
<el-row v-if="father.child == 'yes' && father.data.length > 0" :gutter="20">
<template v-for="(child, childIndex) in father.data" :key="child.id">
<el-col :span="child.span">
<div
class="childLabel"
v-if="father.key == 'apiProductPlanAdditionalInfoDtoList'"
@click="deleteChildren(father, childIndex)"
>
<span>{{ `${child.childTitle}-${childIndex + 1}` }}</span>
<el-icon
v-if="child.deleteBtn"
style="color: red; font-size: 18px; margin-left: 10px"
><Delete
/></el-icon>
</div>
</el-col>
<template v-for="grandchildren in child.children" :key="grandchildren.key">
<el-col
:sm="grandchildren.sm"
:lg="grandchildren.lg"
class="formItem"
v-if="grandchildren.show && form[father.key] && form[father.key][childIndex]"
>
<el-form-item
:label="grandchildren.label"
:prop="grandchildren.key"
:key="grandchildren.key"
:label-width="grandchildren.labelWidth"
:label-position="grandchildren.labelPosition"
>
<el-input
v-if="grandchildren.domType === 'Input'"
:type="grandchildren.inputType"
v-model="form[father.key][childIndex][grandchildren.key]"
:placeholder="grandchildren.placeholder"
maxlength="30"
:disabled="grandchildren.disabled"
/>
<!-- 下拉框 -->
<el-select
v-if="grandchildren.domType === 'Select'"
v-model="form[father.key][childIndex][grandchildren.key]"
:placeholder="grandchildren.placeholder"
:disabled="grandchildren.disabled"
>
<el-option
v-for="item in grandchildren.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
style="width: 100%"
v-if="grandchildren.domType === 'DatePicker'"
v-model="form[father.key][childIndex][grandchildren.key]"
type="date"
:placeholder="grandchildren.placeholder"
:disabled="grandchildren.disabled"
/>
<!-- 搜索下拉框 -->
<el-select
v-model="form[father.key][childIndex][grandchildren.key]"
v-if="grandchildren.domType === 'SearchSelect'"
filterable
remote
reserve-keyword
placeholder="请输入关键词搜索"
:remote-method="query => searchSelectList(query, grandchildren.key)"
:loading="searchLoadingStates[grandchildren.key]"
:disabled="grandchildren.disabled"
>
<el-option
v-for="item in searchOptions[grandchildren.key] || []"
:key="item.id"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</template>
</template>
</el-row>
</div>
</el-row>
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
size="large"
@click="resetForm()"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="success"
icon="Check"
@click="submitForm()"
size="large"
:disabled="editStatus"
>保存</el-button
>
</div>
</el-col>
</el-row>
</el-form>
</div>
</div>
</template>
<script setup name="customer">
import useDictStore from '@/store/modules/dict'
import productDomData from '@/formJson/productPlan'
import { watch } from 'vue'
import { addfanForm, getfanFormDetail, editFanForm, getCustomerList } from '@/api/sign/fna'
import { getInsuranceProductList, getAdditionalProductList } from '@/api/common'
import { editProductPlanInfo, delAdditional } from '@/api/sign/appointment'
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
fnaFormBizId: { type: String, default: '' }, //提交状态,新增、修改
customerBizId: { type: String, default: '' }, //提交状态,新增、修改
dictTypeLists: { type: Array, default: () => [] }, //多个字典值数据
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiProductPlanInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number } //父组件传递过来的预约的状态
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { sys_no_yes } = proxy.useDict('sys_no_yes')
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const currencyType = ref([]) // 是否列表
const searchOptions = ref({}) // 存储不同key对应的选项
const searchLoadingStates = ref({}) // 存储不同key对应的加载状态
const data = reactive({
form: {},
tempForm: {}, //由于切换tab的时候,表单数据会重置,所以需要保存一份临时表单数据
processedProductData: [], // 处理后的表单数据
oldProductDomData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const { form, rules, processedProductData, queryParams, oldProductDomData, tempForm } = toRefs(data)
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
form.value = { ...oldObjInfo.value }
editStatus.value = true
processedProductData.value = JSON.parse(JSON.stringify(oldProductDomData.value))
proxy.$refs['productFormRef'].resetFields()
})
.catch(() => {})
}
const handleSearchSelectChange = (father, child) => {
let productItem = dictStore.insureProductList.filter(item => {
return item.value == form.value[father.key][child.key]
})
let options = productItem[0].paymentTerm.split(',').map(item => {
return {
label: item,
value: item
}
})
const processedData = JSON.parse(JSON.stringify(processedProductData.value))
for (const section of processedData) {
if (section.key == father.key) {
if (section.data) {
for (const field of section.data) {
if (field.dictType && field.dictType == 'paymentTerm') {
field.options = options
}
}
}
}
}
if (options.length > 0) {
form.value[father.key]['paymentTerm'] = options[0].value
}
processedProductData.value = processedData
}
// 下拉框搜索方法
// 搜索方法
const searchSelectList = async (query, fieldKey) => {
// 设置该字段的加载状态
searchLoadingStates.value[fieldKey] = true
try {
// 根据不同的字段key调用不同的API
if (fieldKey === 'productName') {
const params = {
loginTenantBizId: userStore.projectInfo.tenantBizId,
productName: query.trim(),
pageNo: 1,
pageSize: 10
}
const response = await getInsuranceProductList(params)
if (response.code == 200) {
response.data.records = response.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.productBizId
}
})
searchOptions.value[fieldKey] = response.data.records
}
}
// 可以添加其他字段的处理,可以放其他的字段得请求,目前只有accountName,以后有了其他的在填充
else if (fieldKey === 'addProductName') {
const params = {
productName: query.trim(),
pageNo: 1,
pageSize: 10
}
const response = await getAdditionalProductList(params)
if (response.code == 200) {
response.data.records = response.data.records.map(item => {
return {
...item,
label: item.productName,
value: item.additionalProductBizId
}
})
searchOptions.value[fieldKey] = response.data.records
}
}
} catch (error) {
console.error(`${fieldKey} 搜索失败`, error)
searchOptions.value[fieldKey] = []
} finally {
searchLoadingStates.value[fieldKey] = false
}
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 处理表单配置,添加字典数据
const processFormData = async () => {
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(productDomData))
for (const section of processedData) {
if (section.fatherRequired) {
rules.value[section.key] = {}
}
//给表单赋值各模块key,对应表单的father.key便于收集值
if (section.keyType == 'Array') {
form.value[section.key] = []
} else if (section.keyType == 'Object') {
form.value[section.key] = {}
}
if (section.data) {
for (const formKey in form.value) {
if (section.key == formKey) {
if (section.dataLength) {
for (let i = 1; i < section.dataLength; i++) {
section.data.push(JSON.parse(JSON.stringify(section.data[0])))
}
}
for (const field of section.data) {
// 为下拉搜索框加options
if (field.domType == 'SearchSelect') {
if (field.key == 'accountName') {
searchOptions.value[field.key] = dictStore.tenantUserList
}
}
if (section.key == formKey && field.children) {
for (const child of field.children) {
if (child.dictType) {
child.options = fetchDictData(child.dictType)
if (child.dictType == 'bx_currency_type') {
currencyType.value = child.options
}
}
if (props.fnaFormBizId) {
child.disabled = true
} else {
child.disabled = false
}
}
}
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
//
/*
1.没有嵌套子级的也就是没有children的数据加rules,根据data中的required字段判断是否必填
*/
if (field.required && section.child == 'no') {
rules.value[section.key][field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' }
]
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
}
// 新增的时候需要,修改的时候暂时不需要
if (!props.idsObj.appointmentBizId) {
// 切换tab的时侯当在切换回来的时候,依据tempForm.value的值来设置form.value的值
for (const key in form.value) {
for (const key2 in tempForm.value) {
if (key == key2 && isObject(form.value[key])) {
form.value[key] = tempForm.value[key2]
}
if (key == key2 && isArray(form.value[key])) {
if (tempForm.value[key2].length > 0) {
if (
key2 == 'apiProductPlanAdditionalInfoDtoList' &&
section.key == key2 &&
key == key2
) {
section.data = form.value[key] = tempForm.value[key2]
}
}
}
}
}
}
}
if (props.idsObj.appointmentBizId) {
editStatus.value = true
setFormValue(props.apiProductPlanInfoDto, processedData)
} else {
editStatus.value = false
processedProductData.value = processedData
}
}
// 添加表单子级dom
const addChildren = father => {
if (editStatus.value) {
proxy.$message.warning('请先点击编辑')
return
}
const processedData = JSON.parse(JSON.stringify(processedProductData.value))
let obj = {
id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
span: 24, //栅格布局份数
childTitle: '附加险',
deleteBtn: true,
children: [
{
label: '产品名称',
key: 'addProductName',
domType: 'SearchSelect',
required: true,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
labelPosition: 'top', //标签的位置
lg: 8 //栅格布局份数
},
{
label: '保额',
key: 'sumInsured',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保费',
key: 'premium',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保障地区',
key: 'guaranteeRegion',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '货币',
key: 'currency',
domType: 'Select',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
dictType: 'bx_currency_type',
options: fetchDictData('bx_currency_type'),
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '等级',
key: 'insuranceType',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '自付额',
key: 'deductibles',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '附加保障',
key: 'additionalSafeguards',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
}
for (const section of processedData) {
if (father.key == 'apiProductPlanAdditionalInfoDtoList' && section.key == father.key) {
section.data.push(obj)
}
}
//更新form表单对应的数据,以便收集填写的值
form.value[father.key].push(obj)
processedProductData.value = processedData
}
const deleteChildren = (father, childIndex) => {
if (editStatus.value) {
proxy.$message.warning('编辑状态下才能删除')
return
}
const processedData = JSON.parse(JSON.stringify(processedProductData.value))
if (props.idsObj.appointmentBizId && form.value[father.key][childIndex].additionalBizId) {
delAdditional(form.value[father.key][childIndex].additionalBizId).then(res => {
if (res.code == 200) {
proxy.$message.success('附加险删除成功')
for (const section of processedData) {
if (father.key == 'apiProductPlanAdditionalInfoDtoList' && section.key == father.key) {
section.data.splice(childIndex, 1)
}
}
//更新form表单对应的数据,以便收集填写的值
form.value[father.key].splice(childIndex, 1)
}
})
} else {
for (const section of processedData) {
if (father.key == 'apiProductPlanAdditionalInfoDtoList' && section.key == father.key) {
section.data.splice(childIndex, 1)
}
}
//更新form表单对应的数据,以便收集填写的值
form.value[father.key].splice(childIndex, 1)
}
processedProductData.value = processedData
}
// 根据联动重置表单项的显示与否
const resetShow = (childKey, status) => {
console.log(childKey, status)
for (const section of processedProductData.value) {
// 暂时没考虑data里嵌套children的情况
if (section.data) {
for (const field of section.data) {
if (field.key == childKey) {
// 获取字典数据
field.show = status
}
}
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'employment':
// 选择吸烟,展示吸烟数量
if (form.value[father.key][child.key] == 'OTHER') {
resetShow('otherEmployment', true)
form.value[father.key]['otherEmployment'] = ''
} else {
resetShow('otherEmployment', false)
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedProductData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
// 改变data中字段得编辑状态
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
// 改变data中的children字段得编辑状态
if (field.children) {
for (const child of field.children) {
if (editStatus.value) {
child.disabled = true
} else {
child.disabled = false
}
}
}
}
}
}
processedProductData.value = processedData
}
//给表单赋值 方便表单回显 obj 为表单数据
const setFormValue = (obj, formData) => {
let newForm = JSON.parse(JSON.stringify(obj))
// 1.先正确的拿到表单的回显值
for (const key in newForm) {
for (const key2 in obj) {
if (isObject(newForm[key]) && key == key2) {
newForm[key] = obj[key2]
}
if (isArray(newForm[key]) && key == key2 && obj[key2] && obj[key2].length > 0) {
newForm[key] = obj[key2]
}
}
}
// 2.根据最新的表单数据更新processedProductData的值,因为有些模块是多项的,所以表单数据要和dom对应上,防止dom有form表单里没有对应的数据会报错
let newChildren = {
id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
span: 24, //栅格布局份数
childTitle: '附加险',
deleteBtn: true,
children: [
{
label: '产品名称',
key: 'addProductName',
domType: 'SearchSelect',
required: true,
maxLength: 30,
disabled: false,
placeholder: '请输入',
show: true,
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
labelPosition: 'top', //标签的位置
lg: 8 //栅格布局份数
},
{
label: '保额',
key: 'sumInsured',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保费',
key: 'premium',
domType: 'Input',
inputType: 'number',
required: true,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '保障地区',
key: 'guaranteeRegion',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '货币',
key: 'currency',
domType: 'Select',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
dictType: 'bx_currency_type',
options: fetchDictData('bx_currency_type'),
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '等级',
key: 'insuranceType',
domType: 'Input',
inputType: 'text',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '自付额',
key: 'deductibles',
domType: 'Input',
inputType: 'number',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 12, //栅格布局份数
lg: 8 //栅格布局份数
},
{
label: '附加保障',
key: 'additionalSafeguards',
domType: 'Input',
inputType: 'textarea',
required: false,
maxLength: 300,
disabled: false,
placeholder: '请输入',
show: true,
labelPosition: 'top', //标签的位置
labelWidth: '120px', //标签宽度
sm: 24, //栅格布局份数
lg: 24 //栅格布局份数
}
]
}
// 深拷贝原始表单dom数据
const processedData = JSON.parse(JSON.stringify(formData))
for (const section of processedData) {
for (const key in newForm) {
//回显的数据有的没填写就会是null,收集表单值得时候和dom对应不上,对于null值得项要根据section得keyType给form正确得数据类型
if (!newForm[key]) {
if (section.keyType == 'Array') {
newForm[key] = []
} else if (section.keyType == 'Object') {
newForm[key] = {}
}
}
if (section.data) {
// 为附加险增加dom
if (
section.key == 'apiProductPlanAdditionalInfoDtoList' &&
key == 'apiProductPlanAdditionalInfoDtoList' &&
newForm[section.key].length > 0
) {
section.data.push(newChildren)
}
for (const field of section.data) {
if (section.child == 'yes' && field.children && field.children.length > 0) {
for (const child of field.children) {
if (props.idsObj.appointmentBizId) {
child.disabled = true
} else {
child.disabled = false
}
}
}
}
}
}
}
form.value = newForm
processedProductData.value = oldProductDomData.value = processedData
// 保存一份就得表单数据便于做撤销操作
oldObjInfo.value = JSON.parse(JSON.stringify(obj))
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 判断是否为数组
const isArray = value => {
return Array.isArray(value)
}
// 判断是否为对象
const isObject = value => {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
const handleSubmitForm = () => {
let result = {}
if (props.activeName == 'productPlan') {
result = JSON.parse(JSON.stringify(form.value))
} else {
result = JSON.parse(JSON.stringify(tempForm.value))
}
for (const key in result) {
if (isObject(result[key])) {
for (const key2 in result[key]) {
if (key2 == 'policyEffectiveDate' && result[key][key2]) {
result[key][key2] = proxy.formatToDateTime(result[key][key2])
}
for (const section of dictStore.insureProductList) {
if (key2 == 'productName' && section.productBizId == result[key][key2]) {
result[key][key2] = section.productName
result[key]['productBizId'] = section.productBizId
result[key]['companyName'] = section.ssDeptName
}
}
}
}
if (isArray(result[key])) {
result[key] = result[key]
.map(item => {
// 删除指定字段
delete item.childTitle
delete item.children
delete item.disabled
delete item.id
delete item.span
delete item.deleteBtn
return item
})
.filter(item => Object.keys(item).length > 0) // 过滤空对象
}
if (key == 'apiProductPlanAdditionalInfoDtoList') {
if (result[key].length > 0) {
result[key] = result[key].filter(item => {
for (const key4 in item) {
for (const section of dictStore.additionalProductList) {
if (key4 == 'addProductName' && section.additionalProductBizId == item[key4]) {
item[key4] = section.productName
item['additionalProductBizId'] = section.additionalProductBizId
}
}
if (item[key4]) return item
}
})
}
}
}
return result
}
// 表单提交
const submitForm = saveType => {
// return
proxy.$refs['productFormRef'].validate((valid, fields) => {
if (valid) {
let result = handleSubmitForm()
console.log('====================================')
console.log('提交的数据', result)
console.log('====================================')
if (props.idsObj.appointmentBizId) {
editProductPlanInfo(result).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('产品计划修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
// 获取流程详情
function getFanformInfo(fnaFormBizId, formData) {
getfanFormDetail(fnaFormBizId).then(async res => {
if (res.code == 200) {
// 回显值
setFormValue(res.data, formData)
}
})
}
watch(
() => props.activeName,
newVal => {
tempForm.value = { ...form.value }
if (newVal === 'productPlan') {
openList.value = false
setTimeout(() => {
processFormData()
}, 500)
}
}
)
if (props.formStatus == 'appointmentAdd') {
setTimeout(() => {
processFormData()
}, 1000)
}
// 暴露给父组件
defineExpose({
handleSubmitForm,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
margin-bottom: 5px;
display: flex;
align-items: center;
}
.subTitle {
font-size: 16px;
padding-left: 8px;
margin-bottom: 10px;
}
.childLabel {
font-size: 14px;
margin: 15px 0;
display: flex;
align-items: center;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
.infoItem {
display: flex;
align-items: center;
margin: 5px 0;
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
/* 新增的样式:防止label换行并显示省略号 */
.formFna :deep(.el-checkbox) {
margin-right: 10px;
}
/* 确保标签对齐方式正确 */
/* :deep(.el-form-item) {
display: flex;
align-items: center;
} */
/* :deep(.el-form-item__content) {
flex: 1;
margin-left: 0 !important;
} */
</style>
<template>
<div>
<div v-if="processedSecondHolderData.length > 0">
<el-row>
<el-col :span="24">
<div class="topBtn">
<!-- <el-button type="warning" icon="DocumentAdd" @click="exportInfo" v-if="showContacts"
>导入联系人</el-button
> -->
<el-button
v-if="props.idsObj.appointmentBizId"
type="primary"
icon="EditPen"
@click="handleEditStatus"
>编辑</el-button
>
</div>
</el-col>
</el-row>
<el-form ref="secondHolderFormRef" :model="form" :rules="rules" label-width="120px">
<div v-for="father in processedSecondHolderData">
<el-row style="margin-bottom: 10px" v-if="father.showMoudle">
<div class="formBox">
<div class="fatherLable">{{ father.fatherTitle }}</div>
<div class="fatherDes">{{ father.description }}</div>
<el-row :gutter="20">
<template v-for="child in father.data" :key="child.key">
<el-col :sm="child.sm" :lg="child.lg" class="formItem" v-if="child.show">
<div>
<el-form-item
:label-width="child.labelWidth"
:label="child.label"
:prop="child.key"
:key="child.key"
:label-position="child.labelPosition"
>
<el-input
v-if="child.domType === 'Input'"
:type="child.inputType"
v-model="form[child.key]"
:placeholder="child.placeholder"
maxlength="30"
:disabled="child.disabled"
/>
<el-select
v-if="child.domType === 'Select'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@change="handleSelectChange(father, child)"
:disabled="child.disabled"
>
<el-option
v-for="item in child.options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-model="form[child.key]"
style="width: 100%"
v-if="child.domType === 'DatePicker'"
type="date"
:placeholder="child.placeholder"
:disabled="child.disabled"
:disabled-date="disabledDate"
@change="handleDateChange(child)"
/>
<el-input
v-if="child.domType === 'arrowRight'"
v-model="form[child.key]"
:placeholder="child.placeholder"
@click="handleFoucs(child)"
:suffix-icon="ArrowRight"
readonly
:disabled="child.disabled"
>
</el-input>
<el-button v-if="child.domType === 'button'" :type="child.buttonType">{{
child.buttonTxt
}}</el-button>
</el-form-item>
</div>
</el-col>
</template>
</el-row>
</div>
</el-row>
</div>
<!-- v-if="props.idObj.appointmentBizId" -->
<el-row>
<el-col>
<div class="tabButton">
<!-- <el-button
type="primary"
icon="RefreshRight"
@click="resetForm"
size="large"
:disabled="editStatus"
>重置</el-button
> -->
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row>
</el-form>
<el-dialog title="联系人信息" v-model="openList" width="600px" append-to-body>
<div>
<el-form :model="queryParams" ref="queryRef" :inline="true" label-width="85px">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" @input="customerList" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" circle @click="customerList" />
<el-button type="info" icon="Refresh" circle @click="resetCustomerList" />
</el-form-item>
</el-form>
<div class="customerBox">
<div class="customerItem" v-for="item in tableData" :key="item.id">
<div class="top">
<div class="right">
<el-button type="primary" size="small" @click="handleExport(item)"
>导入联系人</el-button
>
</div>
</div>
<div class="bottom">
<div class="left">
<div class="infoItem">
<span>姓名:</span>
<span> {{ item.name || '暂无' }}</span>
</div>
<div class="infoItem">
<span>性别:</span>
<span>
<dict-tag :options="fetchDictData('sys_gender')" :value="item.gender"
/></span>
</div>
<div class="infoItem">
<span>年龄:</span>
<span> {{ item.age || '暂无' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
<Phone
@close="handleCloseDrawer"
:showDrawer="showPhoneDrawer"
:drawerInfo="drawerInfo"
:phoneMenuList="phoneMenuList"
:phoneQuickList="phoneQuickList"
@confirmDrawer="confirmDrawer"
/>
<Address
@close="handleCloseDrawer"
:showAddressDrawer="showAddressDrawer"
:drawerInfo="drawerInfo"
:addressMenuList="addressMenuList"
:addressQuickList="addressQuickList"
@confirmDrawer="confirmDrawer"
/>
<Country
:showCountryDrawer="showCountryDrawer"
@close="handleCloseDrawer"
@confirmCountry="confirmDrawer"
/>
</div>
</template>
<script setup name="secondHolderInfo">
import { calculateExactAge } from '@/utils/date'
import { ArrowRight } from '@element-plus/icons-vue'
import secondHolderDomData from '@/formJson/secondHolder'
import Country from '@/views/components/country'
import Phone from '@/views/components/phone'
import Address from '@/views/components/address'
import { watch, nextTick } from 'vue'
import { getCustomerList } from '@/api/sign/fna'
import { editSecondHolderInfo } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict'
const dictStore = useDictStore() //获取字典数据
const props = defineProps({
activeName: { type: String, default: '' }, //tab名称
fearthStatus: { type: String, default: '' }, //父组件状态,新增、修改
formStatus: { type: String, default: '' }, //父组件状态,新增、修改
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
apiSecondHolderInfoDto: { type: Object, default: () => ({}) }, //父组件传递过来的预约信息的详情
appointmentStatus: { type: Number }, //父组件传递过来的预约的状态
customerInfo: { type: Object, default: () => ({}) } //客户详情回显表单用
})
const emit = defineEmits(['handleSuccessEdit'])
const { proxy } = getCurrentInstance()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const showPhoneDrawer = ref(false) //电话抽屉开关
const showAddressDrawer = ref(false) //地址抽屉开关
const showCountryDrawer = ref(false) //国家/地区抽屉开关
const drawerInfo = ref({}) // 用于存储所有arrowRight类型的输入框输入值
const saveKey = ref({}) // 用于存储当前点击的drawer框返回的对象,修改的时候回显值也要存key
const tempSaveKey = ref({}) // 用于tab切换的时候保存一份临时的值,防止切换的时候数据丢失
const errorFields = ref([]) // 存储校验失败的字段信息
const editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const openList = ref(false) // 客户列表弹窗
const oldObjInfo = ref({}) // 修改时存储原始数据,便于撤销操作
const showContacts = ref(true)
const tableLoading = ref(false)
const tableData = ref([])
const total = ref(0)
// 地址组件菜单数据
const addressMenuList = ref([
{
name: '国家/地区',
icon: false,
value: '',
placeholder: '请输入国家/地区',
key: 'region'
},
{
name: '省市',
icon: false,
value: '',
placeholder: '请输入省市',
key: 'city'
},
{
name: '街道',
icon: false,
value: '',
placeholder: '请输入街道',
key: 'street'
},
{
name: '详细地址',
icon: false,
value: '',
placeholder: '请输入详细地址',
key: 'location'
}
])
// 快捷地址的数据
const addressQuickList = ref([])
const phoneMenuList = ref([
{
name: '区号',
icon: true,
value: '',
placeholder: '请输入区号',
arrow: true,
type: 'string'
},
{
name: '电话号码',
icon: false,
value: '',
placeholder: '请输入电话号码',
type: 'number'
}
])
const phoneQuickList = ref([])
const personalObj = ref({}) //存储个人key
const companyObj = ref({}) //存储公司key
const commonObj = ref({}) //存储个人和公司的公共key
const deleteKeyList = ref([
'objType',
'mailingAddress',
'residentialAddress',
'residenceAddress',
'companyAddress',
'txAddress',
'companyEnterAddress',
'phoneString',
'phoneCode'
]) // 存储需要删除的key
const data = reactive({
form: {},
tempSecondHolderForm: {}, //由于切换tab的时候,表单数据会重置,所以需要
processedSecondHolderData: [], // 处理后的表单数据
oldAppointmentData: [], // 保存旧的表单Dom,便于撤销操作
rules: {}, //表单验证规则,
queryParams: {
pageNo: 1,
pageSize: 4,
name: undefined
}
})
const {
form,
rules,
processedSecondHolderData,
queryParams,
oldAppointmentData,
tempSecondHolderForm
} = toRefs(data)
const handleDateChange = child => {
let age = null
if (child.key == 'birthTime') {
age = calculateExactAge(proxy.formatToDate(form.value.birthTime))
if (age >= 0) {
form.value.age = age
}
}
}
const disabledDate = time => {
return time.getTime() > Date.now()
}
const exportInfo = () => {
if (props.customerBizId && editStatus.value) {
proxy.$modal.confirm(`请先点击编辑在导入客户信息`, { showCancel: '0', title: '填写提示' })
return
}
openList.value = true
customerList()
}
const customerList = () => {
tableLoading.value = true
getCustomerList(queryParams.value).then(res => {
if (res.code == 200) {
tableData.value = res.data.records
total.value = res.data.total
tableLoading.value = false
}
})
}
const resetCustomerList = () => {
queryParams.value = {
pageNo: 1,
pageSize: 4,
name: undefined
}
customerList()
}
// 从客户列表中导入客户信息到当前表单
const handleExport = row => {
oldObjInfo.value = JSON.parse(JSON.stringify(form.value)) // 修改时存储原始数据,便于撤销操作
processFormData({
domdata: processedSecondHolderData.value,
customerInfo: row,
exportValue: true
})
openList.value = false
}
// 获取字典数据
const fetchDictData = dictType => {
let options = []
try {
dictStore.dictTypeLists.forEach(item => {
if (item.dictType == dictType) {
options = item.dictItemList
}
})
return options
} catch (error) {
console.error('获取字典数据失败:', error)
return []
}
}
// 添加英文校验函数
const validateEnglish = (rule, value, callback) => {
if (value && !/^[A-Za-z]*$/.test(value)) {
// 清空非英文字符
form.value.firstNamePinyin = ''
callback(new Error('只能输入英文字母'))
} else {
callback()
}
}
// 处理表单配置,添加字典数据
/**
* domdata:表单的dom数据
* customerInfo:根据客户信息回显表单
* exportValue:是否从导入联系人列表中导入客户信息到当前表单
*/
const processFormData = async obj => {
form.value = {}
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(obj.domdata))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (field.dictType) {
// 获取字典数据
field.options = fetchDictData(field.dictType)
}
if (field.required) {
if (field.showEn) {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' },
{ validator: validateEnglish, trigger: 'change' }
]
} else {
rules.value[field.key] = [
{ required: true, message: `${field.label}不能为空`, trigger: 'blur' }
]
}
}
if (obj.customerInfo) {
for (const key1 in obj.customerInfo) {
if (key1 == 'birthdate' && obj.customerInfo[key1]) {
obj.customerInfo[key1] = proxy.formatToDate(obj.customerInfo[key1])
}
// 对应客户和dom表单字段方便赋值
if (field.customerKey && key1 == field.customerKey) {
form.value[field.key] = obj.customerInfo[key1]
}
}
}
if (props.idsObj.appointmentBizId) {
field.disabled = true
} else {
if (field.key == 'age') {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
}
//当tab切换走,在切换回来的时候,需要把之前保存的值赋值回来
if (JSON.stringify(tempSecondHolderForm.value) !== '{}' && !props.idsObj.appointmentBizId) {
form.value = { ...tempSecondHolderForm.value }
}
if (props.idsObj.appointmentBizId) {
form.value = { ...props.apiSecondHolderInfoDto }
editStatus.value = true
} else {
editStatus.value = false
}
processedSecondHolderData.value = oldAppointmentData.value = processedData
}
//弹出右侧抽屉
const handleFoucs = child => {
if (child.disabled) return
console.log('saveKey.value', saveKey.value)
console.log('child', child)
drawerInfo.value = JSON.parse(JSON.stringify(child))
switch (child.drawerType) {
case 'phone':
phoneMenuList.value[0].key = child.code
phoneMenuList.value[1].key = child.key
phoneMenuList.value.forEach(item => {
item.value = ''
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showPhoneDrawer.value = true
break
case 'address':
addressMenuList.value.forEach(item => {
for (const key in saveKey.value) {
if (key == child.key) {
for (const key2 in saveKey.value[key]) {
if (item.key == key2) {
item.value = saveKey.value[key][key2]
}
}
}
}
})
showAddressDrawer.value = true
break
case 'country':
showCountryDrawer.value = true
break
default:
break
}
}
// 处理抽屉关闭
const handleCloseDrawer = () => {
showPhoneDrawer.value = false
showAddressDrawer.value = false
showCountryDrawer.value = false
drawerInfo.value = {}
}
const confirmDrawer = info => {
// info 为抽屉返回的值
if (drawerInfo.value.domType == 'arrowRight' && drawerInfo.value.drawerType) {
let newObj = info[drawerInfo.value.key]
if (form.value['customerType'] == 'COMPANY') {
newObj.fatherKey = 'company'
} else if (form.value['customerType'] == 'INDIVIDUAL') {
newObj.fatherKey = 'person'
}
//要判断drawerType
switch (drawerInfo.value.drawerType) {
case 'phone':
newObj.objType = drawerInfo.value.drawerType
// 因为电话有多个,根据点击的电话类型在抽屉里回显,所以要用drawerInfo.value.code来控制
form.value[info.key] = `${newObj[drawerInfo.value.code]} ${newObj[drawerInfo.value.key]}`
saveKey.value[drawerInfo.value.key] = newObj
break
case 'address':
newObj.objType = drawerInfo.value.drawerType
newObj.type = drawerInfo.value.key
form.value[info.key] = `${newObj.region} ${newObj.city} ${newObj.street} ${newObj.location}`
saveKey.value[info.key] = newObj
break
case 'country':
info.objType = drawerInfo.value.drawerType
form.value[drawerInfo.value.key] = info.name
saveKey.value[drawerInfo.value.key] = info
break
default:
break
}
}
handleCloseDrawer()
}
// 根据联动重置表单项的显示与否
const resetShow = obj => {
for (const section of processedSecondHolderData.value) {
switch (obj.type) {
case 'father':
if (section.key == obj.key) {
section.showMoudle = obj.status
}
break
case 'child':
if (section.data) {
for (const field of section.data) {
if (field.key == obj.key) {
// 获取字典数据
field.show = obj.status
}
}
}
break
default:
break
}
}
}
const handleSelectChange = (father, child) => {
switch (child.key) {
case 'customerType':
if (form.value[child.key] == 'COMPANY') {
showContacts.value = false
for (const section of processedSecondHolderData.value) {
if (section.key == 'company') {
for (const key1 in saveKey.value) {
for (const key2 in commonObj.value) {
if (key1 == key2) {
saveKey.value[key1]['fatherKey'] = section.key
}
}
}
section.showMoudle = true
} else if (section.key !== 'customer') {
section.showMoudle = false
}
}
} else {
showContacts.value = true
for (const section of processedSecondHolderData.value) {
if (section.key == 'company') {
section.showMoudle = false
} else {
section.showMoudle = true
}
}
}
break
case 'smokingAllowed':
// 选择吸烟,展示吸烟数量
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'smokingVolume', status: true })
} else {
resetShow({ type: 'child', key: 'smokingVolume', status: false })
}
break
case 'isVip':
// 选择vip,展示vip备注
if (form.value[child.key] == '1') {
resetShow({ type: 'child', key: 'vipRemark', status: true })
} else {
resetShow({ type: 'child', key: 'vipRemark', status: false })
}
break
default:
break
}
}
// 改变编辑状态
const handleEditStatus = () => {
editStatus.value = !editStatus.value
console.log('触发了编辑状态', editStatus.value)
// 深拷贝原始数据
const processedData = JSON.parse(JSON.stringify(processedSecondHolderData.value))
for (const section of processedData) {
if (section.data) {
for (const field of section.data) {
if (editStatus.value) {
field.disabled = true
} else {
field.disabled = false
}
}
}
}
processedSecondHolderData.value = processedData
}
// 数组去重
function removeDuplicates(arr, key) {
const seen = new Map()
const result = []
for (const item of arr) {
if (item[key] && !seen.has(item[key])) {
seen.set(item[key], true)
result.push(item)
}
}
return result
}
// 获取校验失败的字段信息
const getInvalidFields = fields => {
const errors = []
for (const field in fields) {
if (fields[field] && fields[field].length > 0) {
errors.push({
field: field,
message: fields[field][0].message
})
}
}
return errors
}
// 处理表单填写得数据
const handleFormValues = () => {
let submitObj = {}
if (props.activeName == 'secondHolder') {
submitObj = JSON.parse(JSON.stringify(form.value))
} else {
submitObj = JSON.parse(JSON.stringify(tempSecondHolderForm.value))
}
//处理表单数据
for (const key1 in submitObj) {
if (key1 == 'birthTime') {
submitObj[key1] = proxy.formatToDateTime(submitObj[key1])
}
}
return submitObj
}
// 表单提交
const submitForm = () => {
proxy.$refs['secondHolderFormRef'].validate((valid, fields) => {
if (valid) {
let submitObj = handleFormValues()
console.log('====================================')
console.log('submitObj', submitObj)
console.log('====================================')
// return
if (props.idsObj.appointmentBizId) {
editSecondHolderInfo(submitObj).then(res => {
if (res.code == 200) {
handleEditStatus()
proxy.$message.success('第二持有人修改成功')
emit('handleSuccessEdit')
}
})
}
errorFields.value = [] // 清空错误信息
} else {
// 获取校验失败的字段信息
errorFields.value = getInvalidFields(fields)
if (errorFields.value.length > 0) {
proxy.$message.error(errorFields.value[0].message)
}
}
})
}
const resetForm = () => {
proxy.$modal
.confirm('是否确认撤销所作操作?')
.then(function () {
if (props.customerBizId) {
form.value = { ...oldObjInfo.value }
editStatus.value = true
} else {
// resetShow('smokeQuantity', false)
proxy.$refs['secondHolderFormRef'].resetFields()
}
processedSecondHolderData.value = JSON.parse(JSON.stringify(oldAppointmentData.value))
})
.catch(() => {})
}
watch(
() => props.activeName,
newVal => {
// 切换tab的时侯把表单值保存在临时变量里,方便切换回来的时候回显
tempSecondHolderForm.value = { ...form.value }
if (newVal === 'secondHolder') {
openList.value = false
setTimeout(() => {
processFormData({
domdata: secondHolderDomData,
exportValue: null
})
}, 500)
}
}
)
// 暴露给父组件
defineExpose({
handleFormValues,
handleEditStatus
})
</script>
<style lang="scss" scoped>
.topBtn {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.formBox {
width: 100%;
.fatherLable {
font-size: 18px;
border-left: 4px solid #165dff;
padding-left: 5px;
}
.fatherDes {
font-size: 14px;
color: #a8abb2;
margin-top: 5px;
margin-bottom: 20px;
}
.inputBox {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: space-between;
min-height: 32px;
padding: 0px 11px;
.rightArrow {
font-size: 14px;
color: #a8abb2;
}
}
.desBox {
display: flex;
justify-content: flex-start;
.title {
width: 120px;
font-size: 14px;
text-align: right;
}
.informationBox {
margin-left: 5px;
font-size: 14px;
border: 1px solid #dcdfe6;
width: 100%;
border-radius: 4px;
padding: 2px 4px;
box-sizing: border-box;
}
}
}
.tabButton {
box-shadow: 0 -1px 14px #00000014;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
/* padding-right: 20px; */
padding-top: 20px;
.sumbitBtn {
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
height: 60px;
background-color: #165dff;
color: #fff;
padding: 0 30px;
.buttonIcon {
font-size: 16px;
color: #fff;
}
}
}
.customerBox {
.customerItem {
padding: 10px;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0 -1px 14px #00000014;
.top {
display: flex;
align-items: center;
justify-content: flex-end;
width: 100%;
.left {
width: 40%;
display: flex;
align-items: center;
justify-content: flex-start;
.gender {
display: flex;
align-items: center;
}
}
}
.bottom {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.left {
/* display: flex;
align-items: center; */
.infoItem {
display: flex;
align-items: center;
margin: 5px 10px;
}
}
}
}
.customerItem:last-child {
margin-bottom: 0px;
}
}
</style>
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 步骤条 --> <!-- 步骤条 -->
<el-row style="margin-bottom: 30px"> <!-- <el-row style="margin-bottom: 30px">
<el-col :span="24"> <el-col :span="24">
<Step :stepList="stepList"></Step> <Step :stepList="stepList"></Step>
</el-col> </el-col>
</el-row> </el-row> -->
<!-- 条件查询 --> <!-- 条件查询 -->
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
...@@ -14,15 +14,15 @@ ...@@ -14,15 +14,15 @@
ref="queryRef" ref="queryRef"
:inline="true" :inline="true"
v-show="showSearch" v-show="showSearch"
label-width="70px" label-width="100px"
> >
<el-form-item <el-form-item
><el-button type="primary" icon="Plus" @click="handleAdd" ><el-button type="primary" icon="Plus" @click="handleAdd"
>新建FNA</el-button >上传EXECL</el-button
></el-form-item ></el-form-item
> >
<el-form-item label="创建时间" style="width: 300px"> <el-form-item label="确认预约时间" style="width: 300px">
<el-date-picker <el-date-picker
v-model="dateRange" v-model="dateRange"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
...@@ -30,36 +30,27 @@ ...@@ -30,36 +30,27 @@
range-separator="-" range-separator="-"
start-placeholder="开始日期" start-placeholder="开始日期"
end-placeholder="结束日期" end-placeholder="结束日期"
@clear="clearDate"
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="FNA编号" prop="tenantName"> <el-form-item label="预约编号" prop="appointmentNo">
<el-input <el-input
v-model="queryParams.tenantName" v-model="queryParams.appointmentNo"
placeholder="请输入FNA编号" placeholder="请输入预约编号"
clearable clearable
style="width: 150px" style="width: 150px"
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="姓名" prop="contactName"> <el-form-item label="预约状态" prop="status">
<el-input
v-model="queryParams.contactName"
placeholder="请输入姓名"
clearable
style="width: 100px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="租户状态" placeholder="请选择"
clearable clearable
style="width: 100px" style="width: 110px"
> >
<el-option <el-option
v-for="dict in sys_status" v-for="dict in csf_ap_status"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"
...@@ -68,6 +59,7 @@ ...@@ -68,6 +59,7 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">查询</el-button> <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-col> </el-col>
...@@ -77,160 +69,117 @@ ...@@ -77,160 +69,117 @@
v-loading="loading" v-loading="loading"
:data="tenantList" :data="tenantList"
@selection-change="tableSelect" @selection-change="tableSelect"
:default-sort="{ prop: 'createTime', order: 'descending' }" @sort-change="sortChange"
> >
<el-table-column type="selection" width="55" /> <!-- <el-table-column type="selection" width="55" /> -->
<el-table-column label="FNA编号" align="center" prop="tenantName" /> <el-table-column type="index" label="序号" width="50" />
<el-table-column label="预约编号" align="center" prop="tenantName" /> <el-table-column label="预约编号" align="center" prop="appointmentNo" width="200" />
<el-table-column label="新单编号" align="center" prop="contactName" /> <el-table-column label="预约状态" align="center">
<el-table-column label="保单号" align="center" prop="contactPhone" /> <template #default="scope">
<dict-tag :options="csf_ap_status" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column label="产品名称" align="center" prop="productName" width="150" />
<el-table-column label="保险公司" align="center" prop="companyName" width="150" />
<el-table-column label="业务员" align="center" prop="businessRepresentName1" width="150" />
<el-table-column label="客户姓名" align="center" prop="maxProject" /> <el-table-column label="投保人" align="center" prop="policyholder" />
<el-table-column label="受保人" align="center" prop="insurant" />
<el-table-column label="供款年期" align="center" prop="paymentTerm" />
<el-table-column label="每期保费" align="center" prop="eachIssuePremium" />
<el-table-column label="状态" align="center"> <el-table-column label="货币" align="center" width="150">
<template #default="scope"> <template #default="scope">
<span v-if="scope.row.status == 0"> <dict-tag :options="bx_currency_type" :value="scope.row.currency" />
<span style="color: #ff7d00" class="iconfont icon-yanqiweiwancheng"></span> 未完成
</span>
<span v-if="scope.row.status == 1"
><span style="color: #43cf7c" class="iconfont icon-yiwancheng"></span> 已完成
</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="创建时间" sortable align="center" prop="createTime">
<el-table-column label="时间" align="center" prop="time" width="240" show-overflow-tooltip>
</el-table-column>
<!-- sortable -->
<el-table-column label="创建时间" align="center" prop="createTime" width="150">
<template #default="scope"> <template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ formatToDate(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
label="操作" label="操作"
align="center" align="left"
width="200" width="250"
class-name="small-padding fixed-width" class-name="small-padding fixed-width"
fixed="right"
> >
<template #default="scope"> <template #default="scope">
<el-button link type="primary" @click="handlePermission(scope.row)">查看</el-button>
<el-button link type="primary" @click="handleUpdate(scope.row)">修改</el-button> <el-button link type="primary" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" @click="handleDelete(scope.row)">删除</el-button> <el-button
link
type="primary"
v-if="scope.row.status == 2 || scope.row.status == 3"
@click="getAppointmentInfo(scope.row.appointmentBizId)"
>查看行程单</el-button
>
<el-button link type="primary" @click="handleExprot(scope.row)">导出</el-button>
<el-button
link
type="danger"
v-if="scope.row.status === 0"
@click="handleDelete(scope.row)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="total >= 0" v-show="total >= 0"
:total="total" :total="total"
v-model:page="queryParams.pageNum" v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getList" @pagination="getList"
/> />
<!-- 下一步到预约 --> <!-- 下一步到预约 -->
<div class="bottomBtn"> <div class="bottomBtn">
<el-button type="primary" @click="goToAppointment">下一步</el-button> <el-button type="success" @click="goToAppointment('previousStep')">上一步</el-button>
<el-button type="primary" @click="goToAppointment('nextStep')">下一步</el-button>
</div> </div>
<!-- 添加或修改租户对话框 --> <!-- 展示行程单详情 -->
<el-dialog :title="title" v-model="open" width="650px" append-to-body> <el-dialog v-model="dialogVisible" width="70%">
<el-form :model="form" :rules="rules" ref="tenantRef" label-width="100px"> <div class="dialogBox">
<el-row> <div class="dialogTitle">
<el-col :span="12"> {{ appointmentSummeryInfo.apiAppointmentInfoDto.creatorName }} - 香港行程安排
<el-form-item label="租户名称" prop="tenantName"> </div>
<el-input v-model="form.tenantName" placeholder="请输入租户名称" maxlength="30" /> <div class="dialogItem" v-for="item in detailData">
</el-form-item> <div class="dialogItemTitle">{{ item.title }}</div>
</el-col> <DetailPanel
<el-col :span="12"> :data="item.data"
<el-form-item label="联系人姓名" prop="contactName"> :row-span="24"
<el-input v-model="form.contactName" placeholder="请输入联系人姓名" maxlength="30" /> col-gap="16px"
</el-form-item> label-width="120px"
</el-col> row-height="45px"
</el-row> :show-col-border="true"
<el-row> />
<el-col :span="12">
<el-form-item label="联系电话" prop="contactPhone">
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系邮箱" prop="contactEmail">
<el-input v-model="form.contactEmail" placeholder="请输入联系邮箱" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所属行业" prop="industry">
<el-input v-model="form.industry" placeholder="请输入所属行业" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系地址" prop="address">
<el-input v-model="form.address" placeholder="请输入联系地址" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="最大项目数" prop="maxProject">
<el-input v-model="form.maxProject" placeholder="请输入最大项目数" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="最大用户数" prop="maxUser">
<el-input v-model="form.maxUser" placeholder="请输入最大用户数" maxlength="50" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="服务到期时间" prop="expireTime">
<el-date-picker
v-model="form.expireTime"
type="datetime"
placeholder="选择到期日期"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<!-- <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>-->
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="租户LOGO">
<el-input v-model="form.logoUrl" type="textarea" placeholder="请输入内容"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div> </div>
</template> <div class="exprotBtn">
<el-button :loading="exportLoading" type="primary" @click="handleExprotPdf"
>下载行程单</el-button
>
</div>
</div>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script setup name="Appointment"> <script setup name="Appointment">
import DetailPanel from '@/components/DetailPanel'
import { onMounted, onActivated, ref } from 'vue'
import Step from '@/views/components/moduleStep' import Step from '@/views/components/moduleStep'
import { getToken } from '@/utils/auth'
import useAppStore from '@/store/modules/app'
import { import {
changeUserStatus, getAppointmentList,
listTenant, getAppointmentExprot,
resetUserPwd, delSigleAppointment,
delUser, getAppointmentDetail,
getTenant, getItineraryExprot
updateTenant, } from '@/api/sign/appointment'
addTenant,
changeTenantStatus
} from '@/api/system/tenant'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const stepList = ref([ const stepList = ref([
{ title: 'FNA', id: 1, finish: true, todo: false, unFinish: false }, { title: 'FNA', id: 1, finish: true, todo: false, unFinish: false },
{ title: '预约', id: 2, todo: true, finish: false, unFinish: false }, { title: '预约', id: 2, todo: true, finish: false, unFinish: false },
...@@ -238,85 +187,226 @@ const stepList = ref([ ...@@ -238,85 +187,226 @@ const stepList = ref([
]) ])
const userStore = useUserStore() const userStore = useUserStore()
const router = useRouter() const router = useRouter()
const appStore = useAppStore()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const { sys_status, sys_scope, sys_no_yes } = proxy.useDict('sys_status', 'sys_scope', 'sys_no_yes') const dialogVisible = ref(false)
const appointmentSummeryInfo = ref({})
const tenantList = ref([]) const tenantList = ref([])
const open = ref(false)
const loading = ref(true) const loading = ref(true)
const showSearch = ref(true) const showSearch = ref(true)
const ids = ref([]) const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0) const total = ref(0)
const title = ref('')
const dateRange = ref([]) const dateRange = ref([])
const deptName = ref('') const detailData = ref([]) //行程单-行程信息
const deptOptions = ref(undefined) const exportLoading = ref(false)
const enabledDeptOptions = ref(undefined)
const initPassword = ref(undefined)
const postOptions = ref([])
const roleOptions = ref([])
const selectIdsList = ref([])
const data = reactive({ const data = reactive({
form: {}, form: {},
queryParams: { queryParams: {
pageNum: 1, pageNo: 1,
pageSize: 8, pageSize: 8,
loginTenantBizId: userStore.currentTenant.apiLoginTenantInfoResponse.tenantBizId, startTime: '',
tenantName: undefined, endTime: ''
contactName: undefined,
contactPhone: undefined,
status: undefined
},
rules: {
tenantName: [{ required: true, message: '租户名称不能为空', trigger: 'blur' }],
contactEmail: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
contactPhone: [
{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }
]
} }
}) })
const { queryParams, form, rules } = toRefs(data) const { queryParams, form, rules } = toRefs(data)
const { bx_currency_type, csf_ap_status } = proxy.useDict('bx_currency_type', 'csf_ap_status')
const handleExprotPdf = () => {
exportLoading.value = true
getItineraryExprot(appointmentSummeryInfo.value.apiAppointmentInfoDto.appointmentBizId).then(
res => {
if (res.code == 200) {
// 创建隐藏的下载链接
const link = document.createElement('a')
link.href = res.data
link.target = '_blank' // 新窗口打开
// 设置下载文件名(重要)
// 从URL中提取文件名,或者使用返回的文件名
const fileName = `${appointmentSummeryInfo.value.apiAppointmentInfoDto.creatorName} - 香港行程安排.pdf`
link.download = fileName
// 触发下载
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
exportLoading.value = false
// proxy.$message.success('行程单下载成功')
dialogVisible.value = false
}
}
)
}
// 获取预约详情
function getAppointmentInfo(appointmentBizId) {
getAppointmentDetail(appointmentBizId).then(res => {
if (res.code == 200) {
appointmentSummeryInfo.value = res.data
let appointment = appointmentSummeryInfo.value.apiAppointmentInfoDto
let insurant = appointmentSummeryInfo.value.apiInsurantInfoDto
let productPlan = appointmentSummeryInfo.value.apiProductPlanInfoDto.apiProductPlanMainInfoDto
productPlan.total = (productPlan.paymentTerm * productPlan.eachIssuePremium).toFixed(2)
detailData.value = [
{
title: '集合信息',
data: [
// 第一行:2列布局(各占12)
{
label: '集合时间',
value: appointment.arrivalTime,
span: 12 // 占12/24
},
{
label: '集合地点',
value: appointment.meetingPoint,
span: 12 // 占12/24
},
{
label: '意向地点',
value: appointment.signingAddress,
span: 12 // 占12/24
}
]
},
{
title: '业务代表',
data: [
// 第一行:2列布局(各占12)
{
label: '姓名',
value: appointment.businessRepresentName1,
span: 12 // 占12/24
},
{
label: '联系电话',
value: appointment.businessRepresentMobile1
? appointment.businessRepresentMobile1Code + appointment.businessRepresentMobile1
: '-',
span: 12 // 占12/24
}
]
},
{
title: '咨询内容',
data: [
// 第一行:2列布局(各占12)
{
label: '咨询人',
value: appointment.arrivalTime,
span: 12 // 占12/24
},
{
label: '受保人',
value: insurant.insurantName,
span: 12 // 占12/24
},
{
label: '意向缴费年期',
value: productPlan.paymentTerm,
span: 12 // 占12/24
},
{
label: '保单证费',
value: productPlan.policyFee || '-',
span: 12 // 占12/24
},
{
label: '币种',
value: productPlan.currency,
span: 12 // 占12/24
},
{
label: '意向咨询产品',
value: productPlan.productName,
span: 12 // 占12/24
},
{
label: '合计金额',
value: productPlan.total,
span: 12 // 占12/24
}
]
}
]
console.log('detailData.value', detailData.value)
dialogVisible.value = true
}
})
}
const handleExprot = async row => {
try {
const res = await getAppointmentExprot(row.appointmentBizId)
if (res.code == 200) {
// 创建隐藏的下载链接
const link = document.createElement('a')
link.href = res.data.url
// link.target = '_blank' // 新窗口打开
// 设置下载文件名(重要)
// 从URL中提取文件名,或者使用返回的文件名
const fileName = '预约导出.xlsx'
link.download = fileName
// 触发下载
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
proxy.$message.success('导出成功')
}
} catch (error) {
console.error('导出失败:', error)
}
}
const clearDate = () => {
dateRange.value = []
queryParams.value.startTime = ''
queryParams.value.endTime = ''
}
const sortChange = ({ prop, order }) => {
if (order == 'ascending') {
queryParams.value.sortOrder = 'ascend'
} else {
queryParams.value.sortOrder = 'descend'
}
if (prop) {
queryParams.value.sortField = prop
}
getList()
}
/** 多选框选中数据 */ /** 多选框选中数据 */
function tableSelect(selection) { function tableSelect(selection) {
selectIdsList.value = selection.map(item => item.projectBizId) // selectIdsList.value = selection.map(item => item.projectBizId)
}
const goToAppointment = type => {
if (type == 'previousStep') {
router.push({ path: '/sign/FnaList' })
} else if (type == 'nextStep') {
router.push({ path: '/sign/appointment' })
}
} }
/** 查询租户列表 */ /** 查询租户列表 */
function getList() { function getList() {
if (dateRange.value && dateRange.value.length > 0) {
queryParams.value.startTime = `${dateRange.value[0]} 00:00:00`
queryParams.value.endTime = `${dateRange.value[1]} 23:59:59`
}
loading.value = true loading.value = true
listTenant(queryParams.value).then(response => { try {
tenantList.value = response.data.records getAppointmentList(queryParams.value).then(response => {
total.value = response.data.total tenantList.value = response.data.records
total.value = response.data.total
loading.value = false
})
} catch (error) {
tenantList.value = []
} finally {
loading.value = false loading.value = false
}) }
}
/** 过滤禁用的部门 */
function filterDisabledDept(deptList) {
return deptList.filter(dept => {
if (dept.disabled) {
return false
}
if (dept.children && dept.children.length) {
dept.children = filterDisabledDept(dept.children)
}
return true
})
}
/** 节点单击事件 */
function handleNodeClick(data) {
queryParams.value.deptId = data.id
handleQuery()
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
queryParams.value.pageNum = 1 queryParams.value.pageNo = 1
getList() getList()
} }
...@@ -324,16 +414,21 @@ function handleQuery() { ...@@ -324,16 +414,21 @@ function handleQuery() {
function resetQuery() { function resetQuery() {
dateRange.value = [] dateRange.value = []
proxy.resetForm('queryRef') proxy.resetForm('queryRef')
queryParams.value = {
pageNo: 1,
pageSize: 8,
startTime: '',
endTime: ''
}
handleQuery() handleQuery()
} }
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row) { function handleDelete(row) {
const userIds = row.userId || ids.value
proxy.$modal proxy.$modal
.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') .confirm('是否确认删除' + row.creatorName + '的预约流程?')
.then(function () { .then(function () {
return delUser(userIds) return delSigleAppointment(row.appointmentBizId)
}) })
.then(() => { .then(() => {
getList() getList()
...@@ -342,178 +437,42 @@ function handleDelete(row) { ...@@ -342,178 +437,42 @@ function handleDelete(row) {
.catch(() => {}) .catch(() => {})
} }
/** 导出按钮操作 */
function handleExport() {
proxy.download(
'system/user/export',
{
...queryParams.value
},
`user_${new Date().getTime()}.xlsx`
)
}
/** 租户状态修改 */
function handleStatusChange(row, event) {
let text = row.status === 0 ? '停用' : '启用'
const tenantName = row.tenantName
proxy.$modal
.confirm(`确认要${text}"${tenantName}"租户吗?`)
.then(() => changeTenantStatus({ tenantBizId: row.tenantBizId, status: row.status }))
.then(() => proxy.$modal.msgSuccess(`${text}成功`))
.catch(() => {
// 操作取消时恢复原状态
row.status = row.status === 0 ? 1 : 0
})
}
/** 更多操作 */
function handleCommand(command, row) {
switch (command) {
case 'handleResetPwd':
handleResetPwd(row)
break
case 'handleAuthRole':
handleAuthRole(row)
break
default:
break
}
}
/** 跳转角色分配 */
function handleAuthRole(row) {
const userId = row.userId
router.push('/system/user-auth/role/' + userId)
}
/** 重置密码按钮操作 */
function handleResetPwd(row) {
proxy
.$prompt('请输入"' + row.userName + '"的新密码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
closeOnClickModal: false,
inputPattern: /^.{5,20}$/,
inputErrorMessage: '用户密码长度必须介于 5 和 20 之间',
inputValidator: value => {
if (/<|>|"|'|\||\\/.test(value)) {
return '不能包含非法字符:< > " \' \\\ |'
}
}
})
.then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
proxy.$modal.msgSuccess('修改成功,新密码是:' + value)
})
})
.catch(() => {})
}
/** 选择条数 */
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.userId)
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 下载模板操作 */
function importTemplate() {
proxy.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`)
}
/**文件上传中处理 */
const handleFileUploadProgress = (event, file, fileList) => {
upload.isUploading = true
}
/** 文件上传成功处理 */
const handleFileSuccess = (response, file, fileList) => {
upload.open = false
upload.isUploading = false
proxy.$refs['uploadRef'].handleRemove(file)
proxy.$alert(
"<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
response.msg +
'</div>',
'导入结果',
{ dangerouslyUseHTMLString: true }
)
getList()
}
/** 提交上传文件 */
function submitFileForm() {
proxy.$refs['uploadRef'].submit()
}
/** 重置操作表单 */ /** 重置操作表单 */
function reset() { function reset() {
form.value = { form.value = {
tenantBizId: undefined, pageNo: 1,
tenantName: undefined, pageSize: 8
logoUrl: undefined,
contactName: undefined,
contactPhone: undefined,
contactEmail: undefined,
industry: undefined,
address: undefined,
status: '0',
expireTime: undefined,
maxProject: undefined,
maxUser: undefined
} }
proxy.resetForm('tenantRef') proxy.resetForm('tenantRef')
} }
/** 取消按钮 */
function cancel() {
open.value = false
reset()
}
/** 新增按钮操作 */ /** 新增按钮操作 */
function handleAdd() { function handleAdd() {
reset() router.push('/sign/FnaList/edit?type=add')
open.value = true
title.value = '添加租户'
} }
/** 修改按钮操作 */ /** 修改按钮操作 */
function handleUpdate(row) { function handleUpdate(row) {
reset() // 对预约status进行转换,到编辑页面在转换会有时机问题
const tenantBizId = row.tenantBizId csf_ap_status._object.csf_ap_status.forEach(element => {
getTenant(tenantBizId).then(response => { element.value = Number(element.value)
form.value = response.data if (row.status == element.value) {
open.value = true row.status = element.label
title.value = '修改用户'
})
}
/** 分配权限 */
function handlePermission(row) {
router.push(`/system/tenant/permission?tenantBizId=` + row.tenantBizId)
}
/** 新增或者修改租户提交按钮 */
function submitForm() {
proxy.$refs['tenantRef'].validate(valid => {
if (valid) {
if (form.value.tenantBizId != undefined) {
updateTenant(form.value).then(response => {
proxy.$modal.msgSuccess('修改成功')
open.value = false
getList()
})
} else {
addTenant(form.value).then(response => {
proxy.$modal.msgSuccess('新增成功')
open.value = false
getList()
})
}
} }
}) })
let status = row.status
let data = {
status: status,
createTime: row.createTime,
appointmentNo: row.appointmentNo,
creatorName: row.creatorName,
appointmentBizId: row.appointmentBizId,
source: 'appointmentList'
}
router.push({
path: '/sign/appointment/appointmentEdit',
query: data
})
} }
getList() getList()
...@@ -532,4 +491,27 @@ getList() ...@@ -532,4 +491,27 @@ getList()
text-align: right; text-align: right;
margin-top: 20px; margin-top: 20px;
} }
.dialogBox {
.dialogTitle {
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 600;
color: #333;
}
.dialogItem {
.dialogItemTitle {
font-size: 16px;
font-weight: 500;
margin: 10px 0;
}
}
.exprotBtn {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
</style> </style>
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