智慧教务系统
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.
 
 
 
 
 
 

2360 lines
66 KiB

<!--添加客户-->
<template>
<view class="assemble">
<fui-segmented-control
style="padding-top: 30rpx;"
:values="optionTable"
:current="(Number(optionTableId))"
type="text"
activeColor="#29d3b4"
color="#fff"
@click="segmented">
</fui-segmented-control>
<!-- 添加客户-->
<view style="margin-top: 20rpx;" v-if="optionTableId == 0">
<view class="search_box">
<view class="input_box">
<input type="text" v-model="student_name" placeholder="请输入客户名称">
</view>
<view class="btn" @click="clientList()">查重</view>
</view>
<view class="form-style">
<fui-form ref="form" top="0" :model="formData" :show="false">
<view class="title" style="margin-top: 20rpx; display: flex; justify-content: space-between; align-items: center;">
<text>基础信息</text>
<view class="quick-fill-btn" @click="openQuickFill">
<text style="color: #29d3b4; font-size: 24rpx;">快速填写</text>
</view>
</view>
<view class="input-style">
<!--姓名-->
<fui-form-item
label="姓名"
labelSize='26'
asterisk asteriskPosition="right"
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="点击填写"
v-model="formData.name"
backgroundColor="#434544"
size="26"
color="#fff"
></fui-input>
</view>
</fui-form-item>
<!--联系电话-->
<fui-form-item
label="联系电话"
asterisk asteriskPosition="right"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="点击填写"
v-model="formData.phone_number"
backgroundColor="#434544"
size="26"
color="#fff"
@blur="handlePhoneBlur"
></fui-input>
</view>
</fui-form-item>
<!--校区-->
<fui-form-item
label="校区"
labelSize='26'
prop="campus"
asterisk asteriskPosition="right"
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`campus`)">
{{ (formData.campus) ? picker_config.campus.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--来源-->
<fui-form-item
label="来源"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`source`)">
{{ (formData.source) ? picker_config.source.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--来源渠道-->
<fui-form-item
v-if="formData.source == 1"
label="来源渠道"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`source_channel`)">
{{ (formData.source_channel) ? picker_config.source_channel.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--转介绍资源选择-->
<fui-form-item
v-if="formData.source == 3"
label="转介绍资源"
asterisk asteriskPosition="right"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<!-- 搜索输入框 -->
<view class="referral-search-container">
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="输入姓名或手机号搜索"
v-model="referralSearchQuery"
backgroundColor="#434544"
size="26"
color="#fff"
@input="searchReferralResources"
></fui-input>
<!-- 搜索结果列表 -->
<view v-if="referralSearchResults.length > 0" class="referral-search-results">
<view
v-for="resource in referralSearchResults"
:key="resource.id"
class="referral-search-item"
:class="{ 'selected': formData.referral_resource_id === resource.id }"
@click="selectReferralResource(resource)"
>
<view class="resource-info">
<view class="resource-name">{{ resource.name }}</view>
<view class="resource-phone">{{ resource.phone_number }}</view>
</view>
<view v-if="formData.referral_resource_id === resource.id" class="check-icon">✓</view>
</view>
</view>
<!-- 已选择的资源显示 -->
<view v-if="selectedReferralResource && !referralSearchQuery" class="selected-referral-resource">
<view class="selected-resource-info">
<view class="selected-resource-name">{{ selectedReferralResource.name }}</view>
<view class="selected-resource-phone">{{ selectedReferralResource.phone_number }}</view>
</view>
<view class="clear-selection" @click="clearReferralSelection">✕</view>
</view>
</view>
</view>
</fui-form-item>
<fui-form-item
v-show="false"
label="顾问"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input
:borderBottom="false"
:padding="[0]"
:disabled="true"
placeholder="点击填写"
v-model="picker_config.consultant.text"
backgroundColor="#434544"
size="26"
color="#808080"
></fui-input>
</view>
</fui-form-item>
<!--生日-->
<fui-form-item
label="生日"
labelSize='26'
prop="birthday"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<view
@click="openBirthdayPicker"
style="color: #fff; cursor: pointer;">
{{ formData.birthday ? formData.birthday : '请选择生日' }}
</view>
<fui-date-picker
:show="picker_show_birthday"
type="3"
:minDate="minDate"
:maxDate="maxDate"
:value="getCurrentBirthdayValue()"
@change="changePickerBirthday"
@cancel="closeBirthdayPicker"
></fui-date-picker>
</view>
</fui-form-item>
<!--需求-->
<fui-form-item
label="需求"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="点击填写"
v-model="formData.demand"
backgroundColor="#434544"
size="26"
color="#fff"
></fui-input>
</view>
</fui-form-item>
<!--决策人-->
<fui-form-item
label="决策人"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`decision_maker`)">
{{ (formData.decision_maker) ? picker_config.decision_maker.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--客户初步意向度-->
<fui-form-item
label="客户初步意向度"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`initial_intent`)">
{{ (formData.initial_intent) ? picker_config.initial_intent.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--客户状态-->
<fui-form-item
v-show="false"
label="客户状态"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`status`)">
{{ (formData.status) ? picker_config.status.text : '点击选择' }}
</view>
</view>
</fui-form-item>
</view>
</fui-form>
</view>
<view class="fui-btn__box">
<fui-button background="#434544" color="#24BA9F" borderColor="#24BA9F" @click="nextStep('1')">下一步</fui-button>
</view>
</view>
<!-- 添加六要素-->
<view style="margin-top: 20rpx;" v-if="optionTableId == 1">
<view class="form-style">
<fui-form ref="form" top="0" :model="formData" :show="false">
<view class="title" style="margin-top: 20rpx;">六要素信息</view>
<view class="input-style">
<!--购买力-->
<fui-form-item
label="购买力"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`purchasing_power`)">
{{ (formData.purchasing_power) ? picker_config.purchasing_power.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--认知理念-->
<fui-form-item
label="认知理念"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`cognitive_idea`)">
{{ (formData.cognitive_idea) ? picker_config.cognitive_idea.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--可选上课时间-->
<fui-form-item
label="可选上课时间"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openDate(`optional_class_time`)">
{{ (formData.optional_class_time) ? formData.optional_class_time : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--承诺到访时间-->
<fui-form-item
label="承诺到访时间"
labelSize='26'
prop=""
background='#434544'
labelColor='#fff'
:bottomBorder='false'
>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openDate(`promised_visit_time`)">
{{ (formData.promised_visit_time) ? formData.promised_visit_time : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--距离-->
<fui-form-item
label="距离"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<view
class="input-title"
style="margin-right:14rpx;"
@click="openCicker(`distance`)">
{{ (formData.distance) ? picker_config.distance.text : '点击选择' }}
</view>
</view>
</fui-form-item>
<!--沟通备注-->
<fui-form-item
label="沟通备注"
labelSize='26'
prop="title"
background='#434544'
labelColor='#fff'
:bottomBorder='false'>
<view class="input-title" style="margin-right:14rpx;">
<fui-input
:borderBottom="false"
:padding="[0]"
placeholder="点击填写"
v-model="formData.communication"
backgroundColor="#434544"
size="26"
color="#fff"
></fui-input>
</view>
</fui-form-item>
</view>
</fui-form>
</view>
<view class="fui-btn__box">
<fui-button background="#434544" color="#24BA9F" borderColor="#24BA9F" @click="submit">保存</fui-button>
</view>
</view>
<!-- 年月日-选择时间 -->
<fui-date-picker
:show="date_picker_show"
type="3"
:startYear="2020"
:endYear="2030"
:value="getCurrentDate()"
@change="change_date"
@cancel="cancel_date">
</fui-date-picker>
<!-- 选择器 -->
<fui-picker
:linkage='picker_linkage'
:options="picker_options"
:layer="1"
:show="picker_show"
@change="changeCicker"
@cancel="cancelCicker">
</fui-picker>
<!-- 查重弹出层-->
<fui-bottom-popup :show="showDuplicateCheck" @close="closeDuplicateCheck">
<view class="fui-scroll__wrap">
<view class="title_box">
<view></view>
<view class="title">查重结果</view>
<view class="close" @tap="closeDuplicateCheck">
<fui-icon name="close" :size="48"></fui-icon>
</view>
</view>
<scroll-view scroll-y class="section_ul">
<!--暂无数据时展示-->
<view class="not_list" v-if="clientUserList.length == 0">
<image :src="$util.img('/uniapp_src/static/images/index/zan_wu.png')" class="img"></image>
<view class="title">暂无重复客户</view>
</view>
<!--数据列表-->
<view class="ul" v-else>
<view class="duplicate-notice">
<text style="color: #ff6b35; font-size: 28rpx; margin-bottom: 20rpx;">检测到手机号重复,是否为现有用户添加新学员?</text>
<fui-button
background="#29d3b4"
color="#fff"
@click="confirmAddStudent"
style="margin: 20rpx 0;">
确认添加学员
</fui-button>
</view>
<view class="li" v-for="(v,k) in clientUserList" :key="k" @click="openViewClueInfo(v)">
<view class="left_box">
<view class="box_1">
<image
class="img"
:src="$util.img('/uniapp_src/static/images/index/myk.png')"></image>
<view class="name">{{v.name}}</view>
<!-- <view class="tag">{{ v.is_status == 1 ? '试听' : '成交' }}</view>-->
</view>
<view class="box_2">
<view class="left">
<view class="name">首选联系人:{{v.decision_maker}}</view>
<!-- <view class="call">妈妈</view>-->
</view>
</view>
<view class="box_2">
<view class="left">
<view class="name">联系电话:{{v.phone_number || ''}}</view>
</view>
</view>
<view class="box_3">
<view class="left">
{{ $util.formatToDateTime((v.updated_at || ''), 'm-d H:i') }} 跟进
</view>
<view class="right">
<image
v-if="v.initial_intent == 'high'"
:src="$util.img('/uniapp_src/static/images/index/intention3.png')"
class="img"
></image>
<image
v-else-if="v.initial_intent == 'medium'"
:src="$util.img('/uniapp_src/static/images/index/intention2.png')"
class="img"
></image>
<image
v-else
:src="$util.img('/uniapp_src/static/images/index/intention1.png')"
class="img"
></image>
<view>意向:{{ v.initial_intent_name || '' }}</view>
</view>
</view>
</view>
<view class="right_box">
<!-- <image v-if="v.member_id" class="img" :src="$util.img('/uniapp_src/static/images/index/message.png')" @click="openViewMyMessage(v)"></image>-->
<!-- <image v-if="v.phone_number" class="img" :src="$util.img('/uniapp_src/static/images/index/phone.png')" @click="dialTel(v)"></image>-->
</view>
</view>
</view>
</scroll-view>
</view>
</fui-bottom-popup>
<!-- 快速填写弹窗 -->
<view v-if="showQuickFill" class="quick-fill-mask" @tap="showQuickFill=false">
<view class="quick-fill-content" @tap.stop>
<view class="quick-fill-header">
<view class="quick-fill-title">快速填写</view>
<view class="quick-fill-close" @tap="showQuickFill=false">
<text class="close-text">✕</text>
</view>
</view>
<view class="quick-fill-body">
<view class="quick-fill-tip">
<text>请粘贴包含客户信息的文本,支持格式:</text>
<text>姓名:张三,电话:13800138000,校区:测试校区</text>
</view>
<textarea
class="quick-fill-textarea"
placeholder="请粘贴客户信息文本..."
v-model="quickFillText"
:maxlength="1000"
></textarea>
</view>
<view class="quick-fill-buttons">
<view class="quick-fill-btn cancel-btn" @click="showQuickFill=false">取消</view>
<view class="quick-fill-btn confirm-btn" @click="parseQuickFillText">解析并填写</view>
</view>
</view>
</view>
</view>
</template>
<script>
import apiRoute from '@/api/apiRoute.js';
import commonApi from '@/api/common.js';
import marketApi from '@/api/market.js';
import memberApi from '@/api/member.js';
import util from '@/common/util.js';
import dictUtil from '@/common/dictUtil.js';
import dictUtilSimple from '@/common/dictUtilSimple.js';
const rules = [
{
name: "student_name",
rule: ["required"],
msg: ["请输入学员姓名"]
},
{
name: "title",
rule: ["required"],
msg: ["请输入线索标题"]
},
{
name: "student_phone",
rule: ["required", "isMobile"],
msg: ["请输入电话", "请输入正确的手机号"]
},
{
name: "age",
rule: ["required", "isNumber"],
msg: ["请输入年龄", "请输入正确的数字"]
},
{
name: "school_name",
rule: ["required"],
msg: ["请输入学校"]
},
{
name: "grade",
rule: ["required"],
msg: ["请输入年级"]
},
{
name: "class_name",
rule: ["required"],
msg: ["请输入班级"]
},
{
name: "customer_source",
rule: ["required"],
msg: ["请选择客户来源"]
},
{
name: "add_staff_id",
rule: ["required"],
msg: ["请选择顾问"]
},
{
name: "contact_name",
rule: ["required"],
msg: ["请输入联系人"]
},
{
name: "full_address",
rule: ["required"],
msg: ["请选择所在地区"]
},
{
name: "community_name",
rule: ["required"],
msg: ["请输入小区"]
},
{
name: "customer_tags_name",
rule: ["required"],
msg: ["请选择客户标签"]
}
];
export default {
data() {
return {
switchChange_type: 1,
rules,
is_submit: true,//是否提交(防止重复提交)|true=可提交,false=不可提交
// 快速填写相关
showQuickFill: false, // 是否显示快速填写弹窗
quickFillText: '', // 快速填写文本内容
//表单
formData: {
// 客户基础信息
source_channel:'',//来源渠道
source:'',//来源
consultant:'',//顾问
name:'',//姓名
age:'',//年龄
gender:'male',//性别|male-男性, female-女性, other-其他
phone_number:'',//联系电话
demand:'',//需求
decision_maker:'',//决策人
initial_intent:'',//客户初步意向度: high-高, medium-中, low-低
status:'pending',//客户状态: active-活跃, inactive-不活跃, pending-待定
birthday:'',//生日
//六要素信息
purchasing_power:'',//购买力
cognitive_idea:'',//认知理念
communication:'',//沟通备注
promised_visit_time:'',//承诺到访时间
staff_id:'',//人员ID
distance:'',//距离
optional_class_time:'',//可选上课时间
campus:'',
referral_resource_id:'',//转介绍资源ID
},
campus_list:[],
//下拉选择器相关
picker_input_name:'',//下拉组件的input_name
picker_show:false,//下拉组件是否展示
picker_linkage:true,//选择器是否为联动选择
picker_options:[
// {
// text:'张三',
// value:'1'
// },
],//选择器可选值列表
picker_config:{
//来源渠道
source_channel:{
text:'',//回显中文名字
options:[
// {
// text:'张三',
// value:'1'
// }
],//可选值列表
},
//来源
source:{
text:'',
options:[],
},
//顾问
consultant:{
text:'',
options:[],
},
//购买力
purchasing_power:{
text:'',
options:[],
},
//认知理念
cognitive_idea:{
text:'',
options:[],
},
//客户初步意向度
initial_intent:{
text:'',
options:[],
},
//决策人
decision_maker:{
text:'',
options:[],
},
//所属校区
campus:{
text:'',
options:[],
},
//客户状态
status:{
text:'',
options:[],
},
//距离
distance:{
text:'',
options:[],
},
},//选择器选项配置
// 年月日选择组件
data_picker_input_name:'',//时间组件的input_name
date_picker_show:false,//时间选择器是否展示
//生日选择器
picker_show_birthday: false,
minDate: '1900-01-01', // 最小日期
maxDate: new Date().toISOString().split('T')[0], // 最大日期,只取日期部分
//地区三级联动
show_area: false,
options_area: [],
//登录用户信息
userInfo:{},
// 查重相关
student_name:'',//检索关键字
clientUserList:[],//查重用户列表
showDuplicateCheck:false,//是否显示查重弹出层
//tab切换
optionTableId:0,
optionTable: [
{
id: 0,
name: '添加客户'
},
{
id: 1,
name: '添加六要素'
}
],
// 转介绍资源相关
referralSearchQuery: '', // 转介绍资源搜索关键词
referralSearchResults: [], // 搜索结果列表
selectedReferralResource: null, // 已选择的转介绍资源
referralSearchTimer: null, // 搜索防抖定时器
}
},
onLoad() {
// 预加载字典数据
this.preloadDictData()
},
onShow() {
this.init()
},
onUnload() {
// 清理定时器
if (this.referralSearchTimer) {
clearTimeout(this.referralSearchTimer)
this.referralSearchTimer = null
}
},
methods: {
// 预加载字典数据
async preloadDictData() {
const dictKeys = [
'SourceChannel', 'source', 'customer_purchasing_power',
'preliminarycustomerintention', 'cognitive_concept',
'kh_status', 'decision_maker', 'distance'
]
// 静默预加载,不阻塞页面显示
// 暂时使用简化版本进行测试
dictUtilSimple.getBatchDict(dictKeys).catch(error => {
console.warn('字典预加载失败:', error)
})
},
//初始化
async init() {
//获取登录用户信息
await this.getUserInfo()
// 使用批量获取字典数据,提升性能
await this.getBatchDictData()
// 设置时间相关默认值
this.setDefaultTimes()
// this.getStaffList()//获取人员列表
// this.getAreaTree()//获取地区树形结构
},
// 设置时间相关默认值
setDefaultTimes() {
// 移除可选上课时间的默认值设置,让用户手动选择
this.formData.optional_class_time = ''
// 移除承诺到访时间的默认值设置,让用户手动选择
this.formData.promised_visit_time = ''
console.log('时间默认值已清空,用户需手动选择')
},
// 快速填写相关方法
// 打开快速填写弹窗
openQuickFill() {
this.showQuickFill = true
this.quickFillText = ''
},
// 解析快速填写文本
parseQuickFillText() {
if (!this.quickFillText.trim()) {
uni.showToast({
title: '请输入要解析的文本',
icon: 'none'
})
return
}
try {
// 定义字段映射规则
const fieldRules = [
{ key: 'name', patterns: ['姓名', '客户姓名', '用户姓名', '学员姓名', '学生姓名'] },
{ key: 'phone_number', patterns: ['电话', '手机', '联系电话', '手机号', '电话号码', '联系方式'] },
{ key: 'campus', patterns: ['校区', '所属校区', '校区名称'] },
{ key: 'age', patterns: ['年龄'] },
{ key: 'birthday', patterns: ['生日', '出生日期', '生日日期'] }
]
// 用于存储解析结果
const parsedData = {}
const text = this.quickFillText.trim()
// 对每个字段规则进行匹配
fieldRules.forEach(rule => {
rule.patterns.forEach(pattern => {
// 匹配模式:字段名 + 冒号/等号 + 数据内容
const regex = new RegExp(`${pattern}\\s*[::=]\\s*([^,,\\n\\s]+)`, 'g')
const match = regex.exec(text)
if (match && match[1]) {
parsedData[rule.key] = match[1].trim()
}
})
})
console.log('解析结果:', parsedData)
// 填写到表单中
let fillCount = 0
if (parsedData.name) {
this.formData.name = parsedData.name
fillCount++
}
if (parsedData.phone_number) {
this.formData.phone_number = parsedData.phone_number
fillCount++
}
if (parsedData.campus) {
// 需要在校区选项中查找匹配的项
this.findAndSetCampus(parsedData.campus)
fillCount++
}
if (parsedData.age) {
const age = parseInt(parsedData.age)
if (!isNaN(age) && age > 0 && age < 150) {
this.formData.age = age
fillCount++
}
}
if (parsedData.birthday) {
this.formData.birthday = parsedData.birthday
fillCount++
}
if (fillCount > 0) {
uni.showToast({
title: `成功填写${fillCount}个字段`,
icon: 'success'
})
this.showQuickFill = false
} else {
uni.showToast({
title: '未能识别到有效信息,请检查格式',
icon: 'none'
})
}
} catch (error) {
console.error('解析失败:', error)
uni.showToast({
title: '解析失败,请检查格式',
icon: 'none'
})
}
},
// 查找并设置校区
findAndSetCampus(campusText) {
const campusOptions = this.picker_config.campus?.options || []
const matchedCampus = campusOptions.find(option =>
option.text.includes(campusText) || campusText.includes(option.text)
)
if (matchedCampus) {
this.formData.campus = matchedCampus.value
this.picker_config.campus.text = matchedCampus.text
}
},
// 统一的日期格式化方法
formatDate(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
// FirstUI 日期选择器通常支持多种格式
// 根据实际测试结果可以调整以下格式:
// 格式选项(如果当前格式不工作,可以尝试其他格式):
const formats = {
standard: `${year}-${month}-${day}`, // YYYY-MM-DD
chinese: `${year}${month}${day}`, // YYYY年MM月DD日
slash: `${year}/${month}/${day}`, // YYYY/MM/DD
dot: `${year}.${month}.${day}`, // YYYY.MM.DD
space: `${year} ${month} ${day}` // YYYY MM DD
}
// 优先使用标准格式,如果组件显示异常可以在这里切换格式
return formats.standard
// 如果标准格式不工作,可以尝试:
// return formats.chinese // 中文格式
// return formats.slash // 斜杠格式
},
// 统一日期格式处理方法
normalizeDate(dateStr) {
if (!dateStr) return ''
// 如果已经是标准格式 YYYY-MM-DD,直接返回
if (/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) {
return dateStr
}
// 处理 YYYY/MM/DD 格式
if (/^\d{4}\/\d{1,2}\/\d{1,2}$/.test(dateStr)) {
const parts = dateStr.split('/')
const year = parts[0]
const month = String(parts[1]).padStart(2, '0')
const day = String(parts[2]).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 处理 YYYY.MM.DD 格式
if (/^\d{4}\.\d{1,2}\.\d{1,2}$/.test(dateStr)) {
const parts = dateStr.split('.')
const year = parts[0]
const month = String(parts[1]).padStart(2, '0')
const day = String(parts[2]).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 处理中文格式 YYYY年MM月DD日
if (/^\d{4}年\d{1,2}月\d{1,2}日$/.test(dateStr)) {
const year = dateStr.match(/^(\d{4})年/)[1]
const month = String(dateStr.match(/年(\d{1,2})月/)[1]).padStart(2, '0')
const day = String(dateStr.match(/月(\d{1,2})日/)[1]).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 其他格式尝试用Date对象解析
try {
const date = new Date(dateStr)
if (!isNaN(date.getTime())) {
return this.formatDate(date)
}
} catch (error) {
console.warn('日期格式解析失败:', dateStr, error)
}
// 如果都无法解析,返回原值
return dateStr
},
// 获取当前日期(用于日期选择器的默认显示)
getCurrentDate() {
const today = new Date()
return this.formatDate(today)
},
// 批量获取字典数据
async getBatchDictData() {
try {
// 定义需要的字典keys
const dictKeys = [
'SourceChannel', // 来源渠道
'source', // 来源
'customer_purchasing_power', // 购买力
'preliminarycustomerintention', // 客户初步意向度
'cognitive_concept', // 认知理念
'kh_status', // 客户状态
'decision_maker', // 决策人
'distance' // 距离
]
// 批量获取字典数据(静默获取,不显示加载提示)
// 暂时使用简化版本进行测试
const dictData = await dictUtilSimple.getBatchDict(dictKeys)
// 处理字典数据
this.processDictData(dictData)
console.log('批量获取字典数据成功:', dictData)
} catch (error) {
console.error('批量获取字典数据失败:', error)
// 如果批量获取失败,回退到单个获取
await this.fallbackGetDict()
}
},
// 处理批量获取的字典数据
processDictData(dictData) {
// 字典key与本地配置的映射关系
const keyMapping = {
'SourceChannel': 'source_channel',
'source': 'source',
'customer_purchasing_power': 'purchasing_power',
'preliminarycustomerintention': 'initial_intent',
'cognitive_concept': 'cognitive_idea',
'kh_status': 'status',
'decision_maker': 'decision_maker',
'distance': 'distance'
}
// 处理每个字典数据
Object.keys(keyMapping).forEach(dictKey => {
const localKey = keyMapping[dictKey]
const dictItems = dictData[dictKey] || []
if (Array.isArray(dictItems) && dictItems.length > 0) {
const formattedOptions = dictItems.map(item => ({
text: item.name || '',
value: item.value || ''
}))
// 设置到picker配置中
if (this.picker_config[localKey]) {
this.picker_config[localKey].options = formattedOptions
}
}
})
},
// 回退方案:单个获取字典(兼容原有逻辑)
async fallbackGetDict() {
console.log('使用回退方案获取字典数据')
try {
await this.getDict('source_channel')
await this.getDict('source')
await this.getDict('purchasing_power')
await this.getDict('initial_intent')
await this.getDict('cognitive_idea')
await this.getDict('status')
await this.getDict('decision_maker')
await this.getDict('distance')
} catch (error) {
console.error('回退方案也失败了:', error)
}
},
async get_campus_list(){
let res = await apiRoute.common_getCampusesList({})
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
this.campus_list = res.data
let arr = []
this.campus_list.forEach((v,k)=>{
arr.push({
text: v.campus_name,
value: v.id,
})
})
this.picker_config['campus'].options = arr
},
//获取用户信息
async getUserInfo(){
let res = await apiRoute.getPersonnelInfo({})
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
this.userInfo = res.data
this.formData.consultant = res.data.id//顾问id
this.formData.staff_id = res.data.id//人员ID
this.picker_config['consultant'].text = res.data.name//顾问名字
await this.get_campus_list()//获取校区
},
//获取字典-课程id选择
async getDict_courses_id(){
let res = await marketApi.selectCourseList({})
if(res.code != 1){
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
let dictionary = res.data
let arr = []
dictionary.forEach((v,k)=>{
arr.push({
text: v.name,
value: v.id,
})
})
this.options_courses_id = arr
},
//获取人员列表
async getStaffList() {
let res = await memberApi.staffList({type: 2})
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
let arr = []
res.data.forEach((v,k)=>{
arr.push({
text: v.name,
value: v.id,
})
})
this.options_add_staff_id = arr
},
//获取人员列表 role_id|5=市场,6=销售
async getRoleStaffList(role_id) {
let res = await memberApi.staffList({
type: 2,
role_id:role_id
})
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
let arr = []
res.data.forEach((v,k)=>{
arr.push({
text: v.name,
value: v.id,
})
})
if(role_id == 5){
this.options_staff_id_5 = arr
console.log('市场',arr)
}else{
this.options_staff_id_6 = arr
console.log('销售',arr)
}
},
//获取地区树形结构
async getAreaTree() {
let res = await commonApi.getAreaTree()
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
this.options_area = res.data
},
//获取字典
async getDict(inputName){
let key = ''
switch (inputName){
case 'source_channel': key = 'SourceChannel'; break;
case 'source': key = 'source'; break;
case 'purchasing_power': key = 'customer_purchasing_power'; break;
case 'cognitive_idea': key = 'cognitive_concept'; break;
case 'decision_maker': key = 'decision_maker'; break;
case 'initial_intent': key = 'preliminarycustomerintention'; break;
case 'status': key = 'kh_status'; break;
case 'distance': key = 'distance'; break;
}
if(!key){ return }
// 使用 util.getDict 获取并缓存字典
let dictionary = await util.getDict(key)
if(!dictionary || !Array.isArray(dictionary) || dictionary.length === 0){
uni.showToast({ title: '暂无选项', icon: 'none' })
return
}
let arr = []
// 处理接口返回的数据结构 [{name: "抖音", value: "1", sort: 0, memo: ""}, ...]
dictionary.forEach((v) => {
arr.push({ text: v.name, value: v.value })
})
this.picker_config[inputName].options = arr
},
//##### 查重相关 #####
//客户列表--查重
async clientList(){
if(!this.student_name){
uni.showToast({
title: '请输入检索关键字',
icon: 'none'
})
return
}
this.clientUserList = []
let param = {
name:this.student_name
}
let res = await apiRoute.xs_getAllCustomerResources(param)
if(res.code != 1){
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
console.log('查重',res)
this.clientUserList = res.data
this.openDuplicateCheck()
},
//打开结果列表
openDuplicateCheck(){
this.showDuplicateCheck = true
},
//关闭结果列表
closeDuplicateCheck(e){
this.showDuplicateCheck = false
},
//跳转页面-客户详情
openViewClueInfo(item) {
let resource_sharing_id = '';
if (item.resourceSharingHasMany && item.resourceSharingHasMany.length > 0) {
resource_sharing_id = item.resourceSharingHasMany[0].id; // 共享资源表id
}
if (!resource_sharing_id) {
uni.showToast({
title: '暂时无法查看',
icon: 'none'
});
return;
}
this.$navigateTo({
url: `/pages/market/clue/clue_info?resource_sharing_id=${resource_sharing_id}`
})
},
//跳转页面-我的消息
openViewMyMessage(item) {
let from_id = this.userInfo.id//发送者的id
let to_id = item.customerResource.id//接收者ID
this.$navigateTo({
url: `/pages/common/im_chat_info?from_id=${from_id}&to_id=${to_id}`
})
},
//拨打电话
async dialTel(item) {
let tel = item.phone_number
if (!tel) {
uni.showToast({
title: '电话号码为空',
icon: 'none'
});
return;
}
let param = {
staff_id: this.userInfo.id,//员工id
resource_id: item.id,//资源ID
resource_type: '',//资源类型(如设备、文件、系统等)
communication_type: 'phone',//沟通类型: phone-电话, email-邮件, meeting-会议, other-其他
communication_result: 'success',//沟通结果: success-成功, failure-失败, pending-待定
remarks: null,//备注
tag: null,//标签
}
let res = await apiRoute.xs_communicationRecordsAdd(param)//添加通过记录
if (res.code != 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
uni.makePhoneCall({
phoneNumber: tel
})
},
//联系电话失去焦点时间
async handlePhoneBlur(){
if(!this.formData.phone_number){
return
}
this.clientUserList = []
let param = {
phone_number:this.formData.phone_number
}
let res = await apiRoute.xs_getAllCustomerResources(param)
if(res.code != 1){
if(res.msg == '暂无数据'){
return
}
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
console.log('查重',res)
this.clientUserList = res.data
this.openDuplicateCheck()
},
//确认添加学员
async confirmAddStudent(){
if(!this.clientUserList || this.clientUserList.length == 0){
uni.showToast({
title: '没有找到重复的用户',
icon: 'none'
})
return
}
//取第一个重复用户的ID作为user_id
const userId = this.clientUserList[0].id
//检查必要字段
if(!this.formData.name){
uni.showToast({
title: '请填写学员姓名',
icon: 'none'
})
return
}
if(!this.formData.gender){
uni.showToast({
title: '请选择学员性别',
icon: 'none'
})
return
}
//准备学员数据
const studentData = {
name: this.formData.name,
gender: this.formData.gender,
user_id: userId,
status: 1
}
try {
const res = await apiRoute.xs_addStudent(studentData)
if(res.code != 1){
uni.showToast({
title: res.msg || '添加学员失败',
icon: 'none'
})
return
}
uni.showToast({
title: '学员添加成功',
icon: 'success'
})
//关闭弹窗并跳转回列表页
this.showDuplicateCheck = false
setTimeout(() => {
uni.redirectTo({
url: `/pages/market/clue/index`
})
}, 1000)
} catch (error) {
console.error('添加学员失败:', error)
uni.showToast({
title: '添加学员失败',
icon: 'none'
})
}
},
//多选客户标签-选中后回调
onConfirmCustomerTags(e) {
console.log('多选客户标签', e)
this.show_customer_tags = false
let customer_tags_name_arr = []
let customer_tags_arr = []
e.options.forEach((v, k) => {
customer_tags_arr.push(v.value)
customer_tags_name_arr.push(v.text)
//根据v.value 设置this.options_customer_tags中对应元素的checked属性为true
this.options_customer_tags.forEach((v, k) => {
if (v.value == v.value) {
v.checked = true
}
})
})
this.formData.customer_tags_name = customer_tags_name_arr.join(',')//数组转字符串
this.formData.customer_tags = customer_tags_arr//数组转字符串
},
//地区选择相关
changeArea(e) {
this.show_area = false
console.log('地区选择', e)
this.formData.province_id = e.value[0]
this.formData.city_id = e.value[1]
this.formData.district_id = e.value[2]
this.formData.full_address = `${e.text[0]}-${e.text[1]}-${e.text[2]}`
},
//开关选择
switchChange(e) {
if (e.detail.value) {
this.switchChange_type = 1
} else {
this.switchChange_type = 2
}
},
//性别选择器
changeSex(e){
this.formData.gender = e.detail.value
},
//监听-是否创建跟进任务
changeIsFollow(e) {
console.log(111, e.detail.value)
this.is_follow = e.detail.value
//是否创建跟进任务 1跟进
if (this.is_follow) {
this.formData.is_follow = '1'
} else {
//2不跟进
this.formData.is_follow = '2'
this.formData.entry_type = ''//跟进类型
this.formData.staff_id = ''//跟进人员
this.formData.follow_up_time = ''//跟进时间
this.formData.follow_up_content = ''//备注
}
},
//切换tag列表
async segmented(e) {
console.log(e)
//e.id|0=基础信息 1=六要素
let status = e.id
this.optionTableId = String(status)
},
//######-----下拉选择器组件相关-----######
//打开下拉选择器
openCicker(input_name, linkage = true) {
this.picker_options = []
this.picker_input_name = input_name
let arr = this.picker_config[input_name]?.options || []
if (!arr.length) {
uni.showToast({ title: '暂无选项', icon: 'none' })
return
}
this.picker_options =arr
this.picker_linkage = linkage
// 使用 nextTick 确保数据更新后再打开 picker
this.$nextTick(() => {
this.picker_show = true
})
},
//监听-下拉选择器
changeCicker(e) {
console.log('监听-下拉选择器', this.picker_input_name, e,this.formData)
let input_name = this.picker_input_name
this.formData[input_name] = e.value
this.picker_config[input_name]['text'] = e.text
if(input_name == 'source'){
if(e.value != 1){
this.formData.source_channel = '0'//0=线下
}else{
this.formData.source_channel = ''//线下
}
}
// 清空转介绍资源选择,当来源改变时
if(input_name == 'source'){
this.clearReferralSelection()
}
this.cancelCicker()
},
//关闭下拉选择器
cancelCicker() {
this.picker_show = false
this.picker_input_name = ''
this.picker_options = []
},
// 转介绍资源搜索功能
async searchReferralResources() {
// 清除之前的定时器
if (this.referralSearchTimer) {
clearTimeout(this.referralSearchTimer)
}
// 如果搜索关键词为空,清空结果
if (!this.referralSearchQuery.trim()) {
this.referralSearchResults = []
return
}
// 设置防抖定时器
this.referralSearchTimer = setTimeout(async () => {
await this.doReferralSearch()
}, 300) // 300ms防抖
},
// 实际执行搜索的方法
async doReferralSearch() {
try {
// 搜索客户资源 - 优化参数处理
let param = {}
const searchQuery = this.referralSearchQuery.trim()
// 判断搜索内容是手机号还是姓名
if (/^1[3-9]\d{9}$/.test(searchQuery)) {
// 如果是手机号格式,只传递phone_number参数
param.phone_number = searchQuery
} else if (/^\d+$/.test(searchQuery)) {
// 如果是纯数字但不是手机号格式,也当作手机号搜索
param.phone_number = searchQuery
} else {
// 如果包含非数字字符,当作姓名搜索
param.name = searchQuery
}
let res = await apiRoute.xs_getAllCustomerResources(param)
if (res.code != 1) {
if (res.msg !== '暂无数据') {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
this.referralSearchResults = []
return
}
// 过滤掉当前正在添加的客户(如果手机号相同)
this.referralSearchResults = (res.data || []).filter(resource => {
return resource.phone_number !== this.formData.phone_number
})
// 如果没有搜索结果,给用户提示
if (this.referralSearchResults.length === 0 && searchQuery.length >= 2) {
// 静默处理,不显示"暂无数据"提示,让用户继续输入
console.log('未找到匹配的转介绍资源')
}
} catch (error) {
console.error('搜索转介绍资源失败:', error)
this.referralSearchResults = []
// 网络错误时给用户提示
if (this.referralSearchQuery.trim()) {
uni.showToast({
title: '搜索失败,请重试',
icon: 'none'
})
}
}
},
// 选择转介绍资源
selectReferralResource(resource) {
this.formData.referral_resource_id = resource.id
this.selectedReferralResource = resource
this.referralSearchQuery = ''
this.referralSearchResults = []
uni.showToast({
title: '已选择转介绍资源',
icon: 'success'
})
},
// 清空转介绍资源选择
clearReferralSelection() {
this.formData.referral_resource_id = ''
this.selectedReferralResource = null
this.referralSearchQuery = ''
this.referralSearchResults = []
},
//######-----时间选择器组件相关-----######
//打开日期选择器
openDate(input_name) {
console.log('打开日期选择器:', input_name)
this.data_picker_input_name = input_name
// 设置日期选择器显示
this.$nextTick(() => {
this.date_picker_show = true
})
},
//选择跟进时间
change_date(e) {
console.log('日期选择器返回数据:', e)
// 获取选择的日期值,兼容不同的返回格式
let val = ''
if (e.result) {
val = e.result
} else if (e.value) {
val = e.value
} else if (e.detail && e.detail.result) {
val = e.detail.result
} else if (e.detail && e.detail.value) {
val = e.detail.value
}
// 确保日期格式为 YYYY-MM-DD
if (val && typeof val === 'string') {
// 如果是时间戳,转换为日期字符串
if (/^\d+$/.test(val)) {
const date = new Date(parseInt(val))
val = this.formatDate(date)
}
// 如果包含时间部分,只保留日期部分
else if (val.includes(' ')) {
val = val.split(' ')[0]
}
// 统一格式为 YYYY-MM-DD
if (val.includes('/')) {
const parts = val.split('/')
if (parts.length === 3) {
val = `${parts[0]}-${parts[1].padStart(2, '0')}-${parts[2].padStart(2, '0')}`
}
}
}
let input_name = this.data_picker_input_name
this.formData[input_name] = val
console.log(`设置${input_name}为:`, val)
this.cancel_date()
},
//关闭选择跟进时间
cancel_date() {
this.date_picker_show = false
},
// 打开生日选择器
openBirthdayPicker() {
console.log('打开生日选择器')
this.picker_show_birthday = true
},
// 关闭生日选择器
closeBirthdayPicker() {
console.log('关闭生日选择器')
this.picker_show_birthday = false
},
// 获取生日选择器的当前值
getCurrentBirthdayValue() {
if (this.formData.birthday) {
return this.formData.birthday
}
// 默认返回30年前的日期作为初始值
const defaultDate = new Date()
defaultDate.setFullYear(defaultDate.getFullYear() - 30)
return this.formatDate(defaultDate)
},
//生日选择器
changePickerBirthday(e) {
console.log('生日选择器返回数据:', e)
let val = ''
// 尝试多种方式获取返回值
if (e.result) {
val = e.result
} else if (e.value) {
val = e.value
} else if (e.detail && e.detail.result) {
val = e.detail.result
} else if (e.detail && e.detail.value) {
val = e.detail.value
} else if (Array.isArray(e) && e.length >= 3) {
// 如果返回数组格式 [2023, 1, 15]
const year = e[0]
const month = String(e[1]).padStart(2, '0')
const day = String(e[2]).padStart(2, '0')
val = `${year}-${month}-${day}`
}
// 处理不同的日期格式
if (val && typeof val === 'string') {
// 如果是时间戳格式
if (/^\d+$/.test(val)) {
const date = new Date(parseInt(val))
val = this.formatDate(date)
}
// 如果包含时间部分,只保留日期部分
else if (val.includes('T')) {
val = val.split('T')[0]
}
// 如果包含空格,只保留日期部分
else if (val.includes(' ')) {
val = val.split(' ')[0]
}
// 统一日期格式
val = this.normalizeDate(val)
}
console.log('最终设置的生日值:', val)
this.formData.birthday = val
this.closeBirthdayPicker()
},
//下一步 index|0=添加客户,1六要素
async nextStep(index) {
this.optionTableId = String(index)
},
//表单验证
async validatorForm(data) {
//姓名
if(!data.name){
uni.showToast({
title: '学生姓名必填',
icon: 'none'
})
this.nextStep('0')
return false
}
//电话
if(!data.phone_number){
uni.showToast({
title: '电话必填',
icon: 'none'
})
this.nextStep('0')
return false
}
//校区必填
if(!data.campus){
uni.showToast({
title: '校区必填',
icon: 'none'
})
this.nextStep('0')
return false
}
//转介绍资源必填(当来源为转介绍时)
if(data.source == 3 && !data.referral_resource_id){
uni.showToast({
title: '请选择转介绍资源',
icon: 'none'
})
this.nextStep('0')
return false
}
return true
},
//提交
async submit() {
console.log('提交',this.formData)
let data = {...this.formData}
//表单验证
let validatorForm = await this.validatorForm(data)
console.log('验证结果',validatorForm)
if(!validatorForm){
return
}
//防止重复提交
if (!this.is_submit) {
return
}
this.is_submit = false
let res = await apiRoute.xs_addCustomerResources(data)
this.is_submit = true
if(res.code != 1){
uni.showToast({
title: res.msg,
icon: 'none'
})
return
}
uni.showToast({
title: res.msg,
icon: 'success'
})
//延迟1s执行
setTimeout(() => {
//跳转页面-线索列表
//关闭当前页跳转新页面
uni.redirectTo({
url: `/pages/market/clue/index`
})
}, 1000)
},
}
}
</script>
<style lang="less" scoped>
.search_box{
padding: 20rpx 40rpx;
border-bottom: 1px solid #333333;
display: flex;
justify-content: space-between;
align-items: center;
.input_box{
width: 70%;
input{
width: 100%;
height: 60rpx;
color: #fff;
font-size: 28rpx;
}
}
.btn{
font-size: 28rpx;
color: #24BA9F;
}
}
.assemble {
width: 100%;
height: 100vh;
background: #292929;
overflow: auto;
}
.title {
font-size: 26rpx;
color: #fff;
padding: 26rpx 0 26rpx 32rpx;
}
.input-title {
font-size: 26rpx;
color: #fff;
}
.form-style {
width: 100%;
// background: #434544;
}
.form-style-vid {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12rpx 0;
}
.input-style {
text-align: right !important;
}
.fui-btn__box {
margin: 50rpx auto 120rpx;
width: 92%;
}
//查重结构弹出层
.fui-scroll__wrap{
height: 60vh;
.title_box{
padding: 10rpx 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
.title{
font-size: 28rpx;
color: #101010;
}
}
.section_ul{
margin-bottom: 100rpx;
height: 98%;
.not_list{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.img{
width: 112rpx;
height: 112rpx;
}
.title{
padding: 0;
margin-top: 10rpx;
color: #101010;
font-size: 28rpx;
text-align: center;
}
}
.ul{
padding: 26rpx;
padding-bottom: 100rpx;
display: flex;
flex-direction: column;
.li{
margin-bottom: 26rpx;
padding: 26rpx;
display: flex;
justify-content: space-between;
gap: 10rpx;
border-radius: 18rpx;
background-color: rgba(67,69,68,1);
color: #fff;
font-size: 28rpx;
border: 0rpx solid rgba(121,121,121,1);
.left_box{
width: 80%;
display: flex;
flex-direction: column;
gap: 20rpx;
.box_1 {
display: flex;
align-items: center;
.img {
width: 48rpx;
height: 48rpx;
border-right: 50%;
}
.name{
margin-left: 20rpx;
}
.tag{
margin-left: 20rpx;
width: 84rpx;
height: 32rpx;
line-height: 28rpx;
border-radius: 0rpx 20rpx 20rpx 20rpx;
background-color: rgba(236,128,141,0.3);
color: rgba(240,90,90,1);
font-size: 20rpx;
text-align: center;
border: 0rpx solid rgba(121,121,121,1);
}
}
.box_2{
display: flex;
justify-content: space-between;
align-items: center;
.left{
display: flex;
align-items: flex-end;
.name{
font-size: 28rpx;
}
.call{
margin-left: 10rpx;
font-size: 24rpx;
color: #ba7b30;
}
}
}
.box_3{
display: flex;
gap: 30rpx;
.left{}
.right{
display: flex;
align-items: center;
gap: 10rpx;
.img{
width: 16rpx;
height: 16rpx;
border-right: 50%;
}
}
}
}
.right_box{
width: 25%;
display: flex;
justify-content: space-between;
align-items: center;
.img{
width: 70rpx;
height: 70rpx;
border-radius: 50%;
}
}
}
}
}
}
// 快速填写弹窗样式
.quick-fill-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 1500;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
}
.quick-fill-content {
background: #fff;
border-radius: 16rpx;
width: 100%;
max-width: 600rpx;
max-height: 80vh;
display: flex;
flex-direction: column;
}
.quick-fill-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
border-bottom: 1px solid #f0f0f0;
}
.quick-fill-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.quick-fill-close {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
.close-text {
font-size: 32rpx;
color: #999;
}
}
.duplicate-notice {
padding: 32rpx;
text-align: center;
border-bottom: 1px solid #eee;
margin-bottom: 20rpx;
text {
display: block;
margin-bottom: 20rpx;
}
}
.quick-fill-body {
padding: 32rpx;
flex: 1;
overflow-y: auto;
}
.quick-fill-tip {
margin-bottom: 24rpx;
font-size: 24rpx;
color: #666;
line-height: 1.5;
text:first-child {
display: block;
margin-bottom: 8rpx;
}
text:last-child {
display: block;
color: #29d3b4;
font-weight: 500;
}
}
.quick-fill-textarea {
width: 100%;
height: 300rpx;
border: 1px solid #ddd;
border-radius: 8rpx;
padding: 16rpx;
font-size: 28rpx;
line-height: 1.5;
background: #fafafa;
box-sizing: border-box;
}
.quick-fill-buttons {
display: flex;
gap: 20rpx;
padding: 32rpx;
border-top: 1px solid #f0f0f0;
}
.quick-fill-btn {
flex: 1;
height: 72rpx;
line-height: 72rpx;
text-align: center;
border-radius: 8rpx;
font-size: 28rpx;
font-weight: 600;
&.cancel-btn {
background: #f5f5f5;
color: #666;
border: 1px solid #ddd;
}
&.confirm-btn {
background: #29d3b4;
color: #fff;
}
}
// 转介绍资源选择相关样式
.referral-search-container {
position: relative;
.referral-search-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: #333;
border-radius: 8rpx;
border: 1px solid #555;
max-height: 400rpx;
overflow-y: auto;
z-index: 100;
margin-top: 8rpx;
.referral-search-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx;
border-bottom: 1px solid #555;
transition: background-color 0.2s;
&:last-child {
border-bottom: none;
}
&:hover, &.selected {
background: #434544;
}
.resource-info {
flex: 1;
.resource-name {
font-size: 28rpx;
color: #fff;
margin-bottom: 8rpx;
}
.resource-phone {
font-size: 24rpx;
color: #999;
}
}
.check-icon {
color: #29d3b4;
font-size: 32rpx;
font-weight: bold;
}
}
}
.selected-referral-resource {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx;
background: #4a4a4a;
border-radius: 8rpx;
margin-top: 8rpx;
.selected-resource-info {
flex: 1;
.selected-resource-name {
font-size: 28rpx;
color: #29d3b4;
margin-bottom: 8rpx;
}
.selected-resource-phone {
font-size: 24rpx;
color: #999;
}
}
.clear-selection {
color: #f44336;
font-size: 32rpx;
font-weight: bold;
padding: 8rpx;
cursor: pointer;
}
}
}
</style>