WXL
2025-08-06 53f4f0add976a4b402dfc2ad8547056227156693
src/components/CallButton/index.vue
@@ -3,17 +3,19 @@
    <div class="sip-status" :class="sipStatusClass">
      SIP状态: {{ sipStatus }}
    </div>
    <!-- 号码输入 -->
    <input
      v-model="phoneNumber"
      type="text"
      placeholder="输入电话号码"
      @keyup.enter="startCall"
    />
    <!-- 状态显示 -->
    <div class="call-status" :class="callStatusClass">
      {{ callStatusText }}
    </div>
    <!-- 呼叫按钮 -->
    <button :class="['call-btn', { calling: isCalling }]" @click="startCall">
      {{ isCalling ? "通话中..." : "一键呼叫" }}
    <button
      :class="['call-btn', { calling: isCalling }]"
      @click="startCall"
      :disabled="isCalling || sipStatus !== '已注册'"
    >
      {{ callButtonText }}
    </button>
    <!-- 挂断按钮 -->
@@ -21,11 +23,6 @@
    <!-- 音频元素(隐藏) -->
    <audio id="remoteAudio" autoplay></audio>
    <!-- 状态显示 -->
    <div class="call-status">
      {{ callStatus }}
    </div>
  </div>
</template>
@@ -33,76 +30,87 @@
import sipService from "@/utils/sipService";
export default {
  props: {
    phoneNumber: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      phoneNumber: "",
      isCalling: false,
      callStatus: "准备就绪",
      callStatus: 'idle', // idle, calling, connected, ended
      sipStatus: "未连接",
      sipStatusClass: "status-disconnected",
     randomNum = Math.floor(Math.random() * 21) + 1000, // 生成 1000-1020 的随机整数
      sipConfig: {
        wsUrl: "wss://192.168.100.6:7443",
        sipUri: "1000@192.168.100.6",
        sipUri: `${randomNum}`+"@192.168.100.6",
        password: "Smartor@2023",
        displayName: "Web 小龙",
        // realm: "192.168.100.6:8090",
      },
    };
  },
  computed: {
    callStatusText() {
      const statusMap = {
        idle: '准备就绪',
        calling: '呼叫中...',
        connected: '通话中',
        ended: '通话结束'
      };
      return statusMap[this.callStatus];
    },
    callStatusClass() {
      return `status-${this.callStatus}`;
    },
    callButtonText() {
      return this.isCalling ? "通话中..." : "一键呼叫";
    }
  },
  mounted() {
    // 测试
    const ws = new WebSocket("wss://192.168.100.6:7443");
    ws.onopen = () => console.log("WebSocket 连接成功");
    ws.onerror = (e) => console.error("WebSocket 错误:", e);
    // 初始化SIP连接
    sipService.init(this.sipConfig);
    sipService.onStatusChange = (status) => {
      this.sipStatus = status.text;
      this.sipStatusClass = `status-${status.type}`;
    };
      // 根据状态更新UI或执行其他操作
      if (status.type === "registered") {
        console.log("SIP注册成功,可以开始呼叫");
      } else if (status.type === "failed") {
        console.error("SIP注册失败");
      }
    // 监听通话状态变化
    sipService.onCallStatusChange = (status) => {
      this.callStatus = status.type;
      this.isCalling = status.type === 'calling' || status.type === 'connected';
      // 通知父组件通话状态变化
      this.$emit('call-status-change', status);
    };
  },
  beforeDestroy() {
    // 组件销毁时结束通话
    this.endCall();
  },
  methods: {
    // 开始呼叫
    async startCall() {
      if (!this.phoneNumber) {
        this.callStatus = "请输入电话号码";
        this.$message.error("请输入电话号码");
        return;
      }
      try {
        this.isCalling = true;
        this.callStatus = "呼叫中...";
        // 调用SIP服务
        sipService.makeCall(this.phoneNumber);
        this.callStatus = "通话已建立";
      try {
        this.callStatus = 'calling';
        this.isCalling = true;
        await sipService.makeCall(this.phoneNumber);
      } catch (error) {
        console.error("呼叫失败:", error);
        this.callStatus = `呼叫失败: ${error.message}`;
        this.callStatus = 'ended';
        this.isCalling = false;
        this.$message.error(`呼叫失败: ${error.message}`);
      }
    },
    // 结束通话
    endCall() {
      sipService.endCall();
      this.callStatus = 'ended';
      this.isCalling = false;
      this.callStatus = "通话已结束";
    },
  },
    }
  }
};
</script>
@@ -132,7 +140,106 @@
  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;
}