高德商户

This commit is contained in:
zhonghua.li
2026-05-03 10:26:52 +08:00
parent 8fd3aa00e2
commit 69f6cf78ac
3 changed files with 212 additions and 16 deletions

View File

@@ -70,23 +70,17 @@
<!-- 操作按钮区域 -->
<el-card class="action-container" shadow="never">
<el-button type="primary" icon="el-icon-plus" @click="handleAdd">添加客户</el-button>
<el-button type="primary" icon="el-icon-upload2" @click="handleExport">导出客流</el-button>
<el-button type="danger" icon="el-icon-delete" :disabled="selectedIds.length === 0" @click="handleBatchDelete">批量删除</el-button>
<el-button type="success" plain icon="el-icon-location-outline" @click="openGaodeMerchantDialog">高德商户</el-button>
</el-card>
<!-- 视图切换和操作按钮区域 -->
<el-card class="view-container" shadow="never">
<div class="view-tabs">
<el-tabs v-model="activeView" @tab-click="handleViewChange">
<el-tab-pane label="列表" name="list">
<div class="action-buttons">
<el-button type="primary" icon="el-icon-upload2" @click="handleExport">导出客流</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="卡片" name="card">
<div class="action-buttons">
<el-button type="primary" icon="el-icon-upload2" @click="handleExport">导出客流</el-button>
</div>
</el-tab-pane>
<el-tab-pane label="列表" name="list" />
<el-tab-pane label="卡片" name="card" />
</el-tabs>
</div>
</el-card>
@@ -548,6 +542,76 @@
</el-dialog>
<!-- 列表中按类型查看客户照片 -->
<!-- 高德附近商家检索 -->
<el-dialog
title="高德商户 · 附近商家检索"
:visible.sync="gaodeMerchantDialogVisible"
width="720px"
append-to-body
@close="onGaodeMerchantDialogClose"
>
<el-form
ref="gaodeNearbyFormRef"
class="gaode-nearby-form"
:model="gaodeNearbyForm"
:rules="gaodeNearbyRules"
label-width="260px"
size="small"
>
<el-form-item label="城市 CITY" prop="CITY">
<el-input v-model="gaodeNearbyForm.CITY" placeholder="传给高德地理编码的 city如 北京、上海" clearable />
</el-form-item>
<el-form-item label="地址 ADDRESS" prop="ADDRESS">
<el-input v-model="gaodeNearbyForm.ADDRESS" placeholder="地址或地标,传给高德地理编码 address" clearable />
</el-form-item>
<el-form-item label="半径 RADIUS" prop="RADIUS">
<el-input-number v-model="gaodeNearbyForm.RADIUS" :min="1" :max="50000" controls-position="right" />
</el-form-item>
<el-form-item label="最大页数 MAX_PAGE" prop="MAX_PAGE">
<el-input-number v-model="gaodeNearbyForm.MAX_PAGE" :min="1" :max="100" :precision="0" controls-position="right" />
</el-form-item>
<el-form-item label="每页条数 maxRecordsOfpage" prop="maxRecordsOfpage">
<el-input-number v-model="gaodeNearbyForm.maxRecordsOfpage" :min="1" :max="50" :precision="0" controls-position="right" />
</el-form-item>
</el-form>
<div v-if="nearbySearchResult" class="gaode-nearby-result">
<el-alert
:title="nearbySearchResult.success ? '检索成功' : '检索失败'"
:type="nearbySearchResult.success ? 'success' : 'error'"
:closable="false"
show-icon
>
<div>{{ nearbySearchResult.message || '—' }}</div>
<div v-if="nearbySearchResult.success" class="gaode-nearby-meta">
<span v-if="nearbySearchResult.totalCount != null">总数{{ nearbySearchResult.totalCount }}</span>
<span v-if="nearbySearchResult.centerLocation">中心点{{ formatGaodeCenter(nearbySearchResult.centerLocation) }}</span>
</div>
</el-alert>
<el-table
v-if="nearbySearchResult.success && Array.isArray(nearbySearchResult.data) && nearbySearchResult.data.length"
:data="nearbySearchResult.data"
border
stripe
max-height="320"
size="small"
style="width: 100%; margin-top: 12px"
>
<el-table-column
v-for="col in nearbyMerchantTableColProps"
:key="col"
:prop="col"
:label="col"
min-width="100"
show-overflow-tooltip
/>
</el-table>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="gaodeMerchantDialogVisible = false"> </el-button>
<el-button type="primary" :loading="gaodeNearbyLoading" @click="submitGaodeNearbySearch"> </el-button>
</div>
</el-dialog>
<el-dialog
:title="photoPreviewTitle"
:visible.sync="photoPreviewVisible"
@@ -582,7 +646,8 @@ import {
deleteCustomer,
batchDeleteCustomer,
exportCustomerFlow,
addCommunicationRecord
addCommunicationRecord,
searchNearbyMerchants
} from '@/api/customer'
import { getProjectList } from '@/api/project'
import { getSalesList } from '@/api/sales'
@@ -677,7 +742,33 @@ export default {
photoPreviewSrc: '',
photoPreviewObjectUrl: '',
photoPreviewLoading: false,
photoPreviewLoadError: false
photoPreviewLoadError: false,
gaodeMerchantDialogVisible: false,
gaodeNearbyLoading: false,
gaodeNearbyForm: {
CITY: '河北省廊坊市三河市燕郊镇',
ADDRESS: '',
RADIUS: 2000,
MAX_PAGE: 5,
maxRecordsOfpage: 20
},
gaodeNearbyRules: {
CITY: [{ required: true, message: '请输入城市', trigger: 'blur' }],
ADDRESS: [{ required: true, message: '请输入地址或地标', trigger: 'blur' }],
RADIUS: [{ required: true, message: '请填写搜索半径', trigger: 'change' }],
MAX_PAGE: [{ required: true, message: '请填写最大页数', trigger: 'change' }],
maxRecordsOfpage: [{ required: true, message: '请填写每页条数', trigger: 'change' }]
},
nearbySearchResult: null
}
},
computed: {
nearbyMerchantTableColProps() {
const rows = this.nearbySearchResult && this.nearbySearchResult.data
if (!Array.isArray(rows) || !rows.length || typeof rows[0] !== 'object') {
return []
}
return Object.keys(rows[0]).slice(0, 16)
}
},
created() {
@@ -688,6 +779,65 @@ export default {
this.getSalesOptions()
},
methods: {
openGaodeMerchantDialog() {
this.nearbySearchResult = null
this.gaodeNearbyForm = {
CITY: '河北省廊坊市三河市燕郊镇',
ADDRESS: '',
RADIUS: 2000,
MAX_PAGE: 5,
maxRecordsOfpage: 20
}
this.gaodeMerchantDialogVisible = true
this.$nextTick(() => {
if (this.$refs.gaodeNearbyFormRef) {
this.$refs.gaodeNearbyFormRef.clearValidate()
}
})
},
onGaodeMerchantDialogClose() {
this.nearbySearchResult = null
this.gaodeNearbyLoading = false
},
formatGaodeCenter(loc) {
if (loc == null) return ''
if (typeof loc === 'string') return loc
try {
return JSON.stringify(loc)
} catch (e) {
return String(loc)
}
},
submitGaodeNearbySearch() {
this.$refs.gaodeNearbyFormRef.validate(valid => {
if (!valid) return
const { CITY, ADDRESS, RADIUS, MAX_PAGE, maxRecordsOfpage } = this.gaodeNearbyForm
this.gaodeNearbyLoading = true
searchNearbyMerchants({
CITY: String(CITY).trim(),
ADDRESS: String(ADDRESS).trim(),
RADIUS: Number(RADIUS),
MAX_PAGE: Number(MAX_PAGE),
maxRecordsOfpage: Number(maxRecordsOfpage)
}).then(res => {
this.nearbySearchResult = res && typeof res === 'object' ? res : { success: false, message: '响应格式异常' }
if (this.nearbySearchResult.success) {
this.$message.success(this.nearbySearchResult.message || '检索成功')
} else {
this.$message.error(this.nearbySearchResult.message || '检索失败')
}
}).catch(err => {
const rd = err && err.response && err.response.data
if (rd && typeof rd === 'object' && ('success' in rd || 'message' in rd)) {
this.nearbySearchResult = rd
} else {
this.nearbySearchResult = { success: false, message: (err && err.message) || '请求失败' }
}
}).finally(() => {
this.gaodeNearbyLoading = false
})
})
},
// 获取列表数据
getList() {
this.loading = true
@@ -1237,10 +1387,6 @@ export default {
margin-bottom: 20px;
}
.action-buttons {
margin-top: 10px;
}
.customer-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
@@ -1395,4 +1541,29 @@ export default {
color: #909399;
font-size: 14px;
}
.gaode-nearby-result {
margin-top: 8px;
}
.gaode-nearby-meta {
margin-top: 8px;
font-size: 13px;
color: #606266;
}
.gaode-nearby-meta span {
margin-right: 16px;
}
/* 高德商户弹窗label 单行不换行,控件区宽度为原先的 70% */
.gaode-nearby-form ::v-deep .el-form-item__label {
white-space: nowrap;
}
.gaode-nearby-form ::v-deep .el-form-item__content > .el-input,
.gaode-nearby-form ::v-deep .el-form-item__content > .el-input-number {
width: 70%;
max-width: 100%;
}
</style>