salary
qsh 4 months ago
parent e35a32e985
commit cff4280705
  1. 2
      src/api/clue/source.js
  2. 271
      src/views/Clue/Pool/Comp/DialogClue.vue
  3. 9
      src/views/Clue/Pool/cluePool.data.js
  4. 11
      src/views/Clue/Pool/index.vue

@ -2,7 +2,7 @@ import request from '@/config/axios'
// 查询(精简)列表
export const getSimpleSourceList = async () => {
return await request.get({ url: '/admin-api/crm/source/list-all-simple' })
return await request.get({ url: '/admin-api/crm/source/list' })
}
// 查询列表

@ -2,45 +2,51 @@
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
<el-tabs v-model="tabName">
<el-tab-pane label="线索信息" name="info">
<Form
ref="formRef"
v-loading="formLoading"
:rules="rules"
isCol
:schema="allSchemas.formSchema"
/>
<Form ref="formRef" v-loading="formLoading" :rules="rules" isCol :schema="formSchema" />
</el-tab-pane>
<el-tab-pane label="跟进信息" name="follow">
<el-button type="primary" @click="handleAppendFollow">新增跟进人</el-button>
<el-table :data="followList">
<el-table-column label="跟进人">
<template #default="{ row }">
<el-select v-model="row.followUser" placeholder="选择跟进人" filterable>
<el-select
v-model="row.userId"
placeholder="选择跟进人"
filterable
:disabled="!row.editable"
>
<el-option
v-for="item in userOptions"
:key="item.value"
:label="item.label"
:value="item.value"
:key="item.id"
:label="item.nickname"
:value="item.id"
/>
</el-select>
</template>
</el-table-column>
<el-table-column prop="nextFollowTime" label="下次跟进时间">
<el-table-column prop="followTime" label="下次跟进时间">
<template #default="{ row }">
<el-date-picker v-model="row.nextFollowTime" type="date" placeholder="选择日期时间" />
<el-date-picker
v-model="row.followTime"
type="date"
placeholder="选择日期时间"
:disabled="!row.editable"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ $index }">
<Icon icon="ep:remove-filled" class="text-red-500" @click="handleRemove($index)" />
<!-- <el-button @click="handleRemove(row, $index)">
</el-button> -->
<template #default="{ row, $index }">
<Icon
v-if="row.editable"
icon="ep:remove-filled"
class="text-red-500"
@click="handleRemove($index)"
/>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="位置信息" name="map">
<el-tab-pane v-if="appStore.getAppInfo?.instanceType == 1" label="位置信息" name="map">
<div class="flex justify-between">
<el-select
v-model="areaValue"
@ -64,11 +70,15 @@
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.district }}</span>
</el-option>
</el-select>
<el-checkbox v-model="showSchool" :label="true" @change="handleShowSchool"
>展示场地</el-checkbox
>
<el-checkbox v-model="showSchool" :label="true" @change="handleShowSchool">
展示场地
</el-checkbox>
</div>
<div id="dialogMap" class="mt-20px" style="height: 400px; width: 100%"></div>
<div class="flex items-center mt-10px mb-10px">
<div class="w-100px">线索位置</div>
<el-input v-model="address" placeholder="请输入线索位置" clearable />
</div>
</el-tab-pane>
</el-tabs>
<template #footer>
@ -80,12 +90,55 @@
</Dialog>
</template>
<script setup>
import { allSchemas, rules } from '../cluePool.data'
<script setup name="DialogClue">
import { useAppStore } from '@/store/modules/app'
import { getSimpleUserList as getUserOption } from '@/api/system/user'
import { getPlaceList } from '@/api/school/place'
import * as ClueApi from '@/api/clue'
import { formatDate } from '@/utils/formatTime'
import AMapLoader from '@amap/amap-jsapi-loader'
import ImgPostion from '@/assets/imgs/flag/flag_red.png'
import ImgFlag from '@/assets/imgs/flag/position_blue.png'
import FlagRed from '@/assets/imgs/flag/flag_red.png'
import FlagYellow from '@/assets/imgs/flag/flag_yellow.png'
import FlagPurple from '@/assets/imgs/flag/flag_purple.png'
import FlagGreen from '@/assets/imgs/flag/flag_green.png'
import FlagBlue from '@/assets/imgs/flag/flag_blue.png'
import FlagBlack from '@/assets/imgs/flag/flag_black.png'
const message = useMessage() //
const { t } = useI18n() //
const appStore = useAppStore()
const props = defineProps({
schema: {
type: Array
}
})
const formSchema = computed(() => {
return [
...props.schema,
{
component: 'Input',
label: '诉求',
field: 'requirement',
componentProps: {
type: 'textarea'
},
colProps: {
span: 24
}
},
{
component: 'Editor',
label: '备注',
field: 'remark',
colProps: {
span: 24
}
}
]
})
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
@ -93,47 +146,106 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加
const formType = ref('') // create - update -
const formRef = ref() // Ref
const rules = {
name: { required: true, message: '线索名称不可为空', trigger: 'blur' },
phone: { required: true, message: '联系方式不可为空', trigger: 'blur' },
source: { required: true, message: '线索来源不可为空', trigger: 'change' },
intentionState: { required: true, message: '意向状态不可为空', trigger: 'change' }
}
const tabName = ref('info')
const followList = ref([])
const userOptions = ref([])
const areaValue = ref('新天地国际')
const areaValue = ref('')
const areaList = ref([])
const address = ref('')
const defaultLatLng = ref({
lat: 31.86119,
lng: 117.283042
})
const info = ref({})
const open = async (type, info) => {
const open = async (type, id) => {
dialogVisible.value = true
dialogTitle.value = type == 'create' ? '新增线索' : '修改线索'
formType.value = type
//
if (info) {
if (id) {
formLoading.value = true
try {
const data = { ...info }
const data = await ClueApi.getClue(id)
info.value = { ...data, ...data.diyParams }
nextTick(() => {
formRef.value.setValues(data)
followList.value = data.followUser
address.value = data.address || ''
formRef.value.setValues(info.value)
})
} finally {
formLoading.value = false
}
}
if (!dialogMap.value) {
if (appStore.getAppInfo?.instanceType == 1 && !dialogMap.value) {
nextTick(() => {
initMap()
remoteMethod('新天地国际')
getSchoolPlace()
initMap(info.value)
remoteMethod(address.value)
})
}
}
defineExpose({ open }) // open
function handleSave() {
console.log('保存')
const placeList = ref([])
function getSchoolPlace() {
getPlaceList().then((data) => {
placeList.value = data.placeList
})
}
async function handleSave() {
//
if (!formRef.value) return
const valid = await formRef.value.getElFormRef().validate()
if (!valid) return
if (followList.value && followList.value.length && followList.value.some((it) => !it.userId)) {
message.info('请将跟进人填写完整!')
return
}
//
formLoading.value = true
try {
let params = { ...formRef.value.formModel, address: address.value }
params.lat = defaultLatLng.value.lat
params.lng = defaultLatLng.value.lng
params.followUsers = [...followList.value]
params.diyParams = {}
debugger
for (const key in info.value.diyParams) {
if (Object.hasOwnProperty.call(info.value.diyParams, key)) {
params.diyParams[key] = params.key
}
}
if (formType.value === 'create') {
await ClueApi.createClue(params)
message.success(t('common.createSuccess'))
} else {
await ClueApi.updateClue(params)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
function handleAppendFollow() {
followList.value.push({
followUser: undefined,
nextFollowTime: formatDate(new Date())
userId: undefined,
followTime: formatDate(new Date()),
editable: true
})
}
function handleRemove(index) {
@ -145,28 +257,55 @@ const dialogMap = ref(null)
const aMap = ref(null)
let AutoComplete = ref(null)
let geoCoder = ref(null)
function initMap() {
function initMap(data) {
AMapLoader.load({
key: '2ffb0e2ea90b1df0b8be48ed66e18fc8', //key
version: '2.0',
plugins: ['AMap.Geocoder', 'AMap.AutoComplete']
}).then((AMap) => {
aMap.value = AMap
if (data.lng || data.lat) {
defaultLatLng.value = {
lng: data.lng,
lat: data.lat
}
addmark(data.lng, data.lat, AMap)
}
dialogMap.value = new AMap.Map('dialogMap', {
zoom: 12,
zooms: [2, 22],
center: [117.283042, 31.86119]
center: [defaultLatLng.value.lng, defaultLatLng.value.lat]
})
AutoComplete.value = new AMap.AutoComplete({
city: '全国'
})
geoCoder.value = new AMap.Geocoder()
dialogMap.value.on('click', (e) => {
defaultLatLng.value = {
lng: e.lnglat.getLng(),
lat: e.lnglat.getLat()
}
addmark(e.lnglat.getLng(), e.lnglat.getLat(), AMap)
regeoCode(e.lnglat.getLng(), e.lnglat.getLat())
})
})
}
function regeoCode(lng, lat) {
try {
geoCoder.value.getAddress([lng, lat], (status, result) => {
if (status === 'complete' && result.regeocode) {
address.value = result.regeocode.formattedAddress
} else {
message.error('根据经纬度查询地址失败')
}
})
} catch (error) {
console.log(error)
}
}
let marker = ref(null)
function addmark(lat, lng, AMap) {
marker.value && removeMarker()
@ -186,29 +325,30 @@ const showSchool = ref(false)
const schoolMarkers = ref([])
function handleShowSchool() {
if (showSchool.value) {
let marker1 = new aMap.value.Marker({
map: dialogMap.value,
position: [117.258001, 31.895216],
label: {
content: '慧安驾校桃花社区训练基地',
direction: 'left'
},
icon: ImgFlag,
// extData: element,
clickable: true
})
let marker2 = new aMap.value.Marker({
map: dialogMap.value,
position: [117.286731, 31.902396],
label: {
content: '(皖西)瑞星驾校总校(D)',
direction: 'left'
},
icon: ImgFlag,
// extData: element,
clickable: true
})
schoolMarkers.value = [marker1, marker2]
const flagMap = {
red: FlagRed,
yellow: FlagYellow,
purple: FlagPurple,
green: FlagGreen,
blue: FlagBlue,
black: FlagBlack
}
schoolMarkers.value = []
for (let i = 0; i < placeList.value.length; i++) {
const place = placeList.value[i]
const marker = new aMap.value.Marker({
map: dialogMap.value,
position: [place.lng, place.lat],
label: {
content: place.name,
direction: 'left'
},
icon: flagMap[place.flagColor || 'red'],
extData: place,
clickable: true
})
schoolMarkers.value.push(marker)
}
} else {
dialogMap.value.remove(schoolMarkers.value)
}
@ -231,8 +371,15 @@ function currentSelect(val) {
if (area) {
addmark(area.location?.lng, area.location?.lat, aMap.value)
dialogMap.value.setCenter([area.location?.lng, area.location?.lat], '', 500)
regeoCode(area.location?.lng, area.location?.lat)
}
}
onMounted(() => {
getUserOption().then((data) => {
userOptions.value = data
})
})
</script>
<style scoped>

@ -4,11 +4,10 @@ import { dateFormatter } from '@/utils/formatTime'
// 表单校验
export const rules = reactive({
username: [required],
password: [required],
host: [required],
port: [required],
sslEnable: [required]
name: [required],
phone: [required],
source: [required],
intentionState: [required]
})
// const userList = await MailAccountApi.getSimpleMailAccountList()

@ -115,7 +115,12 @@
</el-table-column>
</SSTable>
<DialogClue ref="formRef" />
<DialogClue
v-if="!loading"
ref="formRef"
:schema="allSchemas.formSchema"
@sucess="getTableList"
/>
<DrawerClue ref="drawerRef" />
<DialogSuccess ref="successRef" />
<DialogFollow ref="followRef" />
@ -192,7 +197,7 @@ async function getTableList() {
queryType: queryType.value
}
const data = await ClueApi.getCluePage(removeNullField(params))
tableObject.value.tableList = data.list
tableObject.value.tableList = data.list.map((it) => ({ ...it, ...it.diyParams }))
tableObject.value.total = data.total
} finally {
tableObject.value.loading = false
@ -216,7 +221,7 @@ function handleInsert() {
}
//
function handleEdit(row) {
formRef.value.open('update', row)
formRef.value.open('update', row.clueId)
}
//
function handleDetail(row) {

Loading…
Cancel
Save