2c6a2dafec
desc_collect 富文本中的图片(如WhatsApp导入截图)点击后用 el-image-viewer 全屏放大(支持滚轮缩放/旋转,点击遮罩关闭), 图片加 cursor:zoom-in 提示可点击。 覆盖:业务端客户列表/公海、管理后台客户/公海/回收站/审核,共6处。 Co-Authored-By: Claude <noreply@anthropic.com>
341 lines
10 KiB
Vue
341 lines
10 KiB
Vue
<template>
|
||
<div class="boxshadow">
|
||
<div class="heard">
|
||
<div class="heard-title">公海</div>
|
||
<el-select
|
||
v-model="remindRange"
|
||
placeholder="请选择"
|
||
class="heard-select"
|
||
style="min-width: 120px"
|
||
>
|
||
<el-option label="全部" value="" />
|
||
<el-option label="当天" value="0" />
|
||
<el-option label="近三天" value="1" />
|
||
<el-option label="近七天" value="2" />
|
||
</el-select>
|
||
</div>
|
||
<div class="table">
|
||
<ArtTable
|
||
ref="tableRef"
|
||
row-key="id"
|
||
:loading="loading"
|
||
:data="tableData"
|
||
:currentPage="pagination.currentPage"
|
||
:pageSize="pagination.pageSize"
|
||
:total="pagination.total"
|
||
:marginTop="10"
|
||
@selection-change="handleSelectionChange"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
>
|
||
<template #default>
|
||
<el-table-column prop="contacts" label="客户名称"></el-table-column>
|
||
<!-- <el-table-column prop="phone" label="电话"></el-table-column>
|
||
<el-table-column prop="WhatsApp" label="WhatsApp"></el-table-column>
|
||
<el-table-column prop="email" label="邮箱"></el-table-column> -->
|
||
<el-table-column prop="follow" label="联系方式" width="240px" show-overflow-tooltip>
|
||
<template #default="scope">
|
||
<div
|
||
>WhatsApp:{{
|
||
scope.row.WhatsApp == '' ? ' --' : '【' + scope.row.WhatsApp + ' 】'
|
||
}}</div
|
||
>
|
||
<div>电话:{{ scope.row.phone == '' ? ' --' : '【' + scope.row.phone + ' 】' }}</div>
|
||
<div>邮箱:{{ scope.row.email == '' ? ' --' : '【' + scope.row.email + ' 】' }}</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="magnitude_txt" label="客户商机"></el-table-column>
|
||
<el-table-column prop="channel_name" label="渠道"></el-table-column>
|
||
<el-table-column prop="country_name" label="国家"></el-table-column>
|
||
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
|
||
<el-table-column prop="created_at" label="创建时间"></el-table-column>
|
||
<el-table-column fixed="right" label="操作" width="160px">
|
||
<template #default="scope">
|
||
<div
|
||
class="follow-detli"
|
||
@click="onDetail(scope.row)"
|
||
v-if="hasAuth('highseas@show')"
|
||
>
|
||
<span class="custom-clock-icon" style="vertical-align: middle; margin-right: 4px">
|
||
<i class="iconfont-sys"></i>
|
||
</span>
|
||
详情
|
||
</div>
|
||
<div
|
||
class="follow-action"
|
||
@click="onFollow(scope.row)"
|
||
v-if="hasAuth('highseas@claim')"
|
||
>
|
||
<span class="custom-clock-icon" style="vertical-align: middle; margin-right: 4px">
|
||
<i class="iconfont-sys"></i>
|
||
</span>
|
||
领单
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</template>
|
||
</ArtTable>
|
||
</div>
|
||
</div>
|
||
<el-dialog v-model="detailDialogVisible" title="详情">
|
||
<div v-if="detailRow" v-html="detailRow.desc_collect" class="detils-content" @click="onDescImgClick"></div>
|
||
<el-image-viewer v-if="descViewerUrl" :url-list="[descViewerUrl]" hide-on-click-modal @close="descViewerUrl = ''" />
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, onMounted, onUnmounted } from 'vue'
|
||
import dayjs from 'dayjs'
|
||
import { ElMessageBox } from 'element-plus'
|
||
import { CrmService } from '@/api/crmApi'
|
||
import { useAuth } from '@/composables/useAuth'
|
||
const { hasAuth } = useAuth()
|
||
defineOptions({ name: 'CrmHighseas' })
|
||
const loading = ref(false)
|
||
const pagination = reactive({
|
||
currentPage: 1,
|
||
pageSize: 10,
|
||
total: 0
|
||
})
|
||
const remindRange = ref('')
|
||
const tableData = ref<any[]>([])
|
||
watch([remindRange], () => {
|
||
pagination.currentPage = 1
|
||
gettableList()
|
||
})
|
||
// 获取列表数据
|
||
const gettableList = async () => {
|
||
loading.value = true
|
||
try {
|
||
const { currentPage, pageSize } = pagination
|
||
const params: any = {
|
||
current: currentPage,
|
||
size: pageSize,
|
||
seas: 'seas'
|
||
}
|
||
if (remindRange.value) params.follow_last = remindRange.value
|
||
const { data, current, size, total } = await CrmService.getcustomerList(params)
|
||
tableData.value = data.map((item: any) => ({
|
||
...item
|
||
}))
|
||
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||
} catch (error) {
|
||
console.error('获取用户列表失败:', error)
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
// 选中的行数据
|
||
const selectedRows = ref<any[]>([])
|
||
// 处理表格行选择变化
|
||
const handleSelectionChange = (selection: any[]) => {
|
||
selectedRows.value = selection
|
||
}
|
||
// 处理表格分页变化
|
||
const handleSizeChange = (newPageSize: number) => {
|
||
pagination.pageSize = newPageSize
|
||
gettableList()
|
||
}
|
||
|
||
const handleCurrentChange = (newCurrentPage: number) => {
|
||
pagination.currentPage = newCurrentPage
|
||
gettableList()
|
||
}
|
||
const timer = ref(0)
|
||
const refreshKey = ref(0)
|
||
const detailDialogVisible = ref(false)
|
||
const detailRow = ref<any>(null)
|
||
|
||
onMounted(() => {
|
||
gettableList()
|
||
timer.value = window.setInterval(() => {
|
||
refreshKey.value++
|
||
}, 1000)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
if (timer.value) {
|
||
clearInterval(timer.value)
|
||
}
|
||
})
|
||
|
||
function getCountdown(targetDate: string) {
|
||
// 让 refreshKey 成为依赖,确保每秒刷新
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||
refreshKey.value
|
||
const now = dayjs()
|
||
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||
if (!target.isValid()) return '时间格式错误'
|
||
const diff = target.diff(now)
|
||
if (diff <= 0) return '已超时'
|
||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24)
|
||
const minutes = Math.floor((diff / (1000 * 60)) % 60)
|
||
const seconds = Math.floor((diff / 1000) % 60)
|
||
return `${days > 0 ? days + '天' : ''}${hours}小时${minutes}分${seconds}秒`
|
||
}
|
||
|
||
function getCountdownClass(targetDate: string) {
|
||
const now = dayjs()
|
||
const target = dayjs(targetDate, 'YYYY-MM-DD HH:mm:ss')
|
||
if (!target.isValid() || target.diff(now) <= 0) {
|
||
return 'countdown-danger'
|
||
}
|
||
return 'countdown-success'
|
||
}
|
||
const onFollow = async (row: any) => {
|
||
ElMessageBox.confirm('确定要领取此客户吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
.then(async () => {
|
||
const res = await CrmService.customerclaim({ customer_id: row.id })
|
||
ElMessage.success(res?.message || '提交成功!')
|
||
gettableList()
|
||
// 你可以在这里调用接口或做后续处理
|
||
})
|
||
.catch(() => {
|
||
// 用户点击了取消
|
||
})
|
||
}
|
||
function processImages(html: string) {
|
||
const parser = new DOMParser()
|
||
const doc = parser.parseFromString(html, 'text/html')
|
||
doc.querySelectorAll('img').forEach((img) => {
|
||
img.style.maxWidth = '100%'
|
||
img.style.height = 'auto'
|
||
img.style.cursor = 'zoom-in'
|
||
})
|
||
return doc.body.innerHTML
|
||
}
|
||
// 点击 desc_collect 中的图片 -> el-image-viewer 放大查看
|
||
const descViewerUrl = ref('')
|
||
function onDescImgClick(e: MouseEvent) {
|
||
const target = e.target as HTMLElement
|
||
if (target.tagName === 'IMG') {
|
||
descViewerUrl.value = (target as HTMLImageElement).src
|
||
}
|
||
}
|
||
function onDetail(row: any) {
|
||
row.desc_collect = processImages(row.desc_collect) // 处理图片
|
||
detailRow.value = row
|
||
detailDialogVisible.value = true
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.detils-content {
|
||
padding-left: 15px;
|
||
img {
|
||
max-width: 100% !important;
|
||
}
|
||
}
|
||
.boxshadow {
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 12px 0 rgba(0, 10, 118, 0.1);
|
||
background: var(--el-card-bg-color);
|
||
padding: 20px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.heard {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 10px;
|
||
.heard-title {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
border-left: 4px solid #3471ff;
|
||
padding-left: 12px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.heard-date-picker {
|
||
width: 120px;
|
||
}
|
||
.heard-select {
|
||
width: 120px;
|
||
}
|
||
}
|
||
|
||
.dark {
|
||
.card-list {
|
||
.art-custom-card {
|
||
.iconfont-sys {
|
||
background-color: #232323 !important;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.table {
|
||
:deep(.el-table__empty-block) {
|
||
height: 300px !important;
|
||
}
|
||
:deep(.el-table__header th) {
|
||
background: #f7f9fa !important;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
:deep(.el-table__body tr.custom-table-row td) {
|
||
border-bottom: 1px solid #f7f9fa !important;
|
||
border-right: 1px solid #f7f9fa !important;
|
||
}
|
||
:deep(.el-table__body tr td:last-child) {
|
||
border-right: none !important;
|
||
}
|
||
:deep(.el-table__body tr:last-child td) {
|
||
border-bottom: none !important;
|
||
}
|
||
:deep(.el-table__header-wrapper th) {
|
||
border-bottom: 1px solid #f7f9fa !important;
|
||
border-right: 1px solid #f7f9fa !important;
|
||
}
|
||
:deep(.el-table__header-wrapper th:last-child) {
|
||
border-right: none !important;
|
||
}
|
||
:deep(.el-table) {
|
||
border: 1px solid #f7f9fa !important;
|
||
border-radius: 6px;
|
||
}
|
||
:deep(.el-table th),
|
||
:deep(.el-table td) {
|
||
text-align: center !important;
|
||
}
|
||
}
|
||
.countdown-danger {
|
||
color: #ff0000 !important;
|
||
}
|
||
.countdown-success {
|
||
color: #00a43f !important;
|
||
}
|
||
.follow-detli {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
color: #00a43f;
|
||
padding: 4px 10px;
|
||
border-radius: 4px;
|
||
transition: background 0.2s;
|
||
&:hover {
|
||
background: #f5f7fa;
|
||
}
|
||
}
|
||
.follow-action {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
color: #409eff;
|
||
padding: 4px 10px;
|
||
border-radius: 4px;
|
||
transition: background 0.2s;
|
||
&:hover {
|
||
background: #f5f7fa;
|
||
}
|
||
}
|
||
</style>
|