工具-页面搭建

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. 276
      src/views/utility/index.vue
  7. 8
      src/views/videoCommunication/realTimeConsultation.vue

@ -45,9 +45,9 @@ export default {
} else {
matched = router.matched.filter(item => item.meta && item.meta.title)
}
//
//
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)
},

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

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

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

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

@ -4,202 +4,166 @@
<div slot="header">
<span>传输管理器</span>
<el-button
type="text"
style="float: right; padding: 3px 0"
@click="clearRecords"
type="text"
@click="handleClearRecords"
>
清空记录
</el-button>
</div>
<div class="date-divider">
<span class="date-text">2026-05-09</span>
</div>
<div v-if="transferList.length > 0" class="transfer-list">
<div v-for="item in transferList" :key="item.id" class="transfer-item">
<div class="file-icon">
<i class="el-icon-video-camera"></i>
</div>
<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>
<el-divider>
<el-tag type="info">2026-05-13</el-tag>
</el-divider>
<el-table :data="fileList" :show-header="false">
<el-table-column prop="name" label="缩略图" width="80" align="center">
<template slot-scope="scope">
<div class="video-thumb">
<i class="el-icon-video-camera" />
</div>
</div>
<el-tag :type="item.status">{{ item.status === "failed" ? "上传失败" : "上传成功" }}</el-tag>
<div class="file-actions">
<el-button type="text" class="action-btn" @click="openFile(item)">
</template>
</el-table-column>
<el-table-column prop="name" label="文件名" show-overflow-tooltip />
<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
type="text"
class="action-btn"
@click="openLocation(item)"
icon="el-icon-folder"
@click="handleOpenPath(scope.row)"
>
打开位置
</el-button>
</div>
</div>
</div>
<div v-else class="empty-state">
<i class="el-icon-folder-opened"></i>
<span>暂无传输记录</span>
</div>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
const transferList = [
export default {
name: "TransferManager",
data() {
return {
// filePath 访
fileList: [
{
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",
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.mp4",
name: "TG-2023-01-21-215030828...",
size: "11.86M",
time: "14:33",
status: "success",
path: "/uploads/TG-2023-01-21-215030828.mp4",
progress: 100,
time: "14:31",
status: "上传成功",
filePath: "D:/手机照片/风景宜人/1633500241136.mp4", //
folderPath: "D:/手机照片/风景宜人",
},
];
export default {
name: "UtilityPage",
data() {
return {
transferList,
{
id: 3,
name: "VID_20230121_200603.mp4",
size: "10.02M",
progress: 100,
time: "14:16",
status: "上传成功",
filePath: "D:/手机照片/风景宜人/1633500241136.mp4", //
folderPath: "D:/手机照片/风景宜人",
},
],
};
},
methods: {
clearRecords() {
this.$confirm("是否要清除本地传输记录?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
})
//
handleClearRecords() {
this.$modal
.confirm("是否要清除本地传输记录?")
.then(() => {
this.transferList = [];
this.$message.success("已清空传输记录");
this.fileList = [];
this.$modal.msgSuccess("清空成功");
})
.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>
<style lang="scss" scoped>
.date-divider {
.video-thumb {
width: 40px;
height: 40px;
border-radius: 4px;
line-height: 40px;
text-align: center;
margin-bottom: 15px;
.date-text {
font-size: 12px;
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;
font-size: 20px;
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;
}
margin: 0 auto;
}
</style>

@ -204,6 +204,10 @@ export default {
key: "fixedHeader",
value: false,
});
this.$store.dispatch("settings/changeSetting", {
key: "tagsView",
value: false,
});
this.updateClock();
setInterval(this.updateClock, 1000);
this.startTimer();
@ -264,8 +268,8 @@ export default {
},
methods: {
minimizeWindow() {
//
this.$router.push("/videoCommunication");
//
this.$router.push("/video/index");
},
closeWindow() {
this.$store.dispatch("app/toggleSideBarHide", false);

Loading…
Cancel
Save