20 changed files with 1774 additions and 10 deletions
Unified View
Diff Options
-
50src/api/clue/index.ts
-
22src/enums/customerEnum.ts
-
5src/locales/lang/zh-CN/routes/invite.ts
-
26src/router/menu.ts
-
2src/views/clue/customer/modal.vue
-
2src/views/invite/myList/data.ts
-
17src/views/invite/myList/index.vue
-
77src/views/market/appointment/data.ts
-
163src/views/market/appointment/index.vue
-
68src/views/market/appointment/modal.vue
-
90src/views/market/client/contract.vue
-
376src/views/market/client/data.ts
-
171src/views/market/client/index.vue
-
203src/views/market/client/modal.vue
-
74src/views/market/components/data.ts
-
95src/views/market/components/modal.vue
-
5src/views/market/contract/index.vue
-
78src/views/market/task/data.ts
-
171src/views/market/task/index.vue
-
89src/views/market/task/modal.vue
@ -0,0 +1,77 @@ |
|||||
|
import { BasicColumn, FormSchema } from '/@/components/Table' |
||||
|
import { genderList, incomeList, maritalList, appointmentStatusList } from '/@/enums/customerEnum' |
||||
|
|
||||
|
export const tableColumns: BasicColumn[] = [ |
||||
|
{ width: 120, title: '用户名称', dataIndex: 'nickName' }, |
||||
|
{ width: 90, title: '用户性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} }, |
||||
|
{ width: 120, title: '手机号码', dataIndex: 'phone' }, |
||||
|
{ width: 80, title: '年龄', dataIndex: 'age' }, |
||||
|
{ width: 90, title: '婚姻状态', dataIndex: 'maritalStatusCode', |
||||
|
customRender: ({ text }) => { |
||||
|
return maritalList.find((find) => find.value === text)?.label |
||||
|
}, |
||||
|
}, |
||||
|
{ width: 120, title: '月收入', dataIndex: 'incomeCode', |
||||
|
customRender: ({ text }) => { |
||||
|
return incomeList.find((find) => find.value === text)?.label |
||||
|
}, |
||||
|
}, |
||||
|
{ width: 120, title: '面谈销售', dataIndex: 'salesConsultantName' }, |
||||
|
{ width: 160, title: '预约时间', dataIndex: 'appointmentTime' }, |
||||
|
{ title: '跟进进度', dataIndex: 'datingStoreAppointmentStatus', slots: { customRender: 'datingStoreAppointmentStatus' } }, |
||||
|
] |
||||
|
|
||||
|
export const tableFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'phone', |
||||
|
label: ' 用户电话号码', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'salesConsultantName', |
||||
|
label: '面谈销售', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'createTime', |
||||
|
label: '预约时间', |
||||
|
component: 'RangePicker', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
export const appointmentFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
label: '跟进阶段', |
||||
|
component: 'Select', |
||||
|
field: 'datingStoreAppointmentFollowStage', |
||||
|
required: true, |
||||
|
componentProps: { |
||||
|
options: appointmentStatusList, |
||||
|
style: { width: '100%' }, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '约见时间', |
||||
|
component: 'DatePicker', |
||||
|
field: 'appointmentTime', |
||||
|
required: true, |
||||
|
componentProps: { |
||||
|
showTime: true, |
||||
|
style: { width: '100%' }, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'remark', |
||||
|
label: '备注', |
||||
|
required: false, |
||||
|
component: 'InputTextArea', |
||||
|
componentProps: { |
||||
|
autosize: { |
||||
|
minRows: 4, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
@ -0,0 +1,163 @@ |
|||||
|
<template> |
||||
|
<div class="order-list"> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<div style="width: 100%; padding: 2px" class="flex-row-center-space"> |
||||
|
<RadioGroup button-style="solid" v-model:value="radioVal" @change="handleRadioChange"> |
||||
|
<RadioButton v-for="item in followStatusList" :key="item.value" :value="item.value">{{item.label}}</RadioButton> |
||||
|
</RadioGroup> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #datingStoreAppointmentStatus="{ text, record }"> |
||||
|
<Tag :color="appointmentStatusList.find((find) => find.value === text)?.color">{{appointmentStatusList.find((find) => find.value === text)?.label}}</Tag> |
||||
|
</template> |
||||
|
<template #action="{ record }"> |
||||
|
<div class="flex-row-center-start" v-if="record.datingStoreAppointmentStatus != 5"> |
||||
|
<Popconfirm placement="topRight" :icon="'分配'" @confirm="allocateList(record.id)"> |
||||
|
<template #title> |
||||
|
<div class="flex-row-center-start" style="padding: 8px 8px 8px 0px;border-bottom: 1px solid #ddd;" v-for="item in memberList" :key="item.userId"> |
||||
|
<Checkbox :checked="verifier == item.userId" @change="e => onCheckChange(e, item)"> |
||||
|
<span style="color: #333;font-weight: bold;margin-left: 4px;">{{item.realName}}</span> |
||||
|
<span style="color: #666;margin-left: 4px;">({{item.phone}})</span> |
||||
|
</Checkbox> |
||||
|
</div> |
||||
|
</template> |
||||
|
<Button style="width: 88px;margin-right: 12px;" type="primary" danger>分配销售</Button> |
||||
|
</Popconfirm> |
||||
|
<Button style="width: 72px;margin-right: 12px;" @click="handleAppointment(record)">约见</Button> |
||||
|
<Button style="width: 72px;margin-right: 12px;" danger @click="handleReport(record)">跟进</Button> |
||||
|
<Button type="primary" style="width: 88px;margin-right: 4px;" @click="handleSign(record)">签约登记</Button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<SignModal @register="signModal" @success="handleSuccess" /> |
||||
|
<AppointmentModal @register="appointmentModal" @success="handleSuccess" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { Radio } from 'ant-design-vue' |
||||
|
|
||||
|
export default { |
||||
|
name: 'MyList', |
||||
|
components: { RadioGroup: Radio.Group, RadioButton: Radio.Button }, |
||||
|
} |
||||
|
</script> |
||||
|
<script setup lang="ts"> |
||||
|
import moment from 'moment/moment' |
||||
|
import { computed, ref, onMounted } from 'vue' |
||||
|
import { Avatar, Card, Button, Popconfirm, Result, Tag, Checkbox } from 'ant-design-vue' |
||||
|
import { useRouter } from 'vue-router' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { tableColumns, tableFormSchema } from './data' |
||||
|
import { BasicTable, useTable, TableAction } from '/@/components/Table' |
||||
|
import { useModal } from '/@/components/Modal' |
||||
|
import FollowModal from '../components/modal.vue' |
||||
|
import AppointmentModal from './modal.vue' |
||||
|
import SignModal from '/@/views/market/components/modal.vue' |
||||
|
import { getStoreAppointmentList, allocationSaler } from '/@/api/clue' |
||||
|
import { appointmentStatusList } from '/@/enums/customerEnum' |
||||
|
import { pageOrganizationMember } from '/@/api/staff/staff' |
||||
|
|
||||
|
const memberList = ref<any[]>([]); |
||||
|
const verifier = ref<any>('') |
||||
|
onMounted(async () => { |
||||
|
const result = await pageOrganizationMember({}) |
||||
|
memberList.value = result.items |
||||
|
}) |
||||
|
|
||||
|
const [registerTable, { reload, setPagination }] = useTable({ |
||||
|
bordered: false, |
||||
|
useSearchForm: true, |
||||
|
columns: tableColumns, |
||||
|
showIndexColumn: false, |
||||
|
showTableSetting: false, |
||||
|
api: getStoreAppointmentList, |
||||
|
formConfig: { |
||||
|
labelWidth: 120, |
||||
|
schemas: tableFormSchema, |
||||
|
}, |
||||
|
beforeFetch: (arg) => { |
||||
|
const { createTime } = arg |
||||
|
if (createTime) { |
||||
|
arg.appointmentTimeFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00') |
||||
|
arg.appointmentTimeTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59') |
||||
|
delete arg.createTime |
||||
|
} |
||||
|
arg.datingStoreAppointmentStatus = radioVal.value |
||||
|
}, |
||||
|
actionColumn: { |
||||
|
width: 360, |
||||
|
title: '操作', |
||||
|
fixed: 'right', |
||||
|
dataIndex: 'action', |
||||
|
slots: { customRender: 'action' }, |
||||
|
}, |
||||
|
}) |
||||
|
const followStatusList = [ |
||||
|
{ label: '待到店', value: 1 }, |
||||
|
{ label: '已到店', value: 2 }, |
||||
|
{ label: '未到店', value: 3 }, |
||||
|
{ label: '全部', value: '' }, |
||||
|
] |
||||
|
const radioVal = ref<any>('') |
||||
|
function handleRadioChange() { |
||||
|
setPagination({ current: 1 }) |
||||
|
reload() |
||||
|
} |
||||
|
|
||||
|
function onCheckChange(e, item){ |
||||
|
if(e.target.checked){ |
||||
|
verifier.value = item.userId |
||||
|
} |
||||
|
} |
||||
|
const { createMessage } = useMessage() |
||||
|
async function allocateList(id = null){ |
||||
|
if(!verifier.value){ |
||||
|
createMessage.warning('请选择分配人') |
||||
|
return |
||||
|
} |
||||
|
try { |
||||
|
await allocationSaler({salesConsultant: verifier.value, id}) |
||||
|
createMessage.success(`分配成功`) |
||||
|
} finally { |
||||
|
reload() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const router = useRouter() |
||||
|
function toDetail(record: any) { |
||||
|
const { id } = record |
||||
|
router.push({ |
||||
|
query: { id }, |
||||
|
path: '/clue/customer', |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 上传modal |
||||
|
const [appointmentModal, { openModal: openAppointmentModal, closeModal: closeAppointmentModal }] = useModal() |
||||
|
const [signModal, { openModal: openSignModal, closeModal: closeSignModal }] = useModal() |
||||
|
|
||||
|
function handleReport(record: any) { |
||||
|
openAppointmentModal(true, {record, ifUpdate: true}) |
||||
|
} |
||||
|
function handleAppointment(record: any) { |
||||
|
openAppointmentModal(true, {record}) |
||||
|
} |
||||
|
function handleSign(record: any) { |
||||
|
openSignModal(true, {record}) |
||||
|
} |
||||
|
// 操作成功 |
||||
|
function handleSuccess() { |
||||
|
closeAppointmentModal() |
||||
|
closeSignModal() |
||||
|
reload() |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="less"> |
||||
|
.single-line { |
||||
|
overflow: hidden; /* 超出部分隐藏 */ |
||||
|
white-space: nowrap; /* 文本不换行 */ |
||||
|
text-overflow: ellipsis; /* 超出部分显示省略号 */ |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,68 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" @ok="handleOk" @register="registerModal"> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue' |
||||
|
import { appointmentFormSchema } from './data' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { BasicForm, useForm } from '/@/components/Form' |
||||
|
import { BasicModal, useModalInner } from '/@/components/Modal' |
||||
|
import { appointmentCustomer, remarkCustomer } from '/@/api/clue' |
||||
|
import { formatToDateTime } from '/@/utils/dateUtil' |
||||
|
|
||||
|
const [registerForm, { resetFields, updateSchema, validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: appointmentFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const id = ref<string>('') |
||||
|
const ifUpdate = ref<boolean>(false) |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
const { record } = data |
||||
|
await resetFields() |
||||
|
id.value = record?.id |
||||
|
ifUpdate.value = !!data.ifUpdate |
||||
|
setModalProps({ |
||||
|
minHeight: 50, |
||||
|
title: ifUpdate.value ? `预约跟进` : '预约客户', |
||||
|
confirmLoading: false, |
||||
|
}) |
||||
|
if (!!ifUpdate.value) { |
||||
|
await updateSchema({ field: 'datingStoreAppointmentFollowStage', ifShow: true }) |
||||
|
await updateSchema({ field: 'remark', ifShow: true }) |
||||
|
await updateSchema({ field: 'appointmentTime', ifShow: false }) |
||||
|
} else { |
||||
|
await updateSchema({ field: 'datingStoreAppointmentFollowStage', ifShow: false }) |
||||
|
await updateSchema({ field: 'remark', ifShow: false }) |
||||
|
await updateSchema({ field: 'appointmentTime', ifShow: true }) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
const values = await validate() |
||||
|
setModalProps({ confirmLoading: true }) |
||||
|
if (!!ifUpdate.value) { |
||||
|
values.datingStoreAppointmentId = id.value |
||||
|
await remarkCustomer(values) |
||||
|
createMessage.success(`跟进成功!`) |
||||
|
} else { |
||||
|
values.id = id.value |
||||
|
const { appointmentTime } = values |
||||
|
values.appointmentTime = formatToDateTime(appointmentTime) |
||||
|
await appointmentCustomer(values) |
||||
|
createMessage.success(`预约成功!`) |
||||
|
} |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
@ -0,0 +1,90 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" @ok="handleOk" @register="registerModal"> |
||||
|
<div class="flex-col" v-if="detail"> |
||||
|
<div class="flex-col" style="font-size: 14px;color: #333;padding-left: 12px;" v-if="detail"> |
||||
|
<span>合同编号:{{detail.id}}</span> |
||||
|
<span style="margin-top: 16rpx;">合同金额:{{detail.amount}}元</span> |
||||
|
<span style="margin-top: 16rpx;">合同状态:{{contractStatusList.find((find) => find.value === detail.status)?.label}}</span> |
||||
|
<span style="margin-top: 16rpx;">服务次数:{{detail.contractTermList[0].name}}次</span> |
||||
|
<span style="margin-top: 16rpx;">甲方:{{detail.firstPartyName}}</span> |
||||
|
<span style="margin-top: 16rpx;">甲方身份编号:{{detail.firstPartyIdentityNo}}</span> |
||||
|
<span style="margin-top: 16rpx;">乙方:{{detail.secondPartyName}}</span> |
||||
|
<span style="margin-top: 16rpx;">乙方身份编号:{{detail.secondPartyIdentityNo}}</span> |
||||
|
<span style="margin-top: 16rpx;">签约日期:{{detail.signDate}}</span> |
||||
|
<span style="margin-top: 16rpx;">服务开始日期:{{detail.startDate}}</span> |
||||
|
<span style="margin-top: 16rpx;">服务结束日期:{{detail.endDate}}</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="flex-col" style="padding-left: 12px;" v-if="detail.contractImageList && detail.contractImageList.length"> |
||||
|
<span style="font-size: 14px;color: #333;padding: 12px 12px 12px 0rpx;">合同凭证:</span> |
||||
|
<!-- <image-upload :file-list="imageList" :album="true" :enable="false" size="200rpx"/> --> |
||||
|
<div class="flex-row"> |
||||
|
<ImagePreviewGroup> |
||||
|
<Image |
||||
|
v-for="(item, index) in detail.contractImageList" |
||||
|
style="width: 120px; height: 120px; border-radius: 5px; margin: 0 5px 5px 0" |
||||
|
:key="index" |
||||
|
:src="item.url" |
||||
|
/> |
||||
|
</ImagePreviewGroup> |
||||
|
</div> |
||||
|
</div> |
||||
|
<view class="flex-col" style="font-size: 28rpx;color: #333;padding-left: 24rpx;margin-top: 24rpx;" v-if="detail.remark"> |
||||
|
<text>合同备注:</text> |
||||
|
<text style="margin-top: 8rpx;">{{detail.remark}}</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="flex-col" style="font-size: 28rpx;color: #333;padding: 24rpx;margin-top: 24rpx;" v-if="paymentInfo"> |
||||
|
<text style="font-size: 28rpx;color: #333;font-weight: bold;">支付信息:</text> |
||||
|
<text style="margin-top: 16rpx;">订单标识:{{paymentInfo.orderId}}</text> |
||||
|
<text style="margin-top: 16rpx;">应付金额:{{paymentInfo.payableAmount}}元</text> |
||||
|
<text style="margin-top: 16rpx;">实付金额:{{paymentInfo.paidAmount}}元</text> |
||||
|
<text style="margin-top: 16rpx;">未付金额:{{paymentInfo.unpaidAmount}}元</text> |
||||
|
<text style="margin-top: 16rpx;">付款时间:{{paymentInfo.paidTime}}</text> |
||||
|
<text style="margin-top: 16rpx;">付款方式:{{paymentInfoList.find((find) => find.value === paymentInfo.paymentMethod)?.label}}</text> |
||||
|
</view> |
||||
|
<view class="flex-col" style="padding-left: 24rpx;" v-if="paymentInfo && paymentInfo.voucherImageList && paymentInfo.voucherImageList.length"> |
||||
|
<text style="font-size: 28rpx;color: #333;padding: 24rpx 24rpx 24rpx 0rpx;">支付凭证:</text> |
||||
|
<ImagePreviewGroup> |
||||
|
<Image |
||||
|
v-for="(item, index) in paymentInfo.voucherImageList" |
||||
|
style="width: 120px; height: 120px; border-radius: 5px; margin: 0 5px 5px 0" |
||||
|
:key="index" |
||||
|
:src="item" |
||||
|
/> |
||||
|
</ImagePreviewGroup> |
||||
|
</view> |
||||
|
</div> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue' |
||||
|
import { ImagePreviewGroup, Image } from 'ant-design-vue' |
||||
|
import { BasicModal, useModalInner } from '/@/components/Modal' |
||||
|
import { getContractInfo, getPaymentInfo } from '/@/api/clue' |
||||
|
import { contractStatusList, paymentInfoList } from '/@/enums/customerEnum' |
||||
|
|
||||
|
const detail = ref<any>(null) |
||||
|
const paymentInfo = ref<any>(null) |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
const { record } = data |
||||
|
// id.value = record?.id |
||||
|
setModalProps({ |
||||
|
minHeight: 50, |
||||
|
title: '合同信息', |
||||
|
confirmLoading: false, |
||||
|
}) |
||||
|
detail.value = await getContractInfo({datingStoreCustomerId: record?.id}) |
||||
|
paymentInfo.value = await getPaymentInfo({datingStoreCustomerId: record?.id}) |
||||
|
}) |
||||
|
// const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
@ -0,0 +1,376 @@ |
|||||
|
import { BasicColumn, FormSchema } from '/@/components/Table' |
||||
|
|
||||
|
export const contactStatusList = [ |
||||
|
{ label: '进行中', value: 1 }, |
||||
|
{ label: '生效中', value: 2 }, |
||||
|
{ label: '已终止', value: 3 }, |
||||
|
] |
||||
|
|
||||
|
export const tableColumns: BasicColumn[] = [ |
||||
|
{ title: '用户信息', dataIndex: 'userInfo', slots: { customRender: 'userInfo' } }, |
||||
|
{ width: 120, title: '手机号码', dataIndex: 'phone' }, |
||||
|
{ width: 240, title: '服务任务', dataIndex: 'inProgressTaskId', slots: { customRender: 'inProgressTaskId' } }, |
||||
|
{ width: 120, title: '服务红娘', dataIndex: 'serviceMatchmakerName' }, |
||||
|
{ width: 160, title: '面谈销售', dataIndex: 'salesConsultantName' }, |
||||
|
{ width: 160, title: '创建时间', dataIndex: 'createTime' }, |
||||
|
] |
||||
|
|
||||
|
export const tableFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'name', |
||||
|
label: '客户姓名', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'phone', |
||||
|
label: '电话', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'salesConsultantName', |
||||
|
label: '面谈销售', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'serviceMatchmakerName', |
||||
|
label: '服务红娘', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
|
||||
|
import { ref } from 'vue' |
||||
|
import dayjs, { Dayjs } from 'dayjs' |
||||
|
import { genderList, incomeList } from '/@/enums/customerEnum' |
||||
|
import { useAddressData } from '/@/hooks/common' |
||||
|
import { |
||||
|
getNationList, |
||||
|
getEducationList, |
||||
|
getOccupationList, |
||||
|
getPropertyPermits, |
||||
|
getMaritalStatusList, |
||||
|
getConstellationList, |
||||
|
getCarPurchaseSituation, |
||||
|
} from '/@/api/essentialData' |
||||
|
|
||||
|
// 基础信息的额外数据
|
||||
|
export const basicInfoData = 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 addressName = ref<string[]>([]) |
||||
|
// 基本信息
|
||||
|
export const modalFormSchema: FormSchema[] = [ |
||||
|
{ field: 'name', label: '客户姓名', component: 'Input', required: true, colProps: { span: 12 },}, |
||||
|
{ |
||||
|
field: 'genderCode', |
||||
|
label: '性别', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
required: true, |
||||
|
componentProps: { |
||||
|
options: genderList, |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'phone', label: '电话号码', component: 'Input', required: true, colProps: { span: 12 },}, |
||||
|
{ |
||||
|
label: '出生日期', |
||||
|
component: 'DatePicker', |
||||
|
field: 'birthDate', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
componentProps: { |
||||
|
style: { width: '100%' }, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maritalStatusCode', |
||||
|
label: '婚姻状况', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getMaritalStatusList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoData.value.maritalStatusName = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'educationCode', |
||||
|
label: '学历', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getEducationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoData.value.education = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'height', label: '身高(cm)', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ field: 'weight', label: '体重(kg)', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ field: 'annualIncome', label: '年收入(万元)', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ field: 'netAsset', label: '净资产(万元)', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ field: 'graduateSchool', label: '毕业高校', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ |
||||
|
field: 'nationCode', |
||||
|
label: '民族', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'cn', |
||||
|
valueField: 'id', |
||||
|
api: getNationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
demandMarriageMoreData.value.nation = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'homeAddress', |
||||
|
label: '现居住地', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Cascader', |
||||
|
componentProps: { |
||||
|
options: addressList, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
basicInfoData.value.homeProvinceName = v?.[0]?.label |
||||
|
basicInfoData.value.homeCityName = v?.[1]?.label |
||||
|
basicInfoData.value.homeDistrictName = v?.[2]?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'homeDetailAddress', label: '详细地址', component: 'Input', colProps: { span: 12 }, }, |
||||
|
{ |
||||
|
label: '职业', |
||||
|
field: 'occupationList', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Cascader', |
||||
|
componentProps: { |
||||
|
options: occupationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
const industry = v?.[0] || {} |
||||
|
const occupation = v?.[1] || {} |
||||
|
basicInfoData.value.industry = industry.label |
||||
|
basicInfoData.value.industryCode = industry.value |
||||
|
basicInfoData.value.occupation = occupation.label |
||||
|
basicInfoData.value.occupationCode = occupation.value |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 12 }, }, |
||||
|
{ |
||||
|
field: 'housePurchase', |
||||
|
label: '购房情况', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '已购房', value: 1 }, |
||||
|
{ label: '未购房', value: 0 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'carPurchase', |
||||
|
label: '购车情况', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '已购车', value: 1 }, |
||||
|
{ label: '未购车', value: 0 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'profilePhoto', |
||||
|
component: 'Upload', |
||||
|
label: '资料头像', |
||||
|
colProps: { span: 8 }, |
||||
|
slot: 'profilePhoto', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'remark', |
||||
|
label: '个人描述', |
||||
|
component: 'InputTextArea', |
||||
|
colProps: { span: 16 }, |
||||
|
componentProps: ({ formModel }) => { |
||||
|
return { |
||||
|
autoSize: { |
||||
|
minRows: 4, |
||||
|
}, |
||||
|
disabled: formModel?.describeAudit, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
// 择偶标准的额外数据
|
||||
|
export const demandMarriageMoreData = ref<any>({}) |
||||
|
// 择偶标准
|
||||
|
export const demandMarriageSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'educationCode', |
||||
|
label: '学历要求', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'ApiSelect', |
||||
|
componentProps: { |
||||
|
labelField: 'desc', |
||||
|
api: getEducationList, |
||||
|
getPopupContainer: () => document.body, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
demandMarriageMoreData.value.education = v?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'minimumAnnualIncome', |
||||
|
label: '年收入(万元)', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
slot: 'income', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maximumAnnualIncome', |
||||
|
label: '年收入', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
ifShow: false, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'cityList', |
||||
|
label: '所在城市', |
||||
|
colProps: { span: 24 }, |
||||
|
component: 'Cascader', |
||||
|
componentProps: { |
||||
|
options: domicilePlaceList, |
||||
|
onChange: (_: any, v: any) => { |
||||
|
demandMarriageMoreData.value.provinceName = v?.[0]?.label |
||||
|
demandMarriageMoreData.value.cityName = v?.[1]?.label |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'minAge', |
||||
|
label: '年龄范围', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
slot: 'age', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maxAge', |
||||
|
label: '年龄', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
ifShow: false, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'minHeight', |
||||
|
label: '身高(cm)', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
slot: 'height', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maxHeight', |
||||
|
label: '身高', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
ifShow: false, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'minWeight', |
||||
|
label: '体重(kg)', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
slot: 'weight', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'maxWeight', |
||||
|
label: '体重', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'InputNumber', |
||||
|
ifShow: false, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'isDivorceAccepted', |
||||
|
label: '是否接受离异', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '不接受', value: 0 }, |
||||
|
{ label: '接受', value: 1 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'isChildAccepted', |
||||
|
label: '是否跟老人一起生活', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '不接受', value: 0 }, |
||||
|
{ label: '接受', value: 1 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'isLivingWithElderly', |
||||
|
label: '是否跟老人一起生活', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '跟男方', value: 1 }, |
||||
|
{ label: '跟女方', value: 2 }, |
||||
|
{ label: '不跟老人居住', value: 3 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'otherRequirements', |
||||
|
label: '其他需求', |
||||
|
component: 'InputTextArea', |
||||
|
colProps: { span: 24 }, |
||||
|
componentProps: ({ formModel }) => { |
||||
|
return { |
||||
|
autoSize: { |
||||
|
minRows: 4, |
||||
|
}, |
||||
|
disabled: formModel?.describeAudit, |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
@ -0,0 +1,171 @@ |
|||||
|
<template> |
||||
|
<div class="order-list"> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<!-- <template #toolbar> |
||||
|
<div style="width: 100%; padding: 2px" class="flex-row-center-space"> |
||||
|
<RadioGroup button-style="solid" v-model:value="radioVal" @change="handleRadioChange"> |
||||
|
<RadioButton v-for="item in followStatusList" :key="item.value" :value="item.value">{{item.label}}</RadioButton> |
||||
|
</RadioGroup> |
||||
|
</div> |
||||
|
</template> --> |
||||
|
<template #userInfo="{ text, record }"> |
||||
|
<div class="flex-row-center-start" style="padding-left: 12px;"> |
||||
|
<Avatar :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" :size="36" /> |
||||
|
<div class="flex-col" style="margin-left: 12px;"> |
||||
|
<div class="flex-row"> |
||||
|
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.name}}</span> |
||||
|
</div> |
||||
|
<div class="flex-row"> |
||||
|
<span class="single-line" style="font-size: 13px;color: #333;">{{record.genderCode == 1 ? '女' : '男'}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #inProgressTaskId="{ text }"> |
||||
|
<Tag color="pink" v-if="text">任务进行中</Tag> |
||||
|
</template> |
||||
|
<template #action="{ record }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<Popconfirm placement="topRight" :icon="'分配'" @confirm="allocateList(record.id)"> |
||||
|
<template #title> |
||||
|
<div class="flex-row-center-start" style="padding: 8px 8px 8px 0px;border-bottom: 1px solid #ddd;" v-for="item in memberList" :key="item.userId"> |
||||
|
<Checkbox :checked="verifier == item.userId" @change="e => onCheckChange(e, item)"> |
||||
|
<span style="color: #333;font-weight: bold;margin-left: 4px;">{{item.realName}}</span> |
||||
|
<span style="color: #666;margin-left: 4px;">({{item.phone}})</span> |
||||
|
</Checkbox> |
||||
|
</div> |
||||
|
</template> |
||||
|
<Button style="width: 88px;margin-right: 12px;" type="primary" danger>分配红娘</Button> |
||||
|
</Popconfirm> |
||||
|
<Button style="width: 88px;margin-right: 12px;" @click.stop="openContract(record)">查看合同</Button> |
||||
|
<Button style="width: 88px;margin-right: 12px;" danger @click.stop="handleSign(record)" v-if="!record.inProgressTaskId">续签</Button> |
||||
|
<Button style="width: 88px;" type="primary" @click.stop="handleCustomer(record)">编辑信息</Button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
|
||||
|
<SignModal @register="signModal" @success="handleSuccess" /> |
||||
|
<ContractModal @register="contractModal" @success="handleSuccess" /> |
||||
|
<CustomerModal @register="customerModal" @success="handleSuccess" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { Radio } from 'ant-design-vue' |
||||
|
|
||||
|
export default { |
||||
|
name: 'ClueList', |
||||
|
components: { RadioGroup: Radio.Group, RadioButton: Radio.Button }, |
||||
|
} |
||||
|
</script> |
||||
|
<script setup lang="ts"> |
||||
|
import moment from 'moment/moment' |
||||
|
import { computed, ref, onMounted } from 'vue' |
||||
|
import { Avatar, Card, Button, ImagePreviewGroup, Image, Tag, Popconfirm, Checkbox} from 'ant-design-vue' |
||||
|
import { useRouter } from 'vue-router' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { tableColumns, tableFormSchema } from './data' |
||||
|
import { BasicTable, useTable, TableAction } from '/@/components/Table' |
||||
|
import { useModal } from '/@/components/Modal' |
||||
|
import SignModal from '/@/views/market/components/modal.vue' |
||||
|
import ContractModal from './contract.vue' |
||||
|
import CustomerModal from './modal.vue' |
||||
|
|
||||
|
import { getClientList, allocationTask } from '/@/api/clue' |
||||
|
import { pageOrganizationMember } from '/@/api/staff/staff' |
||||
|
|
||||
|
const memberList = ref<any[]>([]); |
||||
|
const verifier = ref<any>('') |
||||
|
onMounted(async () => { |
||||
|
const result = await pageOrganizationMember({}) |
||||
|
memberList.value = result.items |
||||
|
}) |
||||
|
|
||||
|
const [registerTable, { reload, setPagination }] = useTable({ |
||||
|
bordered: false, |
||||
|
useSearchForm: true, |
||||
|
columns: tableColumns, |
||||
|
showIndexColumn: false, |
||||
|
showTableSetting: false, |
||||
|
api: getClientList, |
||||
|
formConfig: { |
||||
|
labelWidth: 120, |
||||
|
schemas: tableFormSchema, |
||||
|
}, |
||||
|
beforeFetch: (arg) => { |
||||
|
const { createTime } = arg |
||||
|
if (createTime) { |
||||
|
arg.signDateFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00') |
||||
|
arg.signDateTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59') |
||||
|
delete arg.createTime |
||||
|
} |
||||
|
arg.status = radioVal.value |
||||
|
}, |
||||
|
actionColumn: { |
||||
|
width: 400, |
||||
|
title: '操作', |
||||
|
fixed: 'right', |
||||
|
dataIndex: 'action', |
||||
|
slots: { customRender: 'action' }, |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
|
const followStatusList = [ |
||||
|
{ label: '进行中', value: 1 }, |
||||
|
{ label: '生效中', value: 2 }, |
||||
|
{ label: '已终止', value: 3 }, |
||||
|
{ label: '全部', value: '' }, |
||||
|
] |
||||
|
const radioVal = ref<any>('') |
||||
|
function handleRadioChange() { |
||||
|
setPagination({ current: 1 }) |
||||
|
reload() |
||||
|
} |
||||
|
|
||||
|
function onCheckChange(e, item){ |
||||
|
if(e.target.checked){ |
||||
|
verifier.value = item.userId |
||||
|
} |
||||
|
} |
||||
|
const { createMessage } = useMessage() |
||||
|
async function allocateList(id = null){ |
||||
|
if(!verifier.value){ |
||||
|
createMessage.warning('请选择分配人') |
||||
|
return |
||||
|
} |
||||
|
try { |
||||
|
await allocationTask({serviceMatchmaker: verifier.value, id}) |
||||
|
createMessage.success(`分配成功`) |
||||
|
} finally { |
||||
|
reload() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const [signModal, { openModal: openSignModal, closeModal: closeSignModal }] = useModal() |
||||
|
const [contractModal, { openModal: openContractModal, closeModal: closeContractModal }] = useModal() |
||||
|
const [customerModal, { openModal: openCustomerModal, closeModal: closeCustomerModal }] = useModal() |
||||
|
|
||||
|
function handleSign(record: any) { |
||||
|
openSignModal(true, {record, ifUpdate: true}) |
||||
|
} |
||||
|
function openContract(record: any) { |
||||
|
openContractModal(true, {record}) |
||||
|
} |
||||
|
function handleCustomer(record: any) { |
||||
|
openCustomerModal(true, {record}) |
||||
|
} |
||||
|
// 操作成功 |
||||
|
function handleSuccess() { |
||||
|
closeSignModal() |
||||
|
closeContractModal() |
||||
|
closeCustomerModal() |
||||
|
reload() |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="less"> |
||||
|
.single-line { |
||||
|
overflow: hidden; /* 超出部分隐藏 */ |
||||
|
white-space: nowrap; /* 文本不换行 */ |
||||
|
text-overflow: ellipsis; /* 超出部分显示省略号 */ |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,203 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal"> |
||||
|
<Tabs tab-position="left" v-model:activeKey="activeKey2" :animated="false" @change="onInfoChange"> |
||||
|
<TabPane key="1" tab="个人资料"> |
||||
|
<BasicForm @register="registerForm" style="padding: 16px 48px 0px 0px;" > |
||||
|
<!-- <template #birthYear="{ model, field }"> |
||||
|
<DatePicker v-model:value="model[field]" mode="year" :open="open" format="YYYY" @openChange="openChange" @panelChange="panelChange"/> |
||||
|
</template> --> |
||||
|
<template #profilePhoto="{ model, field }"> |
||||
|
<CropperAvatar :value="model[field]" @change="uploadAvatarAfter"/> |
||||
|
</template> |
||||
|
</BasicForm> |
||||
|
</TabPane> |
||||
|
<TabPane key="2" tab="择偶要求"> |
||||
|
<BasicForm @register="registerForm3" style="padding: 16px 48px 0px 0px;"> |
||||
|
<template #age="{ model }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minAge']" /> |
||||
|
<span style="margin: 0 5px">-</span> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maxAge']" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #height="{ model }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minHeight']" /> |
||||
|
<span style="margin: 0 5px">-</span> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maxHeight']" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #weight="{ model }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minWeight']" /> |
||||
|
<span style="margin: 0 5px">-</span> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maxWeight']" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #income="{ model }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minimumAnnualIncome']" /> |
||||
|
<span style="margin: 0 5px">-</span> |
||||
|
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maximumAnnualIncome']" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
</BasicForm> |
||||
|
</TabPane> |
||||
|
</Tabs> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import moment from 'moment' |
||||
|
import { ref, unref, nextTick } from 'vue' |
||||
|
import dayjs, { Dayjs } from 'dayjs' |
||||
|
import { Tabs, TabPane, Button, Result, InputNumber, DatePicker } from 'ant-design-vue' |
||||
|
import Icon from '/@/components/Icon' |
||||
|
import { modalFormSchema, basicInfoData, demandMarriageSchema, demandMarriageMoreData } 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 { getDemandInfo, getCustomerInfo, editCustomerInfo, editDemandInfo } from '/@/api/clue' |
||||
|
import { formatToDate } from '/@/utils/dateUtil' |
||||
|
import { isEmpty } from '/@/utils/is' |
||||
|
|
||||
|
|
||||
|
const activeKey2 = ref<string>('1') |
||||
|
|
||||
|
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue }] = |
||||
|
useForm({ |
||||
|
labelWidth: 108, |
||||
|
schemas: modalFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const id = ref<string>('') |
||||
|
const details = ref<any>() |
||||
|
const demand = ref<any>() |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
const { record } = data |
||||
|
var title :string = '' |
||||
|
id.value = record?.id |
||||
|
await resetFields() |
||||
|
|
||||
|
if(record && record.id){ |
||||
|
title = '编辑客户信息' |
||||
|
details.value = await getCustomerInfo({id: record.id}) |
||||
|
const { homeProvinceCode, homeCityCode, homeDistrictCode, birthYear, birthMonth, birthDay, nationCode } = details.value || {} |
||||
|
const homeAddress = homeDistrictCode ? [homeProvinceCode, homeCityCode, homeDistrictCode] : [] |
||||
|
const birthDate = moment(`${birthYear}-${birthMonth}-${birthDay}`) |
||||
|
|
||||
|
const { homeProvinceName, homeCityName, homeDistrictName } = details.value || {} |
||||
|
if(homeDistrictName){ |
||||
|
basicInfoData.value.homeProvinceName = homeProvinceName |
||||
|
basicInfoData.value.homeCityName = homeCityName |
||||
|
basicInfoData.value.homeDistrictName =homeDistrictName |
||||
|
} |
||||
|
|
||||
|
await nextTick() |
||||
|
await setFieldsValue({ ...details.value, homeAddress, birthDate, nationCode: `${nationCode}` }) |
||||
|
activeKey2.value = '1' |
||||
|
} |
||||
|
setModalProps({ minHeight: 50, confirmLoading: false, title }) |
||||
|
}) |
||||
|
|
||||
|
// 择偶标准表单配置 |
||||
|
const [registerForm3, { getFieldsValue: getFieldsValue3, setFieldsValue: setFieldsValue3, resetFields: resetFields3 }] = |
||||
|
useForm({ |
||||
|
labelWidth: 160, |
||||
|
schemas: demandMarriageSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
function uploadAvatarAfter(value) { |
||||
|
//修改表单的值 |
||||
|
setFieldsValue({ profilePhoto: value }); |
||||
|
} |
||||
|
|
||||
|
async function onInfoChange(){ |
||||
|
if(activeKey2.value == '2' && (!demand.value || !demand.value.id)){ |
||||
|
await nextTick() |
||||
|
await resetFields3() |
||||
|
demand.value = await getDemandInfo({datingStoreCustomerId: id.value}) |
||||
|
const { isDivorceAccepted, isChildAccepted, customerAreaDemandList } = demand.value || {} |
||||
|
var cityList: any = [] |
||||
|
if(customerAreaDemandList && customerAreaDemandList.length){ |
||||
|
const provinceCode = customerAreaDemandList[0].provinceCode |
||||
|
const provinceName = customerAreaDemandList[0].provinceName |
||||
|
const cityCode = customerAreaDemandList[0].cityCode |
||||
|
const cityName = customerAreaDemandList[0].cityName |
||||
|
cityList = [provinceCode, cityCode] |
||||
|
demandMarriageMoreData.value.provinceName = provinceName |
||||
|
demandMarriageMoreData.value.cityName = cityName |
||||
|
} |
||||
|
if(!isEmpty(isDivorceAccepted)){ |
||||
|
demand.value.isDivorceAccepted = isDivorceAccepted ? 1 : 0 |
||||
|
} |
||||
|
if(!isEmpty(isChildAccepted)){ |
||||
|
demand.value.isChildAccepted = isChildAccepted ? 1 : 0 |
||||
|
} |
||||
|
|
||||
|
await setFieldsValue3({ ...demand.value, cityList}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
await validate() |
||||
|
const values: any = getFieldsValue() |
||||
|
// console.log({...values, ...basicInfoData.value}) |
||||
|
const { birthDate, homeAddress } = values |
||||
|
setModalProps({ confirmLoading: true }) |
||||
|
const birth = dayjs(birthDate) |
||||
|
values.birthYear = birth.year() |
||||
|
values.birthMonth = birth.month() + 1 |
||||
|
values.birthDay = birth.date() |
||||
|
const param = { |
||||
|
...values, |
||||
|
homeCityCode: homeAddress?.[1], |
||||
|
homeCityName: basicInfoData.value.homeCityName, |
||||
|
homeProvinceCode: homeAddress?.[0], |
||||
|
homeProvinceName: basicInfoData.value.homeProvinceName, |
||||
|
homeDistrictCode: homeAddress?.[2], |
||||
|
homeDistrictName: basicInfoData.value.homeDistrictName, |
||||
|
} |
||||
|
param.id = details.value.id |
||||
|
console.log(param) |
||||
|
|
||||
|
const demandInfo: any = getFieldsValue3() |
||||
|
if(demandInfo){ |
||||
|
demandInfo.datingStoreCustomerId = details.value.id |
||||
|
const { cityList } = demandInfo |
||||
|
if(cityList && cityList.length){ |
||||
|
const provinceName = demandMarriageMoreData.value.provinceName |
||||
|
const cityName = demandMarriageMoreData.value.cityName |
||||
|
demandInfo.customerAreaDemandList = [{provinceCode: cityList[0], provinceName, cityCode: cityList[1], cityName}] |
||||
|
} |
||||
|
} |
||||
|
if(details.value && details.value.id){ |
||||
|
await editCustomerInfo(param) |
||||
|
await editDemandInfo(demandInfo) |
||||
|
createMessage.success(`编辑成功!`) |
||||
|
} else { |
||||
|
// await createClueRecord(param) |
||||
|
createMessage.success(`编辑成功!`) |
||||
|
} |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
::v-deep .ant-input-number { |
||||
|
min-width: 60px; |
||||
|
width: 100% !important; |
||||
|
max-width: 100%; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,74 @@ |
|||||
|
import { FormSchema } from '/@/components/Form' |
||||
|
import { genderList } from '/@/enums/customerEnum' |
||||
|
|
||||
|
export const modalFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'phone', |
||||
|
label: '客户电话', |
||||
|
colProps: { span: 12 }, |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'genderCode', |
||||
|
label: '客户性别', |
||||
|
required: true, |
||||
|
component: 'Select', |
||||
|
colProps: { span: 12 }, |
||||
|
componentProps: { |
||||
|
options: genderList, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'name', |
||||
|
label: '客户姓名', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'identityCard', |
||||
|
label: '身份证号', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'amount', |
||||
|
label: '服务金额', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'numberOfServices', |
||||
|
label: '服务次数', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
}, |
||||
|
{ |
||||
|
label: '结束时间', |
||||
|
component: 'DatePicker', |
||||
|
field: 'serviceEndDate', |
||||
|
required: true, |
||||
|
colProps: { span: 12 }, |
||||
|
componentProps: { |
||||
|
style: { width: '100%' }, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '合同凭证', |
||||
|
required: true, |
||||
|
field: 'imageList1', |
||||
|
component: 'Upload', |
||||
|
slot: 'imageList1', |
||||
|
}, |
||||
|
{ |
||||
|
label: '付款凭证', |
||||
|
required: true, |
||||
|
field: 'imageList2', |
||||
|
component: 'Upload', |
||||
|
slot: 'imageList2', |
||||
|
}, |
||||
|
] |
||||
@ -0,0 +1,95 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" :width="720" @ok="handleOk" @register="registerModal"> |
||||
|
<BasicForm @register="registerForm"> |
||||
|
<template #imageList1="{ model, field }"> |
||||
|
<OssUpload v-model="model[field]" /> |
||||
|
</template> |
||||
|
<template #imageList2="{ model, field }"> |
||||
|
<OssUpload v-model="model[field]" /> |
||||
|
</template> |
||||
|
</BasicForm> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue' |
||||
|
import { modalFormSchema } from './data' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { BasicForm, useForm } from '/@/components/Form' |
||||
|
import { BasicModal, useModalInner } from '/@/components/Modal' |
||||
|
import { OssUpload } from '/@/components/OssUpload' |
||||
|
import { signCustomer, resignCustomer } from '/@/api/clue' |
||||
|
import { formatToDate } from '/@/utils/dateUtil' |
||||
|
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: modalFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const id = ref<string>('') |
||||
|
const ifUpdate = ref<boolean>(false) |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
const { record } = data |
||||
|
await resetFields() |
||||
|
id.value = record?.id |
||||
|
ifUpdate.value = !!data.ifUpdate |
||||
|
setModalProps({ |
||||
|
minHeight: 50, |
||||
|
title: ifUpdate.value ? `续签` : '签约', |
||||
|
confirmLoading: false, |
||||
|
}) |
||||
|
if (!!ifUpdate.value) { |
||||
|
await setFieldsValue({ ...record }) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
const values = await validate() |
||||
|
const {name, phone, genderCode, identityCard, amount, numberOfServices, serviceEndDate} = values |
||||
|
var data: any = {name, phone, genderCode, identityCard, amount, numberOfServices} |
||||
|
var imageList1: any = [] |
||||
|
var imageList2: any = [] |
||||
|
Object.keys(values).forEach((key) => { |
||||
|
const val = values[key] |
||||
|
switch (key) { |
||||
|
case 'imageList1': |
||||
|
imageList1 = val?.map?.((item: any) => { |
||||
|
const { url, response, originFileObj } = item |
||||
|
const path = typeof item === 'string' ? item : url || item?.photoUrl || response?.url || originFileObj?.url |
||||
|
return {url: path, type: 1} |
||||
|
}) |
||||
|
break |
||||
|
case 'imageList2': |
||||
|
imageList2 = val?.map?.((item: any) => { |
||||
|
const { url, response, originFileObj } = item |
||||
|
return typeof item === 'string' ? item : url || item?.photoUrl || response?.url || originFileObj?.url |
||||
|
}) |
||||
|
break |
||||
|
} |
||||
|
}) |
||||
|
data.contractImageList = imageList1 |
||||
|
data.paymentVoucherImageList = imageList2 |
||||
|
|
||||
|
data.serviceEndDate = formatToDate(serviceEndDate) |
||||
|
|
||||
|
// console.log('values.............', values) |
||||
|
setModalProps({ confirmLoading: true }) |
||||
|
if (!!ifUpdate.value) { |
||||
|
data.datingStoreCustomerId = id.value |
||||
|
await resignCustomer(data) |
||||
|
createMessage.success(`续签成功!`) |
||||
|
} else { |
||||
|
data.datingStoreAppointmentId = id.value |
||||
|
await signCustomer(data) |
||||
|
createMessage.success(`签约成功!`) |
||||
|
} |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
@ -0,0 +1,78 @@ |
|||||
|
import { BasicColumn, FormSchema } from '/@/components/Table' |
||||
|
|
||||
|
export const contactStatusList = [ |
||||
|
{ label: '进行中', value: 1 }, |
||||
|
{ label: '已交付', value: 2 }, |
||||
|
{ label: '已终止', value: 3 }, |
||||
|
] |
||||
|
|
||||
|
export const tableColumns: BasicColumn[] = [ |
||||
|
{ title: '用户信息', dataIndex: 'userInfo', slots: { customRender: 'userInfo' } }, |
||||
|
{ width: 120, title: '手机号码', dataIndex: 'phone' }, |
||||
|
{ width: 120, title: '合同开始日期', dataIndex: 'contractStartDate' }, |
||||
|
{ width: 120, title: '合同结束日期', dataIndex: 'contractEndDate' }, |
||||
|
{ width: 120, title: '任务状态', dataIndex: 'status', |
||||
|
customRender: ({ text }) => { |
||||
|
return contactStatusList.find((find) => find.value === text)?.label |
||||
|
}, |
||||
|
}, |
||||
|
{ width: 120, title: '服务红娘', dataIndex: 'serviceMatchmakerName' }, |
||||
|
{ width: 100, title: '服务次数', dataIndex: 'numberOfServices' }, |
||||
|
{ width: 100, title: '剩余次数', dataIndex: 'numberOfRemaining' }, |
||||
|
{ title: '任务交付凭证', dataIndex: 'deliveryVoucherList', slots: { customRender: 'deliveryVoucherList' } }, |
||||
|
|
||||
|
] |
||||
|
|
||||
|
export const tableFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'name', |
||||
|
label: '客户姓名', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'phone', |
||||
|
label: '电话', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'serviceMatchmakerName', |
||||
|
label: '服务红娘', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 6 }, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
|
export const modalFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'status', |
||||
|
label: '上报结果', |
||||
|
required: true, |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '已交付', value: 2 }, |
||||
|
{ label: '已终止', value: 3 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '处理凭证', |
||||
|
required: true, |
||||
|
field: 'imageList', |
||||
|
component: 'Upload', |
||||
|
slot: 'imageList', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'remark', |
||||
|
label: '备注', |
||||
|
required: false, |
||||
|
component: 'InputTextArea', |
||||
|
componentProps: { |
||||
|
autosize: { |
||||
|
minRows: 4, |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
@ -0,0 +1,171 @@ |
|||||
|
<template> |
||||
|
<div class="order-list"> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<div style="width: 100%; padding: 2px" class="flex-row-center-space"> |
||||
|
<RadioGroup button-style="solid" v-model:value="radioVal" @change="handleRadioChange"> |
||||
|
<RadioButton v-for="item in followStatusList" :key="item.value" :value="item.value">{{item.label}}</RadioButton> |
||||
|
</RadioGroup> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #userInfo="{ text, record }"> |
||||
|
<div class="flex-row-center-start" style="padding-left: 12px;"> |
||||
|
<Avatar :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" :size="36" /> |
||||
|
<div class="flex-col" style="margin-left: 12px;"> |
||||
|
<div class="flex-row"> |
||||
|
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.name}}</span> |
||||
|
</div> |
||||
|
<div class="flex-row"> |
||||
|
<span class="single-line" style="font-size: 13px;color: #333;">{{record.genderCode == 1 ? '女' : '男'}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<template #deliveryVoucherList="{ text }"> |
||||
|
<ImagePreviewGroup v-if="text && text.length"> |
||||
|
<Image |
||||
|
v-for="(item, index) in text" |
||||
|
style="width: 40px; height: 40px; border-radius: 5px; margin: 0 5px 5px 0" |
||||
|
:key="index" |
||||
|
:src="item" |
||||
|
/> |
||||
|
</ImagePreviewGroup> |
||||
|
</template> |
||||
|
<template #action="{ record }"> |
||||
|
<div class="flex-row-center-start"> |
||||
|
<Popconfirm placement="topRight" :icon="'分配'" @confirm="allocateList(record.datingStoreCustomerId)" v-if="record.status == 1"> |
||||
|
<template #title> |
||||
|
<div class="flex-row-center-start" style="padding: 8px 8px 8px 0px;border-bottom: 1px solid #ddd;" v-for="item in memberList" :key="item.userId"> |
||||
|
<Checkbox :checked="verifier == item.userId" @change="e => onCheckChange(e, item)"> |
||||
|
<span style="color: #333;font-weight: bold;margin-left: 4px;">{{item.realName}}</span> |
||||
|
<span style="color: #666;margin-left: 4px;">({{item.phone}})</span> |
||||
|
</Checkbox> |
||||
|
</div> |
||||
|
</template> |
||||
|
<Button style="width: 72px;margin-right: 12px;" type="primary" danger>分配</Button> |
||||
|
</Popconfirm> |
||||
|
<Button style="width: 96px;margin-right: 12px;" @click.stop="handleReport(record, 1)" v-if="record.status == 1 && record.numberOfRemaining > 0">上报任务</Button> |
||||
|
<Button style="width: 96px;" type="primary" @click.stop="handleReport(record, 2)" v-if="record.status == 1">结束任务</Button> |
||||
|
</div> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
|
||||
|
<ReportModal @register="registerModal" @success="handleSuccess" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import { Radio } from 'ant-design-vue' |
||||
|
|
||||
|
export default { |
||||
|
name: 'ClueList', |
||||
|
components: { RadioGroup: Radio.Group, RadioButton: Radio.Button }, |
||||
|
} |
||||
|
</script> |
||||
|
<script setup lang="ts"> |
||||
|
import moment from 'moment/moment' |
||||
|
import { computed, ref, reactive, onMounted } from 'vue' |
||||
|
import { Avatar, Card, Button, ImagePreviewGroup, Image, Popconfirm, Checkbox } from 'ant-design-vue' |
||||
|
import { useRouter } from 'vue-router' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { useModal } from '/@/components/Modal' |
||||
|
import { tableColumns, tableFormSchema } from './data' |
||||
|
import ReportModal from './modal.vue' |
||||
|
import { BasicTable, useTable, TableAction } from '/@/components/Table' |
||||
|
import { getTaskList, allocationTask } from '/@/api/clue' |
||||
|
import { pageOrganizationMember } from '/@/api/staff/staff' |
||||
|
|
||||
|
const memberList = ref<any[]>([]); |
||||
|
const verifier = ref<any>('') |
||||
|
onMounted(async () => { |
||||
|
const result = await pageOrganizationMember({}) |
||||
|
memberList.value = result.items |
||||
|
}) |
||||
|
|
||||
|
const [registerTable, { reload, setPagination }] = useTable({ |
||||
|
bordered: false, |
||||
|
useSearchForm: true, |
||||
|
columns: tableColumns, |
||||
|
showIndexColumn: false, |
||||
|
showTableSetting: false, |
||||
|
api: getTaskList, |
||||
|
formConfig: { |
||||
|
labelWidth: 120, |
||||
|
schemas: tableFormSchema, |
||||
|
}, |
||||
|
beforeFetch: (arg) => { |
||||
|
const { createTime } = arg |
||||
|
if (createTime) { |
||||
|
arg.signDateFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00') |
||||
|
arg.signDateTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59') |
||||
|
delete arg.createTime |
||||
|
} |
||||
|
arg.status = radioVal.value |
||||
|
}, |
||||
|
actionColumn: { |
||||
|
width: 300, |
||||
|
title: '操作', |
||||
|
fixed: 'right', |
||||
|
dataIndex: 'action', |
||||
|
slots: { customRender: 'action' }, |
||||
|
}, |
||||
|
}) |
||||
|
|
||||
|
const followStatusList = [ |
||||
|
{ label: '进行中', value: 1 }, |
||||
|
{ label: '生效中', value: 2 }, |
||||
|
{ label: '已终止', value: 3 }, |
||||
|
{ label: '全部', value: '' }, |
||||
|
] |
||||
|
const radioVal = ref<any>('') |
||||
|
function handleRadioChange() { |
||||
|
setPagination({ current: 1 }) |
||||
|
reload() |
||||
|
} |
||||
|
|
||||
|
function onCheckChange(e, item){ |
||||
|
if(e.target.checked){ |
||||
|
verifier.value = item.userId |
||||
|
} |
||||
|
} |
||||
|
const { createMessage } = useMessage() |
||||
|
async function allocateList(id = null){ |
||||
|
if(!verifier.value){ |
||||
|
createMessage.warning('请选择分配人') |
||||
|
return |
||||
|
} |
||||
|
try { |
||||
|
await allocationTask({serviceMatchmaker: verifier.value, id}) |
||||
|
createMessage.success(`分配成功`) |
||||
|
} finally { |
||||
|
reload() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const [registerModal, { openModal, closeModal }] = useModal() |
||||
|
function handleReport(record: any, type = 1) { |
||||
|
record.type = type |
||||
|
openModal(true, {record}) |
||||
|
} |
||||
|
// 操作成功 |
||||
|
function handleSuccess() { |
||||
|
closeModal() |
||||
|
reload() |
||||
|
} |
||||
|
|
||||
|
const router = useRouter() |
||||
|
function toDetail(record: any) { |
||||
|
const { id } = record |
||||
|
router.push({ |
||||
|
query: { id }, |
||||
|
path: '/clue/customer', |
||||
|
}) |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped lang="less"> |
||||
|
.single-line { |
||||
|
overflow: hidden; /* 超出部分隐藏 */ |
||||
|
white-space: nowrap; /* 文本不换行 */ |
||||
|
text-overflow: ellipsis; /* 超出部分显示省略号 */ |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,89 @@ |
|||||
|
<template> |
||||
|
<BasicModal v-bind="$attrs" @ok="handleOk" @register="registerModal"> |
||||
|
<BasicForm @register="registerForm"> |
||||
|
<template #imageList="{ model, field }"> |
||||
|
<OssUpload v-model="model[field]" /> |
||||
|
</template> |
||||
|
</BasicForm> |
||||
|
</BasicModal> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue' |
||||
|
import { modalFormSchema } from './data' |
||||
|
import { useMessage } from '/@/hooks/web/useMessage' |
||||
|
import { OssUpload } from '/@/components/OssUpload' |
||||
|
import { BasicForm, useForm } from '/@/components/Form' |
||||
|
import { BasicModal, useModalInner } from '/@/components/Modal' |
||||
|
import { reportTask, finishTask, getTaskItems } from '/@/api/clue' |
||||
|
|
||||
|
const [registerForm, { resetFields, setFieldsValue, validate, updateSchema }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: modalFormSchema, |
||||
|
baseColProps: { span: 22 }, |
||||
|
showActionButtonGroup: false, |
||||
|
}) |
||||
|
|
||||
|
const id = ref<string>('') |
||||
|
const taskId = ref<string>('') |
||||
|
const type = ref<any>(1) |
||||
|
// const ifUpdate = ref<boolean>(false) |
||||
|
const [registerModal, { setModalProps }] = useModalInner(async (data) => { |
||||
|
const { record } = data |
||||
|
await resetFields() |
||||
|
id.value = record?.id |
||||
|
type.value = record?.type |
||||
|
// ifUpdate.value = !!data.ifUpdate |
||||
|
setModalProps({ |
||||
|
minHeight: 50, |
||||
|
title: type.value === 1 ? `上报任务` : '结束任务', |
||||
|
confirmLoading: false, |
||||
|
}) |
||||
|
|
||||
|
if (type.value === 1) { |
||||
|
const taskList = await getTaskItems({datingStoreCustomerTaskId: record?.id}) |
||||
|
taskId.value = taskList.find((item) => !item.isDelivered).id |
||||
|
console.log(taskId.value) |
||||
|
await updateSchema({ field: 'status', ifShow: false }) |
||||
|
await updateSchema({ field: 'remark', ifShow: true }) |
||||
|
} else { |
||||
|
await updateSchema({ field: 'status', ifShow: true }) |
||||
|
await updateSchema({ field: 'remark', ifShow: false }) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
const { createMessage } = useMessage() |
||||
|
const emits = defineEmits(['success']) |
||||
|
async function handleOk() { |
||||
|
try { |
||||
|
const values = await validate() |
||||
|
values.id = type.value === 1 ? taskId.value : id.value |
||||
|
var imageList: any = [] |
||||
|
Object.keys(values).forEach((key) => { |
||||
|
const val = values[key] |
||||
|
switch (key) { |
||||
|
case 'imageList': |
||||
|
imageList = val?.map?.((item: any) => { |
||||
|
const { url, response, originFileObj } = item |
||||
|
return typeof item === 'string' ? item : url || item?.photoUrl || response?.url || originFileObj?.url |
||||
|
}) |
||||
|
break |
||||
|
} |
||||
|
}) |
||||
|
values.deliveryVoucherList = imageList |
||||
|
|
||||
|
// console.log('values.............', values) |
||||
|
setModalProps({ confirmLoading: true }) |
||||
|
if (type.value === 1) { |
||||
|
await reportTask(values) |
||||
|
createMessage.success(`上报成功!`) |
||||
|
} else { |
||||
|
await finishTask(values) |
||||
|
createMessage.success(`上报已结束!`) |
||||
|
} |
||||
|
emits('success') |
||||
|
} finally { |
||||
|
setModalProps({ confirmLoading: false }) |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
Write
Preview
Loading…
Cancel
Save