9 changed files with 571 additions and 0 deletions
Split 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