| | |
| | | <template> |
| | | <div class="call-container"> |
| | | <div class="sip-status" :class="sipStatusClass"> |
| | | SIP状态: {{ sipStatus }} |
| | | </div> |
| | | <!-- 号码输入 --> |
| | | <input |
| | | v-model="phoneNumber" |
| | | type="text" |
| | | placeholder="输入电话号码" |
| | | @keyup.enter="startCall" |
| | | > |
| | | /> |
| | | |
| | | <!-- 呼叫按钮 --> |
| | | <button |
| | | :class="['call-btn', { 'calling': isCalling }]" |
| | | @click="startCall" |
| | | > |
| | | {{ isCalling ? '通话中...' : '一键呼叫' }} |
| | | <button :class="['call-btn', { calling: isCalling }]" @click="startCall"> |
| | | {{ isCalling ? "通话中..." : "一键呼叫" }} |
| | | </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> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import sipService from '@/utils/sipService' |
| | | import sipService from "@/utils/sipService"; |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | phoneNumber: '', |
| | | phoneNumber: "", |
| | | isCalling: false, |
| | | callStatus: '准备就绪', |
| | | callStatus: "准备就绪", |
| | | 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: "1000@192.168.100.6", |
| | | password: "Smartor@2023", |
| | | displayName: "Web 小龙", |
| | | realm: "192.168.100.6:8090", |
| | | }, |
| | | }; |
| | | }, |
| | | 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.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注册失败"); |
| | | } |
| | | }; |
| | | }, |
| | | beforeDestroy() { |
| | | // 组件销毁时结束通话 |
| | | this.endCall() |
| | | this.endCall(); |
| | | }, |
| | | methods: { |
| | | // 开始呼叫 |
| | | async startCall() { |
| | | if (!this.phoneNumber) { |
| | | this.callStatus = '请输入电话号码' |
| | | return |
| | | this.callStatus = "请输入电话号码"; |
| | | return; |
| | | } |
| | | try { |
| | | this.isCalling = true |
| | | this.callStatus = '呼叫中...' |
| | | this.isCalling = true; |
| | | this.callStatus = "呼叫中..."; |
| | | // 调用SIP服务 |
| | | sipService.makeCall(this.phoneNumber) |
| | | sipService.makeCall(this.phoneNumber); |
| | | |
| | | this.callStatus = '通话已建立' |
| | | this.callStatus = "通话已建立"; |
| | | } catch (error) { |
| | | console.error('呼叫失败:', error) |
| | | this.callStatus = `呼叫失败: ${error.message}` |
| | | this.isCalling = false |
| | | console.error("呼叫失败:", error); |
| | | this.callStatus = `呼叫失败: ${error.message}`; |
| | | this.isCalling = false; |
| | | } |
| | | }, |
| | | |
| | | // 结束通话 |
| | | endCall() { |
| | | sipService.endCall() |
| | | this.isCalling = false |
| | | this.callStatus = '通话已结束' |
| | | } |
| | | } |
| | | } |
| | | sipService.endCall(); |
| | | this.isCalling = false; |
| | | this.callStatus = "通话已结束"; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | |
| | | |
| | | .call-btn { |
| | | padding: 10px; |
| | | background-color: #4CAF50; |
| | | background-color: #4caf50; |
| | | color: white; |
| | | border: none; |
| | | border-radius: 4px; |
| | |
| | | } |
| | | |
| | | .call-btn.calling { |
| | | background-color: #2196F3; |
| | | background-color: #2196f3; |
| | | } |
| | | |
| | | .end-call-btn { |
| | |
| | | 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> |
| | |
| | | token: (state) => state.user.token, |
| | | avatar: (state) => state.user.avatar, |
| | | name: (state) => state.user.name, |
| | | nickName: (state) => state.user.nickName, |
| | | Id: (state) => state.user.Id, |
| | | introduction: (state) => state.user.introduction, |
| | | roles: (state) => state.user.roles, |
| | |
| | | state: { |
| | | token: getToken(), |
| | | name: '', |
| | | nickName:'', |
| | | Id: '', |
| | | avatar: '', |
| | | hisUserId:'', |
| | |
| | | SET_NAME: (state, name) => { |
| | | state.name = name |
| | | }, |
| | | SET_nickNAME: (state, name) => { |
| | | state.nickName = name |
| | | }, |
| | | SET_Id: (state, Id) => { |
| | | state.Id = Id |
| | | console.log(state.Id,'user2'); |
| | |
| | | commit('SET_ROLES', ['ROLE_DEFAULT']) |
| | | } |
| | | commit('SET_NAME', user.userName) |
| | | commit('SET_nickNAME', user.nickName) |
| | | commit('SET_Id', user.userId) |
| | | commit('SET_hisUserId', user.hisUserId) |
| | | commit('SET_leavehospitaldistrictcodes', user.belongWards) |
| | |
| | | constructor() { |
| | | this.ua = null |
| | | this.currentSession = null |
| | | this.onStatusChange = null // 状态变化回调 |
| | | } |
| | | |
| | | // 初始化SIP客户端 |
| | | init(config) { |
| | | this.ua = new JsSIP.UA({ |
| | | sockets: [new JsSIP.WebSocketInterface(config.wsUrl)], |
| | | uri: config.sipUri, |
| | | password: config.password, |
| | | display_name: config.displayName, |
| | | realm: config.realm, |
| | | ha1: config.ha1, |
| | | register: true |
| | | }) |
| | | try { |
| | | this.updateStatus('connecting', '连接中...') |
| | | |
| | | this.ua.start() |
| | | this.ua = new JsSIP.UA({ |
| | | sockets: [new JsSIP.WebSocketInterface(config.wsUrl)], |
| | | uri: config.sipUri, |
| | | password: config.password, |
| | | display_name: config.displayName, |
| | | realm: config.realm, |
| | | register: true, |
| | | register_expires: 300, // 注册有效期(秒) |
| | | connection_recovery_min_interval: 2, // 最小重连间隔 |
| | | connection_recovery_max_interval: 30 // 最大重连间隔 |
| | | }) |
| | | |
| | | // 注册事件监听 |
| | | this.ua.on('registered', () => { |
| | | console.log('SIP注册成功') |
| | | }) |
| | | this.ua.start() |
| | | |
| | | this.ua.on('registrationFailed', (e) => { |
| | | console.error('SIP注册失败:', e) |
| | | }) |
| | | // 注册事件监听 |
| | | this.ua.on('registered', () => { |
| | | this.updateStatus('registered', '已注册') |
| | | }) |
| | | |
| | | // 监听来电 |
| | | this.ua.on('newRTCSession', (data) => { |
| | | this.handleIncomingCall(data.session) |
| | | }) |
| | | this.ua.on('registrationFailed', (e) => { |
| | | this.updateStatus('failed', `注册失败: ${e.cause}`) |
| | | }) |
| | | |
| | | this.ua.on('disconnected', () => { |
| | | this.updateStatus('disconnected', '连接断开') |
| | | }) |
| | | |
| | | this.ua.on('connected', () => { |
| | | this.updateStatus('connecting', '重新连接中...') |
| | | }) |
| | | |
| | | // 监听来电 |
| | | this.ua.on('newRTCSession', (data) => { |
| | | this.handleIncomingCall(data.session) |
| | | }) |
| | | |
| | | } catch (error) { |
| | | this.updateStatus('failed', `初始化失败: ${error.message}`) |
| | | console.error('SIP初始化失败:', error) |
| | | } |
| | | } |
| | | |
| | | // 一键拨号 |
| | | // 更新状态并通知UI |
| | | updateStatus(type, text) { |
| | | console.log(`SIP状态更新: ${type} - ${text}`) |
| | | if (this.onStatusChange) { |
| | | this.onStatusChange({ type, text }) |
| | | } |
| | | } |
| | | |
| | | // 一键拨号 - 增加注册状态检查 |
| | | makeCall(targetNumber) { |
| | | if (!this.ua) { |
| | | console.error('SIP客户端未初始化') |
| | | return |
| | | throw new Error('SIP客户端未初始化') |
| | | } |
| | | |
| | | if (!this.ua.isRegistered()) { |
| | | throw new Error('SIP未注册,无法呼叫') |
| | | } |
| | | |
| | | const options = { |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row > |
| | | <el-col :span="8"> |
| | | <el-form-item label="过滤医生" width="100" prop="filterDrname"> |
| | | <el-input |
| | | v-model="form.filterDrname" |
| | | placeholder="请输入医生姓名" |
| | | maxlength="30" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="过滤原因"> |
| | |
| | | handleUpdate(row) { |
| | | particularpatient(row.patid).then((response) => { |
| | | this.form = response.data; |
| | | this.form.filterDrname = store.getters.nickName; |
| | | }); |
| | | this.amendtag = true; |
| | | this.Labelchange = true; |
| | |
| | | handleUpdate(row) { |
| | | particularpatient(row.patid).then((response) => { |
| | | this.form = response.data; |
| | | this.form.filterDrname = store.getters.name; |
| | | this.form.filterDrname = store.getters.nickName; |
| | | }); |
| | | this.amendtag = true; |
| | | this.Labelchange = true; |
| | |
| | | </el-collapse> |
| | | </div> |
| | | </div> |
| | | <div> |
| | | <!-- <div> |
| | | <h2>一键呼叫功能</h2> |
| | | <CallButton/> |
| | | </div> |
| | | </div> --> |
| | | <div> |
| | | <el-tabs v-model="activeName" type="border-card"> |
| | | <el-tab-pane name="wj"> |
| | |
| | | const userIds = row.id || this.ids; |
| | | particularpatient(userIds).then((response) => { |
| | | this.form = response.data; |
| | | this.form.filterDrname = store.getters.name; |
| | | this.form.filterDrname = store.getters.nickName; |
| | | }); |
| | | this.amendtag = true; |
| | | this.Labelchange = true; |
| | |
| | | > |
| | | <el-date-picker |
| | | v-model="queryParams.dateRange" |
| | | value-format="yyyy-MM-dd" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | |
| | | // 获取科室树 |
| | | getDeptTree() { |
| | | // 科室列表 |
| | | this.flatArraydept = store.getters.belongDepts.map((dept) => { |
| | | return { |
| | | label: dept.deptName, |
| | | value: dept.deptCode, |
| | | }; |
| | | }); |
| | | this.flatArrayhospit = store.getters.belongWards.map((dept) => { |
| | | return { |
| | | label: dept.districtName, |
| | | value: dept.districtCode, |
| | | }; |
| | | }); |
| | | this.flatArraydept = store.getters.belongDepts.map((dept) => { |
| | | return { |
| | | label: dept.deptName, |
| | | value: dept.deptCode, |
| | | }; |
| | | }); |
| | | this.flatArrayhospit = store.getters.belongWards.map((dept) => { |
| | | return { |
| | | label: dept.districtName, |
| | | value: dept.districtCode, |
| | | }; |
| | | }); |
| | | // deptTreeSelect().then((response) => { |
| | | // this.deptOptions = response.data; |
| | | // console.log(this.deptOptions, " this.deptOptions"); |
| | |
| | | } else if (this.queryParams.statisticaltype == 2) { |
| | | this.queryParams.leavehospitaldistrictcodes = []; |
| | | } |
| | | console.log(this.queryParams.dateRange); |
| | | |
| | | this.queryParams.startTime = this.parseTime( |
| | | this.queryParams.dateRange[0] |
| | | ); |