9 changed files with 571 additions and 0 deletions
Unified View
Diff Options
-
17src/api/clue/index.ts
-
1src/locales/lang/zh-CN/routes/clue.ts
-
8src/router/menu.ts
-
4src/router/menus/modules/clue.ts
-
8src/router/routes/modules/clue.ts
-
50src/views/clue/clueFlow/checkModal.vue
-
263src/views/clue/clueFlow/data.ts
-
118src/views/clue/clueFlow/index.vue
-
102src/views/clue/clueFlow/modal.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> |
||||
@ -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 }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
] |
||||
@ -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> |
||||
@ -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> |
||||
Write
Preview
Loading…
Cancel
Save