Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-csf-front
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
yuzhenWang
yd-csf-front
Commits
7f6b6010
Commit
7f6b6010
authored
Dec 22, 2025
by
yuzhenWang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
提交代码写到了预约信息
parent
19b678da
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1758 additions
and
760 deletions
+1758
-760
src/formJson/appointmentInfo.js
+266
-212
src/formJson/customer.js
+50
-50
src/utils/validate.js
+435
-1
src/views/components/commonForm.vue
+159
-0
src/views/sign/FnaList/components/customer.vue
+469
-288
src/views/sign/FnaList/edit.vue
+30
-29
src/views/sign/FnaList/index.vue
+1
-10
src/views/sign/appointment/appointmentEdit.vue
+42
-17
src/views/sign/appointment/components/appointmentInfo.vue
+305
-152
src/views/sign/appointment/index.vue
+1
-1
No files found.
src/formJson/appointmentInfo.js
View file @
7f6b6010
const
appointmentInfo
=
[
// 申请
{
fatherTitle
:
''
,
type
:
'object'
,
key
:
'personInfo'
,
fatherTitle
:
'行政信息'
,
keyType
:
'object'
,
key
:
'administration'
,
anchorKey
:
'administration'
,
showMoudle
:
true
,
//模块是否展示
data
:
[
{
...
...
@@ -21,83 +22,12 @@ const appointmentInfo = [
lg
:
8
//栅格布局份数
},
{
label
:
'预约时间'
,
key
:
'confirmAppointmentTime'
,
domType
:
'datetimePicker'
,
required
:
false
,
disabled
:
true
,
placeholder
:
'请选择'
,
show
:
false
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
' '
,
key
:
'newPolicyButton'
,
domType
:
'button'
,
buttonTxt
:
'生成新单跟进记录'
,
buttonType
:
'primary'
,
required
:
false
,
maxLength
:
10
,
disabled
:
false
,
show
:
false
,
// labelPosition: 'top', //标签的位置
labelWidth
:
'0px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
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
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'签单员账号'
,
key
:
'businessRepresentAccount1'
,
domType
:
'Input'
,
inputType
:
'text'
,
required
:
false
,
maxLength
:
20
,
disabled
:
false
,
placeholder
:
'请输入'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'签单员姓名'
,
key
:
'businessRepresentName1'
,
domType
:
'Input'
,
inputType
:
'text'
,
required
:
false
,
maxLength
:
20
,
label
:
'意向签单日'
,
key
:
'intentionAppointmentTime'
,
domType
:
'DatePicker'
,
required
:
true
,
disabled
:
false
,
placeholder
:
'请
输入
'
,
placeholder
:
'请
选择
'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
...
...
@@ -105,66 +35,24 @@ const appointmentInfo = [
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
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'签单员邮箱'
,
key
:
'businessRepresentEmail1'
,
domType
:
'Input'
,
inputType
:
'text'
,
maxLength
:
30
,
required
:
false
,
disabled
:
false
,
placeholder
:
'请输入'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
},
// 基础信息
{
fatherTitle
:
'基础信息'
,
type
:
'object'
,
key
:
'basic'
,
showMoudle
:
true
,
//模块是否展示
// description: '证件信息至少填写一项',
data
:
[
{
label
:
'意向预约时间'
,
key
:
'intentionAppointmentTime'
,
domType
:
'datetimePicker'
,
label
:
'转介人是否陪同'
,
key
:
'isReferrerAccompany'
,
domType
:
'Select'
,
required
:
true
,
disabled
:
false
,
placeholder
:
'请选择'
,
dictType
:
'sys_no_yes'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'
转介人是否陪同
'
,
key
:
'is
Accompany
'
,
label
:
'
是否需用车
'
,
key
:
'is
UseCar
'
,
domType
:
'Select'
,
required
:
fals
e
,
required
:
tru
e
,
disabled
:
false
,
placeholder
:
'请选择'
,
dictType
:
'sys_no_yes'
,
...
...
@@ -175,10 +63,10 @@ const appointmentInfo = [
lg
:
8
//栅格布局份数
},
{
label
:
'是否
有用车需求
'
,
key
:
'is
UseCar
'
,
label
:
'是否
开户
'
,
key
:
'is
OpenAccount
'
,
domType
:
'Select'
,
required
:
fals
e
,
required
:
tru
e
,
disabled
:
false
,
placeholder
:
'请选择'
,
dictType
:
'sys_no_yes'
,
...
...
@@ -188,69 +76,66 @@ const appointmentInfo = [
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
// {
// label: '预约时间',
// key: 'confirmAppointmentTime',
// domType: 'datetimePicker',
// required: false,
// disabled: true,
// placeholder: '请选择',
// show: false,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: ' ',
// key: 'newPolicyButton',
// domType: 'button',
// buttonTxt: '生成新单跟进记录',
// buttonType: 'primary',
// required: false,
// maxLength: 10,
// disabled: false,
// show: false,
// // labelPosition: 'top', //标签的位置
// labelWidth: '0px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// }
]
},
// 陪同
顾问
信息
// 陪同
转介人
信息
{
fatherTitle
:
'转介人信息'
,
type
:
'object'
,
key
:
'consult'
,
showMoudle
:
false
,
//模块是否展示
fatherTitle
:
'陪同转介人'
,
keyType
:
'Array'
,
//用于表单收集值时,判断是数组还是对象
key
:
'referrerDtoList'
,
anchorKey
:
'referrerDtoList'
,
moudleType
:
'referrerDtoList'
,
dataLength
:
1
,
//设置dataLength,用于控制子级dom的个数,子级保存一个样例数据,便于加子级数据
showTable
:
true
,
showMoudle
:
true
,
//模块是否展示
addChildren
:
true
,
//是否可以新增子级dom
addChildrenTxt
:
'陪同转介人'
,
//新增按钮得文本
fatherRequired
:
false
,
//父级必填,代表个人资料这个模块有必填项
isOpen
:
false
,
//dom是否展开
data
:
[
{
label
:
'姓名'
,
key
:
'accompanyName'
,
domType
:
'Input'
,
inputType
:
'text'
,
required
:
false
,
maxLength
:
30
,
disabled
:
false
,
placeholder
:
'请输入'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
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
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'邮箱'
,
key
:
'accompanyEmail'
,
domType
:
'Input'
,
inputType
:
'text'
,
maxLength
:
30
,
required
:
false
,
disabled
:
false
,
placeholder
:
'请输入'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
// {
// id: Date.now() + Math.floor(Math.random() * 1000), //唯一标识
// span: 24, //栅格布局份数
// email: '',
// phone: '',
// realName: ''
// }
]
},
// 到港信息
{
fatherTitle
:
'到港信息'
,
t
ype
:
'object'
,
fatherTitle
:
'到港
/离港
信息'
,
keyT
ype
:
'object'
,
key
:
'position'
,
anchorKey
:
'position'
,
showMoudle
:
true
,
//模块是否展示
data
:
[
{
...
...
@@ -295,7 +180,7 @@ const appointmentInfo = [
},
{
label
:
'签单地
址
'
,
label
:
'签单地
点
'
,
key
:
'signingAddress'
,
domType
:
'Input'
,
inputType
:
'text'
,
...
...
@@ -310,7 +195,7 @@ const appointmentInfo = [
lg
:
8
//栅格布局份数
},
{
label
:
'
客户在港期间联络
电话'
,
label
:
'
在港联系
电话'
,
key
:
'hkMobile'
,
domType
:
'arrowRight'
,
//带有区号得电话一定要有一个和key一样得对象用于收集区号和号码
required
:
false
,
...
...
@@ -328,34 +213,12 @@ const appointmentInfo = [
}
]
},
// 其他情况
{
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
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
},
// 开户信息
{
fatherTitle
:
'开户信息'
,
type
:
'object'
,
key
:
'openAccount'
,
anchorKey
:
'openAccount'
,
showMoudle
:
false
,
//模块是否展示
data
:
[
{
...
...
@@ -391,7 +254,7 @@ const appointmentInfo = [
},
{
label
:
'开户时间
段(开始
)'
,
label
:
'开户时间
(起
)'
,
key
:
'openAccountStartTime'
,
domType
:
'DatePicker'
,
timeType
:
'date'
,
...
...
@@ -405,7 +268,7 @@ const appointmentInfo = [
lg
:
8
//栅格布局份数
},
{
label
:
'开户时间段(
结束
,先选择开始时间)'
,
label
:
'开户时间段(
止
,先选择开始时间)'
,
key
:
'openAccountEndTime'
,
domType
:
'DatePicker'
,
required
:
false
,
...
...
@@ -498,5 +361,196 @@ const appointmentInfo = [
}
]
}
// 业务信息
// {
// 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: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '签单员账号',
// key: 'businessRepresentAccount1',
// domType: 'Input',
// inputType: 'text',
// required: false,
// maxLength: 20,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '签单员姓名',
// key: 'businessRepresentName1',
// domType: 'Input',
// inputType: 'text',
// required: false,
// maxLength: 20,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// 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: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '签单员邮箱',
// key: 'businessRepresentEmail1',
// domType: 'Input',
// inputType: 'text',
// maxLength: 30,
// required: false,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// 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: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '是否有用车需求',
// key: 'isUseCar',
// domType: 'Select',
// required: false,
// disabled: false,
// placeholder: '请选择',
// dictType: 'sys_no_yes',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// 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: 12, //栅格布局份数
// 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: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// },
// {
// label: '邮箱',
// key: 'accompanyEmail',
// domType: 'Input',
// inputType: 'text',
// maxLength: 30,
// required: false,
// disabled: false,
// placeholder: '请输入',
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
// sm: 12, //栅格布局份数
// lg: 8 //栅格布局份数
// }
// ]
// },
// 其他情况
// {
// fatherTitle: '其他情况',
// type: 'object',
// key: 'other',
// showMoudle: true, //模块是否展示
// data: []
// },
]
export
default
appointmentInfo
src/formJson/customer.js
View file @
7f6b6010
...
...
@@ -21,7 +21,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -37,7 +37,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
// {
...
...
@@ -51,7 +51,7 @@ const customer = [
// show: true,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
//
sm: 8,
//栅格布局份数
//
sm: 12,
//栅格布局份数
// lg: 8 //栅格布局份数
// },
{
...
...
@@ -65,7 +65,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -80,7 +80,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -95,7 +95,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -108,7 +108,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -123,7 +123,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -137,7 +137,7 @@ const customer = [
drawerType
:
'country'
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -152,11 +152,11 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
label
:
'是否拥有其他国家公民身份
(如美国、日本等)
'
,
label
:
'是否拥有其他国家公民身份'
,
key
:
'isOtherCountry'
,
domType
:
'Select'
,
required
:
false
,
...
...
@@ -166,7 +166,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -180,7 +180,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
// {
...
...
@@ -195,7 +195,7 @@ const customer = [
// show: false,
// labelPosition: 'top', //标签的位置
// labelWidth: '120px', //标签宽度
//
sm: 8,
//栅格布局份数
//
sm: 12,
//栅格布局份数
// lg: 8 //栅格布局份数
// },
{
...
...
@@ -209,7 +209,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -223,7 +223,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -237,7 +237,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -252,7 +252,7 @@ const customer = [
show
:
false
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -266,7 +266,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -282,7 +282,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -297,7 +297,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -307,12 +307,12 @@ const customer = [
inputType
:
'text'
,
required
:
false
,
maxLength
:
300
,
disabled
:
fals
e
,
disabled
:
tru
e
,
placeholder
:
'请输入'
,
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
...
...
@@ -361,7 +361,7 @@ const customer = [
value
:
''
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -379,7 +379,7 @@ const customer = [
maxLength
:
20
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -394,7 +394,7 @@ const customer = [
maxLength
:
20
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -409,7 +409,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -424,7 +424,7 @@ const customer = [
show
:
false
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -440,7 +440,7 @@ const customer = [
mailingAddress
:
{},
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -455,7 +455,7 @@ const customer = [
residentialAddress
:
{},
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -470,7 +470,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
...
...
@@ -495,7 +495,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -510,7 +510,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -525,7 +525,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -541,7 +541,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -556,7 +556,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -571,7 +571,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -586,7 +586,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -606,7 +606,7 @@ const customer = [
maxLength
:
20
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'180px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -622,7 +622,7 @@ const customer = [
companyAddress
:
{},
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -637,7 +637,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
...
...
@@ -663,7 +663,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -679,7 +679,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -695,7 +695,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -711,7 +711,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
...
...
@@ -737,7 +737,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -751,7 +751,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -765,7 +765,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
{
...
...
@@ -779,7 +779,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
},
...
...
@@ -795,7 +795,7 @@ const customer = [
show
:
true
,
labelPosition
:
'top'
,
//标签的位置
labelWidth
:
'120px'
,
//标签宽度
sm
:
8
,
//栅格布局份数
sm
:
12
,
//栅格布局份数
lg
:
8
//栅格布局份数
}
]
...
...
src/utils/validate.js
View file @
7f6b6010
...
...
@@ -153,6 +153,46 @@ export const validateEnglish = (rule, value, callback) => {
callback
()
}
/**
* 英文姓名校验规则
*/
export
const
validateChinese
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
callback
(
new
Error
(
'请输入中文姓名'
))
return
}
// 验证是否只包含中文字符
const
chineseRegex
=
/^
[\u
4e00-
\u
9fa5
]
+$/
if
(
!
chineseRegex
.
test
(
value
))
{
callback
(
new
Error
(
'只能输入中文'
))
return
}
// 验证长度在2-6之间
if
(
value
.
length
<
2
||
value
.
length
>
6
)
{
callback
(
new
Error
(
'长度应在2-6个字符之间'
))
return
}
callback
()
}
/**
* BMI校验规则
*/
export
const
validateBMI
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
return
}
if
(
value
<
19
)
{
return
callback
(
new
Error
(
'BMI值不能小于19'
))
}
if
(
value
>=
23.5
)
{
return
callback
(
new
Error
(
'BMI值不能大于23.5'
))
}
callback
()
}
/**
* 手机号校验规则
...
...
@@ -169,7 +209,401 @@ export const validatePhone = (rule, value, callback) => {
callback
()
}
// 身份证验证相关方法
/**
* 验证身份证号码是否合法
* @param {string} idCard 身份证号码
* @returns {boolean} 是否合法
*/
export
function
validIDCard
(
idCard
)
{
if
(
!
idCard
)
return
false
const
idCardStr
=
idCard
.
toString
().
trim
()
// 长度验证
if
(
idCardStr
.
length
!==
15
&&
idCardStr
.
length
!==
18
)
{
return
false
}
// 格式验证
if
(
idCardStr
.
length
===
15
)
{
// 15位身份证:全部为数字
if
(
!
/^
\d{15}
$/
.
test
(
idCardStr
))
{
return
false
}
// 验证出生日期
const
birthDateStr
=
'19'
+
idCardStr
.
substr
(
6
,
6
)
// 19yyMMdd
if
(
!
validateBirthDate
(
birthDateStr
))
{
return
false
}
// 验证省份代码
const
provinceCode
=
idCardStr
.
substr
(
0
,
2
)
if
(
!
validateProvinceCode
(
provinceCode
))
{
return
false
}
}
else
if
(
idCardStr
.
length
===
18
)
{
// 18位身份证:前17位为数字,最后一位为数字或X(大小写)
if
(
!
/^
\d{17}[\d
Xx
]
$/
.
test
(
idCardStr
))
{
return
false
}
// 验证出生日期
const
birthDateStr
=
idCardStr
.
substr
(
6
,
8
)
// yyyyMMdd
if
(
!
validateBirthDate
(
birthDateStr
))
{
return
false
}
// 验证省份代码
const
provinceCode
=
idCardStr
.
substr
(
0
,
2
)
if
(
!
validateProvinceCode
(
provinceCode
))
{
return
false
}
// 验证校验码
if
(
!
validateCheckCode
(
idCardStr
.
toUpperCase
()))
{
return
false
}
}
return
true
}
/**
* 验证出生日期是否有效
* @param {string} birthDateStr 出生日期字符串 (yyyyMMdd 或 yyMMdd)
* @returns {boolean} 是否有效
*/
function
validateBirthDate
(
birthDateStr
)
{
// 统一为8位格式
if
(
birthDateStr
.
length
===
6
)
{
birthDateStr
=
'19'
+
birthDateStr
}
if
(
birthDateStr
.
length
!==
8
)
{
return
false
}
const
year
=
parseInt
(
birthDateStr
.
substr
(
0
,
4
))
const
month
=
parseInt
(
birthDateStr
.
substr
(
4
,
2
))
const
day
=
parseInt
(
birthDateStr
.
substr
(
6
,
2
))
// 验证年月日是否有效
if
(
year
<
1900
||
year
>
new
Date
().
getFullYear
())
{
return
false
}
if
(
month
<
1
||
month
>
12
)
{
return
false
}
// 验证每月天数
const
daysInMonth
=
[
31
,
28
,
31
,
30
,
31
,
30
,
31
,
31
,
30
,
31
,
30
,
31
]
// 闰年二月处理
if
(
month
===
2
&&
isLeapYear
(
year
))
{
if
(
day
<
1
||
day
>
29
)
{
return
false
}
}
else
{
if
(
day
<
1
||
day
>
daysInMonth
[
month
-
1
])
{
return
false
}
}
// 验证日期不能晚于当前日期
const
birthDate
=
new
Date
(
year
,
month
-
1
,
day
)
const
currentDate
=
new
Date
()
if
(
birthDate
>
currentDate
)
{
return
false
}
// 验证年龄(最大150岁)
const
age
=
calculateAge
(
birthDate
)
if
(
age
>
150
)
{
return
false
}
return
true
}
/**
* 验证省份代码
* @param {string} code 省份代码
* @returns {boolean} 是否有效
*/
function
validateProvinceCode
(
code
)
{
const
provinceCodes
=
[
'11'
,
'12'
,
'13'
,
'14'
,
'15'
,
// 华北
'21'
,
'22'
,
'23'
,
// 东北
'31'
,
'32'
,
'33'
,
'34'
,
'35'
,
'36'
,
'37'
,
// 华东
'41'
,
'42'
,
'43'
,
'44'
,
'45'
,
'46'
,
// 华中/华南
'50'
,
'51'
,
'52'
,
'53'
,
'54'
,
// 西南
'61'
,
'62'
,
'63'
,
'64'
,
'65'
,
// 西北
'71'
,
'81'
,
'82'
,
'91'
// 港澳台及国外
]
return
provinceCodes
.
includes
(
code
)
}
/**
* 验证18位身份证的校验码
* @param {string} idCard 18位身份证号码(需大写)
* @returns {boolean} 是否校验通过
*/
function
validateCheckCode
(
idCard
)
{
// 校验码对应关系
const
checkCodeMap
=
[
'1'
,
'0'
,
'X'
,
'9'
,
'8'
,
'7'
,
'6'
,
'5'
,
'4'
,
'3'
,
'2'
]
// 系数表
const
coefficient
=
[
7
,
9
,
10
,
5
,
8
,
4
,
2
,
1
,
6
,
3
,
7
,
9
,
10
,
5
,
8
,
4
,
2
]
// 计算校验位
let
sum
=
0
for
(
let
i
=
0
;
i
<
17
;
i
++
)
{
sum
+=
parseInt
(
idCard
.
charAt
(
i
))
*
coefficient
[
i
]
}
// 取模
const
mod
=
sum
%
11
// 获取计算出的校验码
const
expectedCheckCode
=
checkCodeMap
[
mod
]
// 与实际校验码比较
const
actualCheckCode
=
idCard
.
charAt
(
17
)
return
expectedCheckCode
===
actualCheckCode
}
/**
* 判断是否为闰年
* @param {number} year 年份
* @returns {boolean} 是否为闰年
*/
function
isLeapYear
(
year
)
{
return
(
year
%
4
===
0
&&
year
%
100
!==
0
)
||
year
%
400
===
0
}
/**
* 计算年龄
* @param {Date} birthDate 出生日期
* @returns {number} 年龄
*/
function
calculateAge
(
birthDate
)
{
const
today
=
new
Date
()
let
age
=
today
.
getFullYear
()
-
birthDate
.
getFullYear
()
const
monthDiff
=
today
.
getMonth
()
-
birthDate
.
getMonth
()
// 如果当前月份小于出生月份,或者月份相同但日期小于出生日期,则年龄减1
if
(
monthDiff
<
0
||
(
monthDiff
===
0
&&
today
.
getDate
()
<
birthDate
.
getDate
()))
{
age
--
}
return
age
}
/**
* 从身份证提取信息
* @param {string} idCard 身份证号码
* @returns {Object|null} 身份证信息对象,无效返回null
*/
export
function
extractIDCardInfo
(
idCard
)
{
if
(
!
validIDCard
(
idCard
))
{
return
null
}
const
idCardStr
=
idCard
.
toString
().
trim
().
toUpperCase
()
// 提取出生日期
let
birthDateStr
=
''
if
(
idCardStr
.
length
===
15
)
{
birthDateStr
=
'19'
+
idCardStr
.
substr
(
6
,
6
)
}
else
{
birthDateStr
=
idCardStr
.
substr
(
6
,
8
)
}
const
year
=
parseInt
(
birthDateStr
.
substr
(
0
,
4
))
const
month
=
parseInt
(
birthDateStr
.
substr
(
4
,
2
))
const
day
=
parseInt
(
birthDateStr
.
substr
(
6
,
2
))
// 提取性别
let
genderCode
=
0
if
(
idCardStr
.
length
===
15
)
{
genderCode
=
parseInt
(
idCardStr
.
substr
(
14
,
1
))
}
else
{
genderCode
=
parseInt
(
idCardStr
.
substr
(
16
,
1
))
}
const
gender
=
genderCode
%
2
===
1
?
1
:
0
// 1:男, 0:女
// 提取省份代码
const
provinceCode
=
idCardStr
.
substr
(
0
,
2
)
const
province
=
getProvinceName
(
provinceCode
)
// 计算年龄
const
birthDate
=
new
Date
(
year
,
month
-
1
,
day
)
const
age
=
calculateAge
(
birthDate
)
return
{
provinceCode
,
province
,
birthDate
:
`
${
year
}
-
${
month
.
toString
().
padStart
(
2
,
'0'
)}
-
${
day
.
toString
().
padStart
(
2
,
'0'
)}
`
,
year
,
month
,
day
,
gender
,
genderText
:
gender
===
1
?
'男'
:
'女'
,
age
}
}
/**
* 根据省份代码获取省份名称
* @param {string} code 省份代码
* @returns {string} 省份名称
*/
function
getProvinceName
(
code
)
{
const
provinceMap
=
{
11
:
'北京'
,
12
:
'天津'
,
13
:
'河北'
,
14
:
'山西'
,
15
:
'内蒙古'
,
21
:
'辽宁'
,
22
:
'吉林'
,
23
:
'黑龙江'
,
31
:
'上海'
,
32
:
'江苏'
,
33
:
'浙江'
,
34
:
'安徽'
,
35
:
'福建'
,
36
:
'江西'
,
37
:
'山东'
,
41
:
'河南'
,
42
:
'湖北'
,
43
:
'湖南'
,
44
:
'广东'
,
45
:
'广西'
,
46
:
'海南'
,
50
:
'重庆'
,
51
:
'四川'
,
52
:
'贵州'
,
53
:
'云南'
,
54
:
'西藏'
,
61
:
'陕西'
,
62
:
'甘肃'
,
63
:
'青海'
,
64
:
'宁夏'
,
65
:
'新疆'
,
71
:
'台湾'
,
81
:
'香港'
,
82
:
'澳门'
,
91
:
'国外'
}
return
provinceMap
[
code
]
||
'未知'
}
/**
* 身份证校验规则(用于Element Plus表单验证)
*/
export
const
validateIdCard
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
// 如果值为空且字段不是必填的,直接通过校验
// 如果必填,应该在rules中另外添加required规则
return
callback
()
}
// 基本格式检查
const
idCardStr
=
value
.
toString
().
trim
()
if
(
idCardStr
.
length
!==
15
&&
idCardStr
.
length
!==
18
)
{
return
callback
(
new
Error
(
'身份证号码长度应为15位或18位'
))
}
if
(
idCardStr
.
length
===
15
)
{
// 15位身份证:全部为数字
if
(
!
/^
\d{15}
$/
.
test
(
idCardStr
))
{
return
callback
(
new
Error
(
'15位身份证号码应全部为数字'
))
}
}
else
{
// 18位身份证:前17位为数字,最后一位为数字或X
if
(
!
/^
\d{17}[\d
Xx
]
$/
.
test
(
idCardStr
))
{
return
callback
(
new
Error
(
'18位身份证号码格式不正确'
))
}
}
// 使用完整验证函数
if
(
!
validIDCard
(
value
))
{
return
callback
(
new
Error
(
'请输入有效的身份证号码'
))
}
callback
()
}
/**
* 简单验证身份证格式(不验证校验码和详细逻辑)
*/
export
const
validateIdCardSimple
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
value
)
{
return
callback
()
}
const
idCardStr
=
value
.
toString
().
trim
()
// 15位身份证验证
if
(
idCardStr
.
length
===
15
)
{
if
(
!
/^
\d{15}
$/
.
test
(
idCardStr
))
{
return
callback
(
new
Error
(
'15位身份证号码应全部为数字'
))
}
}
else
if
(
idCardStr
.
length
===
18
)
{
// 18位身份证验证
if
(
!
/^
\d{17}[\d
Xx
]
$/
.
test
(
idCardStr
))
{
return
callback
(
new
Error
(
'18位身份证号码格式不正确'
))
}
}
else
{
return
callback
(
new
Error
(
'身份证号码长度应为15位或18位'
))
}
callback
()
}
// 将身份证验证方法添加到默认导出对象中
export
default
{
validateEnglish
,
validatePhone
validateChinese
,
validatePhone
,
validateBMI
,
validateIdCard
,
validateIdCardSimple
}
src/views/components/commonForm.vue
0 → 100644
View file @
7f6b6010
<
template
>
<div
class=
"formContainer"
>
<div
class=
"formLeft"
v-if=
"showAnchor"
>
<el-affix
:offset=
"affixOffset"
>
<el-anchor
:direction=
"direction"
:type=
"type"
:offset=
"anchorOffset"
@
click=
"handleAnchorClick"
>
<!-- -->
<el-anchor-link
v-for=
"item in anchorList"
:href=
"'#' + item.title"
:title=
"item.name"
@
click=
"e => handleLinkClick(e, item.title)"
/>
</el-anchor>
</el-affix>
</div>
<div
class=
"formRight"
:class=
"showAnchor ? 'formRightSelf' : ''"
>
<slot
name=
"form-right"
></slot>
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
getCurrentInstance
}
from
'vue'
const
props
=
defineProps
({
containerRef
:
{
type
:
Object
,
default
:
()
=>
{
return
{}
}
},
direction
:
{
type
:
String
,
default
:
'vertical'
},
type
:
{
type
:
String
,
default
:
'default'
},
anchorOffset
:
{
type
:
Number
,
default
:
30
},
affixOffset
:
{
type
:
Number
,
default
:
60
},
anchorList
:
{
type
:
Array
,
default
:
()
=>
{
return
[]
}
},
// 新增:滚动容器的选择器
scrollContainerSelector
:
{
type
:
String
,
default
:
''
},
// 新增:滚动到元素时额外的偏移量
scrollOffset
:
{
type
:
Number
,
default
:
0
},
domIndex
:
{
type
:
Number
,
default
:
0
},
showAnchor
:
{
type
:
Boolean
,
default
:
true
}
})
const
emit
=
defineEmits
([
'anchor-click'
])
// 处理锚点点击
const
handleAnchorClick
=
e
=>
{
// 阻止默认的锚点跳转
e
.
preventDefault
()
}
// 处理链接点击
const
handleLinkClick
=
(
e
,
anchorId
)
=>
{
e
.
preventDefault
()
e
.
stopPropagation
()
emit
(
'anchor-click'
,
anchorId
)
// 延迟执行滚动,确保 DOM 已经更新
setTimeout
(()
=>
{
scrollToAnchor
(
anchorId
)
},
50
)
}
// 滚动到锚点
const
scrollToAnchor
=
anchorId
=>
{
const
targetElement
=
document
.
getElementById
(
anchorId
)
if
(
!
targetElement
)
return
let
scrollContainer
if
(
props
.
scrollContainerSelector
)
{
scrollContainer
=
document
.
querySelectorAll
(
props
.
scrollContainerSelector
)
}
if
(
scrollContainer
.
length
>
0
)
{
// 计算在容器内的相对位置
const
containerRect
=
scrollContainer
[
props
.
domIndex
].
getBoundingClientRect
()
const
targetRect
=
targetElement
.
getBoundingClientRect
()
// 计算滚动位置
const
scrollTop
=
targetRect
.
top
-
containerRect
.
top
+
scrollContainer
[
props
.
domIndex
].
scrollTop
-
props
.
scrollOffset
// 平滑滚动
scrollContainer
[
props
.
domIndex
].
scrollTo
({
top
:
scrollTop
,
behavior
:
'smooth'
})
}
else
{
// 如果没有指定容器,使用默认滚动
targetElement
.
scrollIntoView
({
behavior
:
'smooth'
,
block
:
'start'
})
}
}
// 暴露方法给父组件
defineExpose
({
scrollToAnchor
})
</
script
>
<
style
lang=
"scss"
scoped
>
.formContainer
{
width
:
100%
;
box-sizing
:
border-box
;
display
:
flex
;
}
.formLeft
{
width
:
15%
;
box-sizing
:
border-box
;
height
:
100vh
;
}
.formRight
{
flex
:
1
;
padding-left
:
10px
;
box-sizing
:
border-box
;
}
.formRightSelf
{
border-left
:
3px
solid
rgb
(
247
247
247
);
}
</
style
>
src/views/sign/FnaList/components/customer.vue
View file @
7f6b6010
<
template
>
<div>
<div
v-if=
"processedCustomerData.length > 0"
class=
"customerContainer
"
>
<div
class=
"customerContainer"
>
<div
ref=
"customerRightRef
"
>
<div
class=
"editBtn"
>
<el-button
v-if=
"props.customerBizId"
...
...
@@ -10,240 +10,197 @@
>
编辑
</el-button
>
</div>
<div
class=
"customerLeft"
v-if=
"customerRightRef"
>
<CommonAnchor
:anchorList=
"anchorList"
:affixOffset=
"250"
:anchorOffset=
"10"
:scrollContainerSelector=
"'.tabPaneBox'"
:scrollOffset=
"10"
:domIndex=
"1"
/>
</div>
<div
class=
"customerRight"
ref=
"customerRightRef"
>
<el-form
ref=
"customerRef"
:model=
"form"
:rules=
"rules"
label-width=
"120px"
>
<el-row
v-for=
"(father, fIndex) in processedCustomerData"
:id=
"father.anchorKey"
>
<div
class=
"formBox"
>
<CardOne
:title=
"father.fatherTitle"
>
<template
#
content
>
<el-row
:gutter=
"20"
v-if=
"!father.showTable"
>
<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.key === 'residentialAddress' && child.type === 'arrowRight'
? ''
: child.label
"
:prop=
"child.key"
:key=
"child.key"
:label-width=
"child.labelWidth"
:label-position=
"child.labelPosition"
>
<!-- 自定义 label 插槽 -->
<template
v-if=
"
child.key === 'residentialAddress' && child.type === 'arrowRight'
<CommonForm
:anchorList=
"anchorList"
:affixOffset=
"250"
:anchorOffset=
"10"
:scrollContainerSelector=
"anchorContainer"
:scrollOffset=
"10"
:domIndex=
"tabIndex"
:containerRef=
"tabPaneRef"
:activeName=
"activeName"
v-if=
"customerRightRef"
>
<template
#
form-right
>
<el-form
ref=
"customerRef"
:model=
"form"
:rules=
"rules"
label-width=
"120px"
>
<el-row
v-for=
"(father, fIndex) in processedCustomerData"
:id=
"father.anchorKey"
>
<div
class=
"formBox"
>
<CardOne
:title=
"father.fatherTitle"
>
<template
#
content
>
<el-row
:gutter=
"20"
v-if=
"!father.showTable"
>
<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.key === 'residentialAddress' && child.domType === 'arrowRight'
? ''
: child.label
"
#
label
>
<div
class=
"custom-label"
>
<span>
{{
child
.
label
}}
</span>
<el-checkbox-group
v-model=
"form.isCopyAddress"
size=
"small"
style=
"margin-left: 8px"
@
change=
"changeAddressStatus(child)"
:disabled=
"copyAddress"
>
<el-checkbox
:value=
"true"
name=
"isCopyAddress"
>
同通讯地址
</el-checkbox>
</el-checkbox-group>
</div>
</
template
>
<el-input
v-if=
"child.domType === 'Input'"
:type=
"child.inputType"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
maxlength=
"30"
:disabled=
"child.disabled"
@
change=
"handleInputChange(child)"
:prop=
"child.key"
:key=
"child.key"
:label-width=
"child.labelWidth"
:label-position=
"child.labelPosition"
>
<
template
#
append
v-if=
"child.unit"
@
click=
"handleAppendInput(child)"
>
<span
:style=
"
{ color: child.unitColor }">
{{
child
.
unit
}}
</span>
<!-- 自定义 label 插槽 -->
<template
v-if=
"
child.key === 'residentialAddress' &&
child.domType === 'arrowRight'
"
#
label
>
<div
class=
"custom-label"
>
<span>
{{
child
.
label
}}
</span>
<el-checkbox-group
v-model=
"form.isCopyAddress"
size=
"small"
style=
"margin-left: 8px"
@
change=
"changeAddressStatus(child)"
:disabled=
"copyAddress"
>
<el-checkbox
:value=
"true"
name=
"isCopyAddress"
>
同通讯地址
</el-checkbox>
</el-checkbox-group>
</div>
</
template
>
</el-input>
<el-select
v-if=
"child.domType === 'Select'"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
@
change=
"handleSelectChange(child)"
:disabled=
"child.disabled"
>
<el-option
v-for=
"item in child.options"
:key=
"item.value"
:label=
"item.label"
:value=
"item.value"
<el-input
v-if=
"child.domType === 'Input'"
:type=
"child.inputType"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
maxlength=
"30"
:disabled=
"child.disabled"
@
blur=
"handleInputBlur(child)"
>
<
template
#
append
v-if=
"child.unit"
>
<span
@
click=
"handleAppendInput(child)"
:style=
"
{ color: child.unitColor }"
>
{{
child
.
unit
}}
</span
>
</
template
>
</el-input>
<el-select
v-if=
"child.domType === 'Select'"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
@
change=
"handleSelectChange(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[child.key]"
type=
"date"
format=
"YYYY-MM-DD"
value-format=
"YYYY-MM-DD"
:placeholder=
"child.placeholder"
:disabled=
"child.disabled"
:disabled-date=
"time => disabledDate(time, child)"
:default-value=
"defaultDisplayDate"
@
change=
"handleDateChange(child)"
/>
</el-select>
<el-date-picker
style=
"width: 100%"
v-if=
"child.domType === 'DatePicker'"
v-model=
"form[child.key]"
type=
"date"
format=
"YYYY-MM-DD"
value-format=
"YYYY-MM-DD"
:placeholder=
"child.placeholder"
:disabled=
"child.disabled"
:disabled-date=
"time => disabledDate(time, child)"
:default-value=
"defaultDisplayDate"
@
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-form-item>
</div>
</el-col>
</template>
</el-row>
<el-row
v-if=
"father.showTable"
>
<el-col
:span=
"24"
v-if=
"father.addChildren"
>
<el-button
:disabled=
"editStatus"
type=
"primary"
icon=
"Plus"
size=
"small"
style=
"margin-bottom: 10px"
@
click=
"addChildren(father)"
>
{{ father.addChildrenTxt }}
</el-button
>
</el-col>
<el-table
:data=
"father.data"
border
v-if=
"father.data.length > 0"
>
<
template
v-if=
"father.key == 'apiTaxationDtoList'"
>
<el-table-column
label=
"税务国家"
prop=
"taxCountry"
align=
"center"
>
<template
#
default=
"scope"
>
<el-input
size=
"default"
placeholder=
"请输入"
v-model=
"scope.row.taxCountry"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"税务编号"
prop=
"taxId"
align=
"center"
>
<
template
#
default=
"scope"
>
<el-input
v-model=
"scope.row.taxId"
size=
"default"
placeholder=
"请输入"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
width=
"60px"
align=
"center"
label=
"操作"
>
<
template
#
default=
"scope"
>
<el-icon
class=
"deleteIcon"
@
click=
"deleteChildren(father, scope.$index)"
><Delete
/></el-icon>
</
template
>
</el-table-column>
<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-form-item>
</div>
</el-col>
</template>
</el-table>
</el-row>
</template>
</CardOne>
</div>
</el-row>
<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
>
</el-row>
<el-row
v-if=
"father.showTable"
>
<el-col
:span=
"24"
v-if=
"father.addChildren"
>
<el-button
:disabled=
"editStatus"
type=
"primary"
icon=
"Plus"
size=
"small"
style=
"margin-bottom: 10px"
@
click=
"addChildren(father)"
>
{{ father.addChildrenTxt }}
</el-button
>
</el-col>
<el-table
:data=
"father.data"
border
v-if=
"father.data.length > 0"
>
<
template
v-if=
"father.key == 'apiTaxationDtoList'"
>
<el-table-column
label=
"税务国家"
prop=
"taxCountry"
align=
"center"
>
<template
#
default=
"scope"
>
<el-input
size=
"default"
placeholder=
"请输入"
v-model=
"scope.row.taxCountry"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"税务编号"
prop=
"taxId"
align=
"center"
>
<
template
#
default=
"scope"
>
<el-input
v-model=
"scope.row.taxId"
size=
"default"
placeholder=
"请输入"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
width=
"60px"
align=
"center"
label=
"操作"
>
<
template
#
default=
"scope"
>
<el-icon
class=
"deleteIcon"
@
click=
"deleteChildren(father, scope.$index)"
><Delete
/></el-icon>
</
template
>
</el-table-column>
</template>
</el-table>
</el-row>
</template>
</CardOne>
</div>
</el-col>
</el-row>
</el-form>
</div>
</el-row>
<el-dialog
title=
"客户信息"
v-model=
"openList"
width=
"600px"
append-to-body
>
<div>
<el-form
:model=
"queryParams"
ref=
"queryRef"
:inline=
"true"
label-width=
"68px"
>
<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=
"left"
>
<div>
{{ item.name }}
</div>
<div
v-if=
"item.gender"
style=
"margin: 0 5px"
>
-
</div>
<div
v-if=
"item.gender"
class=
"gender"
>
<dict-tag
:options=
"sys_gender"
:value=
"item.gender"
/>
</div>
</div>
<div
class=
"right"
>
<el-button
type=
"primary"
size=
"small"
@
click=
"handleExport(item)"
>
导入客户信息
</el-button
<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>
</div>
<div
class=
"bottom"
>
<div
class=
"infoItem"
>
<span>
证件类型:
</span>
<span>
<dict-tag
:options=
"csf_id_type"
:value=
"item.idType"
/></span>
</div>
<div
class=
"infoItem"
>
<span>
证件号码:
</span>
<span>
{{ item.idCard || '暂无' }}
</span>
</div>
<div
class=
"infoItem"
>
<span>
电话号码:
</span>
<span>
{{ item.phone || '暂无' }}
</span>
</div>
<div
class=
"infoItem"
>
<span>
出生日期:
</span>
<span>
{{ formatToDate(item.birthday) || '暂无' }}
</span>
</div>
</div>
</div>
</div>
</div>
</el-dialog>
</el-col>
</el-row>
</el-form>
</template>
</CommonForm>
</div>
<Phone
@
close=
"handleCloseDrawer"
...
...
@@ -267,10 +224,92 @@
@
confirmCountry=
"confirmDrawer"
/>
<!-- 历史客户的弹窗 -->
<CommonDialog
dialogTitle=
"历史客户"
:showConfirm=
"false"
cancleText=
"关闭"
dialogWidth=
"70%"
:openDialog=
"openList"
@
close=
"openList = false"
>
<div
class=
"dialogBox"
>
<CommonPage
:operationBtnList=
"operationBtnList"
:visibleDefaultButtons=
"visibleDefaultButtons"
:showSearchForm=
"true"
:show-pagination=
"true"
:currentPage=
"queryParams.pageNo"
:total=
"total"
:pageSize=
"queryParams.pageSize"
@
current-change=
"changePageNo"
@
size-change=
"changePageSize"
>
<!-- 查询条件插槽 -->
<
template
#
searchForm
>
<el-form
:model=
"queryParams"
ref=
"queryRef"
label-width=
"100px"
>
<el-row
:gutter=
"30"
>
<el-col
:sm=
"12"
:lg=
"8"
:xs=
"24"
>
<el-form-item
label=
"预约编号"
prop=
"appointmentNo"
>
<el-input
v-model=
"queryParams.appointmentNo"
placeholder=
"请输入预约编号"
clearable
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</
template
>
<!-- 表格插槽 -->
<
template
#
table
>
<el-table
v-loading=
"tableLoading"
:data=
"tableData"
@
row-click=
"handleExport"
>
<!--
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
-->
<el-table-column
label=
"姓名"
align=
"center"
prop=
"nameCn"
width=
"200"
/>
<el-table-column
label=
"性别"
align=
"center"
prop=
"gender"
>
<template
#
default=
"scope"
>
<dict-tag
:options=
"fetchDictData('sys_gender')"
:value=
"scope.row.gender"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"证件类型"
align=
"center"
prop=
"documentType"
>
<
template
#
default=
"scope"
>
<dict-tag
:options=
"fetchDictData('csf_id_type')"
:value=
"scope.row.documentType"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"证件号码"
align=
"center"
prop=
"idNumber"
/>
<el-table-column
label=
"电话号码"
align=
"center"
prop=
"mobile"
/>
<el-table-column
label=
"出生日期"
align=
"center"
width=
"180"
prop=
"birthday"
>
<
template
#
default=
"scope"
>
<span>
{{
scope
.
row
.
birthday
?
formatToDate
(
scope
.
row
.
birthday
)
:
'--'
}}
</span>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
align=
"center"
width=
"150"
class-name=
"small-padding fixed-width"
fixed=
"right"
>
<
template
#
default=
"scope"
>
<el-button
link
type=
"primary"
@
click=
"handleExport(scope.row)"
>
使用客户资料
</el-button
>
</
template
>
</el-table-column>
</el-table>
</template>
</CommonPage>
</div>
</CommonDialog>
</div>
</template>
<
script
setup
name=
"customer"
>
import
{
validateEnglish
}
from
'@/utils/validate'
import
{
validateEnglish
,
validateBMI
,
validateIdCard
,
validateChinese
}
from
'@/utils/validate'
import
{
calculateExactAge
}
from
'@/utils/date'
import
dayjs
from
'dayjs'
import
{
ArrowRight
}
from
'@element-plus/icons-vue'
...
...
@@ -278,7 +317,9 @@ import customerDomData from '@/formJson/customer'
import
Country
from
'@/views/components/country'
import
Phone
from
'@/views/components/phone'
import
Address
from
'@/views/components/address'
import
CommonAnchor
from
'@/components/commonAnchor'
import
CommonForm
from
'@/views/components/commonForm'
import
CommonDialog
from
'@/components/commonDialog'
import
CommonPage
from
'@/components/commonPage'
import
CardOne
from
'@/components/formCard/cardOne'
import
{
watch
}
from
'vue'
import
{
...
...
@@ -287,12 +328,15 @@ import {
editCustomer
,
getCustomerList
,
addFna
,
calculateFieldValue
,
calculateFieldValue
}
from
'@/api/sign/fna'
import
useDictStore
from
'@/store/modules/dict'
import
{
HttpStatusCode
}
from
'axios'
const
dictStore
=
useDictStore
()
//获取字典数据
const
props
=
defineProps
({
activeName
:
{
type
:
String
,
default
:
''
},
//tab名称
anchorContainer
:
{
type
:
String
,
default
:
''
},
//锚点滚动容器
tabIndex
:
{
type
:
[
String
,
Number
],
default
:
''
},
//tab索引
tabPaneRef
:
{
type
:
Object
,
default
:
null
...
...
@@ -302,7 +346,7 @@ const props = defineProps({
})
const
emit
=
defineEmits
([
'handleSuccess'
])
const
{
proxy
}
=
getCurrentInstance
()
const
{
csf_id_type
,
sys_gender
}
=
proxy
.
useDict
(
'csf_id_type'
,
'sys_gender'
)
//
const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const
anchorList
=
ref
([])
//锚点列表
const
customerRightRef
=
ref
(
null
)
const
showPhoneDrawer
=
ref
(
false
)
//电话抽屉开关
...
...
@@ -321,7 +365,6 @@ const total = ref(0)
const
customerRef
=
ref
(
null
)
//计算默认显示的日期(18年前的今天)
const
defaultDisplayDate
=
ref
(
dayjs
().
subtract
(
18
,
'year'
).
toDate
())
// const copyAddress = ref(false) //是否可以复制地址
// 地址组件菜单数据
const
addressMenuList
=
ref
([
{
...
...
@@ -377,7 +420,7 @@ const deleteKeyList = ref([
'objType'
,
'mailingAddress'
,
'residentialAddress'
,
'
residence
Address'
,
'
mailing
Address'
,
'companyAddress'
])
// 存储需要删除的key
const
data
=
reactive
({
...
...
@@ -387,12 +430,115 @@ const data = reactive({
rules
:
{},
//表单验证规则,
queryParams
:
{
pageNo
:
1
,
pageSize
:
4
,
pageSize
:
10
,
name
:
undefined
}
})
const
{
form
,
rules
,
processedCustomerData
,
queryParams
,
oldCustomerData
}
=
toRefs
(
data
)
const
handleAppendInput
=
child
=>
{}
// 控制要显示的默认按钮
const
visibleDefaultButtons
=
ref
([
'query'
,
'reset'
])
// 只显示新增和查询两个默认按钮
// 按钮配置
const
operationBtnList
=
ref
([
{
key
:
'reset'
,
size
:
'small'
,
direction
:
'right'
,
click
:
resetQuery
},
{
key
:
'query'
,
size
:
'small'
,
direction
:
'right'
,
click
:
handleQuery
}
])
const
changePageNo
=
val
=>
{
queryParams
.
value
.
pageNo
=
val
customerList
()
}
const
changePageSize
=
val
=>
{
queryParams
.
value
.
pageSize
=
val
customerList
()
}
/** 搜索按钮操作 */
function
handleQuery
()
{
queryParams
.
value
.
pageNo
=
1
customerList
()
}
/** 重置按钮操作 */
function
resetQuery
()
{
proxy
.
resetForm
(
'queryRef'
)
queryParams
.
value
=
{
pageNo
:
1
,
pageSize
:
10
}
handleQuery
()
}
const
handleAppendInput
=
child
=>
{
if
(
child
.
key
==
'nameCn'
)
{
if
(
editStatus
.
value
)
{
proxy
.
$modal
.
confirm
(
`请先点击编辑在导入客户信息`
,
{
showCancel
:
'0'
,
title
:
'填写提示'
})
return
}
openList
.
value
=
true
queryParams
.
value
=
{
pageNo
:
1
,
pageSize
:
10
}
customerList
()
}
}
const
handleInputBlur
=
child
=>
{
if
(
form
.
value
[
'documentType'
]
==
'idCard'
&&
child
.
key
==
'idNumber'
)
{
getFieldValue
(
child
.
key
)
}
else
if
(
(
child
.
key
==
'weight'
||
child
.
key
==
'height'
)
&&
form
.
value
[
'weight'
]
&&
form
.
value
[
'height'
]
)
{
getFieldValue
(
child
.
key
)
}
else
if
(
child
.
key
==
'nameCn'
&&
form
.
value
[
'nameCn'
])
{
getFieldValue
(
child
.
key
)
}
}
const
getFieldValue
=
key
=>
{
let
obj
=
{}
if
(
form
.
value
[
'documentType'
]
==
'idCard'
&&
key
==
'idNumber'
)
{
obj
=
{
calculateType
:
6
,
requestValue
:
form
.
value
[
'idNumber'
]
}
}
else
if
(
key
==
'weight'
||
key
==
'height'
)
{
obj
=
{
calculateType
:
5
,
requestValueList
:
[
form
.
value
[
'height'
],
form
.
value
[
'weight'
]]
}
}
else
if
(
key
==
'nameCn'
)
{
obj
=
{
calculateType
:
1
,
requestValue
:
form
.
value
[
'nameCn'
]
}
}
calculateFieldValue
(
obj
).
then
(
res
=>
{
if
(
res
.
code
==
200
)
{
res
.
data
.
forEach
(
item
=>
{
if
(
obj
.
calculateType
==
6
)
{
if
(
item
.
calculateType
==
2
)
{
form
.
value
[
'gender'
]
=
item
.
responseKey
}
else
if
(
item
.
calculateType
==
3
)
{
form
.
value
[
'birthday'
]
=
item
.
requestValue
}
else
if
(
item
.
calculateType
==
4
)
{
form
.
value
[
'age'
]
=
item
.
requestValue
}
}
else
if
(
obj
.
calculateType
==
5
)
{
form
.
value
[
'bmi'
]
=
item
.
responseValue
}
else
if
(
obj
.
calculateType
==
1
)
{
form
.
value
[
'namePyEn'
]
=
item
.
responseValue
}
})
}
})
}
// 添加表单子级dom
const
addChildren
=
father
=>
{
const
processedData
=
JSON
.
parse
(
JSON
.
stringify
(
processedCustomerData
.
value
))
...
...
@@ -427,10 +573,10 @@ const deleteChildren = (father, childIndex) => {
processedCustomerData
.
value
=
processedData
}
const
copyAddress
=
computed
(()
=>
{
const
residence
AddressIndex
=
addressQuickList
.
value
.
findIndex
(
item
=>
item
.
type
===
'
residence
Address'
const
mailing
AddressIndex
=
addressQuickList
.
value
.
findIndex
(
item
=>
item
.
type
===
'
mailing
Address'
)
if
(
residence
AddressIndex
!==
-
1
)
{
if
(
mailing
AddressIndex
!==
-
1
)
{
return
false
}
else
{
return
true
...
...
@@ -440,10 +586,10 @@ const changeAddressStatus = child => {
// 复用地址
if
(
form
.
value
.
isCopyAddress
.
length
>
0
&&
form
.
value
.
isCopyAddress
[
0
])
{
if
(
child
.
key
==
'residentialAddress'
)
{
form
.
value
[
child
.
key
]
=
form
.
value
[
'
residence
Address'
]
form
.
value
[
child
.
key
]
=
form
.
value
[
'
mailing
Address'
]
// 这里是直接复用地址了,但是地址组件的值是双向绑定的,所以这里需要手动更新地址组件的值
addressQuickList
.
value
.
forEach
(
item
=>
{
if
(
item
.
type
==
'
residence
Address'
)
{
if
(
item
.
type
==
'
mailing
Address'
)
{
saveKey
.
value
[
child
.
key
]
=
{
...
item
,
type
:
child
.
key
}
}
})
...
...
@@ -451,15 +597,7 @@ const changeAddressStatus = child => {
}
console
.
log
(
'saveKey.value'
,
saveKey
.
value
)
}
const
handleInputChange
=
child
=>
{
if
(
(
child
.
key
==
'lastName'
||
child
.
key
==
'firstName'
)
&&
form
.
value
[
'lastName'
]
&&
form
.
value
[
'firstName'
]
)
{
form
.
value
[
'name'
]
=
form
.
value
[
'lastName'
]
+
form
.
value
[
'firstName'
]
}
}
const
handleDateChange
=
child
=>
{
let
age
=
null
if
(
child
.
key
==
'birthday'
)
{
...
...
@@ -479,20 +617,16 @@ const disabledDate = (time, child) => {
return
time
.
getTime
()
>
Date
.
now
()
}
}
const
resetCustomerList
=
()
=>
{
queryParams
.
value
=
{
pageNo
:
1
,
pageSize
:
4
,
name
:
undefined
}
customerList
()
}
const
exportInfo
=
()
=>
{
if
(
props
.
customerBizId
&&
editStatus
.
value
)
{
proxy
.
$modal
.
confirm
(
`请先点击编辑在导入客户信息`
,
{
showCancel
:
'0'
,
title
:
'填写提示'
})
return
}
queryParams
.
value
=
{
pageNo
:
1
,
pageSize
:
10
,
name
:
undefined
}
openList
.
value
=
true
customerList
()
}
...
...
@@ -510,8 +644,10 @@ const customerList = () => {
}
// 从客户列表中导入客户信息到当前表单
const
handleExport
=
row
=>
{
console
.
log
(
'row'
,
row
)
oldObjInfo
.
value
=
JSON
.
parse
(
JSON
.
stringify
(
form
.
value
))
// 修改时存储原始数据,便于撤销操作
setFormValue
(
row
,
processedCustomerData
.
value
,
true
)
//
setFormValue(row, processedCustomerData.value, true)
openList
.
value
=
false
}
...
...
@@ -555,16 +691,22 @@ const processFormData = async () => {
{
required
:
true
,
message
:
`
${
field
.
label
}
不能为空`
,
trigger
:
'blur'
},
{
validator
:
validateEnglish
,
trigger
:
'change'
}
]
}
else
if
(
field
.
key
===
'nameCn'
)
{
rules
.
value
[
field
.
key
]
=
[
{
required
:
true
,
message
:
`
${
field
.
label
}
不能为空`
,
trigger
:
'blur'
},
{
validator
:
validateChinese
,
trigger
:
'blur'
}
]
}
else
{
rules
.
value
[
field
.
key
]
=
[
{
required
:
true
,
message
:
`
${
field
.
label
}
不能为空`
,
trigger
:
'blur'
}
]
}
}
if
(
field
.
key
===
'bmi'
)
{
rules
.
value
[
field
.
key
]
=
[{
validator
:
validateBMI
,
trigger
:
'change'
}]
}
if
(
props
.
customerBizId
)
{
field
.
disabled
=
true
}
else
if
(
field
.
key
!==
'age'
)
{
field
.
disabled
=
false
}
}
}
...
...
@@ -641,8 +783,8 @@ const confirmDrawer = info => {
// console.log('抽屉info', info)
// info 为抽屉返回的值
if
(
drawerInfo
.
value
.
t
ype
==
'arrowRight'
&&
drawerInfo
.
value
.
drawerType
)
{
//
console.log('drawerInfo.value', drawerInfo.value)
if
(
drawerInfo
.
value
.
domT
ype
==
'arrowRight'
&&
drawerInfo
.
value
.
drawerType
)
{
console
.
log
(
'drawerInfo.value'
,
drawerInfo
.
value
)
let
newObj
=
info
[
drawerInfo
.
value
.
key
]
//要判断drawerType
...
...
@@ -714,6 +856,9 @@ const confirmDrawer = info => {
default
:
break
}
console
.
log
(
'form.value'
,
form
.
value
)
console
.
log
(
' saveKey.value'
,
saveKey
.
value
)
// 手动触发表单验证
nextTick
(()
=>
{
// 根据不同的drawerType确定要验证的字段key
...
...
@@ -727,26 +872,31 @@ const confirmDrawer = info => {
const
handleSelectChange
=
child
=>
{
switch
(
child
.
key
)
{
// case 'smokingStatus':
// // 选择吸烟,展示吸烟数量
// if (form.value[child.key] == '1') {
// resetShow('smokeQuantity', true)
// } else {
// resetShow('smokeQuantity', false)
// }
// break
// case 'idType':
// // 选择吸烟,展示吸烟数量
// if (form.value[child.key] == 'idCard') {
// resetShow('idCardAddress', true)
// } else {
// resetShow('idCardAddress', false)
// }
// break
case
'documentType'
:
// 先不加这个验证,有问题
// if (form.value[child.key] == 'idCard') {
// rules.value.idNumber.push({
// validator: validateIdCard,
// trigger: 'blur'
// })
// } else {
// rules.value.idNumber = [{ required: true, message: `证件号码不能为空`, trigger: 'blur' }]
// }
break
case
'isRetirement'
:
if
(
form
.
value
[
child
.
key
]
==
'1'
)
{
resetShow
(
'retirementAge'
,
true
)
}
else
{
resetShow
(
'retirementAge'
,
false
)
}
break
break
default
:
break
}
}
// 改变编辑状态
const
handleEditStatus
=
()
=>
{
editStatus
.
value
=
!
editStatus
.
value
...
...
@@ -757,8 +907,12 @@ const handleEditStatus = () => {
for
(
const
field
of
section
.
data
)
{
if
(
editStatus
.
value
)
{
field
.
disabled
=
true
}
else
if
(
field
.
key
!==
'age'
)
{
field
.
disabled
=
false
}
else
{
if
(
field
.
key
==
'age'
||
field
.
key
==
'bmi'
)
{
field
.
disabled
=
true
}
else
{
field
.
disabled
=
false
}
}
}
}
...
...
@@ -782,13 +936,13 @@ const setFormValue = (obj, formData, exportValue) => {
// }
if
(
section
.
data
)
{
for
(
const
field
of
section
.
data
)
{
// if (obj.smokeQuantity && field.key == 'smokeQuantity') {
// field.show = true
// }
//证件类型是身份证,身份证地址就显示否则不显示
if
(
field
.
key
==
'idCardAddress'
&&
obj
.
idType
==
'idCard'
)
{
if
(
obj
.
isRetirement
&&
obj
.
isRetirement
==
'1'
&&
field
.
key
==
'retirementAge'
)
{
field
.
show
=
true
}
//证件类型是身份证,身份证地址就显示否则不显示
// if (field.key == 'idCardAddress' && obj.idType == 'idCard') {
// field.show = true
// }
//要判断drawerType,因为抽屉要回显数据
switch
(
field
.
drawerType
)
{
case
'phone'
:
...
...
@@ -967,7 +1121,7 @@ const submitForm = () => {
deleteKeyList
.
value
.
forEach
(
item
=>
{
delete
submitObj
[
item
]
})
return
if
(
props
.
customerBizId
)
{
editCustomer
(
submitObj
).
then
(
res
=>
{
if
(
res
.
code
==
200
)
{
...
...
@@ -1035,19 +1189,39 @@ function getCustomerInfo(customerBizId, formData) {
}
})
}
// 根据联动重置表单项的显示与否
const
resetShow
=
(
key
,
status
)
=>
{
for
(
const
section
of
processedCustomerData
.
value
)
{
if
(
section
.
data
)
{
for
(
const
field
of
section
.
data
)
{
if
(
field
.
key
==
key
)
{
// 获取字典数据
field
.
show
=
status
}
}
}
}
}
watch
(
()
=>
props
.
activeName
,
newVal
=>
{
customerRightRef
.
value
=
null
if
(
newVal
===
'customer'
)
{
customerRightRef
.
value
=
null
processFormData
()
}
}
)
</
script
>
<
style
lang=
"scss"
scoped
>
.dialogBox
{
margin
:
10px
;
width
:
100%
;
height
:
600px
;
overflow-y
:
scroll
;
}
.customerContainer
{
display
:
flex
;
/* display: flex; */
height
:
100%
;
box-sizing
:
border-box
;
position
:
relative
;
...
...
@@ -1169,4 +1343,11 @@ watch(
margin-bottom
:
0px
;
}
}
/* 响应式调整 */
/* @media (max-width: 768px) {
.editBtn {
right: 5.5%;
top: 16%;
}
} */
</
style
>
src/views/sign/FnaList/edit.vue
View file @
7f6b6010
...
...
@@ -20,9 +20,20 @@
</div>
</div>
</div>
<div
class=
"tabsBox"
ref=
"tabPaneRef"
>
<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"
>
<div
class=
"tabsBox"
>
<el-tabs
v-model=
"activeName"
class=
"demo-tabs"
:before-leave=
"beforeTabLeave"
ref=
"tabPaneRef"
>
<el-tab-pane
v-for=
"(tab, tIndex) in tabsList"
:key=
"tab.name"
:label=
"tab.label"
:name=
"tab.name"
>
<!-- 注意tabPaneBox这个类名与子组件的锚点定位相关,不能轻易改动 -->
<div
:class=
"
{ tabPaneBox: activeName !== 'appointment' }">
<div
v-if=
"tab.name === 'overview'"
class=
"overviewBox"
>
<div
...
...
@@ -79,6 +90,8 @@
:customerBizId=
"processInfo.customerBizId"
@
handleSuccess=
"handleSuccess"
:tabPaneRef=
"tabPaneRef"
:tabIndex=
"tabsList.findIndex(t => t.name === 'customer')"
anchorContainer=
".tabPaneBox"
/>
<div
v-if=
"tab.name === 'fnaform'"
>
<FanForm
...
...
@@ -206,17 +219,17 @@ const getDictsData = async () => {
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 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
...
...
@@ -276,15 +289,7 @@ const processUpdate = (data, status) => {
}
})
}
// 新建流程
// const getAddInfo = () => {
// addFna({ remark: '' }).then(res => {
// if (res.code == 200) {
// // 获取流程详情
// getProcessInfo(res.data.fnaBizId)
// }
// })
// }
// 获取流程详情
function
getProcessInfo
(
fnaBizId
,
changeTab
)
{
getProcessDetail
(
fnaBizId
).
then
(
res
=>
{
...
...
@@ -515,13 +520,9 @@ getDictsData()
}
}
}
/* .tabPaneBox {
height: calc(100vh - 275px);
overflow-y: auto;
padding-right: 10px;
} */
.tabPaneBox
{
height
:
calc
(
100vh
-
2
75
px
);
height
:
calc
(
100vh
-
2
80
px
);
overflow-y
:
auto
;
padding-right
:
10px
;
position
:
relative
;
...
...
src/views/sign/FnaList/index.vue
View file @
7f6b6010
...
...
@@ -72,6 +72,7 @@
:data=
"tenantList"
@
selection-change=
"tableSelect"
@
sort-change=
"sortChange"
border
>
<el-table-column
type=
"index"
width=
"50"
label=
"序号"
/>
<el-table-column
label=
"客户姓名"
align=
"center"
prop=
"customerName"
width=
"100"
/>
...
...
@@ -130,16 +131,6 @@
</
template
>
</el-table-column>
</el-table>
<!-- <div style="width: 100%; display: flex; justify-content: flex-end; margin-bottom: 30px">
<pagination
v-show="total >= 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
style="text-align: right"
/>
</div> -->
</template>
</CommonPage>
<!-- 下一步到预约 -->
...
...
src/views/sign/appointment/appointmentEdit.vue
View file @
7f6b6010
...
...
@@ -44,12 +44,19 @@
<el-row
v-if=
"isEmbed"
>
<el-col>
<div
class=
"topButtonBox"
>
<el-button
<
!--
<
el-button
v-if=
"idsObj.appointmentBizId && pageSource !== 'policyList'"
type=
"primary"
icon=
"Plus"
@
click=
"handleAddExecl"
>
上传EXECL
</el-button
>
-->
<el-button
v-if=
"pageSource !== 'policyList'"
type=
"primary"
:icon=
"Edit"
@
click=
"handleEdit"
>
编辑
</el-button
>
<el-button
v-if=
"pageSource !== 'policyList'"
...
...
@@ -86,6 +93,10 @@
:appointmentStatus=
"appointmentSummeryInfo.status"
@
handleSuccessEdit=
"getAppointmentInfo(idsObj.appointmentBizId)"
ref=
"appointmentInfoRef"
:tabIndex=
"tabsList.findIndex(t => t.name === 'appointmentInfo')"
anchorContainer=
".appointmentTabPaneBox"
:fatherTabName=
"tabName"
:editStatus=
"editStatus"
/>
</div>
<div
v-if=
"tab.name === 'productPlan'"
>
...
...
@@ -320,7 +331,7 @@ import {
}
from
'@/api/sign/appointment'
import
{
getPolicyfollow
,
getPolicyInfo
,
signName
}
from
'@/api/sign/underwritingMain'
import
{
listTenantUser
,
getInsuranceProductList
,
getAdditionalProductList
}
from
'@/api/common'
import
{
Check
}
from
'@element-plus/icons-vue'
import
{
Check
,
Edit
}
from
'@element-plus/icons-vue'
import
{
ref
,
nextTick
,
onUnmounted
}
from
'vue'
const
emit
=
defineEmits
([
'handleSuccess'
])
...
...
@@ -363,6 +374,7 @@ const processInfo = ref({
createTime
:
proxy
.
parseTime
(
new
Date
()),
customerName
:
userStore
.
name
})
const
editStatus
=
ref
(
true
)
//编辑状态
const
execlDialog
=
ref
(
false
)
const
isEmbed
=
ref
(
false
)
//是否作为组件插入
const
policyNo
=
ref
(
''
)
//新单跟进保单号
...
...
@@ -626,17 +638,17 @@ const getDictsData = async () => {
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 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
...
...
@@ -887,7 +899,9 @@ const handleSubmit = type => {
})
}
}
const
handleEdit
=
()
=>
{
editStatus
.
value
=
!
editStatus
.
value
}
//修改预约数据
if
(
route
.
query
.
appointmentNo
&&
route
.
query
.
source
==
'appointmentList'
)
{
processInfo
.
value
=
route
.
query
...
...
@@ -901,7 +915,7 @@ const pageSource = computed(() => {
})
const
tabHight
=
computed
(()
=>
{
if
(
pageSource
.
value
==
'fnaList'
)
{
return
'calc(100vh - 4
07
px)'
return
'calc(100vh - 4
12
px)'
}
else
if
(
pageSource
.
value
==
'policyList'
)
{
return
'calc(100vh - 225px)'
}
else
{
...
...
@@ -910,7 +924,7 @@ const tabHight = computed(() => {
})
const
minHight
=
computed
(()
=>
{
if
(
pageSource
.
value
==
'fnaList'
)
{
return
'calc(100vh - 8
4.5
px)'
return
'calc(100vh - 8
0
px)'
}
else
if
(
pageSource
.
value
==
'policyList'
)
{
return
'calc(100vh - 84.5px)'
}
else
{
...
...
@@ -983,7 +997,7 @@ watch(
activeName
.
value
=
'appointmentInfo'
})
}
else
{
getAppointmentInfo
(
idsObj
.
value
.
appointmentBizId
)
//
getAppointmentInfo(idsObj.value.appointmentBizId)
tabsList
.
value
=
[
{
label
:
'预约信息'
,
...
...
@@ -1235,6 +1249,17 @@ const showSubmitBtn = computed(() => {
return
false
}
})
if
(
route
.
query
.
appointmentNo
&&
route
.
query
.
source
==
'appointmentList'
)
{
editStatus
.
value
=
true
}
else
if
(
route
.
query
.
source
==
'policyList'
)
{
editStatus
.
value
=
true
}
else
if
(
route
.
query
.
source
==
'fnaList'
&&
idsObj
.
value
.
appointmentBizId
)
{
editStatus
.
value
=
true
}
else
if
(
route
.
query
.
source
==
'fnaList'
&&
!
idsObj
.
value
.
appointmentBizId
)
{
editStatus
.
value
=
false
}
console
.
log
(
'editStatus.value '
,
editStatus
.
value
,
idsObj
.
value
)
onUnmounted
(()
=>
{
// 彻底重置所有响应式数据
submitAppointmentObj
.
value
=
{}
...
...
src/views/sign/appointment/components/appointmentInfo.vue
View file @
7f6b6010
<
template
>
<div>
<div
v-if=
"processedAppointmentData.length > 0
"
>
<el-row>
<div
v-if=
"processedAppointmentData.length > 0"
>
<div
ref=
"appointmentRef
"
>
<
!--
<
el-row>
<el-col
:span=
"24"
>
<div
class=
"topBtn"
>
<el-button
...
...
@@ -13,153 +13,245 @@
>
</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>
-->
<!-- v-if="customerRightRef" -->
<CommonForm
:anchorList=
"anchorList"
:affixOffset=
"360"
:anchorOffset=
"10"
:scrollContainerSelector=
"anchorContainer"
:scrollOffset=
"10"
:domIndex=
"tabIndex"
:activeName=
"activeName"
v-if=
"appointmentRef"
>
<template
#
form-right
>
<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"
:id=
"father.anchorKey"
>
<div
class=
"formBox"
>
<CardOne
:title=
"father.fatherTitle"
>
<template
#
content
>
<!-- 不是表格 -->
<el-row
:gutter=
"20"
v-if=
"!father.showTable"
>
<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=
"editStatus"
/>
<el-select
v-if=
"child.domType === 'Select'"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
@
change=
"handleSelectChange(father, child)"
:disabled=
"editStatus"
>
<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=
"child.timeType || 'datetime'"
:placeholder=
"child.placeholder"
:disabled=
"editStatus"
@
change=
"handleDateChange(child)"
:disabled-date=
"time => disabledDate(time, child)"
format=
"YYYY-MM-DD HH:mm"
value-format=
"YYYY-MM-DD HH:mm:ss"
@
clear=
"handleDateClear(child)"
/>
<!-- 不带时分 -->
<el-date-picker
style=
"width: 100%"
v-if=
"child.domType === 'DatePicker'"
v-model=
"form[child.key]"
type=
"date"
format=
"YYYY-MM-DD"
value-format=
"YYYY-MM-DD"
:placeholder=
"child.placeholder"
:disabled=
"editStatus"
:disabled-date=
"time => disabledDate(time, child)"
@
change=
"handleDateChange(child)"
@
clear=
"handleDateClear(child)"
/>
<el-input
v-if=
"child.domType === 'arrowRight'"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
:suffix-icon=
"ArrowRight"
readonly
:disabled=
"editStatus"
@
focus=
"handleFoucs(child)"
>
</el-input>
<el-button
class=
"formBtn"
v-if=
"child.domType === 'button'"
:type=
"child.buttonType"
@
click=
"handleButtonClick(child)"
>
{{
child
.
buttonTxt
}}
</el-button
>
<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=
"child.timeType || 'datetime'"
:placeholder=
"child.placeholder"
:disabled=
"child.disabled"
@
change=
"handleDateChange(child)"
:disabled-date=
"time => disabledDate(time, child)"
format=
"YYYY-MM-DD HH:mm"
value-format=
"YYYY-MM-DD HH:mm:ss"
@
clear=
"handleDateClear(child)"
/>
<!-- 不带时分 -->
<el-date-picker
style=
"width: 100%"
v-if=
"child.domType === 'DatePicker'"
v-model=
"form[child.key]"
type=
"date"
:placeholder=
"child.placeholder"
:disabled=
"child.disabled"
:disabled-date=
"time => disabledDate(time, child)"
@
change=
"handleDateChange(child)"
@
clear=
"handleDateClear(child)"
/>
<el-input
v-if=
"child.domType === 'arrowRight'"
v-model=
"form[child.key]"
:placeholder=
"child.placeholder"
:suffix-icon=
"ArrowRight"
readonly
:disabled=
"child.disabled"
@
focus=
"handleFoucs(child)"
>
</el-input>
<el-button
class=
"formBtn"
v-if=
"child.domType === 'button'"
:type=
"child.buttonType"
@
click=
"handleButtonClick(child)"
>
{{
child
.
buttonTxt
}}
</el-button
>
<!-- 搜索下拉框 :remote-method="query => searchSelectList(query, child)" remote-->
<el-select
v-model=
"form[child.key]"
v-if=
"child.domType === 'SearchSelect'"
filterable
:allow-create=
"child.allowCreate"
:reserve-keyword=
"false"
placeholder=
"请输入关键词搜索"
:loading=
"searchLoadingStates[child.key]"
:disabled=
"child.disabled"
>
<el-option
v-for=
"item in searchOptions[child.key] || []"
:key=
"item.id"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</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
}}
<el-select
v-model=
"form[child.key]"
v-if=
"child.domType === 'SearchSelect'"
filterable
:allow-create=
"child.allowCreate"
:reserve-keyword=
"false"
placeholder=
"请输入关键词搜索"
:loading=
"searchLoadingStates[child.key]"
:disabled=
"editStatus"
>
<el-option
v-for=
"item in searchOptions[child.key] || []"
:key=
"item.id"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</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>
</div>
</div>
</div>
</div>
</el-col>
</
template
>
</el-col>
</
template
>
</el-row>
<!-- 是表格数据 -->
<el-row
v-if=
"father.showTable"
>
<el-col
:span=
"24"
v-if=
"father.addChildren"
>
<el-button
:disabled=
"editStatus"
type=
"primary"
icon=
"Plus"
size=
"small"
style=
"margin-bottom: 10px"
@
click=
"addChildren(father)"
>
{{ father.addChildrenTxt }}
</el-button
>
</el-col>
<el-table
:data=
"father.data"
border
v-if=
"father.data.length > 0"
>
<
template
v-if=
"father.key == 'referrerDtoList'"
>
<el-table-column
label=
"姓名"
prop=
"realName"
align=
"center"
>
<template
#
default=
"scope"
>
<el-select
v-model=
"scope.row.realName"
filterable
remote
reserve-keyword
placeholder=
"请输入关键词搜索"
:remote-method=
"
query => searchSelectList(query, 'realName', scope.row)
"
:loading=
"searchLoadingStates['realName']"
:disabled=
"editStatus"
>
<el-option
v-for=
"item in searchOptions['realName'] || []"
:key=
"item.id"
:label=
"item.label"
:value=
"item.value"
/>
</el-select>
</
template
>
</el-table-column>
<el-table-column
label=
"手机号"
prop=
"phone"
align=
"center"
>
<!-- <template #header>
<span class="required-label">手机号</span>
</template> -->
<
template
#
default=
"scope"
>
<el-input
v-model=
"scope.row.phone"
size=
"default"
placeholder=
"请输入"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"邮箱"
prop=
"email"
align=
"center"
>
<!-- <template #header>
<span class="required-label">手机号</span>
</template> -->
<
template
#
default=
"scope"
>
<el-input
v-model=
"scope.row.email"
size=
"default"
placeholder=
"请输入"
:disabled=
"editStatus"
/>
</
template
>
</el-table-column>
<el-table-column
width=
"60px"
align=
"center"
label=
"操作"
>
<
template
#
default=
"scope"
>
<el-icon
class=
"deleteIcon"
@
click=
"deleteChildren(father, scope.$index)"
><Delete
/></el-icon>
</
template
>
</el-table-column>
</template>
</el-table>
</el-row>
</template>
</CardOne>
</div>
</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>
<!-- <el-row v-if="props.idsObj.appointmentBizId">
<el-col>
<div class="tabButton">
<el-button
type="primary"
icon="Check"
@click="submitForm"
size="large"
:disabled="editStatus"
>提交</el-button
>
</div>
</el-col>
</el-row> -->
</el-form>
</template>
</CommonForm>
</div>
<!-- <div v-else class="domEmpty" v-loading="loading"></div> -->
<Phone
@
close=
"handleCloseDrawer"
:showDrawer=
"showPhoneDrawer"
...
...
@@ -194,27 +286,35 @@ 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
CommonForm
from
'@/views/components/commonForm'
import
CardOne
from
'@/components/formCard/cardOne'
import
useDictStore
from
'@/store/modules/dict'
const
dictStore
=
useDictStore
()
//获取字典数据
const
props
=
defineProps
({
activeName
:
{
type
:
String
,
default
:
''
},
//tab名称
fatherTabName
:
{
type
:
String
,
default
:
''
},
//一级tab名称
formStatus
:
{
type
:
String
,
default
:
''
},
//父组件状态,新增、修改
idsObj
:
{
type
:
Object
,
default
:
()
=>
({})
},
//父组件传递过来的id对象
apiAppointmentInfoDto
:
{
type
:
Object
,
default
:
()
=>
({})
},
//父组件传递过来的预约信息的详情
appointmentStatus
:
{
type
:
Number
},
//父组件传递过来的预约的状态
customerBizId
:
{
type
:
String
,
default
:
''
}
//提交状态,新增、修改
customerBizId
:
{
type
:
String
,
default
:
''
},
//提交状态,新增、修改
anchorContainer
:
{
type
:
String
,
default
:
''
},
//锚点滚动容器
editStatus
:
{
type
:
Boolean
,
default
:
true
},
//编辑状态
tabIndex
:
{
type
:
[
String
,
Number
],
default
:
''
}
//tab索引
})
const
emit
=
defineEmits
([
'handleSuccessEdit'
])
const
{
proxy
}
=
getCurrentInstance
()
// const { csf_id_type, sys_gender } = proxy.useDict('csf_id_type', 'sys_gender')
const
appointmentRef
=
ref
(
null
)
const
anchorList
=
ref
([])
//锚点列表
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 editStatus = ref(true) // 表单是否可编辑,若是修改初始不可编辑
const
openList
=
ref
(
false
)
// 客户列表弹窗
const
oldObjInfo
=
ref
({})
// 修改时存储原始数据,便于撤销操作
const
consultKey
=
ref
({})
...
...
@@ -292,6 +392,40 @@ const data = reactive({
}
})
const
{
form
,
rules
,
processedAppointmentData
,
queryParams
,
oldAppointmentData
}
=
toRefs
(
data
)
// 添加表单子级dom
const
addChildren
=
father
=>
{
const
processedData
=
JSON
.
parse
(
JSON
.
stringify
(
processedAppointmentData
.
value
))
let
obj4
=
{
id
:
Date
.
now
()
+
Math
.
floor
(
Math
.
random
()
*
1000
),
//唯一标识
span
:
24
,
//栅格布局份数
email
:
''
,
phone
:
''
,
realName
:
''
}
for
(
const
section
of
processedData
)
{
if
(
father
.
key
==
'referrerDtoList'
&&
section
.
key
==
father
.
key
)
{
section
.
data
.
push
(
obj4
)
}
}
//更新form表单对应的数据,以便收集填写的值
// form.value[father.key].push(obj)
processedAppointmentData
.
value
=
processedData
}
const
deleteChildren
=
(
father
,
childIndex
)
=>
{
if
(
editStatus
.
value
)
{
proxy
.
$modal
.
confirm
(
`请先点击编辑再进行删除操作`
,
{
showCancel
:
'0'
,
title
:
'填写提示'
})
return
}
const
processedData
=
JSON
.
parse
(
JSON
.
stringify
(
processedAppointmentData
.
value
))
for
(
const
section
of
processedData
)
{
if
(
father
.
key
==
'referrerDtoList'
&&
section
.
key
==
father
.
key
)
{
section
.
data
.
splice
(
childIndex
,
1
)
}
}
processedAppointmentData
.
value
=
processedData
}
// 搜索方法
const
searchSelectList
=
async
(
query
,
field
)
=>
{
// 设置该字段的加载状态
...
...
@@ -495,10 +629,15 @@ const validateEnglish = (rule, value, callback) => {
// 处理表单配置,添加字典数据
const
processFormData
=
async
()
=>
{
anchorList
.
value
=
[]
// 深拷贝原始数据
const
processedData
=
JSON
.
parse
(
JSON
.
stringify
(
appointmentDomData
))
for
(
const
section
of
processedData
)
{
if
(
section
.
showMoudle
)
{
anchorList
.
value
.
push
({
title
:
section
.
anchorKey
,
name
:
section
.
fatherTitle
})
}
if
(
section
.
data
)
{
for
(
const
field
of
section
.
data
)
{
if
(
section
.
key
==
'openAccount'
)
{
...
...
@@ -531,10 +670,10 @@ const processFormData = async () => {
}
if
(
props
.
idsObj
.
appointmentBizId
)
{
editStatus
.
value
=
true
//
editStatus.value = true
setFormValue
(
props
.
apiAppointmentInfoDto
,
processedData
)
}
else
{
editStatus
.
value
=
false
//
editStatus.value = false
processedAppointmentData
.
value
=
processedData
}
}
...
...
@@ -1006,11 +1145,20 @@ const resetForm = () => {
watch
(
()
=>
props
.
activeName
,
newVal
=>
{
appointmentRef
.
value
=
null
if
(
newVal
===
'appointmentInfo'
)
{
openList
.
value
=
false
setTimeout
(()
=>
{
processFormData
()
},
500
)
processFormData
()
}
}
)
// 因为tab嵌套了两层,所以需要监听父组件的tab否则锚点的显示就会有bug
watch
(
()
=>
props
.
fatherTabName
,
newVal
=>
{
if
(
newVal
)
{
appointmentRef
.
value
=
null
}
}
)
...
...
@@ -1150,6 +1298,11 @@ defineExpose({
margin-bottom
:
0px
;
}
}
.deleteIcon
{
color
:
red
;
font-size
:
18px
;
padding-top
:
10px
;
}
@media
only
screen
and
(
min-width
:
768px
)
{
.formBtn
{
margin-top
:
0
!important
;
...
...
src/views/sign/appointment/index.vue
View file @
7f6b6010
...
...
@@ -203,7 +203,7 @@ import useUserStore from '@/store/modules/user'
const
userStore
=
useUserStore
()
const
router
=
useRouter
()
const
{
proxy
}
=
getCurrentInstance
()
const
dialogVisible
=
ref
(
tru
e
)
const
dialogVisible
=
ref
(
fals
e
)
const
appointmentSummeryInfo
=
ref
({})
const
tenantList
=
ref
([])
const
loading
=
ref
(
true
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment