Browse Source

no message

master
ZHR007 1 month ago
parent
commit
baf6e6106e
9 changed files with 571 additions and 0 deletions
  1. 17
      src/api/clue/index.ts
  2. 1
      src/locales/lang/zh-CN/routes/clue.ts
  3. 8
      src/router/menu.ts
  4. 4
      src/router/menus/modules/clue.ts
  5. 8
      src/router/routes/modules/clue.ts
  6. 50
      src/views/clue/clueFlow/checkModal.vue
  7. 263
      src/views/clue/clueFlow/data.ts
  8. 118
      src/views/clue/clueFlow/index.vue
  9. 102
      src/views/clue/clueFlow/modal.vue

17
src/api/clue/index.ts

@ -151,3 +151,20 @@ export const intendedCustomer = (params: any) => defHttp.post({ url: '/dating-cl
export const getNextClueInfo = (params: any) => defHttp.get<any>({ url: '/dating-clue-service/user/get/own-next-dating-clue/by/telephone-invitation-team', params})
export const getClueFlowPage = (params: any) =>
defHttp.get<PageResultModel<any>>({
url: '/dating-clue-service/user/page/feed-delivery-clue/by/clue-team',
params,
})
export const auditFlowClue= (params: any) =>
defHttp.post({
url: '/dating-clue-service/user/audit/feed-delivery-clue',
params,
})
export const editFlowClue= (params: any) =>
defHttp.post({url: '/dating-clue-service/user/update/feed-delivery-clue', params})
export const getFlowClueInfo = (params: any) =>
defHttp.get<any>({ url: '/dating-clue-service/user/get/feed-delivery-clue/detail', params })

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

@ -3,6 +3,7 @@ export default {
clueIndex: '线索数据统计',
cluePool: '待分配线索',
clueList: '已分配线索',
clueFlow: '投流线索',
customer: '线索详情',
poolist: '我的线索',
followlist: '跟进记录'

8
src/router/menu.ts

@ -59,6 +59,14 @@ const clueMenu: Menu = {
title: 'routes.clue.clueList',
},
},
{
path: 'clueFlow',
name: 'ClueFlow',
component: '/clue/clueFlow/index.vue',
meta: {
title: 'routes.clue.clueFlow',
},
},
{
path: 'poolist',
name: 'Poolist',

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

@ -14,6 +14,10 @@ const clueMenu: MenuModule = {
path: 'cluePool',
name: t('routes.clue.cluePool'),
},
{
path: 'clueFlow',
name: t('routes.clue.clueFlow'),
},
{
path: 'clueList',
name: t('routes.clue.clueList'),

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

@ -39,6 +39,14 @@ const clueRoute: AppRouteModule = {
title: t('routes.clue.clueList'),
},
},
{
path: 'clueFlow',
name: 'ClueFlow',
component: () => import('/src/views/clue/clueFlow/index.vue'),
meta: {
title: t('routes.clue.clueFlow'),
},
},
{
path: 'poolist',
name: 'Poolist',

50
src/views/clue/clueFlow/checkModal.vue

@ -0,0 +1,50 @@
<template>
<BasicModal v-bind="$attrs" @ok="handleOk" @register="registerModal">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { auditFormSchema } from './data'
import { useMessage } from '/@/hooks/web/useMessage'
import { BasicForm, useForm } from '/@/components/Form'
import { BasicModal, useModalInner } from '/@/components/Modal'
import { auditFlowClue } from '/@/api/clue'
const [registerForm, { resetFields, validate }] = useForm({
labelWidth: 100,
schemas: auditFormSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
const id = ref<string>('')
const [registerModal, { setModalProps }] = useModalInner(async (data) => {
const { record } = data
await resetFields()
id.value = record.id
setModalProps({
minHeight: 50,
title: '线索审核',
confirmLoading: false,
})
})
const { createMessage } = useMessage()
const emits = defineEmits(['success', 'register'])
async function handleOk() {
try {
const values = await validate()
values.id = id.value
console.log('values.............', values)
setModalProps({ confirmLoading: true })
// const fun = unref(ifUpdate) ? '' : ''
await auditFlowClue(values)
createMessage.success(`审核成功!`)
emits('success')
} finally {
setModalProps({ confirmLoading: false })
}
}
</script>

263
src/views/clue/clueFlow/data.ts

@ -0,0 +1,263 @@
import { BasicColumn, FormSchema } from '/@/components/Table'
import { genderList, maritalList, educationList } from '/@/enums/customerEnum'
import { getIncomeList, getEducationList, getOccupationList, getMaritalStatusList} from '/@/api/essentialData'
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const flowStatusList = [
{ label: '待审核', value: 1, color: 'orange' },
{ label: '审核成功', value: 2, color: 'green' },
{ label: '审核失败', value: 3, color: 'red' },
{ label: '全部', value: '', color: 'red' },
]
export const tableColumns: BasicColumn[] = [
{ title: '用户昵称', dataIndex: 'nickName' },
{ width: 64, title: '头像', dataIndex: 'avatar', slots: { customRender: 'avatar' } },
{ width: 90, title: '用户性别', dataIndex: 'genderCode', customRender: ({ text }) => (text == 0 ? '男' : '女') },
{ width: 90, title: '出生年月', dataIndex: 'birthYear' },
{ width: 100, title: '电话号码', dataIndex: 'phone' },
{ width: 100, title: '微信号', dataIndex: 'weChatId' },
{ width: 80, title: '婚姻状态', dataIndex: 'maritalStatusCode',
customRender: ({ text }) => {
return maritalList.find((find) => find.value === text)?.label
},
},
{ width: 60, title: '身高', dataIndex: 'height' },
{ width: 60, title: '体重', dataIndex: 'weight' },
{ width: 80, title: '学历', dataIndex: 'educationCode',customRender: ({ text }) => {
return educationList.find((find) => find.value === text)?.label
}, },
{ width: 120, title: '职业', dataIndex: 'occupation' },
{
width: 100, title: '收入范围',
dataIndex: 'income',
customRender: ({ text, record }) => `${record['minimumIncome']}-${record['maximumIncome']}`,
},
{
width: 160, title: '所在区域',
dataIndex: 'address',
customRender: ({ text, record }) => `${record['provinceName']}-${record['cityName']}-${record['districtName']}`,
},
{ width: 100, title: '注册日期', dataIndex: 'clueTime' },
{ width: 100, title: '线索来源', dataIndex: 'creatorName' },
{ width: 100, title: '状态', dataIndex: 'status',
customRender: ({ text }) => {
const item = flowStatusList.find((find) => find.value === text) || {}
return h(Tag, { color: item['color'] }, () => item['label']);
},
},
]
export const tableFormSchema: FormSchema[] = [
{
field: 'genderCode',
label: '用户性别',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: genderList,
},
},
// {
// 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: 'status',
label: '状态',
colProps: { span: 6 },
component: 'Select',
componentProps: {
options: flowStatusList,
},
},
// {
// field: 'maritalStatusCode',
// label: '婚姻状况',
// colProps: { span: 6 },
// component: 'ApiSelect',
// componentProps: {
// labelField: 'desc',
// api: getMaritalStatusList,
// },
// },
{
field: 'age',
label: '年龄',
slot: 'age',
component: 'InputNumber',
colProps: { span: 6 },
},
{
field: 'createTime',
label: '创建时间',
component: 'RangePicker',
colProps: { span: 6 },
},
]
import { ref } from 'vue'
import { useAddressData } from '/@/hooks/common'
// 基础信息的额外数据
export const basicInfoData = ref<any>({})
export const addressName = ref<string[]>([])
const { addressList } = useAddressData()
// 获取职业列表
export const occupationList = ref<any>([])
getOccupationList().then((res) => {
var list = []
res.forEach(element => {
const { occupationList } = element
occupationList.forEach(item => {
list.push({label: item.occupation, value: item.occupationCode})
});
});
occupationList.value = list
})
// 基本信息
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: '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: 'birthYear', label: '出生年', component: 'Input', colProps: { span: 8 },},
{
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
},
},
},
{
label: '职业',
field: 'occupationCode',
colProps: { span: 8 },
component: 'Select',
componentProps: {
options: occupationList,
getPopupContainer: () => document.body,
onChange: (_: any, v: any) => {
basicInfoData.value.occupation = v?.label
},
},
},
{
field: 'profilePhoto',
component: 'Upload',
label: '资料头像',
colProps: { span: 8 },
slot: 'profilePhoto',
},
{
field: 'remark',
label: '个人描述',
component: 'InputTextArea',
colProps: { span: 16 },
componentProps: ({ formModel }) => {
return {
autoSize: {
minRows: 4,
},
disabled: formModel?.describeAudit,
}
},
},
]
export const auditFormSchema: FormSchema[] = [
{
label: '审核',
required: true,
field: 'status',
defaultValue: 1,
component: 'RadioGroup',
componentProps: {
options: [
{ label: '通过', value: 2 },
{ label: '失败', value: 3 },
],
},
},
]

118
src/views/clue/clueFlow/index.vue

@ -0,0 +1,118 @@
<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 #avatar="{ text, record }">
<Avatar :src="record.profilePhoto || 'https://dating-agency-prod.oss-cn-shenzhen.aliyuncs.com/827036501B11.png'" :size="40" />
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
label: '编辑',
onClick: handleEdit.bind(null, record, true),
ifShow: record['status'] == 1
},
{
label: '详情',
onClick: handleEdit.bind(null, record, false),
ifShow: record['status'] !== 1
},
{
label: '审核',
color: 'error',
onClick: handleAudit.bind(null, record),
ifShow: record['status'] == 1
},
]"
/>
</template>
</BasicTable>
<FlowModal @register="registerModal" @success="handleSuccess" />
<CheckModal @register="registerAuditModal" @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 { reactive } from 'vue'
import { InputNumber, Avatar } from 'ant-design-vue'
import { useModal } from '/@/components/Modal'
import { tableColumns, tableFormSchema } from './data'
import { BasicTable, useTable, TableAction } from '/@/components/Table'
import FlowModal from './modal.vue'
import CheckModal from './checkModal.vue'
import { getClueFlowPage } from '/@/api/clue'
const ageModel = reactive({
minAge: '',
maxAge: '',
})
const [registerTable, { reload }] =
useTable({
bordered: false,
useSearchForm: true,
columns: tableColumns,
showIndexColumn: false,
showTableSetting: false,
immediate: true,
api: getClueFlowPage,
formConfig: {
labelWidth: 120,
schemas: tableFormSchema,
},
beforeFetch: (arg) => {
const { createTime } = 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 (ageModel.minAge) {
arg.minimumAge = ageModel.minAge
}
if (ageModel.maxAge) {
arg.maximumAge = ageModel.maxAge
}
},
actionColumn: {
width: 120,
title: '操作',
fixed: 'right',
dataIndex: 'action',
slots: { customRender: 'action' },
},
})
function handleEdit(record: any, edit: boolean) {
openModal(true, { record, edit })
}
async function handleAudit(record) {
openAuditModal(true, { record })
}
const [registerModal, { openModal, closeModal }] = useModal()
const [registerAuditModal, { openModal: openAuditModal, closeModal: closeAuditModal }] = useModal()
//
function handleSuccess() {
closeModal()
closeAuditModal()
reload()
}
</script>

102
src/views/clue/clueFlow/modal.vue

@ -0,0 +1,102 @@
<template>
<BasicModal v-bind="$attrs" :width="960" @ok="handleOk" @register="registerModal">
<BasicForm @register="registerForm" style="padding: 16px 48px 0px 0px;" >
<!-- <template #birthYear="{ model, field }">
<DatePicker v-model:value="model[field]" mode="year" :open="open" format="YYYY" @openChange="openChange" @panelChange="panelChange"/>
</template> -->
<template #profilePhoto="{ model, field }">
<CropperAvatar :value="model[field]" @change="uploadAvatarAfter" v-if="update"/>
<Image :width="100" :src="model[field]" v-else />
</template>
</BasicForm>
</BasicModal>
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import { Image } from 'ant-design-vue'
import { modalFormSchema, basicInfoData } from './data'
import { useMessage } from '/@/hooks/web/useMessage'
import { BasicForm, useForm } from '/@/components/Form'
import { BasicModal, useModalInner } from '/@/components/Modal'
import { CropperAvatar } from '/@/components/Cropper';
import { editFlowClue } from '/@/api/clue'
const update = ref<boolean>(false)
const [registerForm, { setFieldsValue, resetFields, validate, getFieldsValue, setProps }] =
useForm({
labelWidth: 108,
schemas: modalFormSchema,
baseColProps: { span: 22 },
showActionButtonGroup: false,
})
const details = ref<any>()
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
const { record, edit } = data
var title :string = ''
update.value = edit
await setProps({ disabled: !edit })
if(record && record.id){
title = '编辑线索'
details.value = record
const { domicilePlaceProvinceCode, domicilePlaceCityCode } = details.value || {}
const domicilePlace = domicilePlaceCityCode && domicilePlaceProvinceCode ? [domicilePlaceProvinceCode, domicilePlaceCityCode] : []
const { provinceCode, cityCode, districtCode } = details.value || {}
const address = provinceCode && cityCode && districtCode ? [provinceCode, cityCode, districtCode] : []
// basicInfoData.value = {}
basicInfoData.value.occupation = record.occupation
await nextTick()
await setFieldsValue({ ...details.value, domicilePlace, address })
} else {
title = '新增线索'
details.value = {}
basicInfoData.value = {}
await resetFields()
}
setModalProps({ minHeight: 360, confirmLoading: false, title })
})
function uploadAvatarAfter(value) {
//
setFieldsValue({ profilePhoto: value });
}
const { createMessage } = useMessage()
const emits = defineEmits(['success'])
async function handleOk() {
if(!update.value){
closeModal()
return
}
try {
await validate()
const values: any = getFieldsValue()
// console.log({...values, ...basicInfoData.value})
setModalProps({ confirmLoading: true })
const { address } = values || {}
var param = {
...values,
...basicInfoData.value,
cityCode: address?.[1],
cityName: basicInfoData.value.cityName,
provinceCode: address?.[0],
provinceName: basicInfoData.value.provinceName,
districtCode: address?.[2],
districtName: basicInfoData.value.districtName,
}
if(details.value && details.value.id){
param.id = details.value.id
await editFlowClue(param)
createMessage.success(`编辑成功!`)
}
emits('success')
} finally {
setModalProps({ confirmLoading: false })
}
}
</script>
Loading…
Cancel
Save