sinake
2025-08-14 ba4eee2e5ced6aef3e85a7c7b8317817b7ad3cae
src/components/CallButton/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,294 @@
<template>
  <div class="call-container">
    <div class="sip-status" :class="sipStatusClass">
      SIP状态: {{ sipStatus }}
    </div>
    <!-- çŠ¶æ€æ˜¾ç¤º -->
    <div class="call-status" :class="callStatusClass">
      {{ callStatusText }}
    </div>
    <!-- å‘¼å«æŒ‰é’® -->
    <button
      :class="['call-btn', { calling: isCalling }]"
      @click="startCall"
      :disabled="isCalling || sipStatus !== '已注册'"
    >
      {{ callButtonText }}
    </button>
    <!-- æŒ‚断按钮 -->
    <button v-if="isCalling" class="end-call-btn" @click="endCall">挂断</button>
    <!-- éŸ³é¢‘元素(隐藏) -->
    <audio id="remoteAudio" autoplay></audio>
  </div>
</template>
<script>
import sipService from "@/utils/sipService";
export default {
  props: {
    phoneNumber: {
      type: String,
      default: "",
    },
  },
  data() {
    const randomNum = Math.floor(Math.random() * 11) + 1000; // å†…部定义
    return {
      isCalling: false,
      callStatus: "idle", // idle, calling, connected, ended
      sipStatus: "未连接",
      sipStatusClass: "status-disconnected",
      sipConfig: {
        wsUrl: "wss://192.168.10.124:7443",
        sipUri: `${randomNum}` + "@192.168.10.124",
        password: "Smartor@2023",
        displayName: "Web å°é¾™",
      },
    };
  },
  computed: {
    callStatusText() {
      const statusMap = {
        idle: "准备就绪",
        calling: "呼叫中...",
        connected: "通话中",
        ended: "通话结束",
      };
      return statusMap[this.callStatus];
    },
    callStatusClass() {
      return `status-${this.callStatus}`;
    },
    callButtonText() {
      return this.isCalling ? "通话中..." : "一键呼叫";
    },
  },
  mounted() {
    sipService.init(this.sipConfig);
    sipService.onStatusChange = (status) => {
      this.sipStatus = status.text;
      this.sipStatusClass = `status-${status.type}`;
    };
    // ç›‘听通话状态变化
    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.$message.error("请输入电话号码");
        return;
      }
      try {
        this.callStatus = "calling";
        this.isCalling = true;
        await sipService.makeCall(this.phoneNumber);
      } catch (error) {
        console.error("呼叫失败:", error);
        this.callStatus = "ended";
        this.isCalling = false;
        this.$message.error(`呼叫失败: ${error.message}`);
      }
    },
    endCall() {
      sipService.endCall();
      this.callStatus = "ended";
      this.isCalling = false;
    },
  },
};
</script>
<style scoped>
.call-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 300px;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #eee;
  border-radius: 8px;
}
input {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}
.call-btn {
  padding: 10px;
  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;
}
.end-call-btn {
  padding: 10px;
  background-color: #f44336;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
.end-call-btn:hover {
  background-color: #d32f2f;
}
.call-status {
  margin-top: 10px;
  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>