WXL (wul)
4 小时以前 56c5f1f9c7f9ec8d229faf8139093698be65ec87
src/components/CallButton/index.vue
@@ -1,95 +1,215 @@
<template>
  <div class="call-container">
    <!-- 号码输入 -->
    <input
      v-model="phoneNumber"
      type="text"
      placeholder="输入电话号码"
      @keyup.enter="startCall"
    >
    <div class="sip-status" :class="sipStatusClass">
      SIP状态: {{ sipStatus }}
    </div>
    <!-- 状态显示 -->
    <div class="call-status" :class="callStatusClass">
      {{ callStatusText }}
    </div>
    <!-- 呼叫按钮 -->
    <button
      :class="['call-btn', { 'calling': isCalling }]"
      :class="['call-btn', { calling: isCalling }]"
      @click="startCall"
      :disabled="isCalling || sipStatus !== '已注册'"
    >
      {{ isCalling ? '通话中...' : '一键呼叫' }}
      {{ callButtonText }}
    </button>
    <!-- 挂断按钮 -->
    <button
      v-if="isCalling"
      class="end-call-btn"
      @click="endCall"
    >
      挂断
    </button>
    <button v-if="isCalling" class="end-call-btn" @click="endCall">挂断</button>
    <!-- 音频元素(隐藏) -->
    <audio id="remoteAudio" autoplay></audio>
    <!-- 状态显示 -->
    <div class="call-status">
      {{ callStatus }}
    </div>
  </div>
</template>
<script>
import sipService from '@/utils/sipService'
import sipService from "@/utils/sipService";
import { CallsetState, CallgetList } from "@/api/AiCentre/index";
export default {
  props: {
    phoneNumber: {
      type: String,
      default: "",
    },
  },
  data() {
    const randomNum = Math.floor(Math.random() * 20) + 1000; // 定义随机分机号
    return {
      phoneNumber: '',
      isCalling: false,
      callStatus: '准备就绪',
      randomNum: randomNum,
      randomID: null,
      callStatus: "idle", // idle, calling, connected, ended
      sipStatus: "未连接",
      sipStatusClass: "status-disconnected",
      sipConfig: {
        wsUrl: 'wss://192.168.100.6:7443',
        sipUri: '1000@192.168.100.6',
        password: 'Smartor@2023',
        displayName: 'Web 小龙',
        realm: '192.168.100.6:8090'
        wsUrl: "wss://192.168.100.6:7443",
        sipUri: "",
        password: "Smartor@2023",
        displayName: "Web 小龙",
        // realm: "9.208.5.18:8090",
      },
    };
  },
  computed: {
    callStatusText() {
      const statusMap = {
        idle: "准备就绪",
        calling: "呼叫中...",
        connected: "通话中",
        ended: "通话结束",
      };
      return statusMap[this.callStatus];
    },
    countdownText() {
      if (this.sipStatus !== "已注册") return "";
      const { canCall, reason } = sipService.canMakeCall();
      if (!canCall && reason.includes("等待")) {
        return reason;
      }
    }
      return "";
    },
    callStatusClass() {
      return `status-${this.callStatus}`;
    },
    callButtonText() {
      return this.isCalling ? "通话中..." : "一键呼叫";
    },
  },
  mounted() {
    // 初始化SIP连接
    sipService.init(this.sipConfig)
  created() {
    // CallgetList();
  },
  beforeDestroy() {
    // 组件销毁时结束通话
    this.endCall()
  async mounted() {
    await this.CallgetList();
    sipService.init(this.sipConfig);
    // 设置状态回调
    sipService.onStatusChange = (status) => {
      this.sipStatus = status.text;
      this.sipStatusClass = `status-${status.type}`;
      // 处理注册失败和断开连接情况
      if (status.type === "failed" || status.type === "disconnected") {
        this.overCallsetState(); // 释放分机号
      }
    };
    // 监听通话状态变化
    sipService.onCallStatusChange = (status) => {
      this.callStatus = status.type;
      this.isCalling = status.type === "calling" || status.type === "connected";
      // 通知父组件通话状态变化
      this.$emit("call-status-change", status);
    };
  },
  methods: {
    // 开始呼叫
    async startCall() {
      if (!this.phoneNumber) {
        this.callStatus = '请输入电话号码'
        return
        this.$message.error("请输入电话号码");
        return;
      }
      try {
        this.isCalling = true
        this.callStatus = '呼叫中...'
        // 调用SIP服务
        sipService.makeCall(this.phoneNumber)
        this.callStatus = '通话已建立'
      try {
        // 先检查是否可以呼叫
        const { canCall, reason } = sipService.canMakeCall();
        if (!canCall) {
          const { canCall, reason } = sipService.canMakeCall();
          //this.$message.warning(reason);
          //return;
        }
        this.callStatus = "calling";
        this.isCalling = true;
        console.log("开始呼叫:", sipService);
        await sipService.makeCall("0" + this.phoneNumber);
      } catch (error) {
        console.error('呼叫失败:', error)
        this.callStatus = `呼叫失败: ${error.message}`
        this.isCalling = false
        let registrationTime = Date.now(); // 记录注销成功时间
        console.log(registrationTime, "呼叫失败时间");
        console.error("呼叫失败1:", error);
        // this.callStatus = "ended";
        // this.isCalling = false;
        //this.$message.error(`呼叫失败: ${error.message}`);
        try {
          // 先检查是否可以呼叫
          const { canCall, reason } = sipService.canMakeCall();
          if (!canCall) {
            const { canCall, reason } = sipService.canMakeCall();
          }
          this.callStatus = "calling";
          this.isCalling = true;
          console.log("开始呼叫:", sipService);
          await sipService.makeCall("0" + this.phoneNumber);
        } catch (error) {
          this.callStatus = "ended";
          this.isCalling = false;
        }
      }
    },
    // 查询可用分机号
    async CallgetList() {
      try {
        const res = await CallgetList();
        this.randomNum = res.data[0].tel;
        this.randomID = res.data[0].id;
        // 正确设置 sipUri
        this.sipConfig.sipUri = `${this.randomNum}@192.168.100.6`;
        this.startCallsetState();
      } catch (error) {
        console.error("获取分机号失败:", error);
        this.updateStatus("failed", "获取分机号失败");
      }
    },
    async startCallsetState() {
      try {
        await CallsetState({ id: this.randomID, state: 1 });
        console.log("分机号状态更新为使用中");
      } catch (error) {
        console.error("更新分机号状态失败:", error);
      }
    },
    // 结束通话
    async overCallsetState() {
      try {
        if (this.randomID) {
          await CallsetState({ id: this.randomID, state: 0 });
          console.log("分机号状态更新为可用");
        }
      } catch (error) {
        console.error("释放分机号失败:", error);
      }
    },
    endCall() {
      sipService.endCall()
      this.isCalling = false
      this.callStatus = '通话已结束'
    }
  }
}
      sipService.endCall();
      this.callStatus = "ended";
      this.isCalling = false;
    },
    cleanupResources() {
      // 结束通话
      if (this.isCalling) {
        sipService.endCall();
      }
      // 释放分机号
      this.overCallsetState();
      // 断开 SIP 连接
      if (sipService.ua) {
        sipService.ua.stop();
      }
    },
  },
  beforeUnmount() {
    // 组件销毁时确保释放资源
    this.cleanupResources();
  },
};
</script>
<style scoped>
@@ -112,19 +232,118 @@
.call-btn {
  padding: 10px;
  background-color: #4CAF50;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.call-status {
  padding: 8px;
  margin: 10px 0;
  border-radius: 4px;
  text-align: center;
}
.status-idle {
  background-color: #f5f5f5;
  color: #666;
}
.status-calling {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-connected {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-ended {
  background-color: #ffebee;
  color: #c62828;
}
/* 原有样式保持不变 */
.call-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 300px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
}
.call-btn {
  padding: 10px;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.call-btn:hover:not(:disabled) {
  background-color: #45a049;
}
.call-btn:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}
.call-btn.calling {
  background-color: #2196f3;
}
.end-call-btn {
  padding: 10px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.end-call-btn:hover {
  background-color: #d32f2f;
}
.sip-status {
  padding: 8px;
  margin-bottom: 10px;
  border-radius: 4px;
  text-align: center;
}
.status-disconnected {
  background-color: #ffebee;
  color: #c62828;
}
.status-connecting {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-registered {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-failed {
  background-color: #ffebee;
  color: #c62828;
}
.call-btn:hover {
  background-color: #45a049;
}
.call-btn.calling {
  background-color: #2196F3;
  background-color: #2196f3;
}
.end-call-btn {
@@ -145,4 +364,30 @@
  font-size: 14px;
  color: #666;
}
.sip-status {
  padding: 8px;
  margin-bottom: 10px;
  border-radius: 4px;
  text-align: center;
}
.status-disconnected {
  background-color: #ffebee;
  color: #c62828;
}
.status-connecting {
  background-color: #fff8e1;
  color: #ff8f00;
}
.status-registered {
  background-color: #e8f5e9;
  color: #2e7d32;
}
.status-failed {
  background-color: #ffebee;
  color: #c62828;
}
</style>