调整联系方式字段为电话 列表中多个联系方式纵向排列显示 会增加公司信息的自定义输入框 排序搜索 等功能

This commit is contained in:
浅念
2025-08-21 11:12:12 +08:00
parent 70d26f0829
commit b319944007
11 changed files with 299 additions and 51 deletions
@@ -55,13 +55,14 @@
</div>
</div> -->
<div class="btn-box screen-box" @click="clearCachefn">
<div class="btn">
<div class="btn" title="清除缓存">
<i class="iconfont-sys">&#xe847;</i>
</div>
</div>
<!-- 全屏按钮 -->
<div class="btn-box screen-box" @click="toggleFullScreen">
<div
:title="isFullscreen ? '退出全屏' : '全屏'"
class="btn"
:class="{ 'full-screen-btn': !isFullscreen, 'exit-full-screen-btn': isFullscreen }"
>
@@ -123,7 +124,7 @@
</div> -->
<!-- 切换主题 -->
<div class="btn-box" @click="themeAnimation">
<div class="btn theme-btn">
<div class="btn theme-btn" title="切换主题">
<i class="iconfont-sys">{{ isDark ? '&#xe6b5;' : '&#xe725;' }}</i>
</div>
</div>
+48 -2
View File
@@ -12,6 +12,42 @@ let reconnectAttempts = 0
const maxReconnectDelayMs = 30000
const heartbeatIntervalMs = 30000
// 生成全局唯一的 trace_id(优先使用 crypto.randomUUID)
const generateTraceId = (): string => {
try {
// @ts-ignore
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
// @ts-ignore
return `req-${crypto.randomUUID()}`
}
} catch (_) {}
// Fallback:基于时间戳 + 随机数
const timestampPart = Date.now().toString(36)
let randomPart = ''
try {
// @ts-ignore
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
const buf = new Uint8Array(16)
// @ts-ignore
crypto.getRandomValues(buf)
randomPart = Array.from(buf)
.map((b) => b.toString(16).padStart(2, '0'))
.join('')
} else {
randomPart = Array.from({ length: 16 })
.map(() =>
Math.floor(Math.random() * 256)
.toString(16)
.padStart(2, '0')
)
.join('')
}
} catch (_) {
randomPart = Math.random().toString(36).slice(2)
}
return `req-${timestampPart}-${randomPart}`
}
const getReconnectDelay = () => {
const base = 1000 * Math.pow(2, reconnectAttempts)
return Math.min(base, maxReconnectDelayMs)
@@ -38,7 +74,12 @@ const startHeartbeat = () => {
heartbeatTimer = setTimeout(() => {
try {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'ping' }))
const msg = {
event: 'system.ping',
data: {},
trace_id: generateTraceId() // 可选,用于请求-响应匹配
}
socket.send(JSON.stringify(msg))
}
} catch (_) {}
// 下一次心跳
@@ -74,7 +115,12 @@ export const initWebSocket = (token: string) => {
startHeartbeat()
mittBus.emit('ws:open')
try {
socket?.send(JSON.stringify({ type: 'ping' }))
const msg = {
event: 'system.ping',
data: {},
trace_id: generateTraceId() // 可选,用于请求-响应匹配
}
socket?.send(JSON.stringify(msg))
} catch (_) {}
}
+20 -3
View File
@@ -22,14 +22,31 @@
lass="customer-table"
>
<template #default>
<el-table-column prop="code" label="编号" align="center" />
<el-table-column
prop="code"
label="编号"
align="center"
width="170px"
show-overflow-tooltip
/>
<el-table-column prop="contacts" label="客户名称" align="center" />
<el-table-column prop="magnitude_txt" label="客户商机" align="center" />
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<!-- <el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="WhatsApp" label="WhatsApp" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="email" label="邮箱" align="center" /> -->
<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="grade_txt" label="等级" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
+20 -3
View File
@@ -32,14 +32,31 @@
>
<template #default>
<el-table-column type="selection" width="55px" align="center"></el-table-column>
<el-table-column prop="code" label="编号" align="center" />
<el-table-column
prop="code"
label="编号"
align="center"
width="170px"
show-overflow-tooltip
/>
<el-table-column prop="contacts" label="客户名称" align="center" />
<el-table-column prop="magnitude_txt" label="客户商机" align="center" />
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<!-- <el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="WhatsApp" label="WhatsApp" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="email" label="邮箱" align="center" /> -->
<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="grade_txt" label="等级" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
+21 -3
View File
@@ -108,14 +108,31 @@
>
<template #default>
<el-table-column type="selection" width="55px" align="center"></el-table-column>
<el-table-column prop="code" label="编号" align="center" />
<el-table-column
prop="code"
label="编号"
align="center"
width="170px"
show-overflow-tooltip
/>
<el-table-column prop="contacts" label="客户名称" align="center" />
<el-table-column prop="magnitude_txt" label="客户商机" align="center" />
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<!-- <el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="WhatsApp" label="WhatsApp" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="email" label="邮箱" align="center" /> -->
<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="grade_txt" label="等级" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
@@ -126,6 +143,7 @@
</el-table-column>
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
<el-table-column prop="user_name" label="跟单人"></el-table-column>
<el-table-column prop="follow_last" label="上次跟进"></el-table-column>
<el-table-column prop="follow_next" label="下次跟进"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column fixed="right" label="操作" width="200px" align="center">
+14 -3
View File
@@ -128,9 +128,20 @@
<el-table-column prop="magnitude_txt" label="客户商机" align="center" />
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="WhatsApp" label="WhatsApp" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<!-- <el-table-column prop="phone" label="电话" align="center" /> -->
<!-- <el-table-column prop="WhatsApp" label="WhatsApp" align="center" /> -->
<!-- <el-table-column prop="email" label="邮箱" align="center" /> -->
<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="grade_txt" label="等级" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
+1 -6
View File
@@ -81,12 +81,7 @@
</el-select>
</el-form-item>
<el-form-item label="公司" prop="company">
<el-input
v-model="form.company"
placeholder="请输入公司"
@click="showMapDialog = true"
readonly
/>
<el-input v-model="form.company" placeholder="请输入公司" />
</el-form-item>
<el-form-item label="备注" prop="describe">
<el-input v-model="form.describe" type="textarea" :rows="3" placeholder="请输入备注" />
+138 -13
View File
@@ -89,12 +89,23 @@
</div>
<div class="boxshadow">
<!-- Tab切换 -->
<el-tabs v-model="activeTab" class="customer-tabs">
<el-tab-pane label="全部" name=""></el-tab-pane>
<el-tab-pane label="跟进中" name="0"></el-tab-pane>
<el-tab-pane label="已成交" name="1"></el-tab-pane>
<el-tab-pane label="已丢失" name="2"></el-tab-pane>
</el-tabs>
<div class="customer-toolbar">
<el-tabs v-model="activeTab" class="customer-tabs" style="flex: 1">
<el-tab-pane label="全部" name=""></el-tab-pane>
<el-tab-pane label="跟进中" name="0"></el-tab-pane>
<el-tab-pane label="已成交" name="1"></el-tab-pane>
<el-tab-pane label="已丢失" name="2"></el-tab-pane>
</el-tabs>
<div>
<el-form-item label="" label-width="70px">
<el-cascader :options="options" clearable v-model="shots" />
<!-- <el-select v-model="selectValue" placeholder="排序方式" style="width: 120px">
<el-option v-for="v in sortList" :key="v.value" :label="v.label" :value="v.value">
</el-option>
</el-select> -->
</el-form-item>
</div>
</div>
<!-- 表格 -->
<ArtTable
@@ -110,16 +121,32 @@
lass="customer-table"
>
<template #default>
<el-table-column prop="code" label="编号" align="center" />
<el-table-column
prop="code"
label="编号"
align="center"
width="170px"
show-overflow-tooltip
/>
<el-table-column prop="contacts" label="客户名称" align="center" />
<el-table-column prop="magnitude_txt" label="客户商机" align="center" />
<el-table-column prop="channel_name" label="渠道" align="center" />
<el-table-column prop="country_name" label="国家" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<!-- <el-table-column prop="phone" label="电话" align="center" /> -->
<!-- <el-table-column prop="WhatsApp" label="WhatsApp" align="center" /> -->
<el-table-column prop="email" label="邮箱" align="center" />
<!-- <el-table-column prop="email" label="邮箱" align="center" /> -->
<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="grade_txt" label="等级" align="center" />
<el-table-column prop="describe" label="备注" align="center" />
<!-- <el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
<span :class="statusClass(scope.row.follow)">
@@ -127,8 +154,10 @@
</span>
</template>
</el-table-column> -->
<el-table-column prop="follow_next" label="下次跟进时间"></el-table-column>
<el-table-column prop="follow_last" label="上次跟进"></el-table-column>
<el-table-column prop="follow_next" label="下次跟进"></el-table-column>
<el-table-column prop="enter_user_name" label="录单人"></el-table-column>
<el-table-column prop="describe" label="备注" align="center" />
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column fixed="right" label="操作" width="200px" align="center">
<template #default="scope">
@@ -177,7 +206,48 @@
</div>
</div>
<el-dialog v-model="detailDialogVisible" title="详情">
<div v-if="detailRow" v-html="detailRow.desc_collect" class="detils-content"></div>
<div class="detail-info-table">
<div class="row">
<div>客户名称:{{ detailRow.contacts }}</div>
<div>电话:{{ detailRow.phone }}</div>
<div>国家:{{ detailRow.country_name }}</div>
</div>
<div class="row">
<div>渠道:{{ detailRow.channel_name }}</div>
<div>邮箱:{{ detailRow.email }}</div>
<div>WhatsApp:{{ detailRow.WhatsApp }}</div>
</div>
<div class="row">
<div>发布人:{{ detailRow.enter_user_name }}</div>
<div>跟单人:{{ detailRow.user_name }}</div>
<div>录单时间:{{ detailRow.created_at }}</div>
</div>
<div class="row">
<div>
等级:
<span>
{{ detailRow.magnitude_txt }}
</span>
</div>
<div>
状态:<span>{{ detailRow.grade_txt }}</span>
</div>
<div>
跟进状态:<span>{{ detailRow.follow_txt }}</span>
</div>
</div>
<div class="row">
<div>备注:{{ detailRow.describe }}</div>
</div>
</div>
<div v-if="detailRow.desc_collect != '' && detailRow.desc_collect != 'null'" class="dtitle"
>详情内容</div
>
<div
v-if="detailRow.desc_collect != '' && detailRow.desc_collect != 'null'"
v-html="detailRow.desc_collect"
class="detils-content"
></div>
</el-dialog>
<el-dialog v-model="reportDialogVisible" title="标记无效" width="600px">
<el-form :model="reportForm" label-width="80px">
@@ -247,6 +317,19 @@
{ label: '近三天', value: '1' },
{ label: '近七天', value: '2' }
]
const shots = ref([])
const options = ref<
Array<{
label: string
value: string
children: Array<{ label: string; value: string }>
}>
>([
{ label: '默认排序', value: 'id', children: [] },
{ label: '最后跟进', value: 'follow_last', children: [] },
{ label: '下次跟进', value: 'follow_next', children: [] },
{ label: '标签组', value: 'tag_group', children: [] }
])
const countryOptions = ref<any>()
//国家
const getarea = async () => {
@@ -269,6 +352,10 @@
tagActiveMap[group.id] = ''
}
})
options.value[3].children = tagGroups.value.map((group) => ({
label: group.name,
value: group.id
}))
}
// 计算前3组和更多组
// eslint-disable-next-line vue/valid-define-props
@@ -283,7 +370,8 @@
tagGrouplistfn()
})
// tabs 切换联动
watch([activeTab, searchValue, selectValue, country_id], () => {
watch([activeTab, searchValue, selectValue, country_id, shots], () => {
console.log('tabs 联动' + shots.value)
pagination.currentPage = 1
gettableList()
})
@@ -299,6 +387,12 @@
if (selectValue.value) params.follow_last = selectValue.value
if (country_id.value) params.country_id = country_id.value
if (activeTab.value && activeTab.value !== '') params.follow = activeTab.value
if (shots.value.length > 0) {
params.sort = shots.value[0]
if (shots.value[0] == 'tag_group') {
params.sort_id = shots.value[1]
}
}
// 标签参数,所有选中的标签id组成数组
const selectedTagIds = Object.values(tagActiveMap).filter(Boolean)
if (selectedTagIds.length) {
@@ -420,6 +514,37 @@
</script>
<style scoped lang="scss">
.detail-info-table {
padding-left: 15px;
.row {
display: flex;
justify-content: flex-start;
margin-bottom: 6px;
> div {
flex: 1;
min-width: 0;
margin-right: 16px;
overflow: hidden;
font-size: 14px;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.dtitle {
line-height: 40px;
color: #333;
font-size: 16px;
font-weight: bold;
padding-left: 15px;
}
.detils-content {
padding-left: 15px;
img {
max-width: 100% !important;
}
}
:deep(.el-badge) {
--el-badge-size: 16px;
}
+13 -2
View File
@@ -30,9 +30,20 @@
>
<template #default>
<el-table-column prop="contacts" label="客户名称"></el-table-column>
<el-table-column prop="phone" 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="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>
+19 -12
View File
@@ -42,15 +42,22 @@
<template #default>
<el-table-column type="selection" width="55px" align="center"></el-table-column>
<el-table-column prop="code" label="编号" align="center" />
<el-table-column prop="contacts" label="客户名称"></el-table-column>
<el-table-column prop="phone" label="电话"></el-table-column>
<el-table-column prop="contacts" label="客户名称" align="center"></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="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="user_name" label="跟单人"></el-table-column>
<el-table-column prop="created_at" label="创建时间"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column> -->
<el-table-column prop="follow" label="联系方式" min-width="160px">
<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="客户商机" align="center"></el-table-column>
<el-table-column prop="channel_name" label="渠道" align="center"></el-table-column>
<el-table-column prop="country_name" label="国家" align="center"></el-table-column>
<el-table-column prop="user_name" label="跟单人" align="center"></el-table-column>
<el-table-column prop="created_at" label="创建时间" align="center"></el-table-column>
</template>
</ArtTable>
</div>
@@ -268,10 +275,10 @@
border: 1px solid #f7f9fa !important;
border-radius: 6px;
}
:deep(.el-table th),
:deep(.el-table td) {
text-align: center !important;
}
// :deep(.el-table th),
// :deep(.el-table td) {
// text-align: center !important;
// }
}
.countdown-danger {
color: #ff0000 !important;
+2 -2
View File
@@ -134,7 +134,7 @@
<span class="sender-name">{{ message.user_name }}</span>
<span class="message-time">{{ message.updated_at }}</span>
</div>
<div class="message-text">{{ message.content }}</div>
<div class="message-text" v-html="message.content"></div>
<!-- 附件显示区域 -->
<div class="message-attachments" v-if="message.attachment && message.attachment.length > 0">
<div class="attachment-item" v-for="(attachment, attIndex) in message.attachment" :key="attIndex">
@@ -224,7 +224,6 @@
:rows="3"
placeholder="输入消息"
resize="none"
@keyup.enter.prevent="sendMessage"
/>
<ElInput v-model="ticket_id" type="hidden" />
<div class="chat-input-actions">
@@ -775,6 +774,7 @@ const downloadAttachment = (attachment: any) => {
.message-text {
padding: 10px 14px;
line-height: 1.4;
white-space: pre-line;
}
}
}