海信医疗-远程超声管理平台-信创国产化
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

431 lines
11 KiB

<template>
<div class="app-container">
<!-- 1. 会议模式卡片 -->
<el-card class="card" style="margin-bottom: 10px">
<div slot="header" class="card-header">
<span class="line"></span>
会议模式
</div>
<!-- 口令入会区域 -->
<div class="join-area">
<el-input
v-model="room_id"
placeholder="请输入数字口令"
class="join-input"
@keyup.enter="joinMeeting"
/>
<el-button type="success" class="join-btn" @click="joinMeeting">
入会
</el-button>
</div>
<!-- 四种模式卡片 -->
<div class="mode-list">
<div
v-for="(mode, index) in meetingModes"
:key="index"
:class="['mode-item', mode.color]"
@click="handleModeClick(mode)"
>
<div class="title">
{{ mode.title }}
</div>
<div class="icon-bg">
<i :class="mode.icon"></i>
</div>
</div>
</div>
</el-card>
<!-- 2. 会诊记录卡片 -->
<el-card class="card">
<div slot="header" class="card-header">
<span class="line"></span>
会诊记录
</div>
<!-- 会诊表格 -->
<div class="table-wrapper">
<el-table
v-loading="loading"
:data="list"
:show-header="false"
stripe
height="calc(100vh - 550px)"
>
<el-table-column label="头像" prop="avatar" align="center" width="50">
<template slot-scope="scope">
<!-- MINIO_ENDPOINT_HTTPS+scope.row.avatar -->
<el-avatar
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
scope.row.avatar
"
/>
</template>
</el-table-column>
<el-table-column label="会诊名称" prop="name" align="center" />
<el-table-column
label="会议类型名称"
prop="meet_type_name"
align="center"
/>
<el-table-column label="创建时间" prop="create_time" align="center" />
<!-- 状态status 1-开始 0-结束 -->
<el-table-column label="操作" align="center" width="50">
<template slot-scope="scope">
<el-button
type="text"
icon="el-icon-more"
class="more-btn"
@click="handleDetail(scope.row)"
/>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<pagination
v-show="queryParams.total > 0"
:total="queryParams.total"
:page.sync="queryParams.page"
:limit.sync="queryParams.size"
@pagination="getList"
/>
</el-card>
<!-- 会诊详情弹框 -->
<el-dialog
:title="meetingDetail.name"
:visible.sync="meetingDetailVisible"
width="35%"
:close-on-click-modal="false"
>
<el-form :model="meetingDetail" label-width="110px">
<el-form-item>
{{ getStatusText(meetingDetail.status) }}
</el-form-item>
<el-divider />
<el-form-item label="会议时间">
{{ meetingDetail.create_time || "" }}
</el-form-item>
<el-form-item label="会议持续时间">
{{ formatDuration(meetingDetail.duration) }}
</el-form-item>
<el-form-item label="病例数记录">
<el-form-item label="总病例数">
{{ meetingDetail.total_patients }}例
</el-form-item>
<el-form-item label="阳性病例数">
{{ meetingDetail.positive_patients }}例
</el-form-item>
<el-form-item label="上级转诊病例数">
{{ meetingDetail.transfer_patients }}例
</el-form-item>
</el-form-item>
<el-divider />
<el-form-item label="会议发起人">
<el-row>
<el-col :span="3">
<el-form-item>
<el-avatar
:src="
meetingDetail.user_list && meetingDetail.user_list[0]
? $store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
meetingDetail.user_list[0].avatar
: ''
"
class="person-avatar"
/>
</el-form-item>
</el-col>
<el-col :span="21">
<el-form-item>
{{ meetingDetail.user_name || "" }}
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-divider />
<el-form-item label="参会人员" label-position="top">
<el-row v-for="(item, index) in meetingDetail.user_list" :key="index">
<el-col :span="3">
<el-form-item>
<el-avatar
:src="
$store.state.user.netConfig.MINIO_ENDPOINT_HTTPS +
item.avatar
"
class="person-avatar"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item>
{{ item.name || "" }}
</el-form-item>
</el-col>
<el-col :span="15">
<el-form-item label="入会时间">
{{ item.join_time || "" }}
</el-form-item>
</el-col>
</el-row>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import {
meetingModes,
postConsultationInfo,
getConsultationList,
getConsultationMeetingInfo,
} from "@/api/videoCommunication";
import { mapGetters } from "vuex";
export default {
name: "VideoPage",
data() {
return {
room_id: "",
loading: false,
queryParams: {
page: 1,
size: 10,
total: 0,
},
meetingModes: meetingModes(),
list: [],
meetingDetailVisible: false,
meetingDetail: {},
};
},
computed: {
...mapGetters(["userInfo", "config"]),
},
mounted() {
this.getList();
},
methods: {
// 获取状态文本
getStatusText(status) {
const statusMap = {
0: "已结束",
1: "进行中",
2: "空闲",
};
return statusMap[status] || "已结束";
},
// 格式化时长(秒转时分秒)
formatDuration(seconds) {
if (!seconds) return "-";
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
const s = seconds % 60;
return `${h}${m}${s}`;
},
// 口令入会
joinMeeting() {
if (!this.room_id.trim()) {
this.$message.warning("入会口令格式错误");
return;
}
this.loading = true;
// 模拟接口调用
postConsultationInfo({
consultation_id: 0,
from_history: 0,
room_id: this.room_id,
})
.then((res) => {
this.$message.success("成功加入会议");
this.room_id = "";
// 修复:转成数字再匹配 + 增加兜底判断
const firstNum = Number(String(res.data.room_id)[0]);
const targetMode = this.meetingModes.find(
(item) => item.type === firstNum
);
// 兜底:没有匹配到则提示并终止跳转
if (!targetMode) {
this.$message.error("未匹配到对应会议模式");
this.loading = false;
return;
}
// 正常跳转
this.$router.push({
name: targetMode.routeName,
query: {
consultation_id: 0,
from_history: 0,
room_id: res.data.room_id,
},
});
})
.catch(() => {
this.$message.error("入会失败,请检查口令是否正确");
})
.finally(() => {
this.loading = false;
});
},
generateRoomId(meetingType, id) {
// 1. id固定3位,不足左侧补0
const idStr = String(id).padStart(3, "0");
// 拼接 = 会议类型 + 3位id + 前缀
const roomId = meetingType + idStr + this.config.MEETING_PREFIX;
return roomId;
},
// 处理会议模式点击
handleModeClick(mode) {
this.$router.push({
name: mode.routeName,
query: {
name: this.userInfo.group,
roomId_id: this.generateRoomId(mode.type, this.userInfo.id),
},
});
},
// 会议记录列表
getList() {
this.loading = true;
getConsultationList(this.queryParams).then((res) => {
console.log("会诊记录", res.data.list);
this.list = res.data.list;
this.queryParams.total = Number(res.data.total);
this.loading = false;
});
},
// 会议详情
handleDetail(row) {
getConsultationMeetingInfo(row).then((res) => {
console.log("会诊记录详情", res.data);
this.meetingDetail = res.data;
this.meetingDetailVisible = true;
});
},
},
};
</script>
<style lang="scss" scoped>
.app-container {
padding: 10px;
}
// 卡片通用样式
.card {
.card-header {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 500;
color: #333;
.line {
display: inline-block;
width: 3px;
height: 16px;
background-color: #009696;
margin-right: 8px;
}
}
// 口令入会区域
.join-area {
display: flex;
align-items: center;
margin-bottom: 20px;
.join-input {
width: 250px;
margin-right: 10px;
}
.join-btn {
background-color: #009696;
border-color: #009696;
color: #fff;
&:hover {
background-color: #00796b;
border-color: #00796b;
}
}
}
// 会议模式列表
.mode-list {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
.mode-item {
height: 115px;
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
position: relative;
overflow: hidden;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
&:hover {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
}
&:active {
transform: translateY(-1px);
}
.title {
font-size: 18px;
margin-bottom: 10px;
z-index: 1;
}
.icon-bg {
position: absolute;
right: 20px;
bottom: 20px;
font-size: 40px;
opacity: 0.3;
}
&::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 60px;
background: rgba(255, 255, 255, 0.1);
border-radius: 100% 100% 0 0;
}
&.blue {
background: linear-gradient(to right, #67c2ef, #2196f3);
}
&.yellow {
background: linear-gradient(to right, #ffd54f, #ff9800);
}
&.grayblue {
background: linear-gradient(to right, #b0bec5, #29b6f6);
}
&.greenblue {
background: linear-gradient(to right, #43d8c9, #29b6f6);
}
}
}
// 会诊记录表格
.more-btn {
color: #009696;
cursor: pointer;
}
}
</style>