(14)Element Plus项目综合案例


本系列教程目录Vue3+Element Plus全套学习笔记-目录大纲


文章目录

第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}`);
};
相关推荐
halo14162 小时前
vue中scss使用js的变量
javascript·vue3·scss
huohuopro2 小时前
Vue3快速入门/Vue3基础速通
前端·javascript·vue.js·前端框架
草巾冒小子2 小时前
vue3中解决 return‘ inside ‘finally‘ block报错的问题
前端·javascript·vue.js
pianmian18 小时前
坐标系与坐标系数转换
vue.js·html
GoFly开发者8 小时前
GoFly企业版框架升级2.6.6版本说明(框架在2025-05-06发布了)
前端·javascript·vue.js
七灵微10 小时前
ES6入门---第三单元 模块七: Proxy的使用+Reflect的使用
javascript·vue.js·es6
travel_wsy10 小时前
webrtc 视频直播
前端·vue.js·音视频·webrtc
切糕师学AI12 小时前
vue 中如何使用region?
前端·javascript·vue.js
苹果酱056714 小时前
小程序 IView WeappUI组件库(简单增删改查)
java·vue.js·spring boot·mysql·课程设计