本系列教程目录:Vue3+Element Plus全套学习笔记-目录大纲
文章目录
- [第3章 综合案例](#第3章 综合案例)
-
- [3.1 搭建项目](#3.1 搭建项目)
-
- [3.1.1 创建Vite工程](#3.1.1 创建Vite工程)
- [3.1.2 配置路由](#3.1.2 配置路由)
- [3.2 登录模块页面](#3.2 登录模块页面)
-
- [3.2.1 注册页面](#3.2.1 注册页面)
- [3.2.2 登录页面](#3.2.2 登录页面)
- [3.2.3 忘记密码页面](#3.2.3 忘记密码页面)
- [3.3 导航设置](#3.3 导航设置)
- [3.4 仪表盘模块](#3.4 仪表盘模块)
- [3.5 用户模块](#3.5 用户模块)
- [3.6 文章模块](#3.6 文章模块)
- [3.7 部门模块](#3.7 部门模块)
- [3.8 会议模块](#3.8 会议模块)
第3章 综合案例
3.1 搭建项目
3.1.1 创建Vite工程
1)创建Vite工程,输入命令:
shell
npm create vite
进入项目
npm install
2)安装element plus、element plus icon依赖,并配置相关信息:
shell
npm install element-plus
npm install @element-plus/icons-vue
3)配置相关信息(打开main.js):
javascript
import { createApp } from 'vue'
// 导入ElementPlus组件
import ElementPlus from 'element-plus'
// 导入ElementPlus样式
import 'element-plus/dist/index.css'
// 导入App组件
import App from './App.vue'
// 导入ElementPlus图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 创建Vue实例
const app = createApp(App)
app.use(ElementPlus) // 使用ElementPlus组件
app.mount('#app')
// 注册ElementPlus图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
3.1.2 配置路由
1)安装路由依赖:
shell
npm install vue-router
2)创建src/router/index.js,配置路由信息:
javascript
// 导入VueRouter中的createRouter和createWebHashHistory函数
import {createRouter, createWebHashHistory} from 'vue-router'
// 定义路由表
const routes = [
// 访问/login或者/都来到login.vue组件
{path: '/login', component: () => import('../components/login.vue')},
{path: '/', component: () => import('../components/login.vue')},
]
// 创建路由实例
const router = createRouter({
history: createWebHashHistory(),
routes: routes
})
// 导出路由
export default router
3)创建components/login.vue组件:
vue
<script setup>
</script>
<template>
<div>
<h1>Login</h1>
</div>
</template>
<style scoped>
</style>
4)在main.js中配置路由:
javascript
...
// 导入路由
import router from './router/index.js'
// 创建Vue实例
const app = createApp(App)
app.use(router) // 注册路由
...
3.2 登录模块页面
登录模块包括登录页面、忘记密码页面、注册用户页面等三个页面。
3.2.1 注册页面
效果如下:

1)在router/index.js中定义注册组件路由:
javascript
{path: '/register',name: "register", component: () => import('../components/register.vue')}
2)编写components/register.vue组件:
vue
<template>
<div class="body">
<div class="container">
<h2>新用户注册</h2>
<el-text>请输入您的信息</el-text>
<el-divider></el-divider>
<el-form ref="formRef" :model="form" :rules="rules" size="large">
<el-form-item prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" prefix-icon="Message"></el-input>
</el-form-item>
<el-form-item prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" prefix-icon="User"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input type="password" v-model="form.password" placeholder="请输入密码" prefix-icon="Lock"></el-input>
</el-form-item>
<el-form-item prop="confirmPassword">
<el-input type="password" v-model="form.confirmPassword" placeholder="请再次输入密码"
prefix-icon="Lock"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sendEmail" :disabled="isDisabled">{{ buttonText }}</el-button>
</el-form-item>
<el-form-item>
<el-button type="success" style="width: 100%" @click="register">注册</el-button>
</el-form-item>
<el-form-item>
<el-link type="primary" @click="$router.push('/login')">返回登录</el-link>
</el-form-item>
</el-form>
</div>
</div>
</template>
3)css:
javascript
.body {
/*布局*/
display: flex;
/*水平居中*/
justify-content: center;
/*垂直居中*/
align-items: center;
/*高度为 100vh(视窗高度)*/
height: 100vh;
/* 背景颜色(渐变)*/
background: linear-gradient(135deg, #74ebd5 0%, #ACB6E5 100%);
}
.container {
width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
text-align: center;
}
4)script:
javascript
import {reactive} from 'vue'
import {ref, computed, onUnmounted} from 'vue'
import {ElMessage, ElMessageBox} from "element-plus";
// 表单的引用对象
const formRef = ref();
// 表单数据
const form = reactive({
email: '',
username: '',
password: '',
confirmPassword: '',
})
// 响应式数据
const isDisabled = ref(false) // 按钮禁用状态
const remainingTime = ref(0) // 剩余时间(秒)
let timer = null // 定时器实例
// 计算按钮显示文本
const buttonText = computed(() => {
return isDisabled.value
? `${remainingTime.value}秒后重试`
: '发送邮箱'
})
// 发送邮件处理
const sendEmail = () => {
// 校验email字段
formRef.value.validateField("email",(valid) => {
if (valid) {
// 表单验证通过,发送邮件
// 显示成功提示
ElMessage.success('邮箱已发送,请注意查收!')
// 重置表单
form.email = ''
// 设置禁用状态和倒计时
isDisabled.value = true
remainingTime.value = 60
// 启动倒计时定时器
timer = setInterval(() => {
remainingTime.value -= 1
// 倒计时结束后恢复按钮状态
if (remainingTime.value <= 0) {
clearInterval(timer)
isDisabled.value = false
}
}, 1000)
} else {
// 表单验证失败,显示错误信息
ElMessage.error('表单验证失败,请检查输入!')
}
})
}
// 组件卸载时清除定时器(防止内存泄漏)
onUnmounted(() => {
if (timer) clearInterval(timer)
})
// 表单校验规则
const rules = {
email: [
{required: true, message: '请输入邮箱', trigger: 'blur'},
{type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur'}
],
username: [
{required: true, message: '请输入用户名', trigger: 'blur'},
{min: 3, max: 10, message: '用户名长度在 3 到 10 个字符', trigger: 'blur'}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 16, message: '密码长度在 6 到 16 个字符', trigger: 'blur'}
],
confirmPassword: [
{required: true, message: '请再次输入密码', trigger: 'blur'},
{
validator: (rule, value, callback) => {
if (value !== form.password) {
callback('两次输入的密码不一致!')
} else {
callback()
}
}, trigger: 'blur'
}
]
}
// 注册事件
const register = () => {
formRef.value.validate((valid) => {
if (valid) {
// 表单验证通过,发送注册请求
// 注册成功提示
ElMessage.success('注册成功!');
} else {
// 表单验证失败,显示错误信息
ElMessage.error('表单验证失败,请检查输入!')
}
})
}
3.2.2 登录页面
效果如下:

1)在router/index.js中定义组件路由:
javascript
{path: '/login',name: "login", component: () => import('../components/login.vue')}
2)编写components/login.vue组件:
vue
<template>
<div class="body">
<div class="container">
<h2>用户登录</h2>
<el-text>请输入您的信息</el-text>
<el-divider></el-divider>
<el-form ref="formRef" :model="form" :rules="rules" size="large">
<el-form-item prop="username">
<el-input v-model="form.username" placeholder="请输入用户名" prefix-icon="User"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="form.password" placeholder="请输入密码" type="password" prefix-icon="Lock"></el-input>
</el-form-item>
<el-form-item prop="checkCode">
<el-row gutter="20" style="width: 100%;">
<el-col :span="16">
<el-input v-model="form.checkCode" placeholder="请输入验证码" prefix-icon="Check"></el-input>
</el-col>
<el-col :span="6">
<img src="../assets/checkCode.png" alt="" style="width: 100%;height: 40px ">
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-checkbox v-model="form.remember">记住我</el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="success" style="width: 100%" @click="login">登录</el-button>
</el-form-item>
<el-form-item>
<el-row :gutter="20" style="width: 100%;">
<el-col :span="12" style="text-align: left;">
<el-link type="primary" :underline="false" @click="$router.push('/forget')">忘记密码?</el-link>
</el-col>
<el-col :span="12" style="text-align: right;">
<el-link type="primary" :underline="false" @click="$router.push('/register')">没有账号?</el-link>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</div>
</template>
3)css:
css
.body {
/*布局*/
display: flex;
/*水平居中*/
justify-content: center;
/*垂直居中*/
align-items: center;
/*高度为 100vh(视窗高度)*/
height: 100vh;
/* 背景颜色(渐变)*/
background: linear-gradient(135deg, #74ebd5 0%, #ACB6E5 100%);
}
.container {
width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
text-align: center;
}
4)script:
javascript
import {ref, reactive} from 'vue';
import {ElMessage} from 'element-plus';
import {useRouter} from 'vue-router';
// 初始化路由
const router = useRouter();
// 表单的引用对象
const formRef = ref(null);
// 表单数据对象
const form = reactive({
username: '',
password: '',
checkCode: '',
remember: '',
});
// 表单验证规则
const rules = {
username: [
{required: true, message: '请输入用户名', trigger: 'blur'},
{min: 3, max: 10, message: '用户名长度在 3 到 10 个字符', trigger: 'blur'},
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 6, max: 16, message: '密码长度在 6 到 16 个字符', trigger: 'blur'},
],
checkCode: [
{required: true, message: '请输入验证码', trigger: 'blur'},
{min: 4, max: 4, message: '验证码长度为 4', trigger: 'blur'},
],
};
// 用户登录
const login = () => {
// 登录
formRef.value.validate((valid) => {
if (valid) {
// 登录成功
ElMessage.success('登录成功');
// 跳转到首页
router.push({name: 'dashboard'});
} else {
ElMessage.error('登录失败,请检查输入');
}
});
};
3.2.3 忘记密码页面
效果如下:

1)在router/index.js中定义组件路由:
javascript
{path: '/forget', name: "forget", component: () => import('../components/forget.vue')}
2)编写components/forget.vue组件:
vue
<template>
<div class="body">
<div class="container">
<h2>忘记密码</h2>
<el-text>请输入您的信息</el-text>
<el-divider></el-divider>
<el-form ref="formRef" :model="form" :rules="rules" size="large">
<el-form-item prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" prefix-icon="Email"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" style="width: 40%" @click="sendCheckCode">获取验证码</el-button>
</el-form-item>
<el-form-item prop="checkCode">
<el-input v-model="form.checkCode" placeholder="请输入验证码" prefix-icon="Check"></el-input>
</el-form-item>
<el-form-item prop="newPassword">
<el-input v-model="form.newPassword" placeholder="请输入新密码" type="password" prefix-icon="Lock"></el-input>
</el-form-item>
<el-form-item>
<el-row :gutter="20">
<el-col :span="11">
<el-button type="success" @click="resetPassword">重置密码</el-button>
</el-col>
<el-col :span="11">
<el-button @click="$router.push('/login')">返回登录</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</div>
</template>
3)css:
css
.body {
/*布局*/
display: flex;
/*水平居中*/
justify-content: center;
/*垂直居中*/
align-items: center;
/*高度为 100vh(视窗高度)*/
height: 100vh;
/* 背景颜色(渐变)*/
background: linear-gradient(135deg, #74ebd5 0%, #ACB6E5 100%);
}
.container {
width: 600px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
text-align: center;
}
4)script:
javascript
import { ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
import { useRouter } from 'vue-router';
// 初始化路由实例
const router = useRouter();
// 表单验证
const formRef = ref(null);
// 表单数据
const form = reactive({
email: '',
checkCode: '',
newPassword: '',
});
// 表单验证规则
const rules = {
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' },
],
checkCode: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
{ min: 4, max: 4, message: '验证码长度为 4', trigger: 'blur' },
],
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 6, max: 20, message: '密码长度为 6-20 位', trigger: 'blur' },
],
};
// 发送验证码
const sendCheckCode = () => {
formRef.value.validateField('email', (valid) => {
if (valid) {
// 发送验证码
ElMessage.success('验证码已发送,请注意查收');
}
});
};
// 重置密码
const resetPassword = () => {
formRef.value.validate((valid) => {
if (valid) {
// 重置密码
ElMessage.success('密码重置成功,请重新登录');
router.push("/login");
}
});
};
3.3 导航设置
3.3.1 头部
如图所示:

1)定义components/views/home.vue组件:
vue
<template>
<el-container style="height: 100vh">
<el-header style="background: #409EFF; color: white">Header</el-header>
<el-container>
<el-aside width="200px" style="background: #545c64; color: white">
Aside
</el-aside>
<el-main>Main Content</el-main>
</el-container>
<el-footer style="background: #909399; color: white">Footer</el-footer>
</el-container>
</template>
2)在router/index.js中添加路由:
javascript
{path: '/views/', name: "home", component: () => import('../components/views/home.vue')}
3)头部布局:
vue
<!-- *************************************************头部布局************************************************* -->
<el-header>
<div class="el-header-box">
<el-row style="width: 100%">
<el-col :span="12" style="text-align: left">
<el-link to="/views/home" :underline="false" @click="$router.push('/views/dashboard')">协同会议平台</el-link>
</el-col>
<el-col :span="12" style="text-align: right">
<el-link to="/login" :underline="false" @click="$router.push('/login')">退出</el-link>
</el-col>
</el-row>
</div>
</el-header>
4)css:
css
.el-header-box {
display: flex;
align-items: center;
height: 100%;
border-bottom: 1px solid #eee;
}
3.3.2 侧边栏与底部
效果如下:

1)头像部分
效果如下:

1)布局代码:
vue
<!-- *************************************************主体部分 ************************************************* -->
<el-container>
<!-- *************************************************主体-侧边栏部分 ************************************************* -->
<el-aside>
<el-menu default-active="/views/dashboard" mode="vertical" :router="true">
<div class="el-aside-avatar">
<!-- *************************************************头像部分 ************************************************* -->
<el-row style="width: 180px">
<el-col :span="12">
<router-link to="/views/user/update">
<el-avatar src="/src/assets/avatar.jpg" style="width: 70px; height: 70px"></el-avatar>
</router-link>
</el-col>
<el-col :span="4" v-show="!isCollapse">
<el-tag type="success" size="large">小灰</el-tag>
<el-tag type="primary" size="large" style="margin-top: 10px;">研发部</el-tag>
</el-col>
</el-row>
</div>
</el-menu>
</el-aside>
<!-- 主体中心部分 -->
<el-main>
<!-- 当点击菜单时,路由切换到对应的页面 -->
<h1>Dashboard</h1>
</el-main>
</el-container>
2)css:
css
.el-aside-avatar {
padding: 10px;
}
2)折叠效果
效果如下:

1)布局代码:
vue
<!-- *************************************************主体部分 ************************************************* -->
<el-container>
<!-- *************************************************主体-侧边栏部分 ************************************************* -->
<el-aside class="el-aside-demo">
<!-- 折叠按钮 -->
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
<el-radio-button :value="true">隐藏</el-radio-button>
<el-radio-button :value="false">展开</el-radio-button>
</el-radio-group>
<el-menu default-active="/views/dashboard" :collapse="isCollapse"
mode="vertical" :router="true">
<div class="el-aside-avatar">
<!-- *************************************************头像部分 ************************************************* -->
<el-row style="width: 180px" v-show="!isCollapse">
<!-- 没折叠时显示的头像信息 -->
<el-col :span="12">
<router-link to="/views/user/update">
<el-avatar src="/src/assets/avatar.jpg" style="width: 70px; height: 70px"></el-avatar>
</router-link>
</el-col>
<el-col :span="4">
<el-tag type="success" size="large">小灰</el-tag>
<el-tag type="primary" size="large" style="margin-top: 10px;">研发部</el-tag>
</el-col>
</el-row>
<el-row v-show="isCollapse">
<!-- 折叠时显示的头像信息 -->
<el-col :span="24" style="text-align: center">
<router-link to="/views/user/update">
<el-avatar src="/src/assets/avatar.jpg" style="width: 100%; height: 100%"></el-avatar>
</router-link>
</el-col>
</el-row>
</div>
</el-menu>
</el-aside>
<!-- *************************************************主体-中心部分 ************************************************* -->
<el-main>
<!-- 当点击菜单时,路由切换到对应的页面 -->
<h1>Dashboard</h1>
</el-main>
</el-container>
2)css:
css
.el-aside-demo {
/* 宽度自适应 */
--el-aside-width: auto;
}
3)script:
javascript
// 控制侧边栏折叠是否折叠
const isCollapse = ref(false);
3)菜单列表
效果如下:

1)布局代码:
vue
<!-- *************************************************菜单部分 ************************************************* -->
<el-menu-item index="/views/dashboard">
<el-icon>
<location/>
</el-icon>
<span slot="title">主页</span>
</el-menu-item>
<el-sub-menu>
<template #title>
<el-icon>
<user/>
</el-icon>
<span>用户列表</span>
</template>
<el-menu-item index="/views/user">查看用户</el-menu-item>
<el-menu-item index="/views/user/my_user">我关注的用户</el-menu-item>
</el-sub-menu>
<el-sub-menu index="3">
<template #title>
<el-icon>
<Document/>
</el-icon>
<span>文章管理</span>
</template>
<el-menu-item index="/views/article">文章列表</el-menu-item>
<el-menu-item index="/views/article/article_collect">我的收藏</el-menu-item>
</el-sub-menu>
<el-menu-item index="/views/department">
<el-icon>
<OfficeBuilding/>
</el-icon>
<span slot="title">部门列表</span>
</el-menu-item>
<el-menu-item index="/views/meeting">
<el-icon>
<Coordinate/>
</el-icon>
<span slot="title">会议系统</span>
</el-menu-item>
4)路由配置
当点击侧边栏的菜单项时,右边的主体部分内容需要切换到具体的路由。如图所示:

1)定义views/home组件的子路由:
javascript
{
path: '/views/',name:"home", component: () => import('../components/views/home.vue'),
children: [
{path: 'dashboard',name:"dashboard", component: () => import('../components/views/dashboard/index.vue')},
{path: 'article', name:"article", component: () => import('../components/views/article/index.vue')},
{path: 'article/favorite',name:"articleFavorite",
component: () => import('../components/views/article/article_favorite.vue')},
{path: 'department', name:"department", component: () => import('../components/views/department/index.vue')},
{path: 'meeting', name:"meeting", component: () => import('../components/views/meeting/index.vue')},
{path: 'user',name:"user", component: () => import('../components/views/user/index.vue')},
{path: 'user/follow', name:"userFollow", component: () => import('../components/views/user/user_follow.vue')},
{path: 'user/update', name:"myUser", component: () => import('../components/views/user/user_update.vue')},
]
},
2)定义组件:

3)在home.vue组件中的布局主体部分替换成路由组件:
vue
<!-- 主体中心部分 -->
<el-main>
<!-- 当点击菜单时,路由切换到对应的页面 -->
<router-view />
</el-main>
3.4 仪表盘模块
效果如图:

1)主面板部分
效果如下:

1)布局代码:
vue
<!-- *************************************************主面板************************************************* -->
<h2>主面板</h2>
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-card class="card-item">
<h3>新增用户</h3>
<el-progress :percentage="100" :format="format"/>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-card class="card-item">
<h3>新增文章</h3>
<el-progress :percentage="54" :format="format"/>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-card class="card-item">
<h3>新开会议</h3>
<el-progress :percentage="38" :format="format"/>
</el-card>
</el-col>
</el-row>
2)script:
javascript
// 格式化百分比
const format = (percentage) => (percentage === 100 ? '100+' : percentage)
2)图表部分
效果如下:

1)安装echarts依赖:
shell
npm install echarts
2)布局代码:
vue
<!-- *************************************************图标部分************************************************* -->
<div id="charts" class="charts"></div>
3)css:
css
.charts {
width: 80%;
height: 400px;
margin-top: 20px
}
4)script:
javascript
// 导入echarts
import * as echarts from 'echarts'
import {ref, onMounted} from 'vue'
// 计算近七日日期
var date = new Date();
var days = [];
for (var i = -6; i <= 0; i++) {
date.setDate(date.getDate() + i);
var month = date.getMonth() + 1;
var day = date.getDate();
if (month < 10) month = "0" + month;
if (day < 10) day = "0" + day;
days.push(month + "." + day);
date.setDate(date.getDate() - i);
}
// 图表渲染数据
const option = ref({
title: {text: '数据汇总'},
tooltip: {trigger: 'axis', axisPointer: {type: 'cross', label: {backgroundColor: '#aaaaff'}}},
legend: {data: ['新增用户', '新增文章', '新开会议']},
toolbox: {feature: {saveAsImage: {}}},
grid: {left: '3%', right: '4%', bottom: '3%', containLabel: true},
xAxis: [{type: 'category', boundaryGap: false, data: days}],
yAxis: [{type: 'value'}],
series: [
{name: '新增用户', type: 'line', stack: '总量', areaStyle: {}, data: [56, 21, 24, 34, 61, 54, 100]},
{name: '新增文章', type: 'line', stack: '总量', areaStyle: {}, data: [29, 40, 89, 54, 42, 69, 54]},
{name: '新开会议', type: 'line', stack: '总量', areaStyle: {}, data: [31, 28, 49, 61, 39, 72, 38]}
]
})
// 图表实例
let myChart = null
// 图表渲染
onMounted(() => {
const chartDom = document.getElementById('charts')
if (!chartDom) return
// 初始化图表
myChart = echarts.init(chartDom)
myChart.setOption(option.value)
// 窗口变化时自适应
window.addEventListener('resize', () => myChart?.resize())
})
3.5 用户模块
3.5.1 用户列表

1)搜索表单
效果如下:

1)布局代码如下:
vue
<!-- *************************************************表单搜索************************************************* -->
<h3>用户列表</h3>
<el-row>
<el-col :span="15">
<el-form inline size="large">
<el-form-item label="用户名">
<el-input v-model="searchFrom.username" placeholder="请输入搜索内容"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
2)script:
javascript
import {reactive} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
//****************************************搜索表单********************************************//
// 表单搜索条件
const searchFrom = reactive({
username: ''
})
// 表单搜索
const search = () => {
ElMessage.success(`搜索条件${searchFrom.username}`)
}
2)表格组件
效果如下:

1)布局代码:
vue
<!-- *************************************************数据展示部分************************************************* -->
<el-table :data="users" border style="width: 100%;height: 300px">
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="username" label="用户名" width="120"></el-table-column>
<el-table-column prop="realName" label="真实姓名" width="120"></el-table-column>
<el-table-column prop="sex" label="性别" width="80">
<template #default="scope">
<el-tag :type="scope.row.sex === '0'? 'success' : 'warning'">{{ scope.row.sex === '0' ? '男' : '女' }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="age" label="年龄" width="80"></el-table-column>
<el-table-column prop="email" label="邮箱" width="200"></el-table-column>
<el-table-column prop="phone" label="手机号" width="150"></el-table-column>
<el-table-column prop="info" label="简介" width="300"></el-table-column>
<el-table-column prop="isFollowed" label="加关注" width="80" fixed="right">
<template #default="scope">
<el-switch v-model="scope.row.isFollowed" @click="addFollow(scope.row.id)" :active-value="1"
:inactive-value="0"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button type="text" @click="showDialog(scope.row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
2)script:
javascript
const users = reactive([
{
id: 1,
username: 'admin',
realName: '管理员',
sex: '0',
age: 30,
email: '[email protected]',
phone: '12345678901',
info: '这是一段简介',
isFollowed: 1
},
{
id: 2,
username: 'xiaohui',
realName: '小灰',
sex: '0',
age: 22,
email: '[email protected]',
phone: '12345678902',
info: '这是一段简介',
isFollowed: 0
},
{
id: 3,
username: 'xiaolan',
realName: '小蓝',
sex: '1',
age: 20,
email: '[email protected]',
phone: '12345678903',
info: '这是一段简介',
isFollowed: 1
},
{
id: 4,
username: '小绿',
realName: 'xiaolv',
sex: '1',
age: 20,
email: '[email protected]',
phone: '12345678903',
info: '这是一段简介',
isFollowed: 0
},
{
id: 5,
username: 'xiaoming',
realName: '小明',
sex: '0',
age: 20,
email: '[email protected]',
phone: '12345678903',
info: '这是一段简介',
isFollowed: 1
}
])
// 编辑按钮
const showDialog = (scope) => {
ElMessage.success(`查看【${scope.id}】`)
// 显示编辑对话框
detailDialogVisible.value = true
}
// 删除按钮
const deleteRow = (id) => {
ElMessageBox.confirm('确认删除该行吗?').then(() => {
ElMessage.success(`删除成功【${id}】`)
// console.log(row)
}).catch(() => {
// cancel
})
}
// 加关注
const addFollow = (id) => {
ElMessage.success(`关注【${id}】`)
}
3)分页组件
效果如下:

1)布局代码:
vue
<!-- *************************************************分页组件************************************************* -->
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[3, 5, 10]"
size="large"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
2)script:
javascript
//****************************************分页组件********************************************//
// 当前页
const currentPage = ref(1)
// 页大小
const pageSize = ref(10)
// 当页大小发生改变时执行
const handleSizeChange = (val) => {
ElMessage.success(`每页显示:${val}条`)
}
// 当当前页发生改变时执行
const handleCurrentChange = (val) => {
ElMessage.success(`当前页码:${val}`)
}
3.5.2 用户详情
1)用户详情对话框
当点击某一行的"查看详情"按钮时应该弹出对话框,展示用户信息数据。
效果如下:

1)布局代码:
vue
<el-dialog title="用户详情" v-model="detailDialogVisible" width="60%" top="0vh">
<el-divider/>
<el-form :model="userForm" label-width="80px" :disabled="true">
<el-form-item label="头像">
<el-row style="width: 100%;">
<el-col :span="6">
<el-avatar :size="84" shape="square" :src="userForm.pic"></el-avatar>
</el-col>
<el-col :span="18">
<el-row style="width: 100%;" gutter="20">
<el-col :span="10">
<el-text size="large">
粉丝数:
<el-tag type="danger">{{ userForm.fans }}</el-tag>
</el-text>
</el-col>
<el-col :span="10">
<el-text>
<!-- 嵌入一个子form,否则该switch控件会被处于禁止状态-->
<el-form>
加关注:
<el-switch v-model="userForm.isFollowed" @click="addFollow(userForm.id)"
:active-value="1" :inactive-value="0"></el-switch>
</el-form>
</el-text>
</el-col>
</el-row>
<el-divider style="width: 60%;"/>
<el-row style="width: 100%;" gutter="20">
<el-col :span="10">
<el-text>
关注数:
<el-tag type="success">{{ userForm.follows }}</el-tag>
</el-text>
</el-col>
<el-col :span="10">
<el-text>
浏览量:
<el-tag type="primary">{{ userForm.browseCount }}</el-tag>
</el-text>
</el-col>
</el-row>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="userForm.username"></el-input>
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="userForm.realName"></el-input>
</el-form-item>
<el-form-item label="所在部门">
<el-select v-model="userForm.deptName">
<el-option :value="userForm.deptName">{{ userForm.deptName }}</el-option>
</el-select>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="userForm.sex">
<el-radio value="0">男</el-radio>
<el-radio value="1">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="userForm.age"></el-input-number>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="userForm.email"></el-input>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="userForm.phone"></el-input>
</el-form-item>
<el-form-item label="简介">
<el-input type="textarea" v-model="userForm.info"></el-input>
</el-form-item>
<el-form-item label="注册时间">
<el-input v-model="userForm.registerTime"></el-input>
</el-form-item>
<el-form-item label="登录时间">
<el-input v-model="userForm.loginTime"></el-input>
</el-form-item>
<el-form-item label="是否私密">
<el-switch v-model="userForm.isSecret" active-value="0" inactive-value="1"></el-switch>
</el-form-item>
</el-form>
<el-divider/>
<div style="text-align: center">
<el-button :icon="CircleClose" @click="dialogVisible = false" type="danger">关闭窗口</el-button>
</div>
</el-dialog>
2)script:
javascript
//****************************************会议详情********************************************//
// 编辑对话框是否显示
const detailDialogVisible = ref(false)
// 用户数据
const userForm = reactive({
id: "1",
username: 'xiaohui',
realName: '小灰',
sex: '0',
age: '20',
email: '[email protected]',
phone: '110',
info: '我是大帅哥',
pic: '/src/assets/avatar.jpg',
registerTime: '2030-10-10 10:10:10',
loginTime: '2030-10-10 10:10:10',
isSecret: '0',
deptName: "研发部",
isFollowed: 1,
fans: 798,
follows: 148,
browseCount: 102400
})
// 编辑按钮
const showDialog = (scope) => {
ElMessage.success(`查看【${scope.id}】`)
// 显示编辑对话框
detailDialogVisible.value = true
}
// 加关注
const addFollow = (id) => {
ElMessage.success(`关注【${id}】`)
}
2)绑定事件
给"编辑"按钮绑定点击事件:
vue
<el-table-column label="操作" width="150" fixed="right">
<template #default="scope">
<el-button type="text" @click="showDialog(scope.row)">查看详情</el-button>
</template>
</el-table-column>
3.5.3 用户关注列表
1)关注列表

1)布局代码:
vue
<!-- *************************************************用户列表************************************************* -->
<h3>我的关注列表</h3>
<el-table :data="tableData" style="width: 100%;height: 300px">
<el-table-column prop="realName" label="姓名"></el-table-column>
<el-table-column label="操作" fixed="right" width="150">
<template #default="scope">
<el-button type="danger" @click="unFollow(scope.row.id)">取消关注</el-button>
</template>
</el-table-column>
</el-table>
2)script:
javascript
import {ElMessage, ElMessageBox} from "element-plus";
//****************************************用户列表********************************************//
const tableData = [
{
id: 1,
realName: '小灰'
},
{
id: 2,
realName: '小蓝'
},
{
id: 3,
realName: '小绿'
},
{
id: 4,
realName: '小红'
},
{
id: 5,
realName: '小明'
},
{
id: 6,
realName: '小龙'
}
]
// 取消关注
const unFollow = (id) => {
ElMessageBox.confirm('确定取消关注该用户吗?').then(() => {
ElMessage.success(`取消关注成功【${id}】`)
})
}
2)分页
1)布局代码:
vue
<!-- *************************************************分页组件************************************************* -->
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[3, 5, 10]"
size="large"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
2)script:
javascript
//****************************************分页组件********************************************//
// 当前页
const currentPage = ref(1)
// 页大小
const pageSize = ref(10)
// 当页大小发生改变时执行
const handleSizeChange = (val) => {
ElMessage.success(`每页显示:${val}条`)
}
// 当当前页发生改变时执行
const handleCurrentChange = (val) => {
ElMessage.success(`当前页码:${val}`)
}
3.5.4 个人中心
当点击侧边栏中的"头像"时,进入个人中心页面。
效果如下:

1)注意修改/src/components/home.vue组件中的头像路由地址:

2)在/src/router/index.js文件中的home组件中定义子路由:
javascript
{path: 'user/update', name:"userUpdate", component: () => import('../components/views/user/user_update.vue')}
3)定义/src/components/views/user/update.vue组件
vue
<template>
<h3>个人中心</h3>
<el-form ref="form" :model="userForm" label-width="100px" style="width: 80%">
<el-form-item label="头像">
<el-row style="width: 100%;">
<el-col :span="6">
<el-upload action="http://localhost:3000/upload"
:on-success="handleAvatarSuccess">
<img v-if="userForm.pic" :src="userForm.pic" width="70"/>
<el-icon v-else class="avatar-uploader-icon">
<Plus/>
</el-icon>
</el-upload>
</el-col>
<el-col :span="18">
<el-row style="width: 100%;" gutter="20">
<el-col :span="8">
<el-text size="large">
粉丝数:
<el-tag type="danger">{{ userForm.fans }}</el-tag>
</el-text>
</el-col>
<el-col :span="8">
<el-text>
关注数:
<el-tag type="success">{{ userForm.follows }}</el-tag>
</el-text>
</el-col>
<el-col :span="8">
<el-text>
浏览量:
<el-tag type="primary">{{ userForm.browseCount }}</el-tag>
</el-text>
</el-col>
</el-row>
<el-divider style="width: 90%;"/>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="用户名">
<el-input v-model="userForm.username"></el-input>
</el-form-item>
<el-form-item label="真实姓名">
<el-input v-model="userForm.realName"></el-input>
</el-form-item>
<el-form-item label="部门名称">
<el-select v-model="userForm.deptId" placeholder="请选择部门">
<el-option v-for="item in deptList" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="userForm.sex">
<el-radio :value="0">男</el-radio>
<el-radio :value="1">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="userForm.age"></el-input-number>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="userForm.email"></el-input>
</el-form-item>
<el-form-item label="手机号">
<el-input v-model="userForm.phone"></el-input>
</el-form-item>
<el-form-item label="简介">
<el-input type="textarea" v-model="userForm.info"></el-input>
</el-form-item>
<el-form-item label="注册时间">
<el-input v-model="userForm.registerTime" disabled></el-input>
</el-form-item>
<el-form-item label="登录时间">
<el-input v-model="userForm.loginTime" disabled></el-input>
</el-form-item>
<el-form-item label="是否私密">
<el-switch v-model="userForm.isSecret" active-value="0" inactive-value="1"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="update">保存</el-button>
</el-form-item>
</el-form>
</template>
2)script:
javascript
import {reactive} from 'vue'
import {Plus} from "@element-plus/icons-vue";
import {ElMessage} from "element-plus";
import { useRouter } from 'vue-router'
let router = useRouter(); // 创建路由实例
// 定义用户信息表单
const userForm = reactive({
username: 'xiaohui',
realName: '小灰',
deptId: 2,
sex: 0,
age: 20,
email: '[email protected]',
phone: '13800138000',
info: '大家好,我叫小灰,我今年20岁,欢迎来到我的空间,方便的话点个小爱心哦~',
registerTime: '2021-01-01 00:00:00',
loginTime: '2021-01-01 00:00:00',
isSecret: 0,
pic: '/src/assets/avatar.jpg',
fans: 478,
follows: 124,
browseCount: 142714
})
// 定义部门列表
const deptList = reactive([
{
id: 1,
name: '开发部'
},
{
id: 2,
name: '测试部'
},
{
id: 3,
name: '运营部'
}
])
// 上传用户头像
const handleAvatarSuccess = (res) => {
ElMessage.success('上传成功')
}
// 保存用户信息
const update = () => {
ElMessage.success(`保存成功${userForm.username}`)
// 跳转到用户列表组件
router.push({name: 'user'})
}
3.6 文章模块
3.6.1 文章列表
1)搜索表单
效果如下:

1)布局代码:
vue
<!-- *************************************************条件搜索************************************************* -->
<h3>文章列表</h3>
<el-row style="width: 100%;">
<el-col :span="12">
<el-form inline size="large">
<el-form-item label="文章标题">
<el-input v-model="searchForm.title" placeholder="请输入搜索内容"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12" style="text-align: right;">
<el-button type="primary" @click="addDialogVisible = true" size="large">新增文章</el-button>
</el-col>
</el-row>
2)script:
javascript
//****************************************搜索表单********************************************//
// 搜索条件
const searchForm = reactive({
title: ''
});
// 搜索方法
const search = () => {
ElMessage.success(`搜索成功${searchForm.title}`);
};
2)表格组件
效果如下:

1)布局代码:
vue
<!-- 文章列表 -->
<div>
<el-card v-for="(article, index) in articles" :key="index" style="margin-bottom: 20px;">
<el-link type="primary" :underline="false">如何成为一名Java工程师?</el-link>
<p>
<el-text tag="strong">作者:</el-text>
<el-tag>{{ article.publishUser }}</el-tag>
</p>
<p>
<el-text tag="strong">时间:</el-text>
<el-tag type="success">{{ article.publishDate }}</el-tag>
</p>
<el-text>
{{article.content}}
</el-text>
</el-card>
</div>
2)script:
javascript
//****************************************文章列表********************************************//
const articles = [
{
id: '1',
title: '如何成为一名Java工程师?',
publishUser: '小灰',
publishDate: '2030-01-01 10:00:00',
content: '文章内容'
},
{
id: '2',
title: '如何成为一名Java工程师?',
publishUser: '小蓝',
publishDate: '2030-01-01 10:00:00',
content: '文章内容'
}
];
3)分页组件
效果如下:

1)布局代码:
vue
<!-- *************************************************分页组件************************************************* -->
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[3, 5, 10]"
size="large"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
2)script:
javascript
//****************************************分页组件********************************************//
// 当前页
const currentPage = ref(1)
// 页大小
const pageSize = ref(10)
// 当页大小发生改变时执行
const handleSizeChange = (val) => {
ElMessage.success(`每页显示:${val}条`)
}
// 当当前页发生改变时执行
const handleCurrentChange = (val) => {
ElMessage.success(`当前页码:${val}`)
}
3.6.2 发布文章
1)发布文章对话框
当点击"发布文章"按钮时应该弹出对话框,让用户填写文章数据。
效果如下:

1)布局代码:
vue
<!-- *************************************************新增文章弹窗************************************************* -->
<el-dialog title="发布文章" v-model="addDialogVisible" style="width: 60%;height: 50%;">
<el-divider/>
<el-form ref="form" :model="articleForm" label-width="80px">
<el-form-item label="文章标题">
<el-input v-model="articleForm.title" placeholder="请输入文章标题"></el-input>
</el-form-item>
<el-form-item label="文章内容">
<el-input type="textarea" :rows="5" v-model="articleForm.content" placeholder="请输入文章内容"></el-input>
</el-form-item>
</el-form>
<el-divider/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="add">确 定</el-button>
<el-button @click="addDialogVisible = false">取 消</el-button>
</div>
</el-dialog>
2)script:
javascript
//****************************************发布文章********************************************//
// 新增文章弹窗是否显示
const addDialogVisible = ref(false);
// 文章对象
const articleForm = reactive({
title: '',
content: ''
});
// 新增文章方法
const add = () => {
ElMessage.success(`新增文章成功:${JSON.stringify(articleForm)}`);
addDialogVisible.value = false;
console.log(articleForm);
};
2)绑定事件
给"新增文章"按钮绑定点击事件:
vue
<el-button type="primary" @click="addDialogVisible = true" size="large">发布文章</el-button>
3.6.3 文章详情
1)文章详情对话框
当点击某篇文章时,查询文章详情。
效果如下:

1)布局代码:
vue
<!-- *************************************************文章详情弹窗************************************************* -->
<el-dialog title="文章详情" v-model="detailDialogVisible" width="60%" top="5vh">
<div style="position: relative">
<h2 style="text-align: center">如何做一名合格的Java工程师</h2>
<el-button style="position: absolute;top:0;right: 10px;" type="success" @click="addFavorite(articleDetail.id)">
收藏文章
</el-button>
</div>
<el-divider/>
<el-card>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<User/>
</el-icon>
发布人:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.publishUser }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Timer/>
</el-icon>
发布时间:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.publishDate }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Reading/>
</el-icon>
浏览次数:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.browseCount }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<StarFilled/>
</el-icon>
收藏次数:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.favoriteCount }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<p>
<strong>
<el-icon>
<Document/>
</el-icon>
文章内容:</strong>
</p>
<el-input type="textarea" :rows="10" v-model="articleDetail.content" disabled></el-input>
</el-card>
<el-divider/>
<div>
<p>
<strong>
<el-icon>
<UserFilled/>
</el-icon>
您关注的用户也收藏过这篇文章:</strong>
</p>
<el-button v-for="(user, index) in articleDetail.favoriteList">{{ user.realName }}</el-button>
</div>
<el-divider/>
<div style="text-align: center">
<el-button type="danger" @click="detailDialogVisible = false">
<el-icon>
<Close/>
</el-icon>
关闭窗口
</el-button>
</div>
</el-dialog>
2)script:
javascript
//****************************************文章详情********************************************//
// 文章详情弹窗是否显示
const detailDialogVisible = ref(false);
// 文章详情对话框显示
const showDetail = (id) => {
ElMessage.success(`显示文章详情:${id}`);
detailDialogVisible.value = true;
}
// 文章详情
const articleDetail = reactive({
id: 1,
title: '如何成为一名Java工程师?',
content: '如何成为一名Java工程师如何成为一名Java工程师如何成为一名Java工程师如何成为一名Java工程师',
publishUser: '小灰',
publishDate: '2030-01-01 10:00:00',
collectors: ['小灰', '小蓝'],
favoriteCount: 89,
browseCount: 1246,
favoriteList: [
{id: "1", realName: '小灰'},
{id: "2", realName: '小蓝'},
{id: "3", realName: '小绿'},
]
});
// 添加/取消收藏
const addFavorite = (id) => {
ElMessage.success(`收藏成功:${articleDetail.id}`);
};
2)绑定事件
在文章列表中,给文章标题添加点击事件:
javascript
<el-link type="primary" :underline="false" @click="showDetail(article.id)">如何成为一名Java工程师?</el-link>
3.6.4 我的收藏列表
我的收藏页面整体布局和文章列表页面一致,代码可以参考文章列表。
效果如下:

1)布局代码:
vue
<template>
<!-- *************************************************条件搜索************************************************* -->
<h3>我收藏的文章</h3>
<el-row style="width: 100%;">
<el-col :span="12">
<el-form inline size="large">
<el-form-item label="文章标题">
<el-input v-model="searchForm.title" placeholder="请输入搜索内容"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
<!-- *************************************************文章列表************************************************* -->
<div>
<el-card v-for="(article, index) in articles" :key="index" style="margin-bottom: 20px;">
<el-link type="primary" :underline="false" @click="showDetail(article.id)">如何成为一名Java工程师?</el-link>
<p>
<el-text tag="strong">
<el-icon>
<User/>
</el-icon>
作者:
</el-text>
<el-tag>{{ article.publishUser }}</el-tag>
</p>
<p>
<el-text tag="strong">
<el-icon>
<Timer/>
</el-icon>
发布时间:
</el-text>
<el-tag type="success">{{ article.publishDate }}</el-tag>
</p>
<el-text>
{{ article.content }}
</el-text>
</el-card>
</div>
<!-- *************************************************分页组件************************************************* -->
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[3, 5, 10]"
size="large"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
<!-- *************************************************文章详情弹窗************************************************* -->
<el-dialog title="文章详情" v-model="detailDialogVisible" width="60%" top="5vh">
<div style="position: relative">
<h2 style="text-align: center">如何做一名合格的Java工程师</h2>
<el-button style="position: absolute;top:0;right: 10px;" type="success" @click="addFavorite(articleDetail.id)">
收藏文章
</el-button>
</div>
<el-divider/>
<el-card>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<User/>
</el-icon>
发布人:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.publishUser }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Timer/>
</el-icon>
发布时间:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.publishDate }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Reading/>
</el-icon>
浏览次数:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.browseCount }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<StarFilled/>
</el-icon>
收藏次数:</strong>
</el-col>
<el-col :span="12">
{{ articleDetail.favoriteCount }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<p>
<strong>
<el-icon>
<Document/>
</el-icon>
文章内容:</strong>
</p>
<el-input type="textarea" :rows="10" v-model="articleDetail.content" disabled></el-input>
</el-card>
<el-divider/>
<div>
<p>
<strong>
<el-icon>
<UserFilled/>
</el-icon>
您关注的用户也收藏过这篇文章:</strong>
</p>
<el-button v-for="(user, index) in articleDetail.favoriteList">{{ user.realName }}</el-button>
</div>
<el-divider/>
<div style="text-align: center">
<el-button type="danger" @click="detailDialogVisible = false">
<el-icon>
<Close/>
</el-icon>
关闭窗口
</el-button>
</div>
</el-dialog>
</template>
2)script:
javascript
import {ElMessage} from "element-plus";
import {reactive, ref} from "vue";
import {useRouter} from "vue-router";
import {Close, Timer, User} from "@element-plus/icons-vue";
const router = useRouter(); // 创建路由实例
//****************************************搜索表单********************************************//
// 搜索条件
const searchForm = reactive({
title: ''
});
// 搜索方法
const search = () => {
ElMessage.success(`搜索成功${searchForm.title}`);
};
//****************************************文章列表********************************************//
const articles = [
{
id: '1',
title: '如何成为一名Java工程师?',
publishUser: '小灰',
publishDate: '2030-01-01 10:00:00',
content: '文章内容'
},
{
id: '2',
title: '如何成为一名Java工程师?',
publishUser: '小蓝',
publishDate: '2030-01-01 10:00:00',
content: '文章内容'
}
];
//****************************************分页组件********************************************//
// 当前页
const currentPage = ref(1)
// 页大小
const pageSize = ref(10)
// 当页大小发生改变时执行
const handleSizeChange = (val) => {
ElMessage.success(`每页显示:${val}条`)
}
// 当当前页发生改变时执行
const handleCurrentChange = (val) => {
ElMessage.success(`当前页码:${val}`)
}
//****************************************文章详情********************************************//
// 查询文章详情
const showDetail = (id) => {
ElMessage.success(`显示文章详情:${id}`);
detailDialogVisible.value = true;
}
// 文章详情弹窗是否显示
const detailDialogVisible = ref(false);
// 文章详情
const articleDetail = reactive({
id: 1,
title: '如何成为一名Java工程师?',
content: '如何成为一名Java工程师如何成为一名Java工程师如何成为一名Java工程师如何成为一名Java工程师',
publishUser: '小灰',
publishDate: '2030-01-01 10:00:00',
collectors: ['小灰', '小蓝'],
favoriteCount: 89,
browseCount: 1246,
favoriteList: [
{id: "1", realName: '小灰'},
{id: "2", realName: '小蓝'},
{id: "3", realName: '小绿'},
]
});
// 添加/取消收藏
const addFavorite = (id) => {
ElMessage.success(`收藏成功:${articleDetail.id}`);
};
3.7 部门模块
效果如下:

1)布局代码:
vue
<template>
<!-- *************************************************条件搜索************************************************* -->
<h3>全部部门</h3>
<el-form inline>
<el-form-item>
<el-input v-model="searchText" placeholder="请输入关键字搜索"></el-input>
</el-form-item>
</el-form>
<!-- *************************************************树形组件************************************************* -->
<el-tree
ref="treeRef"
:data="data"
:default-expand-all="true"
:filter-node-method="filterNode">
</el-tree>
</template>
2)script:
javascript
<script lang="ts" setup> // 注意是ts语法
import {ref, watch} from 'vue'
import type {TreeInstance} from 'element-plus'
// 树节点数据类型
interface Tree {
[key: string]: any
}
// 搜索框输入值
const searchText = ref('')
// 树组件实例
const treeRef = ref<TreeInstance>()
// 监听searchText变化,使用Tree的filter方法过滤树节点
watch(searchText, (val) => {
treeRef.value!.filter(val)
})
/**
* :filter-node-method: 当调用了filter方法时,会触发该方法,该方法的返回值决定是否显示该节点
* @param value: 调用filter方法时传入的参数
* @param data: 树节点数据
* @returns boolean: true表示显示该节点,false表示不显示该节点
*/
const filterNode = (value: string, data: Tree) => {
// 如果搜索框为空,则显示所有节点
if (!value) return true
// 如果搜索框不为空,则根据节点的label属性进行匹配
return data.label.includes(value)
}
// 树组件数据
const data = [
{
id: 1,
label: '研发部',
children: [
{
id: 1,
label: '小灰'
},
{
id: 2,
label: '小蓝'
},
{
id: 3,
label: '小绿'
}
]
},
{
id: 2,
label: '财务部',
children: [
{
id: 4,
label: '小红'
},
{
id: 5,
label: '小明'
}
]
},
{
id: 3,
label: '人事部',
children: [
{
id: 6,
label: '小龙'
},
{
id: 7,
label: '小军'
}
]
}
]
</script>
3.8 会议模块
3.8.1 会议列表
1)搜索表单
效果如下:

1)布局代码:
vue
<!-- *************************************************条件搜索************************************************* -->
<h3>会议列表</h3>
<el-row style="width: 100%;">
<el-col :span="18">
<el-form inline size="large">
<el-form-item label="会议标题">
<el-input v-model="searchForm.title" placeholder="请输入搜索内容"></el-input>
</el-form-item>
<el-form-item label="会议状态">
<el-select v-model="searchForm.status" placeholder="请选择" style="width: 160px">
<el-option label="全部" :value="-1"></el-option>
<el-option label="未开始" :value="0"></el-option>
<el-option label="进行中" :value="1"></el-option>
<el-option label="已结束" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
</el-form>
</el-col>
<el-col :span="6" style="text-align: right;">
<el-button type="primary" @click="addDialogVisible = true" size="large">发布会议</el-button>
</el-col>
</el-row>
2)script:
javascript
//****************************************搜索表单********************************************//
// 搜索条件
const searchForm = reactive({
title: '',
status: -1
});
// 搜索方法
const search = () => {
ElMessage.success(`搜索成功: ${searchForm.title} - ${searchForm.status}`);
};
2)表格组件
效果如下:

1)布局代码:
vue
<!-- *************************************************会议列表************************************************* -->
<div>
<el-card v-for="(meeting, index) in meetingList" :key="index" style="margin-bottom: 20px;">
<el-link type="primary" :underline="false" @click="showDetail(meeting.id)">{{ meeting.title }}</el-link>
<p>
<el-text tag="strong">
<el-icon>
<OfficeBuilding/>
</el-icon>
部门:
</el-text>
<el-tag>{{ meeting.deptName }}</el-tag>
</p>
<p>
<el-text tag="strong">
<el-icon>
<Timer/>
</el-icon>
发布时间:
</el-text>
<el-tag type="success">{{ meeting.startTime }}</el-tag>
</p>
<el-text>
{{ meeting.content }}
</el-text>
</el-card>
</div>
2)script:
javascript
//****************************************会议列表********************************************//
const meetingList = [
{
id: '1',
title: '关于《协同开发平台》项目部分模块升级的讨论',
deptName: '研发部',
startTime: '2030-01-01 10:00:00',
content: '功能升级如下:支持微信登录、QQ登录,支持通讯录、群组、聊天室、会议室等功能。'
},
{
id: '2',
title: '关于《协同开发平台》项目部分模块升级的讨论',
deptName: '研发部',
startTime: '2030-01-01 10:00:00',
content: '功能升级如下:支持微信登录、QQ登录,支持通讯录、群组、聊天室、会议室等功能。'
}
];
3)分页组件
效果如下:

1)布局代码:
vue
<!-- *************************************************分页组件************************************************* -->
<div style="margin-top: 20px;display: flex;justify-content: center;">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[3, 5, 10]"
size="large"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
2)script:
javascript
//****************************************分页组件********************************************//
// 当前页
const currentPage = ref(1)
// 页大小
const pageSize = ref(10)
// 当页大小发生改变时执行
const handleSizeChange = (val) => {
ElMessage.success(`每页显示:${val}条`)
}
// 当当前页发生改变时执行
const handleCurrentChange = (val) => {
ElMessage.success(`当前页码:${val}`)
}
3.8.2 发布会议
1)发布会议对话框
当点击"发布会议"按钮时,应该弹出对话框。

1)布局代码:
vue
<!-- *************************************************发布会议弹窗************************************************* -->
<el-dialog title="发布会议" v-model="addDialogVisible" style="width: 60%;">
<el-divider/>
<el-form ref="form" :model="meetingForm" label-width="80px" size="large">
<el-form-item label="文章标题">
<el-input v-model="meetingForm.title" placeholder="请输入文章标题"></el-input>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="部门">
<el-select v-model="meetingForm.deptId" placeholder="请选择">
<el-option label="研发部" :value="1"></el-option>
<el-option label="产品部" :value="2"></el-option>
<el-option label="测试部" :value="3"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="抄送人">
<el-select v-model="meetingForm.makeUser" placeholder="请选择" multiple>
<el-option label="小灰" value="1"></el-option>
<el-option label="小蓝" value="2"></el-option>
<el-option label="小绿" value="3"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="开始时间">
<el-date-picker v-model="meetingForm.startTime" type="datetime"
placeholder="请选择开始时间"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间">
<el-date-picker v-model="meetingForm.endTime" type="datetime" placeholder="请选择结束时间"></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="文章内容">
<el-input type="textarea" :rows="8" v-model="meetingForm.content" placeholder="请输入文章内容"></el-input>
</el-form-item>
</el-form>
<el-divider/>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="add">确 定</el-button>
<el-button @click="addDialogVisible = false">取 消</el-button>
</div>
</el-dialog>
2)script:
javascript
//****************************************发布会议********************************************//
// 新增会议弹窗是否显示
const addDialogVisible = ref(false);
// 会议对象
const meetingForm = reactive({
id: '',
title: '',
content: '',
deptId: 1,
startTime: '',
endTime: '',
makeUser: []
});
// 新增会议方法
const add = () => {
ElMessage.success(`新增会议成功:${JSON.stringify(meetingForm)}`);
addDialogVisible.value = false;
console.log(meetingForm);
};
2)绑定事件
给"发布会议"按钮绑定事件:
vue
<el-button type="primary" @click="addDialogVisible = true" size="large">发布会议</el-button>
3.8.2 会议详情对话框
1)会议详情对话框
当点击某个会议标题时,查询会议详情。
效果如下:

1)布局代码:
vue
<!-- *************************************************会议详情弹窗************************************************* -->
<el-dialog title="会议详情" v-model="detailDialogVisible" width="60%" top="2vh">
<div style="position: relative">
<h2 style="text-align: center">{{ meetingDetail.title }}</h2>
<el-button style="position: absolute;top:0;right: 10px;" type="success" @click="joinMeeting(meetingDetail.id)">
参加会议
</el-button>
</div>
<el-divider/>
<el-card>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<OfficeBuilding/>
</el-icon>
部门:</strong>
</el-col>
<el-col :span="12">
{{ meetingDetail.deptName }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Timer/>
</el-icon>
发布时间:</strong>
</el-col>
<el-col :span="12">
{{ meetingDetail.publishDate }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<CirclePlusFilled/>
</el-icon>
开始时间:</strong>
</el-col>
<el-col :span="12">
{{ meetingDetail.startTime }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<RemoveFilled/>
</el-icon>
结束时间:</strong>
</el-col>
<el-col :span="12">
{{ meetingDetail.endTime }}
</el-col>
</el-row>
<el-divider style="width:30%;margin: 10px 0"/>
<el-row>
<el-col :span="3">
<strong>
<el-icon>
<Promotion/>
</el-icon>
应到人数:</strong>
</el-col>
<el-col :span="3">
<el-tag type="primary"> {{ meetingDetail.joinCount }}</el-tag>
</el-col>
<el-col :span="3">
<strong>
<el-icon>
<SuccessFilled/>
</el-icon>
实到人数:</strong>
</el-col>
<el-col :span="3">
<el-tag type="success"> {{ meetingDetail.realCount }}</el-tag>
</el-col>
<el-col :span="3">
<strong>
<el-icon>
<RemoveFilled/>
</el-icon>
未到人数:</strong>
</el-col>
<el-col :span="3">
<el-tag type="danger"> {{ meetingDetail.noCount }}</el-tag>
</el-col>
</el-row>
<el-divider style="width:80%;margin: 10px 0"/>
<p>
<strong>
<el-icon>
<Document/>
</el-icon>
会议内容:</strong>
</p>
<el-input type="textarea" :rows="10" v-model="meetingDetail.content" disabled></el-input>
</el-card>
<el-divider/>
<div>
<p>
<strong>
<el-icon>
<UserFilled/>
</el-icon>
以下用户需要参加本次会议:</strong>
</p>
<el-button :type="user.joinMeeting ? 'primary' : 'danger'" disabled
v-for="(user, index) in meetingDetail.makeUser">{{ user.realName }}
</el-button>
</div>
<el-divider/>
<div style="text-align: center">
<el-button type="danger" @click="detailDialogVisible = false">
<el-icon>
<Close/>
</el-icon>
关闭窗口
</el-button>
</div>
</el-dialog>
2)script:
javascript
//****************************************会议详情********************************************//
// 会议详情弹窗是否显示
const detailDialogVisible = ref(false);
// 查询会议详情
const showDetail = (id) => {
ElMessage.success(`显示会议详情:${id}`);
detailDialogVisible.value = true;
}
// 会议详情
const meetingDetail = reactive({
id: 1,
title: '关于《协同开发平台》项目部分模块升级的讨论',
content: '功能升级如下:支持微信登录、QQ登录,支持通讯录、群组、聊天室、会议室等功能。',
deptName: '研发部',
publishDate: '2030-01-01 10:00:00',
startTime: '2030-01-01 10:00:00',
endTime: '2050-01-01 10:00:00',
joinCount: 4,
realCount: 2,
noCount: 2,
makeUser: [
{id: "1", realName: '小灰', joinMeeting: true},
{id: "2", realName: '小蓝', joinMeeting: false},
{id: "3", realName: '小绿', joinMeeting: true},
{id: "4", realName: '小红', joinMeeting: false},
]
});
// 添加/取消收藏
const joinMeeting = (id) => {
ElMessage.success(`参加成功:${meetingDetail.id}`);
};