Browse Source

no message

master
xpz2018 9 months ago
parent
commit
38522f1b87
40 changed files with 2471 additions and 2295 deletions
  1. 4
      mock/sys/user.ts
  2. 44
      src/api/clue/index.ts
  3. 2
      src/enums/pageEnum.ts
  4. 1
      src/locales/lang/zh-CN/routes/basic.ts
  5. 8
      src/locales/lang/zh-CN/routes/clue.ts
  6. 6
      src/locales/lang/zh-CN/routes/invite.ts
  7. 4
      src/router/helper/menuHelper.ts
  8. 56
      src/router/menu.ts
  9. 8
      src/router/menus/modules/clue.ts
  10. 8
      src/router/menus/modules/invite.ts
  11. 17
      src/router/menus/modules/workbench.ts
  12. 16
      src/router/routes/modules/clue.ts
  13. 16
      src/router/routes/modules/invite.ts
  14. 31
      src/router/routes/workbench.ts
  15. 8
      src/store/modules/permission.ts
  16. 60
      src/views/clue/clueList/data.ts
  17. 48
      src/views/clue/clueList/index.vue
  18. 574
      src/views/clue/cluePool/data.ts
  19. 32
      src/views/clue/cluePool/index.vue
  20. 571
      src/views/clue/components/data.ts
  21. 14
      src/views/clue/components/modal.vue
  22. 2
      src/views/clue/customer/index.vue
  23. 124
      src/views/clue/followlist/data.ts
  24. 171
      src/views/clue/followlist/index.vue
  25. 124
      src/views/clue/poolist/data.ts
  26. 254
      src/views/clue/poolist/index.vue
  27. 42
      src/views/invite/components/data.ts
  28. 54
      src/views/invite/components/modal.vue
  29. 627
      src/views/invite/index/data.ts
  30. 22
      src/views/invite/index/index.vue
  31. 211
      src/views/invite/index/modal.vue
  32. 627
      src/views/invite/list/data.ts
  33. 24
      src/views/invite/list/index.vue
  34. 211
      src/views/invite/list/modal.vue
  35. 124
      src/views/invite/myList/data.ts
  36. 188
      src/views/invite/myList/index.vue
  37. 124
      src/views/invite/seasList/data.ts
  38. 191
      src/views/invite/seasList/index.vue
  39. 109
      src/views/sys/workbench/data.ts
  40. 9
      src/views/sys/workbench/index.vue

4
mock/sys/user.ts

@ -12,7 +12,7 @@ export function createFakeUserList() {
password: '123456',
token:
'QNT iHP4V/g6O5DXHixyNrf7tjJzhv1uzd15gp7AgTwJsmPLbOmqa7ZoSiaGTLfB/eLpbse0PBxScusDqEpdm1ZVRA==',
homePath: '/clue/clueList',
homePath: '/workbench',
roles: [
{
roleName: 'Super Admin',
@ -28,7 +28,7 @@ export function createFakeUserList() {
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=339449197&s=640',
desc: 'tester',
token: 'fakeToken2',
homePath: '/clue/clueList',
homePath: '/workbench',
roles: [
{
roleName: 'Tester',

44
src/api/clue/index.ts

@ -9,7 +9,19 @@ export const getCluePage = (params: any) =>
export const getClueList = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/own-dating-clue',
url: '/dating-clue-service/user/page/allocated-dating-clue-pool/by/clue-team',
params,
})
export const getCluePool = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/own-dating-clue-pool/by/clue-team',
params,
})
export const getClueFollow = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/own-allocated-dating-clue-pool/by/clue-team',
params,
})
@ -29,3 +41,33 @@ export const getClueRecord = (id: string) => defHttp.get<any>({ url: '/dating-cl
export const deleteCluingList = (params: any) => defHttp.post({ url: '/dating-clue-service/user/batch-delete/dating-clue', params })
export const receiveCluing = (params: any) => defHttp.post({ url: '/dating-clue-service/user/collect/dating-clue-public-pool', params })
export const getInvitationPage = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/dating-clue-pool/by/telephone-invitation-team',
params,
})
export const getInvitationList = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/allocated-dating-clue-pool/by/telephone-invitation-team',
params,
})
export const getMyInvitationList = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/own-dating-clue-pool/by/telephone-invitation-team',
params,
})
export const getSeasList = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/dating-clue-public-pool/by/telephone-invitation-team',
params,
})

2
src/enums/pageEnum.ts

@ -2,7 +2,7 @@ export enum PageEnum {
// basic login path
BASE_LOGIN = '/login',
// basic home path
BASE_HOME = '/customer',
BASE_HOME = '/workbench',
// error page path
ERROR_PAGE = '/exception',
// error log page path

1
src/locales/lang/zh-CN/routes/basic.ts

@ -1,4 +1,5 @@
export default {
login: '登录',
workbench: '工作台',
errorLogList: '错误日志列表',
}

8
src/locales/lang/zh-CN/routes/clue.ts

@ -1,6 +1,8 @@
export default {
clue: '线索管理',
cluePool: '线索池',
clueList: '我的线索',
customer: '客户信息'
cluePool: '待分配线索',
clueList: '已分配线索',
customer: '客户信息',
poolist: '我的线索',
followlist: '跟进记录'
}

6
src/locales/lang/zh-CN/routes/invite.ts

@ -1,5 +1,7 @@
export default {
invite: '电邀管理',
index: '线索分配',
list: '我的线索'
index: '待分配线索',
list: '已分配线索',
myList: '我的线索',
seasList: '公海线索'
}

4
src/router/helper/menuHelper.ts

@ -125,12 +125,12 @@ export function transformMenu(menus: any[]): Menu[] {
let element: Menu = {path: item.path, name: item.name, component: 'LAYOUT', redirect: item.redirect, meta: item.meta}
let children: Menu[] = []
item.children?.forEach(menu => {
// 这里只考虑二级菜单,没有做
if(menus.includes(menu.path)){
children.push(cloneDeep(menu))
} else if(item.meta.hideChildrenInMenu && menus.includes(item.path)){
children.push(cloneDeep(menu))
}
})
if(children.length){
element.children = children

56
src/router/menu.ts

@ -1,5 +1,28 @@
import type { Menu } from '/@/router/types'
const workbenchMenu: Menu = {
path: '/workbench',
name: 'Workbench',
component: 'LAYOUT',
redirect: '/workbench/index',
meta: {
orderNo: 90001,
hideChildrenInMenu: true,
icon: 'ant-design:pay-circle-outlined',
title: 'routes.basic.workbench',
},
children: [
{
path: 'index',
name: 'WorkbenchPage',
component: '/sys/workbench/index.vue',
meta: {
title: 'routes.basic.workbench',
},
},
],
}
const clueMenu: Menu = {
path: '/clue',
name: 'clue',
@ -28,6 +51,22 @@ const clueMenu: Menu = {
title: 'routes.clue.clueList',
},
},
{
path: 'poolist',
name: 'Poolist',
component: '/clue/poolist/index.vue',
meta: {
title: 'routes.clue.poolist',
},
},
{
path: 'followlist',
name: 'Followlist',
component: '/clue/followlist/index.vue',
meta: {
title: 'routes.clue.followlist',
},
},
{
path: 'customer',
name: 'Customer',
@ -68,6 +107,22 @@ const inviteMenu: Menu = {
title: 'routes.invite.list',
},
},
{
path: 'myList',
name: 'MyList',
component: '/invite/myList/index.vue',
meta: {
title: 'routes.invite.myList',
},
},
{
path: 'seasList',
name: 'SeasList',
component: '/invite/seasList/index.vue',
meta: {
title: 'routes.invite.seasList',
},
},
],
}
@ -111,6 +166,7 @@ const systemMenu: Menu = {
}
const appMenuList: Menu[] = [
workbenchMenu,
clueMenu,
inviteMenu,
systemMenu,

8
src/router/menus/modules/clue.ts

@ -14,6 +14,14 @@ const clueMenu: MenuModule = {
path: 'clueList',
name: t('routes.clue.clueList'),
},
{
path: 'poolist',
name: t('routes.clue.poolist'),
},
{
path: 'followlist',
name: t('routes.clue.followlist'),
},
{
path: 'customer',
name: t('routes.clue.customer'),

8
src/router/menus/modules/invite.ts

@ -14,6 +14,14 @@ const inviteMenu: MenuModule = {
path: 'list',
name: t('routes.invite.list'),
},
{
path: 'myList',
name: t('routes.invite.myList'),
},
{
path: 'seasList',
name: t('routes.invite.seasList'),
},
],
},
}

17
src/router/menus/modules/workbench.ts

@ -0,0 +1,17 @@
import type { MenuModule } from '/@/router/types'
import { t } from '/@/hooks/web/useI18n'
const workbenchMenu: MenuModule = {
orderNo: 90001,
menu: {
path: '/workbench',
name: t('routes.basic.workbench'),
children: [
{
path: 'index',
name: t('routes.basic.workbench'),
},
],
},
}
export default workbenchMenu

16
src/router/routes/modules/clue.ts

@ -31,6 +31,22 @@ const clueRoute: AppRouteModule = {
title: t('routes.clue.clueList'),
},
},
{
path: 'poolist',
name: 'Poolist',
component: () => import('/src/views/clue/poolist/index.vue'),
meta: {
title: t('routes.clue.poolist'),
},
},
{
path: 'followlist',
name: 'Followlist',
component: () => import('/src/views/clue/followlist/index.vue'),
meta: {
title: t('routes.clue.followlist'),
},
},
{
path: 'customer',
name: 'Customer',

16
src/router/routes/modules/invite.ts

@ -31,6 +31,22 @@ const inviteRoute: AppRouteModule = {
title: t('routes.invite.list'),
},
},
{
path: 'myList',
name: 'MyList',
component: () => import('/src/views/invite/myList/index.vue'),
meta: {
title: t('routes.invite.seasList'),
},
},
{
path: 'seasList',
name: 'SeasList',
component: () => import('/src/views/invite/seasList/index.vue'),
meta: {
title: t('routes.invite.seasList'),
},
},
],
}

31
src/router/routes/workbench.ts

@ -0,0 +1,31 @@
import type { AppRouteModule } from '/@/router/types'
import { LAYOUT } from '/@/router/constant'
import { t } from '/@/hooks/web/useI18n'
const workbenchRoute: AppRouteModule = {
path: '/workbench',
name: 'Workbench',
component: LAYOUT,
redirect: '/workbench/index',
meta: {
hideChildrenInMenu: true,
icon: 'ant-design:pay-circle-outlined',
title: t('routes.basic.workbench'),
orderNo: 90001,
},
children: [
{
path: 'index',
name: 'WorkbenchPage',
component: () => import('@/views/sys/workbench/index.vue'),
meta: {
title: t('routes.basic.workbench'),
icon: 'ant-design:pay-circle-outlined',
hideMenu: true,
},
},
],
}
export default workbenchRoute;

8
src/store/modules/permission.ts

@ -140,9 +140,11 @@ export const usePermissionStore = defineStore({
* @description pathroutes中的affix标记
* */
const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
if (!routes || routes.length === 0) return
// let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME
let homePath: string = routes[1].redirect as string
if (!routes || routes.length === 0) {
return
}
let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME
// let homePath: string = routes[1].redirect as string
userStore.getUserInfo.homePath = homePath || PageEnum.BASE_HOME
// console.log(routes[1].redirect)
function patcher(routes: AppRouteRecordRaw[], parentPath = '') {

60
src/views/clue/clueList/data.ts

@ -1,48 +1,36 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import {
getIncomeList,
getNationList,
getEducationList,
getFamilyTiesList,
getOccupationList,
getBodilyFormList,
getPropertyPermits,
getAccountTypeList,
getIdentityTypeList,
getMaritalStatusList,
getConstellationList,
getCarPurchaseSituation,
} from '/@/api/essentialData'
import { getEducationList, getMaritalStatusList } from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
{ width: 70, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
{ width: 110, title: '手机号码', dataIndex: 'phone' },
{ width: 100, title: '渠道来源', dataIndex: 'channelType',
customRender: ({ text }) => {
return channelList.find((find) => find.value === text)?.label
},
},
// { width: 70, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 110, title: '手机号码', dataIndex: 'phone' },
// { width: 100, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '分配信息', dataIndex: 'allocateInfo', slots: { customRender: 'allocateInfo' } },
// { width: 80, title: '状态', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
{ width: 100, title: '创建人', dataIndex: 'creatorName' },
{ width: 100, title: '核验人', dataIndex: 'verifierName' },
{ width: 100, title: '跟进状态', dataIndex: 'followStatus',
customRender: ({ text }) => {
return followStatusList.find((find) => find.value === text)?.label
},
},
{ width: 160, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
{ width: 100, title: '跟进结果', dataIndex: 'validStatus',
customRender: ({ text }) => {
return validStatusList.find((find) => find.value === text)?.label
},
},
{ width: 160, title: '录入时间', dataIndex: 'creatTime' },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 100, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 100, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '录入时间', dataIndex: 'creatTime' },
]
export const tableFormSchema: FormSchema[] = [
@ -133,4 +121,4 @@ export const tableFormSchema: FormSchema[] = [
component: 'Input',
colProps: { span: 6},
},
]
]

48
src/views/clue/clueList/index.vue

@ -16,12 +16,14 @@
</div>
</template>
<template #userinfo="{ text, record }">
<div class="flex-row">
<div class="flex-row" style="padding-left: 12px;">
<Image style="width: 40px;height: 40px;" :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" />
<div class="flex-col" style="margin-left: 8px;">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.nickName}}</span>
<!-- <span class="single-line" style="font-size: 13px;color: #666;margin: 0 12px;">(ID{{record.id}})</span> -->
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{genderList.find((find) => find.value === record.genderCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.phone">{{record.phone}}</span>
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;">{{record.age}}</span>
@ -32,6 +34,42 @@
</div>
</div>
</template>
<template #allocateInfo="{ text, record }">
<ul class="ant-timeline" style="padding-top: 10px;" v-if="record.datingClueFollowRecordList && record.datingClueFollowRecordList.length">
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;"></span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0px;">
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
</ul>
<div class="flex-row-center-center" style="padding: 8px;" v-else>
<span style="color: #999;">暂无数据</span>
</div>
</template>
<template #action="{ record }">
<TableAction
:actions="[
@ -57,18 +95,18 @@
<script setup lang="ts">
import moment from 'moment/moment'
import { computed, ref, reactive } from 'vue'
import { Card, Image, InputNumber } from 'ant-design-vue'
import { Card, Image, InputNumber, Timeline, TimelineItem, Result } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { tableColumns, tableFormSchema } from './data'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { getClueList } from '/@/api/clue'
import { educationList, maritalList } from '/@/enums/customerEnum'
import { educationList, maritalList, genderList, followStageList } from '/@/enums/customerEnum'
const [registerTable, { reload, setPagination }] = useTable({
bordered: true,
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: true,
showIndexColumn: false,
showTableSetting: false,
api: getClueList,
formConfig: {

574
src/views/clue/cluePool/data.ts

@ -1,5 +1,6 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import moment from 'moment';
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList,} from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
@ -121,574 +122,3 @@ export const tableFormSchema: FormSchema[] = [
colProps: { span: 6},
},
]
import { ref } from 'vue'
import dayjs, { Dayjs } from 'dayjs'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { useAddressData } from '/@/hooks/common'
import {
getIncomeList,
getNationList,
getEducationList,
getFamilyTiesList,
getOccupationList,
getBodilyFormList,
getPropertyPermits,
getAccountTypeList,
getIdentityTypeList,
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: 'genderCode',
label: '性别',
colProps: { span: 8 },
component: 'Select',
required: true,
componentProps: ({ formModel }) => {
return {
options: genderList,
disabled: !!formModel.name && formModel.name !== -1,
onChange: (_: any, v: any) => {
basicInfoData.value.genderValue = v?.label
},
}
},
},
{ field: 'age', label: '年龄', component: 'InputNumber', colProps: { span: 8 },},
{ field: 'nickName', label: '昵称', component: 'Input', colProps: { span: 8 },},
{ field: 'phone', label: '电话号码', component: 'Input', colProps: { span: 8 },},
{ field: 'weChatId', label: '微信号', component: 'Input', colProps: { span: 8 }, },
{ field: 'height', label: '身高(cm)', component: 'InputNumber', colProps: { span: 8 }, },
{ field: 'weight', label: '体重(kg)', component: 'InputNumber', colProps: { span: 8 }, },
// {
// field: 'birthDate',
// label: '出生日期',
// colProps: { span: 8 },
// component: 'DatePicker',
// defaultValue: moment('2001-06-05').format('YYYY-MM-DD 00:00:00'),
// 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: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.education = v?.label
},
},
},
{
field: 'incomeCode',
label: '月收入',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getIncomeList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.income = v?.label
},
},
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.maritalStatusName = v?.label
},
},
},
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
basicInfoData.value.provinceName = v?.[0]?.label
basicInfoData.value.cityName = v?.[1]?.label
basicInfoData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.domicilePlaceProvinceName = v?.[0]?.label
basicInfoData.value.domicilePlaceCityName = v?.[1]?.label
},
}
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.hometownProvinceName = v?.[0]?.label
basicInfoData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.nation = v?.label
},
},
},
{
field: 'bodilyFormCode',
label: '体型',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getBodilyFormList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.bodilyForm = v?.label
},
},
},
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.accountTypeName = v?.label
// },
// },
// },
// {
// field: 'nativePlaceCode',
// label: '籍贯',
// colProps: { span: 8 },
// component: 'Select',
// componentProps: {
// options: domicilePlaceList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.nativePlaceName = v?.label
// },
// },
// },
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
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: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.constellation = v?.label
},
},
},
{
field: 'profilePhoto',
component: 'Upload',
label: '资料头像',
colProps: { span: 8 },
slot: 'profilePhoto',
},
{
field: 'describeInfo',
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: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.maritalStatusName = v?.label
},
},
},
{
field: 'minAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'age',
},
{
field: 'maxAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'minHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'height',
},
{
field: 'maxHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.education = v?.label
},
},
},
{
field: 'minimumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'income',
},
{
field: 'maximumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.provinceName = v?.[0]?.label
demandMarriageMoreData.value.cityName = v?.[1]?.label
demandMarriageMoreData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: domicilePlaceList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.domicilePlaceProvinceName = v?.[0]?.label
demandMarriageMoreData.value.domicilePlaceCityName = v?.[1]?.label
},
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.hometownProvinceName = v?.[0]?.label
demandMarriageMoreData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nation = v?.label
},
},
},
// {
// field: 'bodilyFormCode',
// label: '体型',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getBodilyFormList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.bodilyForm = v?.label
// },
// },
// },
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.accountTypeName = v?.label
// },
// },
// },
{
field: 'nativePlaceCode',
label: '籍贯',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: domicilePlaceList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nativePlaceName = v?.label
},
},
},
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: occupationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
const industry = v?.[0] || {}
const occupation = v?.[1] || {}
demandMarriageMoreData.value.industry = industry.label
demandMarriageMoreData.value.industryCode = industry.value
demandMarriageMoreData.value.occupation = occupation.label
demandMarriageMoreData.value.occupationCode = occupation.value
},
},
},
{
field: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.constellation = v?.label
},
},
},
]

32
src/views/clue/cluePool/index.vue

@ -98,7 +98,7 @@
import { tableColumns, tableFormSchema } from './data'
import { useModal } from '/@/components/Modal'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import ClueModal from './modal.vue'
import ClueModal from '../components/modal.vue'
import { getCluePage, allocateCluing, deleteCluingList } from '/@/api/clue'
import { pageOrganizationMember } from '/@/api/staff/staff'
import { educationList, maritalList } from '/@/enums/customerEnum'
@ -106,12 +106,12 @@
const radioVal = ref<any>('')
const verifier = ref<any>('')
const clueStatusList = [
{ label: '待分配', value: 1 },
{ label: '跟进中', value: 2 },
{ label: '公海线索', value: 3 },
{ label: '全部', value: '' },
]
// const clueStatusList = [
// { label: '', value: 1 },
// { label: '', value: 2 },
// { label: '线', value: 3 },
// { label: '', value: '' },
// ]
const ageModel = reactive({
minAge: '',
@ -132,15 +132,15 @@
showIndexColumn: false,
showTableSetting: false,
api: getCluePage,
rowKey: 'id',
rowSelection: {
type: 'checkbox',
onChange,
// getCheckboxProps(record: Recordable) {
// // Demo: id0
// return { disabled: record.allocationStatus !== 1 };
// },
},
// rowKey: 'id',
// rowSelection: {
// type: 'checkbox',
// onChange,
// // getCheckboxProps(record: Recordable) {
// // // Demo: id0
// // return { disabled: record.allocationStatus !== 1 };
// // },
// },
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,

571
src/views/clue/components/data.ts

@ -0,0 +1,571 @@
import { FormSchema } from '/@/components/Table'
import { ref } from 'vue'
import dayjs, { Dayjs } from 'dayjs'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { useAddressData } from '/@/hooks/common'
import {
getIncomeList,
getNationList,
getEducationList,
getFamilyTiesList,
getOccupationList,
getBodilyFormList,
getPropertyPermits,
getAccountTypeList,
getIdentityTypeList,
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: 'genderCode',
label: '性别',
colProps: { span: 8 },
component: 'Select',
required: true,
componentProps: ({ formModel }) => {
return {
options: genderList,
disabled: !!formModel.name && formModel.name !== -1,
onChange: (_: any, v: any) => {
basicInfoData.value.genderValue = v?.label
},
}
},
},
{ field: 'age', label: '年龄', component: 'InputNumber', colProps: { span: 8 },},
{ field: 'nickName', label: '昵称', component: 'Input', colProps: { span: 8 },},
{ field: 'phone', label: '电话号码', component: 'Input', colProps: { span: 8 },},
{ field: 'weChatId', label: '微信号', component: 'Input', colProps: { span: 8 }, },
{ field: 'height', label: '身高(cm)', component: 'InputNumber', colProps: { span: 8 }, },
{ field: 'weight', label: '体重(kg)', component: 'InputNumber', colProps: { span: 8 }, },
// {
// field: 'birthDate',
// label: '出生日期',
// colProps: { span: 8 },
// component: 'DatePicker',
// defaultValue: moment('2001-06-05').format('YYYY-MM-DD 00:00:00'),
// 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: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.education = v?.label
},
},
},
{
field: 'incomeCode',
label: '月收入',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getIncomeList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.income = v?.label
},
},
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.maritalStatusName = v?.label
},
},
},
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
basicInfoData.value.provinceName = v?.[0]?.label
basicInfoData.value.cityName = v?.[1]?.label
basicInfoData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.domicilePlaceProvinceName = v?.[0]?.label
basicInfoData.value.domicilePlaceCityName = v?.[1]?.label
},
}
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.hometownProvinceName = v?.[0]?.label
basicInfoData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.nation = v?.label
},
},
},
{
field: 'bodilyFormCode',
label: '体型',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getBodilyFormList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.bodilyForm = v?.label
},
},
},
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.accountTypeName = v?.label
// },
// },
// },
// {
// field: 'nativePlaceCode',
// label: '籍贯',
// colProps: { span: 8 },
// component: 'Select',
// componentProps: {
// options: domicilePlaceList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.nativePlaceName = v?.label
// },
// },
// },
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
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: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.constellation = v?.label
},
},
},
{
field: 'profilePhoto',
component: 'Upload',
label: '资料头像',
colProps: { span: 8 },
slot: 'profilePhoto',
},
{
field: 'describeInfo',
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: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.maritalStatusName = v?.label
},
},
},
{
field: 'minAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'age',
},
{
field: 'maxAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'minHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'height',
},
{
field: 'maxHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.education = v?.label
},
},
},
{
field: 'minimumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'income',
},
{
field: 'maximumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.provinceName = v?.[0]?.label
demandMarriageMoreData.value.cityName = v?.[1]?.label
demandMarriageMoreData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: domicilePlaceList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.domicilePlaceProvinceName = v?.[0]?.label
demandMarriageMoreData.value.domicilePlaceCityName = v?.[1]?.label
},
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.hometownProvinceName = v?.[0]?.label
demandMarriageMoreData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nation = v?.label
},
},
},
// {
// field: 'bodilyFormCode',
// label: '体型',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getBodilyFormList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.bodilyForm = v?.label
// },
// },
// },
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.accountTypeName = v?.label
// },
// },
// },
{
field: 'nativePlaceCode',
label: '籍贯',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: domicilePlaceList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nativePlaceName = v?.label
},
},
},
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: occupationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
const industry = v?.[0] || {}
const occupation = v?.[1] || {}
demandMarriageMoreData.value.industry = industry.label
demandMarriageMoreData.value.industryCode = industry.value
demandMarriageMoreData.value.occupation = occupation.label
demandMarriageMoreData.value.occupationCode = occupation.value
},
},
},
{
field: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.constellation = v?.label
},
},
},
]

src/views/clue/cluePool/modal.vue → src/views/clue/components/modal.vue

@ -1,9 +1,9 @@
<template>
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal">
<template v-if="!ifUpdate" #title>
<!-- <template v-if="!ifUpdate" #title>
<span>新增线索</span>
</template>
</template> -->
<div v-if="ifUpdate">
<Result title="请将模板Excel文件导入" v-if="tableListRef.length == 0">
@ -104,9 +104,12 @@
const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
ifUpdate.value = !!data.ifUpdate
const { record } = data
var title :string = ''
if(ifUpdate.value){
title = '导入线索'
tableListRef.value = [];
} else if(record && record.id){
title = '编辑线索'
details.value = await getClueInfo(`${record.id}`)
const { domicilePlaceProvinceCode, domicilePlaceCityCode } = details.value || {}
const domicilePlace = domicilePlaceCityCode && domicilePlaceProvinceCode ? [domicilePlaceProvinceCode, domicilePlaceCityCode] : []
@ -116,6 +119,7 @@
await setFieldsValue({ ...details.value, domicilePlace, address })
activeKey2.value = '1'
} else {
title = '新增线索'
details.value = {}
demandMarriageMoreData.value = {}
basicInfoData.value = {}
@ -123,11 +127,7 @@
await resetFields()
await resetFields3()
}
setModalProps({
minHeight: 50,
confirmLoading: false,
title: ifUpdate.value ? '导入线索' : '新增线索',
})
setModalProps({ minHeight: 50, confirmLoading: false, title })
})
//

2
src/views/clue/customer/index.vue

@ -215,7 +215,7 @@
import { useForm } from '/@/components/Form'
import { formatToDateTime } from '/@/utils/dateUtil'
import { basicSchema, modalFormSchema } from './data'
import { demandMarriageMoreData, demandMarriageSchema } from '/@/views/clue/cluePool/data'
import { demandMarriageMoreData, demandMarriageSchema } from '/@/views/clue/components/data'
import { getClueInfo, editClueRecord, recordClueing, getClueRecord } from '/@/api/clue'
import { genderList, channelList, clueStatusList, followTypeList, followStageList } from '/@/enums/customerEnum'

124
src/views/clue/followlist/data.ts

@ -0,0 +1,124 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList } from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
// { width: 70, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 110, title: '手机号码', dataIndex: 'phone' },
// { width: 100, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '分配信息', dataIndex: 'allocateInfo', slots: { customRender: 'allocateInfo' } },
// { width: 80, title: '状态', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 100, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 100, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '录入时间', dataIndex: 'creatTime' },
]
export const tableFormSchema: FormSchema[] = [
{
field: 'genderCode',
label: '用户性别',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: genderList,
},
},
{
field: 'channelType',
label: '渠道来源',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: channelList,
},
},
// {
// field: 'status',
// label: '状态',
// component: 'Input',
// colProps: { span: 6 },
// },
{
field: 'nickName',
label: '用户昵称',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'phone',
label: '电话号码',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
},
},
{
field: 'age',
label: '年龄',
slot: 'age',
component: 'InputNumber',
colProps: { span: 6 },
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
},
},
{
field: 'createTime',
label: '创建时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'creatorName',
label: '创建人名称',
component: 'Input',
colProps: { span: 6},
},
{
field: 'followTime',
label: '最后跟进时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'verifierName',
label: '核验人名称',
component: 'Input',
colProps: { span: 6},
},
]

171
src/views/clue/followlist/index.vue

@ -0,0 +1,171 @@
<template>
<div class="order-list">
<BasicTable @register="registerTable">
<template #form-age>
<div class="flex-row">
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.minAge" />
<div style="width: 8%" class="flex-row-center-center">-</div>
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.maxAge" />
</div>
</template>
<!-- <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" style="padding-left: 12px;">
<Image style="width: 40px;height: 40px;" :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" />
<div class="flex-col" style="margin-left: 8px;">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.nickName}}</span>
<!-- <span class="single-line" style="font-size: 13px;color: #666;margin: 0 12px;">(ID{{record.id}})</span> -->
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{genderList.find((find) => find.value === record.genderCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.phone">{{record.phone}}</span>
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;">{{record.age}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{educationList.find((find) => find.value === record.educationCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{maritalList.find((find) => find.value === record.maritalStatusCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.occupation">{{record.occupation}}</span>
</div>
</div>
</div>
</template>
<template #allocateInfo="{ text, record }">
<ul class="ant-timeline" style="padding-top: 10px;" v-if="record.datingClueFollowRecordList && record.datingClueFollowRecordList.length">
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;"></span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0px;">
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
</ul>
<div class="flex-row-center-center" style="padding: 8px;" v-else>
<span style="color: #999;">暂无数据</span>
</div>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
label: '详情',
onClick: toDetail.bind(null, record),
},
]"
/>
</template>
</BasicTable>
</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 } from 'vue'
import { Card, Image, InputNumber, Timeline, TimelineItem, Result } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { tableColumns, tableFormSchema } from './data'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { getClueFollow } from '/@/api/clue'
import { educationList, maritalList, genderList, followStageList } from '/@/enums/customerEnum'
const [registerTable, { reload, setPagination }] = useTable({
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: false,
showTableSetting: false,
api: getClueFollow,
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,
},
beforeFetch: (arg) => {
const { createTime, followTime } = arg
if (createTime) {
arg.creatTimeFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00')
arg.creatTimeTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.createTime
}
if (followTime) {
arg.finalFollowTimeFrom = moment(followTime[0]).format('YYYY-MM-DD 00:00:00')
arg.finalFollowTimeTo = moment(followTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.followTime
}
arg.minimumAge = ageModel.minAge
arg.maximumAge = ageModel.maxAge
// arg.followStatus = radioVal.value
},
actionColumn: {
width: 160,
title: '操作',
fixed: 'right',
dataIndex: 'action',
slots: { customRender: 'action' },
},
})
const followStatusList = [
{ label: '待跟进', value: 1 },
{ label: '跟进中', value: 2 },
{ label: '全部', value: '' },
]
const radioVal = ref<any>('')
const ageModel = reactive({
minAge: '',
maxAge: '',
})
function handleRadioChange() {
setPagination({ current: 1 })
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>

124
src/views/clue/poolist/data.ts

@ -0,0 +1,124 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList,} from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
// { width: 60, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 120, title: '手机号码', dataIndex: 'phone' },
// { width: 90, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '录入信息', dataIndex: 'recordInfo', slots: { customRender: 'recordInfo' } },
// { width: 80, title: '状态', dataIndex: 'allocationStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 90, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 90, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '录入时间', dataIndex: 'createTime' },
]
export const tableFormSchema: FormSchema[] = [
{
field: 'genderCode',
label: '用户性别',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: genderList,
},
},
{
field: 'channelType',
label: '渠道来源',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: channelList,
},
},
// {
// field: 'status',
// label: '状态',
// component: 'Input',
// colProps: { span: 6 },
// },
{
field: 'nickName',
label: '用户昵称',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'phone',
label: '电话号码',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
},
},
{
field: 'age',
label: '年龄',
slot: 'age',
component: 'InputNumber',
colProps: { span: 6 },
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
},
},
{
field: 'createTime',
label: '创建时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'creatorName',
label: '创建人名称',
component: 'Input',
colProps: { span: 6},
},
{
field: 'followTime',
label: '最后跟进时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'verifierName',
label: '核验人名称',
component: 'Input',
colProps: { span: 6},
},
]

254
src/views/clue/poolist/index.vue

@ -0,0 +1,254 @@
<template>
<div class="order-list">
<BasicTable @register="registerTable">
<template #form-age>
<div class="flex-row">
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.minAge" />
<div style="width: 8%" class="flex-row-center-center">-</div>
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.maxAge" />
</div>
</template>
<template #toolbar>
<div style="width: 100%; padding: 2px" class="flex-row-center-end">
<!-- <RadioGroup button-style="solid" v-model:value="radioVal" @change="handleRadioChange">
<RadioButton v-for="item in clueStatusList" :key="item.value" :value="item.value">{{item.label}}</RadioButton>
</RadioGroup> -->
<div class="flex-row-center-start">
<Button type="primary" danger :disabled="datingClueIdList.length == 0" @click="handleDelete(null)">删除</Button>
<!-- <Popconfirm placement="bottom" icon="分配线索" :disabled="datingClueIdList.length == 0" @confirm="allocateList(null)">
<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 type="primary" danger style="margin-left: 16px;" :disabled="datingClueIdList.length == 0">分配</Button>
</Popconfirm> -->
<Button style="margin-left: 16px;" @click="handleAdd(true)">批量导入</Button>
<Button :type="'primary'" style="margin-left: 16px;" @click="handleAdd(false)">新增</Button>
</div>
</div>
</template>
<template #userinfo="{ text, record }">
<div class="flex-row" style="padding-left: 12px;">
<Image style="width: 40px;height: 40px;" :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" />
<div class="flex-col" style="margin-left: 8px;">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.nickName}}</span>
<!-- <span class="single-line" style="font-size: 13px;color: #666;margin: 0 12px;">(ID{{record.id}})</span> -->
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;" v-if="record.age">{{record.age}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{educationList.find((find) => find.value === record.educationCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{maritalList.find((find) => find.value === record.maritalStatusCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.occupation">{{record.occupation}}</span>
</div>
</div>
</div>
</template>
<template #recordInfo="{ text, record }">
<div class="flex-col">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.creatorName}}</span>
<!-- <span style="font-size: 13px;color: #666;margin-left: 12px;">{{record.orgName}}</span> -->
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;">{{record.createTime}}</span>
</div>
</div>
</template>
<template #action="{ record }">
<div class="flex-col-center-start">
<Button style="width: 100px;" @click.stop="toDetail(record)">编辑</Button>
<!-- <Popconfirm placement="topRight" :icon="record.allocationStatus == 1 ? '分配' : '重新分配'" @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 danger style="width: 100px;margin-top: 8px;">{{record.allocationStatus == 1 ? '分配' : '重新分配'}}</Button>
</Popconfirm> -->
<Button danger style="width: 100px;margin-top: 8px;" @click.stop="handleDelete(record.id)">删除</Button>
</div>
</template>
</BasicTable>
<ClueModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts">
import { Radio } from 'ant-design-vue'
export default {
name: 'CluePool',
components: { RadioGroup: Radio.Group, RadioButton: Radio.Button },
}
</script>
<script setup lang="ts">
import moment from 'moment/moment'
import { onMounted, reactive, ref } from 'vue'
import { Card, Image, Button, InputNumber, Popconfirm, Checkbox } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { useMessage } from '/@/hooks/web/useMessage'
import { tableColumns, tableFormSchema } from './data'
import { useModal } from '/@/components/Modal'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import ClueModal from '../components/modal.vue'
import { getCluePool, allocateCluing, deleteCluingList } from '/@/api/clue'
import { pageOrganizationMember } from '/@/api/staff/staff'
import { educationList, maritalList } from '/@/enums/customerEnum'
const radioVal = ref<any>('')
const verifier = ref<any>('')
const clueStatusList = [
{ label: '待分配', value: 1 },
{ label: '跟进中', value: 2 },
{ label: '公海线索', value: 3 },
{ label: '全部', value: '' },
]
const ageModel = reactive({
minAge: '',
maxAge: '',
})
const memberList = ref<any[]>([]);
onMounted(async () => {
const result = await pageOrganizationMember({})
memberList.value = result.items
})
const [registerTable, { reload, setPagination, getSelectRowKeys, clearSelectedRowKeys }] = useTable({
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: false,
showTableSetting: false,
api: getCluePool,
rowKey: 'id',
rowSelection: {
type: 'checkbox',
onChange,
// getCheckboxProps(record: Recordable) {
// // Demo: id0
// return { disabled: record.allocationStatus !== 1 };
// },
},
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,
},
beforeFetch: (arg) => {
const { createTime, followTime } = arg
if (createTime) {
arg.creatTimeFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00')
arg.creatTimeTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.createTime
}
if (followTime) {
arg.finalFollowTimeFrom = moment(followTime[0]).format('YYYY-MM-DD 00:00:00')
arg.finalFollowTimeTo = moment(followTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.followTime
}
arg.minimumAge = ageModel.minAge
arg.maximumAge = ageModel.maxAge
arg.allocationStatus = radioVal.value
},
actionColumn: {
width: 160,
title: '操作',
fixed: 'right',
dataIndex: 'action',
slots: { customRender: 'action' },
},
})
function handleRadioChange() {
setPagination({ current: 1 })
datingClueIdList.value = []
reload()
}
const [registerModal, { openModal, closeModal }] = useModal()
function handleAdd(excel) {
openModal(true, {ifUpdate: excel,})
}
//
function handleSuccess() {
closeModal()
reload()
}
const { createMessage } = useMessage()
const router = useRouter()
function toDetail(record: any) {
openModal(true, {record, ifUpdate: false})
// const { id } = record
// router.push({
// query: { id },
// path: '/clue/customer',
// })
}
async function handleDelete(id){
const { createConfirm } = useMessage()
createConfirm({
title: '提示',
iconType: 'warning',
content: `是否确定删除?`,
onOk: () => {
var datingClueIdList: string[] = []
if(id){
datingClueIdList = [id]
} else {
datingClueIdList = getSelectRowKeys()
}
deleteCluingList({datingClueIdList}).then(() => {
createMessage.success('删除成功')
clearSelectedRowKeys()
reload()
})
},
})
}
const datingClueIdList = ref<string[]>([]);
function onChange(selectedRowKeys) {
datingClueIdList.value = selectedRowKeys
}
function onCheckChange(e, item){
if(e.target.checked){
verifier.value = item.userId
}
}
async function allocateList(id = null){
if(!verifier.value){
createMessage.warning('请选择分配人')
return
}
var datingClueIdList: string[] = []
if(id){
datingClueIdList = [id]
} else {
datingClueIdList = getSelectRowKeys()
}
try {
await allocateCluing({verifier: verifier.value, datingClueIdList})
createMessage.success(`分配成功`)
clearSelectedRowKeys()
} finally {
reload()
}
}
</script>
<style scoped lang="less">
.single-line {
overflow: hidden; /* 超出部分隐藏 */
white-space: nowrap; /* 文本不换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
</style>

42
src/views/invite/components/data.ts

@ -0,0 +1,42 @@
import { FormSchema } from '/@/components/Form'
import { followTypeList, followStageList } from '/@/enums/customerEnum'
export const modalFormSchema: FormSchema[] = [
// {
// field: 'datingClueFollowType',
// label: '线索跟进方式',
// component: 'Select',
// required: true,
// componentProps: {
// options: followTypeList,
// },
// },
{
field: 'datingClueFollowStage',
label: '线索跟进阶段',
required: true,
component: 'Select',
componentProps: {
options: followStageList,
},
},
// {
// label: '下次跟进时间',
// component: 'DatePicker',
// field: 'nextFollowTime',
// componentProps: {
// ...dateComProps,
// },
// },
{
field: 'remark',
label: '备注',
required: false,
component: 'InputTextArea',
componentProps: {
autosize: {
minRows: 4,
},
},
},
]

54
src/views/invite/components/modal.vue

@ -0,0 +1,54 @@
<template>
<BasicModal v-bind="$attrs" @ok="handleOk" @register="registerModal">
<BasicForm @register="registerForm" />
</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 { recordClueing } from '/@/api/clue'
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: `上报跟进记录`,
confirmLoading: false,
})
if (!!ifUpdate.value) {
await setFieldsValue({ ...record })
}
})
const { createMessage } = useMessage()
const emits = defineEmits(['success'])
async function handleOk() {
try {
const values = await validate()
values.datingClueId = id.value
// console.log('values.............', values)
setModalProps({ confirmLoading: true })
await recordClueing(values)
createMessage.success(`上报成功!`)
emits('success')
} finally {
setModalProps({ confirmLoading: false })
}
}
</script>

627
src/views/invite/index/data.ts

@ -1,34 +1,36 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import moment from 'moment';
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList,} from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
{ width: 60, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
{ width: 120, title: '手机号码', dataIndex: 'phone' },
{ width: 90, title: '渠道来源', dataIndex: 'channelType',
customRender: ({ text }) => {
return channelList.find((find) => find.value === text)?.label
},
},
{ width: 80, title: '状态', dataIndex: 'allocationStatus',
customRender: ({ text }) => {
return clueStatusList.find((find) => find.value === text)?.label
},
},
{ width: 100, title: '创建人', dataIndex: 'creatorName' },
{ width: 100, title: '核验人', dataIndex: 'verifierName' },
{ width: 90, title: '跟进状态', dataIndex: 'followStatus',
customRender: ({ text }) => {
return followStatusList.find((find) => find.value === text)?.label
},
},
{ width: 150, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
{ width: 90, title: '跟进结果', dataIndex: 'validStatus',
customRender: ({ text }) => {
return validStatusList.find((find) => find.value === text)?.label
},
},
{ width: 150, title: '录入时间', dataIndex: 'createTime' },
// { width: 60, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 120, title: '手机号码', dataIndex: 'phone' },
// { width: 90, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '录入信息', dataIndex: 'recordInfo', slots: { customRender: 'recordInfo' } },
// { width: 80, title: '状态', dataIndex: 'allocationStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 90, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 90, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '录入时间', dataIndex: 'createTime' },
]
export const tableFormSchema: FormSchema[] = [
@ -120,574 +122,3 @@ export const tableFormSchema: FormSchema[] = [
colProps: { span: 6},
},
]
import { ref } from 'vue'
import dayjs, { Dayjs } from 'dayjs'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { useAddressData } from '/@/hooks/common'
import {
getIncomeList,
getNationList,
getEducationList,
getFamilyTiesList,
getOccupationList,
getBodilyFormList,
getPropertyPermits,
getAccountTypeList,
getIdentityTypeList,
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: 'genderCode',
label: '性别',
colProps: { span: 8 },
component: 'Select',
required: true,
componentProps: ({ formModel }) => {
return {
options: genderList,
disabled: !!formModel.name && formModel.name !== -1,
onChange: (_: any, v: any) => {
basicInfoData.value.genderValue = v?.label
},
}
},
},
{ field: 'age', label: '年龄', component: 'InputNumber', colProps: { span: 8 },},
{ field: 'nickName', label: '昵称', component: 'Input', colProps: { span: 8 },},
{ field: 'phone', label: '电话号码', component: 'Input', colProps: { span: 8 },},
{ field: 'weChatId', label: '微信号', component: 'Input', colProps: { span: 8 }, },
{ field: 'height', label: '身高(cm)', component: 'InputNumber', colProps: { span: 8 }, },
{ field: 'weight', label: '体重(kg)', component: 'InputNumber', colProps: { span: 8 }, },
// {
// field: 'birthDate',
// label: '出生日期',
// colProps: { span: 8 },
// component: 'DatePicker',
// defaultValue: moment('2001-06-05').format('YYYY-MM-DD 00:00:00'),
// 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: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.education = v?.label
},
},
},
{
field: 'incomeCode',
label: '月收入',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getIncomeList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.income = v?.label
},
},
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.maritalStatusName = v?.label
},
},
},
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
basicInfoData.value.provinceName = v?.[0]?.label
basicInfoData.value.cityName = v?.[1]?.label
basicInfoData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.domicilePlaceProvinceName = v?.[0]?.label
basicInfoData.value.domicilePlaceCityName = v?.[1]?.label
},
}
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.hometownProvinceName = v?.[0]?.label
basicInfoData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.nation = v?.label
},
},
},
{
field: 'bodilyFormCode',
label: '体型',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getBodilyFormList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.bodilyForm = v?.label
},
},
},
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.accountTypeName = v?.label
// },
// },
// },
// {
// field: 'nativePlaceCode',
// label: '籍贯',
// colProps: { span: 8 },
// component: 'Select',
// componentProps: {
// options: domicilePlaceList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.nativePlaceName = v?.label
// },
// },
// },
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
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: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.constellation = v?.label
},
},
},
{
field: 'profilePhoto',
component: 'Upload',
label: '资料头像',
colProps: { span: 8 },
slot: 'profilePhoto',
},
{
field: 'describeInfo',
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: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.maritalStatusName = v?.label
},
},
},
{
field: 'minAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'age',
},
{
field: 'maxAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'minHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'height',
},
{
field: 'maxHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.education = v?.label
},
},
},
{
field: 'minimumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'income',
},
{
field: 'maximumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.provinceName = v?.[0]?.label
demandMarriageMoreData.value.cityName = v?.[1]?.label
demandMarriageMoreData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: domicilePlaceList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.domicilePlaceProvinceName = v?.[0]?.label
demandMarriageMoreData.value.domicilePlaceCityName = v?.[1]?.label
},
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.hometownProvinceName = v?.[0]?.label
demandMarriageMoreData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nation = v?.label
},
},
},
// {
// field: 'bodilyFormCode',
// label: '体型',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getBodilyFormList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.bodilyForm = v?.label
// },
// },
// },
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.accountTypeName = v?.label
// },
// },
// },
{
field: 'nativePlaceCode',
label: '籍贯',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: domicilePlaceList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nativePlaceName = v?.label
},
},
},
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: occupationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
const industry = v?.[0] || {}
const occupation = v?.[1] || {}
demandMarriageMoreData.value.industry = industry.label
demandMarriageMoreData.value.industryCode = industry.value
demandMarriageMoreData.value.occupation = occupation.label
demandMarriageMoreData.value.occupationCode = occupation.value
},
},
},
{
field: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.constellation = v?.label
},
},
},
]

22
src/views/invite/index/index.vue

@ -14,9 +14,9 @@
<RadioButton v-for="item in clueStatusList" :key="item.value" :value="item.value">{{item.label}}</RadioButton>
</RadioGroup>
<div class="flex-row-center-start">
<Popconfirm placement="bottom" icon="分配线索" :disabled="datingClueIdList.length == 0" @confirm="allocateList(null)">
<Popconfirm placement="bottomRight" icon="分配线索" :disabled="datingClueIdList.length == 0" @confirm="allocateList(null)">
<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">
<div class="flex-row-center-start" style="padding: 8px 8px 8px 0px;border-bottom: 1px solid #ddd;min-width: 185px;" 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>
@ -25,8 +25,6 @@
</template>
<Button type="primary" danger :disabled="datingClueIdList.length == 0">分配</Button>
</Popconfirm>
<Button style="margin-left: 16px;" @click="handleAdd(true)">批量导入</Button>
<Button :type="'primary'" style="margin-left: 16px;" @click="handleAdd(false)">新增</Button>
</div>
</div>
</template>
@ -53,7 +51,7 @@
<span style="color: #999;">|</span>
<Popconfirm placement="topRight" :icon="record.allocationStatus == 1 ? '分配' : '重新分配'" @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">
<div class="flex-row-center-start" style="padding: 8px 8px 8px 0px;border-bottom: 1px solid #ddd;min-width: 160px;" 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>
@ -65,7 +63,6 @@
</div>
</template>
</BasicTable>
<ClueModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
@ -86,8 +83,7 @@
import { tableColumns, tableFormSchema } from './data'
import { useModal } from '/@/components/Modal'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import ClueModal from './modal.vue'
import { getCluePage, allocateCluing } from '/@/api/clue'
import { getInvitationPage, allocateCluing } from '/@/api/clue'
import { pageOrganizationMember } from '/@/api/staff/staff'
import { educationList, maritalList } from '/@/enums/customerEnum'
@ -119,15 +115,15 @@
columns: tableColumns,
showIndexColumn: true,
showTableSetting: false,
api: getCluePage,
api: getInvitationPage,
rowKey: 'id',
rowSelection: {
type: 'checkbox',
onChange,
getCheckboxProps(record: any) {
// Demo: id0
return { disabled: record.allocationStatus !== 1 };
},
// getCheckboxProps(record: any) {
// // Demo: id0
// return { disabled: record.allocationStatus !== 1 };
// },
},
formConfig: {
labelWidth: 120,

211
src/views/invite/index/modal.vue

@ -1,211 +0,0 @@
<template>
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal">
<template v-if="!ifUpdate" #title>
<span>新增线索</span>
</template>
<div v-if="ifUpdate">
<Result title="请将模板Excel文件导入" v-if="tableListRef.length == 0">
<template #icon>
<Icon icon="ant-design:cloud-upload-outlined" size="150px" color="#d6d6d6"/>
</template>
<template #extra>
<ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD">
<Button>导入Excel</Button>
</ImpExcel>
</template>
</Result>
<BasicTable v-for="(table, index) in tableListRef"
:key="index"
:columns="table.columns"
:canResize="false"
:dataSource="table.dataSource"
:pagination="{ pageSize: 10 }"
/>
</div>
<div class="flex-col" v-else>
<Tabs tab-position="left" v-model:activeKey="activeKey2" :animated="false">
<TabPane key="1" tab="个人资料">
<BasicForm @register="registerForm" style="padding: 16px 48px 0px 0px;" >
<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 #income="{ model }">
<div class="flex-row-center-start">
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minimumIncome']" />
<span style="margin: 0 5px">-</span>
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maximumIncome']" />
</div>
</template>
</BasicForm>
</TabPane>
</Tabs>
</div>
<template v-if="ifUpdate" #footer>
<div class="flex-row-center-space">
<ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD">
<Button type="primary">导入Excel</Button>
</ImpExcel>
<div class="flex-row-center-start">
<Button @click="close">取消</Button>
<Button type="primary" @click="handleOk">确定</Button>
</div>
</div>
</template>
</BasicModal>
</template>
<script setup lang="ts">
import { ref, unref } from 'vue'
import { Tabs, TabPane, Button, Result, InputNumber } from 'ant-design-vue'
import Icon from '/@/components/Icon'
import { modalFormSchema, basicInfoData, demandMarriageSchema, demandMarriageMoreData } from './data'
import { ImpExcel, ExcelData } from '/@/components/Excel';
import { BasicTable, BasicColumn } from '/@/components/Table'
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, importClueRecord } from '/@/api/clue'
const activeKey2 = ref<string>('1')
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue }] =
useForm({
labelWidth: 108,
schemas: modalFormSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
const ifUpdate = ref<boolean>(false)
const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
ifUpdate.value = !!data.ifUpdate
if(ifUpdate.value){
tableListRef.value = [];
} else {
demandMarriageMoreData.value = {}
basicInfoData.value = {}
activeKey2.value = '1'
await resetFields()
await resetFields3()
}
setModalProps({
minHeight: 50,
confirmLoading: false,
title: ifUpdate.value ? '导入线索' : '新增线索',
})
})
//
const [registerForm3, { getFieldsValue: getFieldsValue3, resetFields: resetFields3 }] =
useForm({
labelWidth: 100,
schemas: demandMarriageSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
function close(){
closeModal()
}
function uploadAvatarAfter(value) {
//
setFieldsValue({
profilePhoto: value,
});
}
const { createMessage } = useMessage()
const emits = defineEmits(['success'])
async function handleOk() {
try {
if(ifUpdate.value){
await importClueRecord({keyList: tableListRef.value[0].header, dataList: tableListRef.value[0].dataSource})
createMessage.success(`导入成功!`)
emits('success')
return
}
await validate()
const values: any = getFieldsValue()
// console.log({...values, ...basicInfoData.value})
setModalProps({ confirmLoading: true })
const { domicilePlace, address } = values || {}
const demandInfo: any = getFieldsValue3()
if(demandInfo){
const address1 = demandInfo.address
demandInfo.cityCode = address1?.[1]
demandInfo.provinceCode = address1?.[0]
demandInfo.districtCode = address1?.[2]
const domicilePlace1 = demandInfo.domicilePlace
demandInfo.domicilePlaceCityCode = domicilePlace1?.[1]
demandInfo.domicilePlaceProvinceCode = domicilePlace1?.[0]
}
const datingClueDemand = { ...demandInfo, ...demandMarriageMoreData.value }
const param = {
...values,
channelType: 1,
datingClueDemand,
cityCode: address?.[1],
provinceCode: address?.[0],
districtCode: address?.[2],
domicilePlaceCityCode: domicilePlace?.[1],
domicilePlaceProvinceCode: domicilePlace?.[0]
}
await createClueRecord(param)
createMessage.success(`新增成功!`)
emits('success')
} finally {
setModalProps({ confirmLoading: false })
}
}
const tableListRef = ref<{ title: string; columns?: any[]; dataSource?: any[]; header:any[];}[]>([]);
function loadDataSuccess(excelDataList: ExcelData[]) {
tableListRef.value = [];
console.log(excelDataList);
for (const excelData of excelDataList) {
const { header, results, meta: { sheetName }, } = excelData;
const columns: BasicColumn[] = [];
for (const title of header) {
columns.push({ title, dataIndex: title });
}
tableListRef.value.push({ title: sheetName, dataSource: results, columns, header });
}
}
</script>
<style scoped lang="less">
::v-deep .ant-input-number {
min-width: 60px;
width: 100% !important;
max-width: 100%;
}
</style>

627
src/views/invite/list/data.ts

@ -1,34 +1,36 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import moment from 'moment';
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList,} from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
{ width: 60, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
{ width: 120, title: '手机号码', dataIndex: 'phone' },
{ width: 90, title: '渠道来源', dataIndex: 'channelType',
customRender: ({ text }) => {
return channelList.find((find) => find.value === text)?.label
},
},
{ width: 80, title: '状态', dataIndex: 'allocationStatus',
customRender: ({ text }) => {
return clueStatusList.find((find) => find.value === text)?.label
},
},
{ width: 100, title: '创建人', dataIndex: 'creatorName' },
{ width: 100, title: '核验人', dataIndex: 'verifierName' },
{ width: 90, title: '跟进状态', dataIndex: 'followStatus',
customRender: ({ text }) => {
return followStatusList.find((find) => find.value === text)?.label
},
},
{ width: 150, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
{ width: 90, title: '跟进结果', dataIndex: 'validStatus',
customRender: ({ text }) => {
return validStatusList.find((find) => find.value === text)?.label
},
},
{ width: 150, title: '录入时间', dataIndex: 'createTime' },
// { width: 60, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 120, title: '手机号码', dataIndex: 'phone' },
// { width: 90, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '录入信息', dataIndex: 'recordInfo', slots: { customRender: 'recordInfo' } },
// { width: 80, title: '状态', dataIndex: 'allocationStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 90, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 90, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 150, title: '录入时间', dataIndex: 'createTime' },
]
export const tableFormSchema: FormSchema[] = [
@ -120,574 +122,3 @@ export const tableFormSchema: FormSchema[] = [
colProps: { span: 6},
},
]
import { ref } from 'vue'
import dayjs, { Dayjs } from 'dayjs'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { useAddressData } from '/@/hooks/common'
import {
getIncomeList,
getNationList,
getEducationList,
getFamilyTiesList,
getOccupationList,
getBodilyFormList,
getPropertyPermits,
getAccountTypeList,
getIdentityTypeList,
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: 'genderCode',
label: '性别',
colProps: { span: 8 },
component: 'Select',
required: true,
componentProps: ({ formModel }) => {
return {
options: genderList,
disabled: !!formModel.name && formModel.name !== -1,
onChange: (_: any, v: any) => {
basicInfoData.value.genderValue = v?.label
},
}
},
},
{ field: 'age', label: '年龄', component: 'InputNumber', colProps: { span: 8 },},
{ field: 'nickName', label: '昵称', component: 'Input', colProps: { span: 8 },},
{ field: 'phone', label: '电话号码', component: 'Input', colProps: { span: 8 },},
{ field: 'weChatId', label: '微信号', component: 'Input', colProps: { span: 8 }, },
{ field: 'height', label: '身高(cm)', component: 'InputNumber', colProps: { span: 8 }, },
{ field: 'weight', label: '体重(kg)', component: 'InputNumber', colProps: { span: 8 }, },
// {
// field: 'birthDate',
// label: '出生日期',
// colProps: { span: 8 },
// component: 'DatePicker',
// defaultValue: moment('2001-06-05').format('YYYY-MM-DD 00:00:00'),
// 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: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.education = v?.label
},
},
},
{
field: 'incomeCode',
label: '月收入',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getIncomeList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.income = v?.label
},
},
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.maritalStatusName = v?.label
},
},
},
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
basicInfoData.value.provinceName = v?.[0]?.label
basicInfoData.value.cityName = v?.[1]?.label
basicInfoData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.domicilePlaceProvinceName = v?.[0]?.label
basicInfoData.value.domicilePlaceCityName = v?.[1]?.label
},
}
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
basicInfoData.value.hometownProvinceName = v?.[0]?.label
basicInfoData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.nation = v?.label
},
},
},
{
field: 'bodilyFormCode',
label: '体型',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getBodilyFormList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.bodilyForm = v?.label
},
},
},
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.accountTypeName = v?.label
// },
// },
// },
// {
// field: 'nativePlaceCode',
// label: '籍贯',
// colProps: { span: 8 },
// component: 'Select',
// componentProps: {
// options: domicilePlaceList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// basicInfoData.value.nativePlaceName = v?.label
// },
// },
// },
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
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: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.constellation = v?.label
},
},
},
{
field: 'profilePhoto',
component: 'Upload',
label: '资料头像',
colProps: { span: 8 },
slot: 'profilePhoto',
},
{
field: 'describeInfo',
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: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.maritalStatusName = v?.label
},
},
},
{
field: 'minAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'age',
},
{
field: 'maxAge',
label: '年龄',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'minHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'height',
},
{
field: 'maxHeight',
label: '身高',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.education = v?.label
},
},
},
{
field: 'minimumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
slot: 'income',
},
{
field: 'maximumIncome',
label: '月收入',
colProps: { span: 8 },
component: 'InputNumber',
ifShow: false,
},
{ field: 'childrenNum', label: '孩子数量', component: 'InputNumber', colProps: { span: 8 }, },
{
field: 'address',
label: '现居住地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: addressList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.provinceName = v?.[0]?.label
demandMarriageMoreData.value.cityName = v?.[1]?.label
demandMarriageMoreData.value.districtName = v?.[2]?.label
},
},
},
{
field: 'domicilePlace',
label: '户口所在地',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: domicilePlaceList,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.domicilePlaceProvinceName = v?.[0]?.label
demandMarriageMoreData.value.domicilePlaceCityName = v?.[1]?.label
},
},
},
{
field: 'hometown',
label: '家乡',
colProps: { span: 8 },
component: 'Cascader',
componentProps: () => {
return {
options: domicilePlaceList.value,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.hometownProvinceName = v?.[0]?.label
demandMarriageMoreData.value.hometownCityName = v?.[1]?.label
},
}
},
},
{
field: 'nationCode',
label: '民族',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'cn',
valueField: 'id',
api: getNationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nation = v?.label
},
},
},
// {
// field: 'bodilyFormCode',
// label: '体型',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getBodilyFormList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.bodilyForm = v?.label
// },
// },
// },
// {
// field: 'accountTypeCode',
// label: '户口',
// colProps: { span: 8 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getAccountTypeList,
// getPopupContainer: () => document.body,
// onChange: (_: any, v: any) => {
// demandMarriageMoreData.value.accountTypeName = v?.label
// },
// },
// },
{
field: 'nativePlaceCode',
label: '籍贯',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: domicilePlaceList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.nativePlaceName = v?.label
},
},
},
{
label: '职业',
field: 'occupationList',
colProps: { span: 8 },
component: 'Cascader',
componentProps: {
options: occupationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
const industry = v?.[0] || {}
const occupation = v?.[1] || {}
demandMarriageMoreData.value.industry = industry.label
demandMarriageMoreData.value.industryCode = industry.value
demandMarriageMoreData.value.occupation = occupation.label
demandMarriageMoreData.value.occupationCode = occupation.value
},
},
},
{
field: 'onlyChild',
label: '是否独生子女',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: [
{ label: '是', value: 1 },
{ label: '否', value: 0 },
],
},
},
{
field: 'propertyPermitsCode',
label: '购房情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getPropertyPermits,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.propertyPermits = v?.label
},
},
},
{
field: 'carPurchaseSituationCode',
label: '购车情况',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getCarPurchaseSituation,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.carPurchaseSituation = v?.label
},
},
},
{
field: 'constellationCode',
label: '星座',
colProps: { span: 8 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getConstellationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
demandMarriageMoreData.value.constellation = v?.label
},
},
},
]

24
src/views/invite/list/index.vue

@ -73,7 +73,6 @@
</div>
</template>
</BasicTable>
<ClueModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
@ -94,8 +93,7 @@
import { tableColumns, tableFormSchema } from './data'
import { useModal } from '/@/components/Modal'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import ClueModal from './modal.vue'
import { getCluePage, allocateCluing } from '/@/api/clue'
import { getInvitationList, allocateCluing } from '/@/api/clue'
import { pageOrganizationMember } from '/@/api/staff/staff'
import { educationList, maritalList } from '/@/enums/customerEnum'
@ -127,16 +125,16 @@
columns: tableColumns,
showIndexColumn: true,
showTableSetting: false,
api: getCluePage,
rowKey: 'id',
rowSelection: {
type: 'checkbox',
onChange,
getCheckboxProps(record: Recordable) {
// Demo: id0
return { disabled: record.allocationStatus !== 1 };
},
},
api: getInvitationList,
// rowKey: 'id',
// rowSelection: {
// type: 'checkbox',
// onChange,
// getCheckboxProps(record: Recordable) {
// // Demo: id0
// return { disabled: record.allocationStatus !== 1 };
// },
// },
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,

211
src/views/invite/list/modal.vue

@ -1,211 +0,0 @@
<template>
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal">
<template v-if="!ifUpdate" #title>
<span>新增线索</span>
</template>
<div v-if="ifUpdate">
<Result title="请将模板Excel文件导入" v-if="tableListRef.length == 0">
<template #icon>
<Icon icon="ant-design:cloud-upload-outlined" size="150px" color="#d6d6d6"/>
</template>
<template #extra>
<ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD">
<Button>导入Excel</Button>
</ImpExcel>
</template>
</Result>
<BasicTable v-for="(table, index) in tableListRef"
:key="index"
:columns="table.columns"
:canResize="false"
:dataSource="table.dataSource"
:pagination="{ pageSize: 10 }"
/>
</div>
<div class="flex-col" v-else>
<Tabs tab-position="left" v-model:activeKey="activeKey2" :animated="false">
<TabPane key="1" tab="个人资料">
<BasicForm @register="registerForm" style="padding: 16px 48px 0px 0px;" >
<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 #income="{ model }">
<div class="flex-row-center-start">
<InputNumber placeholder="请输入" :min="0" v-model:value="model['minimumIncome']" />
<span style="margin: 0 5px">-</span>
<InputNumber placeholder="请输入" :min="0" v-model:value="model['maximumIncome']" />
</div>
</template>
</BasicForm>
</TabPane>
</Tabs>
</div>
<template v-if="ifUpdate" #footer>
<div class="flex-row-center-space">
<ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD">
<Button type="primary">导入Excel</Button>
</ImpExcel>
<div class="flex-row-center-start">
<Button @click="close">取消</Button>
<Button type="primary" @click="handleOk">确定</Button>
</div>
</div>
</template>
</BasicModal>
</template>
<script setup lang="ts">
import { ref, unref } from 'vue'
import { Tabs, TabPane, Button, Result, InputNumber } from 'ant-design-vue'
import Icon from '/@/components/Icon'
import { modalFormSchema, basicInfoData, demandMarriageSchema, demandMarriageMoreData } from './data'
import { ImpExcel, ExcelData } from '/@/components/Excel';
import { BasicTable, BasicColumn } from '/@/components/Table'
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, importClueRecord } from '/@/api/clue'
const activeKey2 = ref<string>('1')
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue }] =
useForm({
labelWidth: 108,
schemas: modalFormSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
const ifUpdate = ref<boolean>(false)
const [registerModal, { closeModal, setModalProps }] = useModalInner(async (data) => {
ifUpdate.value = !!data.ifUpdate
if(ifUpdate.value){
tableListRef.value = [];
} else {
demandMarriageMoreData.value = {}
basicInfoData.value = {}
activeKey2.value = '1'
await resetFields()
await resetFields3()
}
setModalProps({
minHeight: 50,
confirmLoading: false,
title: ifUpdate.value ? '导入线索' : '新增线索',
})
})
//
const [registerForm3, { getFieldsValue: getFieldsValue3, resetFields: resetFields3 }] =
useForm({
labelWidth: 100,
schemas: demandMarriageSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
function close(){
closeModal()
}
function uploadAvatarAfter(value) {
//
setFieldsValue({
profilePhoto: value,
});
}
const { createMessage } = useMessage()
const emits = defineEmits(['success'])
async function handleOk() {
try {
if(ifUpdate.value){
await importClueRecord({keyList: tableListRef.value[0].header, dataList: tableListRef.value[0].dataSource})
createMessage.success(`导入成功!`)
emits('success')
return
}
await validate()
const values: any = getFieldsValue()
// console.log({...values, ...basicInfoData.value})
setModalProps({ confirmLoading: true })
const { domicilePlace, address } = values || {}
const demandInfo: any = getFieldsValue3()
if(demandInfo){
const address1 = demandInfo.address
demandInfo.cityCode = address1?.[1]
demandInfo.provinceCode = address1?.[0]
demandInfo.districtCode = address1?.[2]
const domicilePlace1 = demandInfo.domicilePlace
demandInfo.domicilePlaceCityCode = domicilePlace1?.[1]
demandInfo.domicilePlaceProvinceCode = domicilePlace1?.[0]
}
const datingClueDemand = { ...demandInfo, ...demandMarriageMoreData.value }
const param = {
...values,
channelType: 1,
datingClueDemand,
cityCode: address?.[1],
provinceCode: address?.[0],
districtCode: address?.[2],
domicilePlaceCityCode: domicilePlace?.[1],
domicilePlaceProvinceCode: domicilePlace?.[0]
}
await createClueRecord(param)
createMessage.success(`新增成功!`)
emits('success')
} finally {
setModalProps({ confirmLoading: false })
}
}
const tableListRef = ref<{ title: string; columns?: any[]; dataSource?: any[]; header:any[];}[]>([]);
function loadDataSuccess(excelDataList: ExcelData[]) {
tableListRef.value = [];
console.log(excelDataList);
for (const excelData of excelDataList) {
const { header, results, meta: { sheetName }, } = excelData;
const columns: BasicColumn[] = [];
for (const title of header) {
columns.push({ title, dataIndex: title });
}
tableListRef.value.push({ title: sheetName, dataSource: results, columns, header });
}
}
</script>
<style scoped lang="less">
::v-deep .ant-input-number {
min-width: 60px;
width: 100% !important;
max-width: 100%;
}
</style>

124
src/views/invite/myList/data.ts

@ -0,0 +1,124 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList } from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
// { width: 70, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 110, title: '手机号码', dataIndex: 'phone' },
// { width: 100, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '分配信息', dataIndex: 'allocateInfo', slots: { customRender: 'allocateInfo' } },
// { width: 80, title: '状态', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 100, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 100, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '录入时间', dataIndex: 'creatTime' },
]
export const tableFormSchema: FormSchema[] = [
{
field: 'genderCode',
label: '用户性别',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: genderList,
},
},
{
field: 'channelType',
label: '渠道来源',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: channelList,
},
},
// {
// field: 'status',
// label: '状态',
// component: 'Input',
// colProps: { span: 6 },
// },
{
field: 'nickName',
label: '用户昵称',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'phone',
label: '电话号码',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
},
},
{
field: 'age',
label: '年龄',
slot: 'age',
component: 'InputNumber',
colProps: { span: 6 },
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
},
},
{
field: 'createTime',
label: '创建时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'creatorName',
label: '创建人名称',
component: 'Input',
colProps: { span: 6},
},
{
field: 'followTime',
label: '最后跟进时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'verifierName',
label: '核验人名称',
component: 'Input',
colProps: { span: 6},
},
]

188
src/views/invite/myList/index.vue

@ -0,0 +1,188 @@
<template>
<div class="order-list">
<BasicTable @register="registerTable">
<template #form-age>
<div class="flex-row">
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.minAge" />
<div style="width: 8%" class="flex-row-center-center">-</div>
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.maxAge" />
</div>
</template>
<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" style="padding-left: 12px;">
<Image style="width: 40px;height: 40px;" :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" />
<div class="flex-col" style="margin-left: 8px;">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.nickName}}</span>
<!-- <span class="single-line" style="font-size: 13px;color: #666;margin: 0 12px;">(ID{{record.id}})</span> -->
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{genderList.find((find) => find.value === record.genderCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.phone">{{record.phone}}</span>
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;">{{record.age}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{educationList.find((find) => find.value === record.educationCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{maritalList.find((find) => find.value === record.maritalStatusCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.occupation">{{record.occupation}}</span>
</div>
</div>
</div>
</template>
<template #allocateInfo="{ text, record }">
<ul class="ant-timeline" style="padding-top: 10px;" v-if="record.datingClueFollowRecordList && record.datingClueFollowRecordList.length">
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;"></span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0px;">
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
</ul>
<div class="flex-row-center-center" style="padding: 8px;" v-else>
<span style="color: #999;">暂无数据</span>
</div>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
label: '详情',
onClick: toDetail.bind(null, record),
},
{
label: '跟进',
onClick: handleReport.bind(null, record),
},
]"
/>
</template>
</BasicTable>
<FollowModal @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 } from 'vue'
import { Card, Image, InputNumber, Timeline, TimelineItem, Result } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { tableColumns, tableFormSchema } from './data'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { useModal } from '/@/components/Modal'
import FollowModal from '../components/modal.vue'
import { getMyInvitationList } from '/@/api/clue'
import { educationList, maritalList, genderList, followStageList } from '/@/enums/customerEnum'
const [registerTable, { reload, setPagination }] = useTable({
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: false,
showTableSetting: false,
api: getMyInvitationList,
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,
},
beforeFetch: (arg) => {
const { createTime, followTime } = arg
if (createTime) {
arg.creatTimeFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00')
arg.creatTimeTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.createTime
}
if (followTime) {
arg.finalFollowTimeFrom = moment(followTime[0]).format('YYYY-MM-DD 00:00:00')
arg.finalFollowTimeTo = moment(followTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.followTime
}
arg.minimumAge = ageModel.minAge
arg.maximumAge = ageModel.maxAge
arg.followStatus = radioVal.value
},
actionColumn: {
width: 160,
title: '操作',
fixed: 'right',
dataIndex: 'action',
slots: { customRender: 'action' },
},
})
const followStatusList = [
{ label: '待跟进', value: 1 },
{ label: '跟进中', value: 2 },
{ label: '全部', value: '' },
]
const radioVal = ref<any>('')
const ageModel = reactive({
minAge: '',
maxAge: '',
})
function handleRadioChange() {
setPagination({ current: 1 })
reload()
}
const router = useRouter()
function toDetail(record: any) {
const { id } = record
router.push({
query: { id },
path: '/clue/customer',
})
}
const [registerModal, { openModal, closeModal }] = useModal()
function handleReport(record: any) {
openModal(true, {record})
}
//
function handleSuccess() {
closeModal()
reload()
}
</script>
<style scoped lang="less">
.single-line {
overflow: hidden; /* 超出部分隐藏 */
white-space: nowrap; /* 文本不换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
</style>

124
src/views/invite/seasList/data.ts

@ -0,0 +1,124 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, channelList, clueStatusList, followStatusList, validStatusList } from '/@/enums/customerEnum'
import { getEducationList, getMaritalStatusList } from '/@/api/essentialData'
export const tableColumns: BasicColumn[] = [
{ title: '用户信息', dataIndex: 'userinfo', slots: { customRender: 'userinfo' } },
// { width: 70, title: '性别', dataIndex: 'genderCode', customRender: ({ text }) => { return genderList.find((find) => find.value === text)?.label} },
// { width: 110, title: '手机号码', dataIndex: 'phone' },
// { width: 100, title: '渠道来源', dataIndex: 'channelType',
// customRender: ({ text }) => {
// return channelList.find((find) => find.value === text)?.label
// },
// },
{ title: '分配信息', dataIndex: 'allocateInfo', slots: { customRender: 'allocateInfo' } },
// { width: 80, title: '状态', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return clueStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 100, title: '创建人', dataIndex: 'creatorName' },
// { width: 100, title: '核验人', dataIndex: 'verifierName' },
// { width: 100, title: '跟进状态', dataIndex: 'followStatus',
// customRender: ({ text }) => {
// return followStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '最后跟进时间', dataIndex: 'finalFollowTime' },
// { width: 100, title: '跟进结果', dataIndex: 'validStatus',
// customRender: ({ text }) => {
// return validStatusList.find((find) => find.value === text)?.label
// },
// },
// { width: 160, title: '录入时间', dataIndex: 'creatTime' },
]
export const tableFormSchema: FormSchema[] = [
{
field: 'genderCode',
label: '用户性别',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: genderList,
},
},
{
field: 'channelType',
label: '渠道来源',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: channelList,
},
},
// {
// field: 'status',
// label: '状态',
// component: 'Input',
// colProps: { span: 6 },
// },
{
field: 'nickName',
label: '用户昵称',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'phone',
label: '电话号码',
component: 'Input',
colProps: { span: 6 },
},
{
field: 'maritalStatusCode',
label: '婚姻状况',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getMaritalStatusList,
},
},
{
field: 'age',
label: '年龄',
slot: 'age',
component: 'InputNumber',
colProps: { span: 6 },
},
{
field: 'educationCode',
label: '学历',
colProps: { span: 6 },
component: 'ApiSelect',
componentProps: {
labelField: 'desc',
api: getEducationList,
},
},
{
field: 'createTime',
label: '创建时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'creatorName',
label: '创建人名称',
component: 'Input',
colProps: { span: 6},
},
{
field: 'followTime',
label: '最后跟进时间',
component: 'RangePicker',
colProps: { span: 6 },
},
{
field: 'verifierName',
label: '核验人名称',
component: 'Input',
colProps: { span: 6},
},
]

191
src/views/invite/seasList/index.vue

@ -0,0 +1,191 @@
<template>
<div class="order-list">
<BasicTable @register="registerTable">
<template #form-age>
<div class="flex-row">
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.minAge" />
<div style="width: 8%" class="flex-row-center-center">-</div>
<InputNumber placeholder="请输入" style="width: 46%" v-model:value="ageModel.maxAge" />
</div>
</template>
<!-- <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" style="padding-left: 12px;">
<Image style="width: 40px;height: 40px;" :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" />
<div class="flex-col" style="margin-left: 8px;">
<div class="flex-row">
<span class="single-line" style="font-size: 14px;color: #333;font-weight: bold;max-width: 160px;">{{record.nickName}}</span>
<!-- <span class="single-line" style="font-size: 13px;color: #666;margin: 0 12px;">(ID{{record.id}})</span> -->
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{genderList.find((find) => find.value === record.genderCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.phone">{{record.phone}}</span>
</div>
<div class="flex-row">
<span style="font-size: 13px;color: #666;">{{record.age}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{educationList.find((find) => find.value === record.educationCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;">{{maritalList.find((find) => find.value === record.maritalStatusCode)?.label}}</span>
<span style="font-size: 13px;color: #666;margin-left: 12px;" v-if="record.occupation">{{record.occupation}}</span>
</div>
</div>
</div>
</template>
<template #allocateInfo="{ text, record }">
<ul class="ant-timeline" style="padding-top: 10px;" v-if="record.datingClueFollowRecordList && record.datingClueFollowRecordList.length">
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;"></span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0 0 10px;">
<div class="ant-timeline-item-tail"></div>
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
<li class="ant-timeline-item" style="padding: 0px;">
<div class="ant-timeline-item-head ant-timeline-item-head-blue"><!----></div>
<div class="ant-timeline-item-content">
<div class="flex-row-center-start">
<span style="color: rgb(153, 153, 153);">2025年6月26日 14:38:26</span>
<span style="color: rgb(51, 51, 51); margin-left: 10px;">果然非-飞鹅趣招亲-电话线索</span>
</div>
</div>
</li>
</ul>
<div class="flex-row-center-center" style="padding: 8px;" v-else>
<span style="color: #999;">暂无数据</span>
</div>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
label: '详情',
onClick: toDetail.bind(null, record),
},
{
label: '领取',
onClick: handleReceive.bind(null, record.id),
},
]"
/>
</template>
</BasicTable>
</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 } from 'vue'
import { Card, Image, InputNumber, Timeline, TimelineItem, Result } from 'ant-design-vue'
import { useRouter } from 'vue-router'
import { tableColumns, tableFormSchema } from './data'
import { useMessage } from '/@/hooks/web/useMessage'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { getSeasList, receiveCluing } from '/@/api/clue'
import { educationList, maritalList, genderList, followStageList } from '/@/enums/customerEnum'
const [registerTable, { reload, setPagination }] = useTable({
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: false,
showTableSetting: false,
api: getSeasList,
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,
},
beforeFetch: (arg) => {
const { createTime, followTime } = arg
if (createTime) {
arg.creatTimeFrom = moment(createTime[0]).format('YYYY-MM-DD 00:00:00')
arg.creatTimeTo = moment(createTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.createTime
}
if (followTime) {
arg.finalFollowTimeFrom = moment(followTime[0]).format('YYYY-MM-DD 00:00:00')
arg.finalFollowTimeTo = moment(followTime[1]).format('YYYY-MM-DD 23:59:59')
delete arg.followTime
}
arg.minimumAge = ageModel.minAge
arg.maximumAge = ageModel.maxAge
arg.followStatus = radioVal.value
},
actionColumn: {
width: 160,
title: '操作',
fixed: 'right',
dataIndex: 'action',
slots: { customRender: 'action' },
},
})
const followStatusList = [
{ label: '待跟进', value: 1 },
{ label: '跟进中', value: 2 },
{ label: '全部', value: '' },
]
const radioVal = ref<any>('')
const ageModel = reactive({
minAge: '',
maxAge: '',
})
function handleRadioChange() {
setPagination({ current: 1 })
reload()
}
const router = useRouter()
function toDetail(record: any) {
const { id } = record
router.push({
query: { id },
path: '/clue/customer',
})
}
const { createMessage } = useMessage()
async function handleReceive(id){
const { createConfirm } = useMessage()
createConfirm({
title: '提示',
iconType: 'warning',
content: `确定领取该线索?`,
onOk: () => {
receiveCluing({id}).then(() => {
createMessage.success('领取成功')
reload()
})
},
})
}
</script>
<style scoped lang="less">
.single-line {
overflow: hidden; /* 超出部分隐藏 */
white-space: nowrap; /* 文本不换行 */
text-overflow: ellipsis; /* 超出部分显示省略号 */
}
</style>

109
src/views/sys/workbench/data.ts

@ -0,0 +1,109 @@
import { BasicColumn, FormSchema } from '/@/components/Table';
export const columns: BasicColumn[] = [
{
title: '菜单名称',
dataIndex: 'name',
width: 300,
align: 'left',
},
{
title: '权限标识',
dataIndex: 'permission',
width: 180,
},
{
title: '路由地址',
dataIndex: 'path',
},
{
title: '组件',
dataIndex: 'component',
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 240,
},
];
const isDir = (type: string) => type === '1';
const isMenu = (type: string) => type === '2';
const isButton = (type: number) => type === 3;
export const searchFormSchema: FormSchema[] = [
// {
// field: 'menuName',
// label: '菜单名称',
// component: 'Input',
// colProps: { span: 8 },
// },
{
field: 'status',
label: '状态',
component: 'Select',
componentProps: {
options: [
{ label: '启用', value: '0' },
{ label: '停用', value: '1' },
],
},
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'type',
label: '菜单类型',
component: 'RadioButtonGroup',
defaultValue: 1,
componentProps: {
options: [
{ label: '目录', value: 1 },
{ label: '菜单', value: 2 },
// { label: '按钮', value: '3' },
],
},
colProps: { lg: 24, md: 24 },
},
{
field: 'name',
label: '菜单名称',
component: 'Input',
required: true,
},
{
field: 'parentId',
label: '上级菜单',
component: 'TreeSelect',
componentProps: {
replaceFields: {
title: 'name',
value: 'id',
key: 'id',
},
getPopupContainer: () => document.body,
},
},
{
field: 'path',
label: '路由地址',
component: 'Input',
required: true,
ifShow: ({ values }) => !isButton(values.type),
},
// {
// field: 'component',
// label: '组件路径',
// component: 'Input',
// ifShow: ({ values }) => isMenu(values.type),
// },
// {
// field: 'permission',
// label: '权限标识',
// component: 'Input',
// ifShow: ({ values }) => !isDir(values.type),
// },
];

9
src/views/sys/workbench/index.vue

@ -0,0 +1,9 @@
<template>
<div style="padding: 16px;">
</div>
</template>
<script lang="ts" setup>
import { nextTick } from 'vue';
</script>
Loading…
Cancel
Save