WXL
12 小时以前 3ae495d3c3e95019b9e0066aae3c3b35802c51fe
测试完成
已添加1个文件
已修改9个文件
198 ■■■■ 文件已修改
dist.zip 补丁 | 查看 | 原始文档 | blame | 历史
src/components/CallButton/index.vue 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/getters.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/sipService.js 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/again/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/discharge/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/followvisit/record/detailpage/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/patient/patient/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sfstatistics/percentage/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
dist.zip
Binary files differ
src/components/CallButton/index.vue
@@ -1,29 +1,23 @@
<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>
@@ -36,60 +30,80 @@
</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>
@@ -112,7 +126,7 @@
.call-btn {
  padding: 10px;
  background-color: #4CAF50;
  background-color: #4caf50;
  color: white;
  border: none;
  border-radius: 4px;
@@ -124,7 +138,7 @@
}
.call-btn.calling {
  background-color: #2196F3;
  background-color: #2196f3;
}
.end-call-btn {
@@ -145,4 +159,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>
src/store/getters.js
@@ -8,6 +8,7 @@
  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,
src/store/modules/user.js
@@ -5,6 +5,7 @@
  state: {
    token: getToken(),
    name: '',
    nickName:'',
    Id: '',
    avatar: '',
    hisUserId:'',
@@ -87,6 +88,9 @@
    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');
@@ -168,6 +172,7 @@
            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)
src/utils/sipService.js
@@ -4,42 +4,72 @@
  constructor() {
    this.ua = null
    this.currentSession = null
    this.onStatusChange = null // 状态变化回调
  }
  // 初始化SIP客户端
  init(config) {
    try {
      this.updateStatus('connecting', '连接中...')
    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
        register: true,
        register_expires: 300, // 注册有效期(秒)
        connection_recovery_min_interval: 2, // 最小重连间隔
        connection_recovery_max_interval: 30 // 最大重连间隔
    })
    this.ua.start()
    // 注册事件监听
    this.ua.on('registered', () => {
      console.log('SIP注册成功')
        this.updateStatus('registered', '已注册')
    })
    this.ua.on('registrationFailed', (e) => {
      console.error('SIP注册失败:', 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 = {
src/views/followvisit/again/index.vue
@@ -644,7 +644,17 @@
            </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="过滤原因">
@@ -1590,6 +1600,7 @@
    handleUpdate(row) {
      particularpatient(row.patid).then((response) => {
        this.form = response.data;
        this.form.filterDrname = store.getters.nickName;
      });
      this.amendtag = true;
      this.Labelchange = true;
src/views/followvisit/discharge/index.vue
@@ -1828,7 +1828,7 @@
    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;
src/views/followvisit/record/detailpage/index.vue
@@ -353,10 +353,10 @@
        </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">
src/views/patient/patient/index.vue
@@ -1297,7 +1297,7 @@
      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;
src/views/sfstatistics/percentage/index.vue
@@ -125,6 +125,7 @@
              >
                <el-date-picker
                  v-model="queryParams.dateRange"
                  value-format="yyyy-MM-dd"
                  type="daterange"
                  range-separator="至"
                  start-placeholder="开始日期"
@@ -731,6 +732,8 @@
      } else if (this.queryParams.statisticaltype == 2) {
        this.queryParams.leavehospitaldistrictcodes = [];
      }
      console.log(this.queryParams.dateRange);
      this.queryParams.startTime = this.parseTime(
        this.queryParams.dateRange[0]
      );