You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

957 lines
27 KiB

<template>
<div>
<xy-dialog ref="dialog" :form="flag === 1 ? form : form1" :is-show.sync="isShow" :rules="flag === 1 ? rules : rules1" title="编辑客户"
:width="74" type="form">
<template v-if="type === 'add'" v-slot:headerContent>
<el-steps :active="flag" simple style="width: 72%;margin: auto;">
<el-step title="客户录入" icon="el-icon-user-solid"></el-step>
<el-step title="订单录入" icon="el-icon-document-add"></el-step>
</el-steps>
</template>
<template v-slot:footerContent>
<Button @click="$refs['dialog'].reset()">重置</Button>
<template v-if="flag === 1">
<Button type="primary" @click="submit">{{type === 'add' ? '保存客户,退出' : '修改'}}</Button>
<template v-if="type === 'add'">
<Button type="primary" @click="submit1">保存客户,继续录入订单</Button>
</template>
</template>
<template v-else>
<Button type="primary" @click="submitOrder">保存订单</Button>
</template>
</template>
<template v-slot:name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>名称:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.name" clearable placeholder="请输入客户名称" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:phone>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>联系电话:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.phone" clearable placeholder="请输入联系电话" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:idcard>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>身份证号:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.idcard" clearable placeholder="请输入身份证号" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:contact_name>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>委托人:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.contact_name " clearable placeholder="请输入委托人姓名" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:contact_phone>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>委托人电话:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.contact_phone " clearable placeholder="请输入委托人电话" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:idcard_address>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>户籍地址:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.idcard_address " clearable placeholder="请输入户籍地址" style="width: 300px;"></el-input>
</div>
</div>
</template>
<template v-slot:area>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>区域:
</div>
<div class="xy-table-item-content">
<el-cascader
v-model="form.area"
style="width: 300px;"
placeholder="区域选择"
:options="cities"
:props="{
label:'value',
value:'id',
}"
@change="areaPick">
</el-cascader>
</div>
</div>
</template>
<template v-slot:customer_address_list>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>地址:
</div>
<div class="xy-table-item-content">
<div v-if="form.customer_address_list.length > 0" class="xy-table-item-content-address">
<xy-table :height="200" :is-page="false" :list="form.customer_address_list" :table-item="addressTable">
<template v-slot:btns>
<el-table-column align="center" fixed="right" header-align="center" label="操作" width="80">
<template v-slot:default="scope">
<Poptip
confirm
title="确认要删除吗"
transfer
@on-ok="deleteAddress(scope)">
<Button ghost size="small" type="primary">删除</Button>
</Poptip>
</template>
</el-table-column>
</template>
</xy-table>
</div>
<avue-input-map v-model="map" :params="option" class="avue-map-input" placeholder="请选择地图"
style="width: 300px;"></avue-input-map>
</div>
</div>
</template>
<template v-slot:remark>
<div class="xy-table-item">
<div class="xy-table-item-label">
备注:
</div>
<div class="xy-table-item-content">
<el-input v-model="form.remark" :autosize="{minRows:2}" clearable placeholder="请输入备注" style="width: 300px;"
type="textarea"></el-input>
</div>
</div>
</template>
<template v-slot:level_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>失能等级:
</div>
<div class="xy-table-item-content">
<el-select v-model="form.level_id" placeholder="请选择失能等级" style="width: 300px;">
<el-option v-for="item in disabilityLevel" :key="item.id" :label="item.value"
:value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:level_type>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>失能类型:
</div>
<div class="xy-table-item-content">
<el-select v-model="form.level_type" placeholder="请选择失能类型" style="width: 300px;">
<el-option v-for="item in levelTypes" :key="item.id" :label="item.value"
:value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<!-- 订单-->
<template v-slot:product_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>产品:
</div>
<div class="xy-table-item-content" :class="ageTemp ? 'xy-table-item-outrange' : ''">
<el-select
:value="pickedProduct.name"
v-load-more="productLoad"
placeholder="请选择产品"
style="width: 300px"
@change="productPick">
<el-option
v-for="item in products"
value-key="id"
:key="item.id"
:label="item.name"
:value="item"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:product_type_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>业务板块:
</div>
<div class="xy-table-item-content">
<el-select
:disabled="flag !== 1"
:value="flag ===1 ? form.product_type_id : form1.product_type_id"
placeholder="请选择业务板块"
style="width: 300px"
@change="e => flag === 1 ? form.product_type_id = e : form1.product_type_id = e">
<el-option v-for="item in types" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:date>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>开始/结束时间:
</div>
<div class="xy-table-item-content">
<el-date-picker
range-separator="~"
v-model="form1.date"
end-placeholder="结束时间"
start-placeholder="开始时间"
style="width: 300px;"
type="daterange"
:picker-options="pickerOptions"
value-format="yyyy-MM-dd"
@change="computedDate"></el-date-picker>
</div>
</div>
</template>
<template v-slot:account_id>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>结算对象:
</div>
<div class="xy-table-item-content">
<el-select
v-model="form1.account_id"
placeholder="请选择结算对象"
style="width: 300px">
<el-option v-for="item in accounts" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
</template>
<template v-slot:status>
<div class="xy-table-item">
<div class="xy-table-item-label">
<span style="color: red;font-weight: 600;padding-right: 4px;">*</span>状态:
</div>
<div class="xy-table-item-content">
<div style="width: 300px;display: flex;">
<el-radio v-model="form1.status" :label="0">未开始</el-radio>
<el-radio v-model="form1.status" :label="1">进行中</el-radio>
<el-radio v-model="form1.status" :label="2"></el-radio>
</div>
</div>
</div>
</template>
</xy-dialog>
</div>
</template>
<script>
import {getparameter} from '@/api/system/dictionary'
import {save, getInfo} from '@/api/customer'
import {save as orderSave} from '@/api/order'
import {getList as productList} from "@/api/product";
import {getBirth,getSex,getAgeByIdcard} from '@/utils'
import moment from "moment";
export default {
props: {
disabilityLevel: {
type: Array,
default: () => []
},
levelTypes:{
type:Array,
default:()=>[]
},
cities:{
type: Array,
default: () => []
},
accounts:{
type: Array,
default: () => []
},
types:{
type:Array,
default:()=>[]
}
},
data() {
const validatePhone = (rule, value, callback) => {
if (!value) {
callback(new Error('请填写联系电话'))
} else if (/^[1][3-9][\d]{9}/.test(value)) {
callback()
} else if (/([0-9]{3,4}-)?[0-9]{7,8}/.test(value)) {
callback()
} else {
callback(new Error('联系电话格式错误'))
}
}
return {
flag:1,//step进度
id: '',
type: '',
isShow: false,
addressInput: '',//地址输入框
addressTable: [
{
width: 40,
type: 'index'
},
{
label: '是否默认',
width: 100,
sortable: false,
customFn: (row, scope) => {
let {form} = this
return (
<div>
<el-radio
value={row.default}
label={1}
on={{
['change']: (e) => {
form.customer_address_list.map((item, index) => {
index === scope.$index ? item.default = 1 : item.default = 0
})
}
}}>默认地址
</el-radio>
</div>
)
}
},
{
prop: 'name',
label: '名称',
width: 160,
align: 'left',
sortable: false,
customFn: (row) => {
return (
<div>
<el-input
placeholder="名称"
value={row.name}
on={{
['input']: e => row.name = e
}}>
</el-input>
</div>
)
}
},
{
prop: 'address',
label: '地址',
width: 220,
align: 'left',
sortable: false,
customFn: (row) => {
return (
<div>
<el-input
placeholder="地址"
value={row.address}
on={{
['input']: e => row.address = e
}}>
</el-input>
</div>
)
}
},
{
prop: 'remark',
label: '备注',
minWidth: 200,
sortable: false,
customFn: (row) => {
return (
<div>
<el-input
placeholder="备注"
type="textarea"
autosize={{minRows: 2}}
value={row.remark}
on={{
['input']: e => row.remark = e
}}>
</el-input>
</div>
)
}
}
],
form: {
name: '',
product_type_id:'',
phone: '',
idcard: '',
contact_name: '',
contact_phone: '',
idcard_address: '',
area:'',
customer_address_list: [],
sex: '',
birthday: '',
remark: '',
level_type:'',
level_id: '',
},
rules: {
name: [
{required: true, message: '请填写姓名'}
],
phone: [
{validator: validatePhone},
],
idcard: [
{required: true, message: '请填写身份证号'},
{
pattern: /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
message: '身份证格式错误'
}
],
contact_name: [
{required: true, message: '请填写联系人姓名'}
],
contact_phone: [
{validator: validatePhone}
],
idcard_address: [
{required: true, message: '请填写户籍地址'},
],
customer_address_list: [
{required: true, message: '请填写地址'},
],
level_id: [
{required: true, message: '请选择失能等级'},
]
},
map: [],
option: {
column: [
{
label: '坐标',
prop: 'map',
type: 'map',
//高德初始化参数
params: {
zoom: 10,
// zoomEnable: false,
// dragEnable: false,
}
}]
},
//订单
products: [],
pickedProduct:{},
ageTemp:false,
productSelect: {
page: 1,
page_size: 10
},
pickerOptions: {
shortcuts: [{
text: '最近一周',
onClick(picker) {
const end = new Date();
const start = new Date();
end.setTime(start.getTime() + 3600 * 1000 * 24 * 7);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近一个月',
onClick(picker) {
const end = new Date();
const start = new Date();
end.setTime(start.getTime() + 3600 * 1000 * 24 * 30);
picker.$emit('pick', [start, end]);
}
}, {
text: '最近三个月',
onClick(picker) {
const end = new Date();
const start = new Date();
end.setTime(start.getTime() + 3600 * 1000 * 24 * 90);
picker.$emit('pick', [start, end]);
}
},{
text: '最近一年',
onClick(picker) {
const end = new Date();
const start = new Date();
end.setTime(start.getTime() + 3600 * 1000 * 24 * 365);
picker.$emit('pick', [start, end]);
}
}]
},
customerIdcard:'',
form1: {
product_id: '',
product_type_id:'',
date: '',
service_times: '',
unit_price: '',
total_time: '',
total_money: '',
account_id:'',
status: 0,
customer_id: '',
},
rules1: {
customer_id:[
{required: true, message: '请选择客户'}
],
product_id:[
{required: true, message: '请选择产品'}
],
date:[
{required: true, message: '请选择开始结束时间'}
],
service_times:[
{required: true, message: '请填写服务次数'}
],
unit_price:[
{required: true, message: '请填写单次单价'}
],
total_time:[
{required: true, message: '请填写总计时长'}
],
total_money:[
{required: true, message: '请填写总计金额'}
],
status:[
{required: true, message: '请选择状态'}
],
account_id:[
{required: true, message: '请选择结算对象'}
]
},
}
},
methods: {
init(){
this.form = {
name: '',
product_type_id:'',
phone: '',
idcard: '',
contact_name: '',
contact_phone: '',
idcard_address: '',
area:'',
customer_address_list: [],
sex: '',
birthday: '',
remark: '',
level_type:'',
level_id: '',
}
this.form1 = {
product_id: '',
product_type_id:'',
date: '',
service_times: '',
unit_price: '',
total_time: '',
total_money: '',
account_id:'',
status: 0,
customer_id: '',
}
},
areaPick(e){
console.log(e)
},
deleteAddress({$index,row}){
this.form.customer_address_list.splice($index,1)
},
async getDetail() {
const res = await getInfo(this.id)
this.$integrateData(this.form, res)
this.form.customer_address_list = res.customer_address
this.form.area = [Number(res.city_id),Number(res.area_id),Number(res.street_id)]
console.log(this.form)
},
submit() {
this.$refs['dialog'].validate().then(res => {
this.form.sex = getSex(this.form.idcard)
this.form.birthday = getBirth(this.form.idcard)
Object.defineProperty(this.form,'city_id',{
value:this.form.area[0] || '',
enumerable: true,
writable: true,
configurable: true
})
Object.defineProperty(this.form,'area_id',{
value:this.form.area[1] || '',
enumerable: true,
writable: true,
configurable: true
})
Object.defineProperty(this.form,'street_id',{
value:this.form.area[2] || '',
enumerable: true,
writable: true,
configurable: true
})
if (this.type === 'editor') {
Object.defineProperty(this.form, 'id', {
value: this.id,
enumerable: true,
writable: true,
configurable: true
})
}
console.log(this.form)
save(this.form).then(res => {
this.$successMessage(this.type, '客户')
this.isShow = false
this.$emit('refresh')
})
})
},
submit1(){
this.$refs['dialog'].validate().then(res => {
Object.defineProperty(this.form,'city_id',{
value:this.form.area[0] || '',
enumerable: true,
writable: true,
configurable: true
})
Object.defineProperty(this.form,'area_id',{
value:this.form.area[1] || '',
enumerable: true,
writable: true,
configurable: true
})
Object.defineProperty(this.form,'street_id',{
value:this.form.area[2] || '',
enumerable: true,
writable: true,
configurable: true
})
if (this.type === 'editor') {
Object.defineProperty(this.form, 'id', {
value: this.id,
enumerable: true,
writable: true,
configurable: true
})
}
console.log(this.form)
save(this.form).then(res => {
this.$successMessage(this.type, '客户')
this.flag = 2
this.form1.customer_id = res.id
this.customerIdcard = res.idcard
})
})
},
//订单
productPick(e){
this.pickedProduct = e
//判断年龄
let age = getAgeByIdcard(this.customerIdcard)
if(age > this.pickedProduct.product_type.max_age || age < this.pickedProduct.product_type.min_age){
this.ageTemp = true
this.$message({
type:'warning',
message:'该客户不在产品服务年龄范围内',
duration:2000
})
}else{
this.ageTemp = false
}
this.form1.product_id = e.id
this.form1.product_type_id = e.product_type_id
this.computedDate()
},
computedDate(){
if(this.form1.product_id && this.form1.date){
let times;
let t1= moment(this.form1.date[0])
let t2 = moment(this.form1.date[1])
let unit;
switch (this.pickedProduct.cycle){
case 1:
unit = 'year'
break;
case 2:
unit = 'month'
break;
case 3:
unit = 'week'
break;
}
this.pickedProduct.cycle === 4 ? times = 1 : times = t2.diff(t1,unit) //几个周期
this.form1.service_times = this.pickedProduct.frequency * times
this.form1.total_money = Number(this.pickedProduct.purchase_price) * this.form1.service_times
this.form1.unit_price = Number(this.pickedProduct.purchase_price)
if(this.pickedProduct.type === 1){
this.form1.total_time = Number(this.pickedProduct.time_lenth) * this.form1.service_times
}else{
this.form1.total_time = this.pickedProduct.total
}
}
},
productLoad() {
this.productSelect.page++
this.getProducts()
},
async getProducts() {
const res = await productList(this.productSelect, false)
if (res.data.length === 0) {
this.productSelect.page--
this.$message({
type: 'warning',
message: '没有跟多产品了'
})
return
}
this.products.push(...res.data)
},
submitOrder(){
this.$refs['dialog'].validate().then(res => {
console.log(this.form1)
Object.defineProperty(this.form1,'start_date',{
value:this.form1.date[0],
enumerable:true,
writable:true,
configurable:true
})
Object.defineProperty(this.form1,'end_date',{
value:this.form1.date[1],
enumerable:true,
writable:true,
configurable:true
})
delete this.form1.date
if(this.type === 'editor'){
Object.defineProperty(this.form,'id',{
value:this.id,
enumerable:true,
writable:true,
configurable:true
})
}
orderSave(this.form1).then(res => {
this.$successMessage(this.type,'订单')
this.isShow = false
this.$emit('refresh')
})
})
},
},
watch: {
isShow(val) {
if (val) {
if (this.type === 'editor') {
this.getDetail()
}
} else {
this.id = ''
this.type = ''
this.map = []
this.flag = 1
this.pickedProduct = {}
this.ageTemp = false
this.init()
}
},
map(val) {
if (val.length === 0 || !val) return
this.form.customer_address_list.push({
name: '',
address: val[2],
lng: val[0],
lat: val[1],
default: this.form.customer_address_list.length === 0 ? 1 : 0,
comment: ''
})
}
},
mounted() {
this.getProducts()
}
}
</script>
<style lang="scss" scoped>
.xy-table-item {
&-label {
width: 160px;
}
&-content {
&-address {
width: 600px;
margin-bottom: 20px;
&-title {
display: flex;
text-align: center;
font-weight: 600;
& > div {
padding: 2px 6px;
}
&__default {
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 100px !important;
}
&__name {
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 140px !important;
}
&__address {
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 300px !important;
}
&__commnet {
flex: 1;
}
}
&-item {
display: flex;
align-items: flex-start;
& > div {
padding: 2px 6px;
}
&__default {
align-self: center;
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 100px !important;
display: flex;
align-items: center;
justify-content: center;
}
&__name {
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 140px !important;
}
&__address {
flex-shrink: 0 !important;
flex-grow: 0 !important;
flex-basis: 300px !important;
}
&__commnet {
flex: 1;
}
}
}
.avue-map-input {
position: relative;
&::after {
visibility: hidden;
content: '地址选择';
font-size: 12px;
line-height: 20px;
zoom: 0.9;
transform: translateY(100%);
position: absolute;
bottom: 0;
right: 0;
}
}
}
}
::v-deep .el-step__title{
font-size: 15px !important;
}
::v-deep .el-steps--simple{
background: transparent !important;
}
.xy-table-item-label {
width: 160px;
}
::v-deep .el-input__inner {
text-align: left;
}
.xy-table-item-outrange{
position: relative;
&::after{
content:'超出年龄范围';
color: red;
font-size: 12px;
position: absolute;
right: 0;
bottom: -30px;
}
}
</style>