工具-页面搭建

main
ysn 4 weeks ago
parent 071d92b009
commit 3e6a497eaa
  1. 4
      src/components/Breadcrumb/index.vue
  2. 127
      src/layout/components/Navbar.vue
  3. 8
      src/router/index.js
  4. 2
      src/views/error/401.vue
  5. 2
      src/views/error/404.vue
  6. 288
      src/views/utility/index.vue
  7. 10
      src/views/videoCommunication/realTimeConsultation.vue

@ -45,9 +45,9 @@ export default {
} else { } else {
matched = router.matched.filter(item => item.meta && item.meta.title) matched = router.matched.filter(item => item.meta && item.meta.title)
} }
// //
if (!this.isDashboard(matched[0])) { if (!this.isDashboard(matched[0])) {
matched = [{ path: "/index", meta: { title: "首页" } }].concat(matched) matched = [{ path: "/video/index", meta: { title: "视讯" } }].concat(matched)
} }
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
}, },

@ -1,9 +1,22 @@
<template> <template>
<div class="navbar" :class="'nav' + navType"> <div class="navbar" :class="'nav' + navType">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger
id="hamburger-container"
:is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb v-if="navType == 1" id="breadcrumb-container" class="breadcrumb-container" /> <breadcrumb
<top-nav v-if="navType == 2" id="topmenu-container" class="topmenu-container" /> v-if="navType == 1"
id="breadcrumb-container"
class="breadcrumb-container"
/>
<top-nav
v-if="navType == 2"
id="topmenu-container"
class="topmenu-container"
/>
<template v-if="navType == 3"> <template v-if="navType == 3">
<logo v-show="showLogo" :collapse="false"></logo> <logo v-show="showLogo" :collapse="false"></logo>
<top-bar id="topbar-container" class="topbar-container" /> <top-bar id="topbar-container" class="topbar-container" />
@ -32,21 +45,24 @@
</template> --> </template> -->
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover"> <el-dropdown
class="avatar-container right-menu-item hover-effect"
trigger="hover"
>
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<img :src="avatar" class="user-avatar"> <img :src="avatar" class="user-avatar" />
<span class="user-nickname"> {{ nickName }} </span> <span class="user-nickname"> {{ nickName }} </span>
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<router-link to="/user/profile"> <router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item> <el-dropdown-item>个人中心</el-dropdown-item>
</router-link> </router-link>
<!-- <el-dropdown-item @click.native="setLayout" v-if="setting"> <el-dropdown-item @click.native="setLayout" v-if="setting">
<span>布局设置</span> <span>布局设置</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click.native="lockScreen"> <el-dropdown-item @click.native="lockScreen">
<span>锁定屏幕</span> <span>锁定屏幕</span>
</el-dropdown-item> --> </el-dropdown-item>
<el-dropdown-item divided @click.native="logout"> <el-dropdown-item divided @click.native="logout">
<span>退出登录</span> <span>退出登录</span>
</el-dropdown-item> </el-dropdown-item>
@ -57,18 +73,18 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from "vuex";
import Breadcrumb from '@/components/Breadcrumb' import Breadcrumb from "@/components/Breadcrumb";
import TopNav from './TopNav' import TopNav from "./TopNav";
import TopBar from './TopBar' import TopBar from "./TopBar";
import Logo from './Sidebar/Logo' import Logo from "./Sidebar/Logo";
import Hamburger from '@/components/Hamburger' import Hamburger from "@/components/Hamburger";
import Screenfull from '@/components/Screenfull' import Screenfull from "@/components/Screenfull";
import SizeSelect from '@/components/SizeSelect' import SizeSelect from "@/components/SizeSelect";
import Search from '@/components/HeaderSearch' import Search from "@/components/HeaderSearch";
import RuoYiGit from '@/components/RuoYi/Git' import RuoYiGit from "@/components/RuoYi/Git";
import RuoYiDoc from '@/components/RuoYi/Doc' import RuoYiDoc from "@/components/RuoYi/Doc";
import HeaderNotice from './HeaderNotice' import HeaderNotice from "./HeaderNotice";
export default { export default {
components: { components: {
@ -82,57 +98,54 @@ export default {
Search, Search,
RuoYiGit, RuoYiGit,
RuoYiDoc, RuoYiDoc,
HeaderNotice HeaderNotice,
}, },
computed: { computed: {
...mapGetters([ ...mapGetters(["sidebar", "avatar", "device", "nickName"]),
'sidebar',
'avatar',
'device',
'nickName'
]),
setting: { setting: {
get() { get() {
return this.$store.state.settings.showSettings return this.$store.state.settings.showSettings;
} },
}, },
navType: { navType: {
get() { get() {
return this.$store.state.settings.navType return this.$store.state.settings.navType;
} },
}, },
showLogo: { showLogo: {
get() { get() {
return this.$store.state.settings.sidebarLogo return this.$store.state.settings.sidebarLogo;
} },
} },
}, },
methods: { methods: {
toggleSideBar() { toggleSideBar() {
this.$store.dispatch('app/toggleSideBar') this.$store.dispatch("app/toggleSideBar");
}, },
setLayout(event) { setLayout(event) {
this.$emit('setLayout') this.$emit("setLayout");
}, },
lockScreen() { lockScreen() {
const currentPath = this.$route.fullPath const currentPath = this.$route.fullPath;
this.$store.dispatch('lock/lockScreen', currentPath).then(() => { this.$store.dispatch("lock/lockScreen", currentPath).then(() => {
this.$router.push('/lock') this.$router.push("/lock");
}) });
}, },
logout() { logout() {
this.$confirm('确定注销并退出系统吗?', '提示', { this.$confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning' type: "warning",
}).then(() => { })
this.$store.dispatch('LogOut').then(() => { .then(() => {
location.href = '/index' this.$store.dispatch("LogOut").then(() => {
location.href = "/index";
});
}) })
}).catch(() => {}) .catch(() => {});
} },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -147,7 +160,7 @@ export default {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: #fff; background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08); box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
display: flex; display: flex;
align-items: center; align-items: center;
// padding: 0 8px; // padding: 0 8px;
@ -157,15 +170,15 @@ export default {
line-height: 46px; line-height: 46px;
height: 100%; height: 100%;
cursor: pointer; cursor: pointer;
transition: background .3s; transition: background 0.3s;
-webkit-tap-highlight-color:transparent; -webkit-tap-highlight-color: transparent;
display: flex; display: flex;
align-items: center; align-items: center;
flex-shrink: 0; flex-shrink: 0;
margin-right: 8px; margin-right: 8px;
&:hover { &:hover {
background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025);
} }
} }
@ -208,10 +221,10 @@ export default {
&.hover-effect { &.hover-effect {
cursor: pointer; cursor: pointer;
transition: background .3s; transition: background 0.3s;
&:hover { &:hover {
background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025);
} }
} }
} }
@ -232,7 +245,7 @@ export default {
border-radius: 50%; border-radius: 50%;
} }
.user-nickname{ .user-nickname {
position: relative; position: relative;
bottom: 10px; bottom: 10px;
left: 2px; left: 2px;

@ -83,28 +83,28 @@ export const constantRoutes = [
path: 'index', path: 'index',
component: () => import('@/views/video/index'), component: () => import('@/views/video/index'),
name: 'video', name: 'video',
meta: { title: '视讯', icon: 'guide', affix: true } meta: { title: '视讯', icon: 'guide' }
}, },
{ {
path: 'realTimeConsultation', path: 'realTimeConsultation',
component: () => import('@/views/videoCommunication/realTimeConsultation'), component: () => import('@/views/videoCommunication/realTimeConsultation'),
name: 'RealTimeConsultation', name: 'RealTimeConsultation',
hidden: true, hidden: true,
meta: { title: '实时会诊', icon: 'dashboard', affix: true, activeMenu: '/videoCommunication' } meta: { title: '实时会诊', icon: 'dashboard', activeMenu: '/video' }
}, },
{ {
path: 'training', path: 'training',
component: () => import('@/views/videoCommunication/training'), component: () => import('@/views/videoCommunication/training'),
name: 'Training', name: 'Training',
hidden: true, hidden: true,
meta: { title: '带教培训', icon: 'dashboard', affix: true, activeMenu: '/videoCommunication' } meta: { title: '带教培训', icon: 'dashboard', activeMenu: '/video' }
}, },
{ {
path: 'qualityControl', path: 'qualityControl',
component: () => import('@/views/videoCommunication/qualityControl'), component: () => import('@/views/videoCommunication/qualityControl'),
name: 'QualityControl', name: 'QualityControl',
hidden: true, hidden: true,
meta: { title: '在线质控', icon: 'dashboard', affix: true, activeMenu: '/videoCommunication' } meta: { title: '在线质控', icon: 'dashboard', activeMenu: '/video' }
}, },
] ]
}, },

@ -13,7 +13,7 @@
<ul class="list-unstyled"> <ul class="list-unstyled">
<li class="link-type"> <li class="link-type">
<router-link to="/"> <router-link to="/">
首页 视讯
</router-link> </router-link>
</li> </li>
</ul> </ul>

@ -18,7 +18,7 @@
对不起您正在寻找的页面不存在尝试检查URL的错误然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容 对不起您正在寻找的页面不存在尝试检查URL的错误然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容
</div> </div>
<router-link to="/" class="bullshit__return-home"> <router-link to="/" class="bullshit__return-home">
返回首页 返回视讯
</router-link> </router-link>
</div> </div>
</div> </div>

@ -4,202 +4,166 @@
<div slot="header"> <div slot="header">
<span>传输管理器</span> <span>传输管理器</span>
<el-button <el-button
type="text"
style="float: right; padding: 3px 0" style="float: right; padding: 3px 0"
@click="clearRecords" type="text"
@click="handleClearRecords"
> >
清空记录 清空记录
</el-button> </el-button>
</div> </div>
<div class="date-divider"> <el-divider>
<span class="date-text">2026-05-09</span> <el-tag type="info">2026-05-13</el-tag>
</div> </el-divider>
<div v-if="transferList.length > 0" class="transfer-list"> <el-table :data="fileList" :show-header="false">
<div v-for="item in transferList" :key="item.id" class="transfer-item"> <el-table-column prop="name" label="缩略图" width="80" align="center">
<div class="file-icon"> <template slot-scope="scope">
<i class="el-icon-video-camera"></i> <div class="video-thumb">
</div> <i class="el-icon-video-camera" />
<div class="file-info">
<div class="file-name">{{ item.name }}</div>
<div class="file-meta">
<span class="file-size">{{ item.size }}</span>
<span class="file-time">{{ item.time }}</span>
</div> </div>
</div> </template>
<el-tag :type="item.status">{{ item.status === "failed" ? "上传失败" : "上传成功" }}</el-tag> </el-table-column>
<div class="file-actions"> <el-table-column prop="name" label="文件名" show-overflow-tooltip />
<el-button type="text" class="action-btn" @click="openFile(item)"> <el-table-column
prop="size"
label="文件大小"
width="120"
align="center"
show-overflow-tooltip
/>
<el-table-column
prop="progress"
label="上传进度"
width="200"
align="center"
>
<template slot-scope="scope">
<el-progress :percentage="scope.row.progress" />
</template>
</el-table-column>
<el-table-column
prop="time"
label="上传时间"
width="120"
align="center"
show-overflow-tooltip
/>
<el-table-column
prop="status"
label="上传状态"
width="90"
align="center"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-tag>
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button
type="text"
icon="el-icon-view"
@click="handleOpen(scope.row)"
>
打开 打开
</el-button> </el-button>
<el-button <el-button
type="text" type="text"
class="action-btn" icon="el-icon-folder"
@click="openLocation(item)" @click="handleOpenPath(scope.row)"
> >
打开位置 打开位置
</el-button> </el-button>
</div> </template>
</div> </el-table-column>
</div> </el-table>
<div v-else class="empty-state">
<i class="el-icon-folder-opened"></i>
<span>暂无传输记录</span>
</div>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
const transferList = [
{
id: 1,
name: "TG-2023-01-21-215030828.mp4",
size: "11.86M",
time: "14:33",
status: "danger",
path: "/uploads/TG-2023-01-21-215030828.mp4",
},
{
id: 2,
name: "TG-2023-01-21-215030828.mp4",
size: "11.86M",
time: "14:33",
status: "success",
path: "/uploads/TG-2023-01-21-215030828.mp4",
},
];
export default { export default {
name: "UtilityPage", name: "TransferManager",
data() { data() {
return { return {
transferList, // filePath 访
fileList: [
{
id: 1,
name: "1633500241136.mp4",
size: "17.92M",
progress: 100,
time: "14:31",
status: "上传成功",
// 使URL使D
filePath: "https://www.w3school.com.cn/i/movie.mp4",
folderPath: "D:/手机照片/风景宜人",
},
{
id: 2,
name: "TG-2023-01-21-215030828...",
size: "11.86M",
progress: 100,
time: "14:31",
status: "上传成功",
filePath: "D:/手机照片/风景宜人/1633500241136.mp4", //
folderPath: "D:/手机照片/风景宜人",
},
{
id: 3,
name: "VID_20230121_200603.mp4",
size: "10.02M",
progress: 100,
time: "14:16",
status: "上传成功",
filePath: "D:/手机照片/风景宜人/1633500241136.mp4", //
folderPath: "D:/手机照片/风景宜人",
},
],
}; };
}, },
methods: { methods: {
clearRecords() { //
this.$confirm("是否要清除本地传输记录?", "提示", { handleClearRecords() {
confirmButtonText: "确定", this.$modal
cancelButtonText: "取消", .confirm("是否要清除本地传输记录?")
})
.then(() => { .then(() => {
this.transferList = []; this.fileList = [];
this.$message.success("已清空传输记录"); this.$modal.msgSuccess("清空成功");
}) })
.catch(() => {}); .catch(() => {});
}, },
openFile(item) { //
this.$message.info(`正在打开文件位置:${item.path}`); // 访
handleOpen(row) {
window.open(row.filePath, "_blank");
}, },
openLocation(item) { //
this.$message.info(`正在打开文件位置:${item.path}`); // 访
handleOpenPath(row) {
try {
this.$message.error(
`由于浏览器安全限制,无法直接打开本地文件夹。<br><br>文件夹路径:<code>${row.folderPath}</code><br><br>请在文件资源管理器中手动打开此路径。`
);
} catch (e) {
this.$message.error("打开失败:" + e.message);
}
}, },
}, },
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.date-divider { .video-thumb {
width: 40px;
height: 40px;
border-radius: 4px;
line-height: 40px;
text-align: center; text-align: center;
margin-bottom: 15px; font-size: 20px;
background: #655dd4;
.date-text { color: #fff;
font-size: 12px; margin: 0 auto;
color: #999;
padding: 5px 20px;
background: #f0f0f0;
border-radius: 20px;
}
}
.transfer-list {
.transfer-item {
display: flex;
align-items: center;
padding: 15px;
background: #f7f9f8;
border-radius: 8px;
margin-bottom: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
.file-icon {
width: 48px;
height: 48px;
border-radius: 8px;
background: #655dd4;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 20px;
margin-right: 15px;
}
.file-info {
flex: 1;
.file-name {
font-size: 14px;
color: #333;
margin-bottom: 4px;
}
.file-meta {
display: flex;
gap: 15px;
font-size: 12px;
color: #999;
}
}
.status-tag {
font-size: 12px;
padding: 4px 12px;
border-radius: 4px;
margin-right: 15px;
&.failed {
background: #fff3e0;
color: #f57c00;
}
&.success {
background: #e8f5e9;
color: #2e7d32;
}
}
.file-actions {
display: flex;
gap: 10px;
.action-btn {
color: #009696;
font-size: 13px;
&:hover {
color: #00796b;
}
}
}
}
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 60px 0;
color: #999;
i {
font-size: 48px;
margin-bottom: 15px;
opacity: 0.5;
}
span {
font-size: 14px;
}
} }
</style> </style>

@ -204,6 +204,10 @@ export default {
key: "fixedHeader", key: "fixedHeader",
value: false, value: false,
}); });
this.$store.dispatch("settings/changeSetting", {
key: "tagsView",
value: false,
});
this.updateClock(); this.updateClock();
setInterval(this.updateClock, 1000); setInterval(this.updateClock, 1000);
this.startTimer(); this.startTimer();
@ -256,7 +260,7 @@ export default {
const roomId = "room_" + (this.meetingCode || "default"); const roomId = "room_" + (this.meetingCode || "default");
const uid = String(this.$store.state.user.id || Date.now()); const uid = String(this.$store.state.user.id || Date.now());
const uName = (this.$store.state.user.nickName || "用户").trim(); const uName = (this.$store.state.user.nickName || "用户").trim();
window.hirtcwebsdk.join(roomId, uid, uName); window.hirtcwebsdk.join(roomId, uid, uName);
window.hirtcwebsdk.addListener("joined", () => { window.hirtcwebsdk.addListener("joined", () => {
this.$message.success("加入会议成功"); this.$message.success("加入会议成功");
@ -264,8 +268,8 @@ export default {
}, },
methods: { methods: {
minimizeWindow() { minimizeWindow() {
// //
this.$router.push("/videoCommunication"); this.$router.push("/video/index");
}, },
closeWindow() { closeWindow() {
this.$store.dispatch("app/toggleSideBarHide", false); this.$store.dispatch("app/toggleSideBarHide", false);

Loading…
Cancel
Save