13 changed files with 1151 additions and 113 deletions
Unified View
Diff Options
-
2.env
-
21src/api/clue/index.ts
-
94src/api/essentialData/index.ts
-
4src/api/essentialData/model.ts
-
20src/components/Cropper/src/CropperAvatar.vue
-
26src/layouts/default/header/index.vue
-
1src/utils/http/axios/index.ts
-
363src/views/clue/clueList/data.ts
-
78src/views/clue/clueList/index.vue
-
76src/views/clue/clueList/modal.vue
-
11src/views/clue/cluePool/index.vue
-
350src/views/clue/customer/data.ts
-
218src/views/clue/customer/index.vue
@ -1,20 +1,17 @@ |
|||||
import { defHttp } from '/@/utils/http/axios' |
import { defHttp } from '/@/utils/http/axios' |
||||
import { PageResultModel } from '/@/api/model/baseModel' |
import { PageResultModel } from '/@/api/model/baseModel' |
||||
|
|
||||
export const getChatMessagePage = (params: any) => |
|
||||
|
export const getCluePage = (params: any) => |
||||
defHttp.get<PageResultModel<any>>({ |
defHttp.get<PageResultModel<any>>({ |
||||
url: '/dating-agency-cim/user/page/room-content-abstract/by/operator', |
|
||||
|
url: '/dating-clue-service/user/page/dating-clue-pool', |
||||
params, |
params, |
||||
}) |
}) |
||||
|
|
||||
export const getChatMessageRoomList = (params: any) => |
|
||||
defHttp.get<PageResultModel<any>>({ |
|
||||
url: '/dating-agency-cim/user/page/room', |
|
||||
params, |
|
||||
}) |
|
||||
|
export const createClueRecord = (params: any) => defHttp.post({ url: '/dating-clue-service/user/create/dating-clue', params }) |
||||
|
|
||||
|
export const editClueRecord = (params: any) => defHttp.post({ url: '/dating-clue-service/user/edit/dating-clue', params }) |
||||
|
|
||||
|
export const allocateCluing = (params: any) => defHttp.post({ url: '/dating-clue-service/user/batch-allocate/dating-clue', params }) |
||||
|
|
||||
|
export const getClueInfo = (id: string) => defHttp.get<any>({ url: '/dating-clue-service/user/get/dating-clue-detail', params: { id } }) |
||||
|
|
||||
export const getChatRoomMessageList = (params: any) => |
|
||||
defHttp.get<PageResultModel<any>>({ |
|
||||
url: '/dating-agency-cim/user/page/room-content-record/by/operator', |
|
||||
params, |
|
||||
}) |
|
||||
@ -0,0 +1,94 @@ |
|||||
|
import { defHttp } from '/@/utils/http/axios' |
||||
|
import { EssentialDataModel } from '/@/api/essentialData/model' |
||||
|
|
||||
|
enum Api { |
||||
|
GetIncomeList = '/dating-agency-service/user/get/income/list', |
||||
|
GetNationList = '/dating-agency-service/user/get/nation/list', |
||||
|
GetAccountType = '/dating-agency-service/user/get/account/type', |
||||
|
GetEducationList = '/dating-agency-service/user/get/education/list', |
||||
|
GetOccupationList = '/dating-agency-service/user/get/occupation/list', |
||||
|
GetBodilyFormList = '/dating-agency-service/user/get/bodily/form/list', |
||||
|
GetFamilyTiesList = '/dating-agency-service/user/get/family/ties/list', |
||||
|
GetPropertyPermits = '/dating-agency-service/user/get/property/permits', |
||||
|
GetNationalityList = '/dating-agency-service/user/get/nationality/list', |
||||
|
GetIdentityTypeList = '/dating-agency-service/user/get/identity/type/list', |
||||
|
GetConstellationList = '/dating-agency-service/user/get/constellation/list', |
||||
|
GetMaritalStatusList = '/dating-agency-service/user/get/marital/status/list', |
||||
|
GetCarPurchaseSituation = '/dating-agency-service/user/get/car/purchase/situation', |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取学历列表数据 |
||||
|
*/ |
||||
|
export const getEducationList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetEducationList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取户口类型列表数据 |
||||
|
*/ |
||||
|
export const getAccountTypeList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetAccountType }) |
||||
|
|
||||
|
/** |
||||
|
* 获取婚姻状态列表数据 |
||||
|
*/ |
||||
|
export const getMaritalStatusList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetMaritalStatusList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取星座列表数据 |
||||
|
*/ |
||||
|
export const getConstellationList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetConstellationList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取体型列表数据 |
||||
|
*/ |
||||
|
export const getBodilyFormList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetBodilyFormList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取购车情况列表数据 |
||||
|
*/ |
||||
|
export const getCarPurchaseSituation = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetCarPurchaseSituation }) |
||||
|
|
||||
|
/** |
||||
|
* 获取家庭关系列表数据 |
||||
|
*/ |
||||
|
export const getFamilyTiesList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetFamilyTiesList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取收入列表表数据 |
||||
|
*/ |
||||
|
export const getIncomeList = () => defHttp.get<EssentialDataModel[]>({ url: Api.GetIncomeList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取民族列表数据 |
||||
|
*/ |
||||
|
export const getNationList = () => defHttp.get<EssentialDataModel[]>({ url: Api.GetNationList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取国籍数据 |
||||
|
*/ |
||||
|
export const getNationalityList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetNationalityList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取身份类型列表数据 |
||||
|
*/ |
||||
|
export const getIdentityTypeList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetIdentityTypeList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取职业列表数据 |
||||
|
*/ |
||||
|
export const getOccupationList = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetOccupationList }) |
||||
|
|
||||
|
/** |
||||
|
* 获取房产情况列表数据 |
||||
|
*/ |
||||
|
export const getPropertyPermits = () => |
||||
|
defHttp.get<EssentialDataModel[]>({ url: Api.GetPropertyPermits }) |
||||
@ -0,0 +1,4 @@ |
|||||
|
export interface EssentialDataModel { |
||||
|
desc: string |
||||
|
value: number |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal"> |
||||
|
<BasicForm @register="registerForm" style="padding: 16px 48px 0px 0px;"> |
||||
|
<template #profilePhoto="{ model, field }"> |
||||
|
<CropperAvatar :value="model[field]" @change="uploadAvatarAfter"/> |
||||
|
</template> |
||||
|
</BasicForm> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref, unref } from 'vue' |
||||
|
import { modalFormSchema, basicInfoData } from './data' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { BasicForm, useForm } from '/@/components/Form' |
||||
|
import { BasicModal, useModalInner } from '/@/components/Modal' |
||||
|
import { CropperAvatar } from '/@/components/Cropper'; |
||||
|
import { createClueRecord, editClueRecord } from '/@/api/clue' |
||||
|
|
||||
|
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue, updateSchema }] = |
||||
|
useForm({ |
||||
|
labelWidth: 120, |
||||
|
schemas: modalFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const ifUpdate = ref<boolean>(false) |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
await resetFields() |
||||
|
ifUpdate.value = !!data.ifUpdate |
||||
|
setModalProps({ |
||||
|
minHeight: 50, |
||||
|
confirmLoading: false, |
||||
|
title: ifUpdate.value ? '编辑' : '新增线索', |
||||
|
}) |
||||
|
await updateSchema({ |
||||
|
field: 'franchiseFee', |
||||
|
componentProps: { |
||||
|
disabled: ifUpdate.value, |
||||
|
}, |
||||
|
}) |
||||
|
if (unref(ifUpdate)) { |
||||
|
await setFieldsValue({ |
||||
|
...data.record, |
||||
|
}) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
function uploadAvatarAfter(value) { |
||||
|
//修改表单的值 |
||||
|
setFieldsValue({ |
||||
|
profilePhoto: value, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
await validate() |
||||
|
const values: any = getFieldsValue() |
||||
|
console.log({...values, ...basicInfoData.value}) |
||||
|
|
||||
|
setModalProps({ confirmLoading: true }) |
||||
|
const fun = unref(ifUpdate) ? editClueRecord : createClueRecord |
||||
|
await fun({...values, ...basicInfoData.value}) |
||||
|
createMessage.success(`${unref(ifUpdate) ? '编辑' : '新增'}成功!`) |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"></style> |
||||
@ -1,26 +1,340 @@ |
|||||
import { BasicColumn, FormSchema } from '/@/components/Table' |
|
||||
const userTypeList = [ |
|
||||
{ label: '正常用户', value: 1 }, |
|
||||
{ label: '录入用户', value: 2}, |
|
||||
{ label: '红娘', value: 3 }, |
|
||||
] |
|
||||
|
import { useAddressData } from '/@/hooks/common' |
||||
|
import { ref } from 'vue' |
||||
|
import dayjs, { Dayjs } from 'dayjs' |
||||
|
import { FormSchema } from '/@/components/Form' |
||||
|
import { genderList } from '/@/enums/customerEnum' |
||||
|
import { |
||||
|
getIncomeList, |
||||
|
getNationList, |
||||
|
getEducationList, |
||||
|
getFamilyTiesList, |
||||
|
getOccupationList, |
||||
|
getBodilyFormList, |
||||
|
getPropertyPermits, |
||||
|
getAccountTypeList, |
||||
|
getIdentityTypeList, |
||||
|
getMaritalStatusList, |
||||
|
getConstellationList, |
||||
|
getCarPurchaseSituation, |
||||
|
} from '/@/api/essentialData' |
||||
|
|
||||
|
// 基础信息的额外数据
|
||||
|
export const basicInfoMoreData = ref<any>({}) |
||||
|
// 获取地区数据
|
||||
|
const { addressList, domicilePlaceList } = useAddressData() |
||||
|
|
||||
|
// 获取职业列表
|
||||
|
export const occupationList = ref<any>([]) |
||||
|
getOccupationList().then((res) => { |
||||
|
handleOccupationList(res) |
||||
|
occupationList.value = res || [] |
||||
|
}) |
||||
|
function handleOccupationList(data: any, ifFirst = true) { |
||||
|
data?.forEach?.((item: any) => { |
||||
|
const { industry, industryCode, occupation, occupationCode, occupationList } = item |
||||
|
item.label = ifFirst ? industry : occupation |
||||
|
item.value = ifFirst ? industryCode : occupationCode |
||||
|
if (occupationList?.length) { |
||||
|
item.children = occupationList |
||||
|
handleOccupationList(occupationList, false) |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
export const tableColumns: BasicColumn[] = [ |
|
||||
{ title: '用户昵称', dataIndex: 'nickName' }, |
|
||||
{ title: '用户身份', dataIndex: 'userMarriageInformationType', |
|
||||
customRender: ({ text }) => { |
|
||||
return userTypeList.find((find) => find.value === text)?.label |
|
||||
|
// 基本信息
|
||||
|
export const basicSchema: FormSchema[] = [ |
||||
|
{ field: 'nickName', label: '昵称', component: 'Input' }, |
||||
|
{ |
||||
|
field: 'address', |
||||
|
label: '居住地', |
||||
|
component: 'Cascader', |
||||
|
componentProps: { |
||||
|
options: addressList, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.provinceName = v?.[0]?.label |
||||
|
basicInfoMoreData.value.cityName = v?.[1]?.label |
||||
|
basicInfoMoreData.value.districtName = v?.[2]?.label |
||||
|
}, |
||||
}, |
}, |
||||
}, |
}, |
||||
// { title: '客户手机号', dataIndex: 'userPhone' },
|
|
||||
{ title: '最新消息时间', dataIndex: 'contentTime' }, |
|
||||
|
{ |
||||
|
field: 'domicilePlace', |
||||
|
label: '户口所在地', |
||||
|
component: 'Cascader', |
||||
|
componentProps: () => { |
||||
|
return { |
||||
|
options: domicilePlaceList.value, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.domicilePlaceProvinceName = v?.[0]?.label |
||||
|
basicInfoMoreData.value.domicilePlaceCityName = v?.[1]?.label |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'genderCode', |
||||
|
label: '性别', |
||||
|
component: 'Select', |
||||
|
componentProps: ({ formModel }) => { |
||||
|
return { |
||||
|
options: genderList, |
||||
|
disabled: !!formModel.name && formModel.name !== -1, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.genderValue = v?.label |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'birthDate', |
||||
|
label: '出生日期', |
||||
|
component: 'DatePicker', |
||||
|
componentProps: ({ formModel }) => { |
||||
|
return { |
||||
|
style: { width: '100%' }, |
||||
|
disabled: !!formModel.name && formModel.name !== -1, |
||||
|
disabledDate: (current: Dayjs) => { |
||||
|
const date: Dayjs = dayjs().subtract(18, 'year') |
||||
|
return current && current > date.endOf('year') |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'height', label: '身高', component: 'InputNumber' }, |
||||
|
{ |
||||
|
field: 'educationCode', |
||||
|
label: '学历', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getEducationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.education = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'incomeCode', |
||||
|
label: '月收入', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getIncomeList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.income = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'name', label: '姓名', component: 'Input', componentProps: { disabled: true } }, |
||||
|
{ |
||||
|
field: 'hometown', |
||||
|
label: '家乡', |
||||
|
component: 'Cascader', |
||||
|
componentProps: () => { |
||||
|
return { |
||||
|
options: domicilePlaceList.value, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.hometownProvinceName = v?.[0]?.label |
||||
|
basicInfoMoreData.value.hometownCityName = v?.[1]?.label |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'identityType', |
||||
|
label: '身份', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getIdentityTypeList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.identityTypeName = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maritalStatusCode', |
||||
|
label: '婚姻状况', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getMaritalStatusList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.maritalStatusName = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'nationCode', |
||||
|
label: '民族', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'cn', |
||||
|
valueField: 'id', |
||||
|
api: getNationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.nation = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'bodilyFormCode', |
||||
|
label: '体型', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getBodilyFormList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.bodilyForm = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'accountTypeCode', |
||||
|
label: '户口', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getAccountTypeList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.accountTypeName = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'nativePlaceCode', |
||||
|
label: '籍贯', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: domicilePlaceList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.nativePlaceName = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '职业', |
||||
|
field: 'occupationList', |
||||
|
component: 'Cascader', |
||||
|
componentProps: { |
||||
|
options: occupationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
const industry = v?.[0] || {} |
||||
|
const occupation = v?.[1] || {} |
||||
|
basicInfoMoreData.value.industry = industry.label |
||||
|
basicInfoMoreData.value.industryCode = industry.value |
||||
|
basicInfoMoreData.value.occupation = occupation.label |
||||
|
basicInfoMoreData.value.occupationCode = occupation.value |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'onlyChild', |
||||
|
label: '是否独生子女', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '是', value: 1 }, |
||||
|
{ label: '否', value: 0 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'propertyPermitsCode', |
||||
|
label: '购房情况', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getPropertyPermits, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.propertyPermits = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'carPurchaseSituationCode', |
||||
|
label: '购车情况', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getCarPurchaseSituation, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.carPurchaseSituation = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'constellationCode', |
||||
|
label: '星座', |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getConstellationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoMoreData.value.constellation = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'describeInfo', |
||||
|
label: '个人描述', |
||||
|
component: 'InputTextArea', |
||||
|
colProps: { span: 24 }, |
||||
|
componentProps: ({ formModel }) => { |
||||
|
return { |
||||
|
autoSize: { |
||||
|
minRows: 4, |
||||
|
}, |
||||
|
disabled: formModel?.describeAudit, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'empty1', label: '', slot: 'empty1', component: 'Input' }, |
||||
] |
] |
||||
|
basicSchema.forEach((schema) => { |
||||
|
!['photoList', 'name', 'avatar', 'empty1'].includes(schema.field) && (schema.required = true) |
||||
|
!schema.colProps && (schema.colProps = { span: 8 }) |
||||
|
}) |
||||
|
|
||||
export const tableFormSchema: FormSchema[] = [ |
|
||||
|
export const modalFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'onlyChild', |
||||
|
label: '跟进方式', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '是', value: 1 }, |
||||
|
{ label: '否', value: 0 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
{ |
{ |
||||
field: 'nickName', |
|
||||
label: '用户昵称', |
|
||||
|
required: true, |
||||
|
field: 'storeName', |
||||
|
label: '门店名称', |
||||
component: 'Input', |
component: 'Input', |
||||
colProps: { span: 8}, |
|
||||
}, |
}, |
||||
] |
|
||||
|
{ |
||||
|
field: 'remark', |
||||
|
label: '备注', |
||||
|
required: false, |
||||
|
component: 'InputTextArea', |
||||
|
componentProps: { |
||||
|
autosize: { |
||||
|
minRows: 3, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
@ -1,56 +1,184 @@ |
|||||
<template> |
<template> |
||||
<Card :borderd="false"> |
|
||||
|
|
||||
</Card> |
|
||||
|
<div class="flex-col" style="height:100%;padding: 16px;"> |
||||
|
<div class="flex-row" style="background: white;width: 100%;padding: 10px;"> |
||||
|
<CropperAvatar :value="avatar" width="90px" @change="uploadAvatarAfter"/> |
||||
|
<div class="flex-col" style="flex: 1;margin-left: 10px;"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<span style="font-size: 18px;font-weight: bold;">用户昵称</span> |
||||
|
<!-- <Icon icon="ant-design:edit-twotone" size="18px" style="margin-left: 12px;color:#0960bd;"/> --> |
||||
|
<Button type="link"><template #icon><Icon icon="ant-design:edit-twotone" size="16px" style="margin-left: 12px;color:#0960bd;"/></template></Button> |
||||
|
<span style="color: #666;margin: 0 12px;">(ID:23762736 | 渠道来源:抖音)</span> |
||||
|
<Tag color="#d5d5d5">#线索阶段-0呼</Tag> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="margin-top: 8px;"> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">电话:</span> |
||||
|
<span style="color: #333;font-weight: bold;">18565126880</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">微信:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">客户标签:</span> |
||||
|
<Tag color="#f50">无效</Tag> |
||||
|
<Button style="height: 22px;line-height: 22px;width: 24px;border: 1px solid #0960bd;"><template #icon><Icon icon="ant-design:plus-outlined" size="14px" style="color:#0960bd;display: block;"/></template></Button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="margin-top: 8px;"> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">下次跟进时间:</span> |
||||
|
<span style="color: #333;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">跟进人:</span> |
||||
|
<span style="color: #333;">彭杰</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-end" style="flex:1;padding-right: 32px;"> |
||||
|
<Button size="small" type="primary">查看下一个客户</Button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex-col" style="background: white;width: 100%;margin-top: 16px;padding: 12px 40px 12px 40px;"> |
||||
|
<div class="flex-row-center-space"> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex-row-center-space" style="margin-top: 8px;"> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--</span> |
||||
|
</div> |
||||
|
<div class="flex-row-center-start" style="width: 240px;"> |
||||
|
<span style="color: #666;">签约红娘:</span> |
||||
|
<span style="color: #333;font-weight: bold;">--dddd</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex-row" style="width: 100%;flex: 1;margin-top: 16px;"> |
||||
|
<div style="flex: 1;background: white;padding: 0px 10px 10px 10px;"> |
||||
|
<Tabs v-model:activeKey="activeKey" :animated="false"> |
||||
|
<TabPane key="1" tab="客户资料"> |
||||
|
<div class="flex-col" style="padding-right: 48px; flex:1;padding-top: 16px;"> |
||||
|
<BasicForm @register="registerForm1"></BasicForm> |
||||
|
</div> |
||||
|
</TabPane> |
||||
|
<TabPane key="2" tab="邀约进店"> |
||||
|
<Spin :spinning="spinning"> |
||||
|
<Result subTitle="暂无数据"></Result> |
||||
|
</Spin> |
||||
|
</TabPane> |
||||
|
<TabPane key="3" tab="合同"> |
||||
|
<Result subTitle="暂无数据"></Result> |
||||
|
</TabPane> |
||||
|
<TabPane key="4" tab="约见记录"> |
||||
|
<Result subTitle="暂无数据"></Result> |
||||
|
</TabPane> |
||||
|
<template v-if="activeKey == '1'" #tabBarExtraContent> |
||||
|
<Button type="link"><template #icon><Icon icon="ant-design:edit-twotone" size="16px" style="margin-right: -4px;"/></template>编辑资料</Button> |
||||
|
</template> |
||||
|
</Tabs> |
||||
|
</div> |
||||
|
<div style="width: 480px;background: white;margin-left: 16px;padding: 0px 10px 10px 10px;"> |
||||
|
<Tabs v-model:activeKey="activeKey2" :animated="false"> |
||||
|
<TabPane key="1" tab="跟进小计"> |
||||
|
<div class="flex-col-center-center" style="flex:1;padding-top: 16px;"> |
||||
|
<BasicForm @register="registerForm"></BasicForm> |
||||
|
<Button type="primary" style="width: 160px;margin-top: 48px;">保存</Button> |
||||
|
</div> |
||||
|
</TabPane> |
||||
|
<TabPane key="2" tab="跟进记录" style="flex:1;padding: 16px 16px 0px 16px;"> |
||||
|
<Timeline> |
||||
|
<TimelineItem color="green">Create a services site 2015-09-01</TimelineItem> |
||||
|
<TimelineItem color="red"> |
||||
|
<p>Solve initial network problems 1</p> |
||||
|
<p>Solve initial network problems 2</p> |
||||
|
<p>Solve initial network problems 3 2015-09-01</p> |
||||
|
</TimelineItem> |
||||
|
<TimelineItem> |
||||
|
<p>Technical testing 1</p> |
||||
|
<p>Technical testing 3 2015-09-01</p> |
||||
|
</TimelineItem> |
||||
|
<TimelineItem color="gray"> |
||||
|
<p>Technical testing 1</p> |
||||
|
<p>Technical testing 2</p> |
||||
|
<p>Technical testing 3 2015-09-01</p> |
||||
|
</TimelineItem> |
||||
|
<TimelineItem color="gray"> |
||||
|
<p>Technical testing 1</p> |
||||
|
<p>Technical testing 3 2015-09-01</p> |
||||
|
</TimelineItem> |
||||
|
</Timeline> |
||||
|
</TabPane> |
||||
|
</Tabs> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
</template> |
</template> |
||||
|
|
||||
|
|
||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import moment from 'moment/moment' |
|
||||
import { computed, ref } from 'vue' |
|
||||
import { Card } from 'ant-design-vue' |
|
||||
import { useRouter } from 'vue-router' |
|
||||
import { tableColumns, tableFormSchema } from './data' |
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table' |
|
||||
import { getChatMessagePage } from '/@/api/clue' |
|
||||
|
import { onActivated, ref } from 'vue' |
||||
|
// import { Spin, Result } from 'ant-design-vue' |
||||
|
import { Tabs, Card, Table, Button, TabPane, Tag, Timeline, TimelineItem, Result, Spin } from 'ant-design-vue' |
||||
|
import { Icon } from '/@/components/Icon' |
||||
|
import { CropperAvatar } from '/@/components/Cropper'; |
||||
|
import BasicForm from '/@/components/Form/src/BasicForm.vue' |
||||
|
import { useForm } from '/@/components/Form' |
||||
|
import { basicSchema, modalFormSchema } from './data' |
||||
|
import { getClueInfo } from '/@/api/clue' |
||||
|
|
||||
|
const activeKey = ref<string>('1') |
||||
|
const activeKey2 = ref<string>('1') |
||||
|
const avatar = ref<string>('') |
||||
|
|
||||
const [registerTable] = useTable({ |
|
||||
bordered: true, |
|
||||
useSearchForm: true, |
|
||||
columns: tableColumns, |
|
||||
showIndexColumn: true, |
|
||||
showTableSetting: false, |
|
||||
api: getChatMessagePage, |
|
||||
formConfig: { |
|
||||
labelWidth: 120, |
|
||||
schemas: tableFormSchema, |
|
||||
}, |
|
||||
// beforeFetch: (arg) => { |
|
||||
// const { orderTime } = arg |
|
||||
// if (orderTime) { |
|
||||
// arg.orderTimeFrom = moment(orderTime[0]).format('YYYY-MM-DD 00:00:00') |
|
||||
// arg.orderTimeTo = moment(orderTime[1]).format('YYYY-MM-DD 23:59:59') |
|
||||
// delete arg.orderTime |
|
||||
// } |
|
||||
// }, |
|
||||
actionColumn: { |
|
||||
width: 160, |
|
||||
title: '操作', |
|
||||
fixed: 'right', |
|
||||
dataIndex: 'action', |
|
||||
slots: { customRender: 'action' }, |
|
||||
}, |
|
||||
|
// 基础信息表单配置 |
||||
|
const [registerForm1, { validate: validate1, setFieldsValue: setFieldsValue1 }] = useForm({ |
||||
|
labelWidth: 120, |
||||
|
schemas: basicSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
}) |
}) |
||||
|
|
||||
|
|
||||
const router = useRouter() |
|
||||
function toDetail(record: any) { |
|
||||
const { miId, userMarriageInformationType } = record |
|
||||
router.push({ |
|
||||
query: { miId, type: userMarriageInformationType }, |
|
||||
path: '/message/chatInfo', |
|
||||
}) |
|
||||
|
//这里是上传头像成功后的回调 |
||||
|
function uploadAvatarAfter(value) { |
||||
|
//修改表单的值 |
||||
|
// setFieldsValue1({ |
||||
|
// avatar: value, |
||||
|
// }); |
||||
} |
} |
||||
|
|
||||
|
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue, updateSchema }] = |
||||
|
useForm({ |
||||
|
labelWidth: 90, |
||||
|
schemas: modalFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const spinning = ref<boolean>(false) |
||||
</script> |
</script> |
||||
<style scoped lang="less"> |
<style scoped lang="less"> |
||||
|
|
||||
|
|||||
Write
Preview
Loading…
Cancel
Save