文件:
@/components/sipCall/sipCallPhoneDialog.vue
本文档面向业务页面接入,参数统一使用sip前缀,避免与调用页本地字段冲突。
打开弹窗后按步骤执行:
高频安全点:
uuid 同步使用队列 + syncedUuids / syncingUuids 去重,不会重复同步| Prop(模板写法) | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
sip-visible.sync |
Boolean | 是 | false |
弹窗显隐。必须 .sync,对应事件 update:sipVisible |
sip-encrypted-phone |
String | 否* | '' |
加密手机号。与明文二选一,优先使用加密号 |
sip-plain-phone |
String | 否* | '' |
明文手机号。无加密号时使用,会跳过解密步骤 |
sip-dial-type |
String | 否 | 'audio' |
'audio' / 'video' |
sip-record-id |
String/Number | 否 | '' |
业务关联 ID(如订单号)。挂断后通过事件回传 |
*
sipEncryptedPhone与sipPlainPhone至少传一个,否则无法拨号。
| 事件名 | 参数 | 说明 |
|---|---|---|
update:sipVisible |
Boolean | 弹窗关闭/打开时触发(.sync 自动处理) |
sip-call-ended |
sipRecordId |
通话结束后触发,回传业务 ID |
<template>
<div>
<el-button type="text" @click="openSipCall">拨号</el-button>
<!--
关键接入约定:
1) 所有绑定字段使用 sip 前缀,避免和页面 phone/visible/recordId 冲突
2) 高频场景加 sipOpening / sipVisible 防重复点击
3) 有加密号优先传 sip-encrypted-phone;医生端常见明文则传 sip-plain-phone
-->
<call-phone-dialog
:sip-visible.sync="sipVisible"
:sip-encrypted-phone="sipEncryptedPhone"
:sip-plain-phone="sipPlainPhone"
:sip-dial-type="sipDialType"
:sip-record-id="sipRecordId"
@sip-call-ended="onSipCallEnded"
/>
</div>
</template>
<script>
import CallPhoneDialog from '@/components/sipCall/sipCallPhoneDialog.vue'
export default {
components: { CallPhoneDialog },
data() {
return {
sipVisible: false,
sipEncryptedPhone: '',
sipPlainPhone: '',
sipDialType: 'audio',
sipRecordId: '',
sipOpening: false
}
},
methods: {
/**
* 打开一键外呼
* @param {Object} payload
* @param {string} [payload.encryptedPhone] 加密号码
* @param {string} [payload.plainPhone] 明文号码
* @param {string|number} [payload.recordId] 业务 ID(订单/客户等)
*/
async openSipCall(payload = {}) {
// 防重复:弹窗已开或正在准备中
if (this.sipOpening || this.sipVisible) {
this.$message.warning('外呼进行中,请勿重复点击')
return
}
const encryptedPhone = payload.encryptedPhone || ''
const plainPhone = payload.plainPhone || ''
const recordId = payload.recordId
if (!encryptedPhone && !plainPhone) {
this.$message.warning('无可用号码')
return
}
this.sipOpening = true
try {
this.sipEncryptedPhone = encryptedPhone
this.sipPlainPhone = plainPhone
this.sipRecordId = recordId == null ? '' : recordId
this.sipDialType = 'audio'
this.sipVisible = true
} finally {
this.sipOpening = false
}
},
onSipCallEnded(recordId) {
// 可在此刷新通话记录列表、更新订单状态等
console.log('[业务页] 外呼结束, recordId=', recordId)
}
}
}
</script>
<call-phone-dialog
:sip-visible.sync="sipVisible"
:sip-plain-phone="sipPlainPhone"
:sip-record-id="sipRecordId"
@sip-call-ended="onSipCallEnded"
/>
点击「拨号」时:
getOrderUserPhone(orderId) 获取号码,失败则回退页面展示号sipPlainPhone / sipRecordId 后打开弹窗gatewayId 作为 myGateway 请求工具条参数并连接挂断后流程:
uuid 规范化后放入同步队列(全局 + 会话去重,避免高频重复同步)callEndSyncByUuid(等待后端生成话单)VUE_APP_SIP_PHONE_ENCRYPT_PRIVATE_KEYvisible / phone / recordId 去绑定本组件,统一用 sip* 字段| 现象 | 可能原因 | 处理 |
|---|---|---|
| 提示未查询到分机号 | 未做外呼配置绑定 | 到「外呼信息 → 外呼配置」绑定分机/线路 |
| 提示暂无可用线路 | 网关列表为空 | 检查 remoteGateWayList / 工具条网关配置 |
| 解密失败 | 传了明文却走加密流程,或私钥缺失 | 明文用 sip-plain-phone;加密用 sip-encrypted-phone |
| 重复点击无反应/提示进行中 | 防重锁生效 | 等当前弹窗结束再拨 |
| 记录未同步 | 挂断后不足 5 秒刷新、或 uuid 为空 | 等待同步完成;检查挂断事件是否产出 uuid |
sip 前缀为准(旧的 visible / encryptedPhone / recordId / call-ended 已废弃)5s5s