(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: 'admin@example.com',
    phone: '12345678901',
    info: '这是一段简介',
    isFollowed: 1
  },
  {
    id: 2,
    username: 'xiaohui',
    realName: '小灰',
    sex: '0',
    age: 22,
    email: 'xiaohui@example.com',
    phone: '12345678902',
    info: '这是一段简介',
    isFollowed: 0
  },
  {
    id: 3,
    username: 'xiaolan',
    realName: '小蓝',
    sex: '1',
    age: 20,
    email: 'xiaolan@example.com',
    phone: '12345678903',
    info: '这是一段简介',
    isFollowed: 1
  },
  {
    id: 4,
    username: '小绿',
    realName: 'xiaolv',
    sex: '1',
    age: 20,
    email: 'xiaolv@example.com',
    phone: '12345678903',
    info: '这是一段简介',
    isFollowed: 0
  },
  {
    id: 5,
    username: 'xiaoming',
    realName: '小明',
    sex: '0',
    age: 20,
    email: 'xiaoming@example.com',
    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: 'xiaohui@example.com',
  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: 'xiaohui@example.com',
  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}`);
};
相关推荐
m0_7400437315 小时前
3、Vuex-Axios-Element UI
前端·javascript·vue.js
鹏北海16 小时前
微信扫码登录 iframe 方案中的状态拦截陷阱
前端·javascript·vue.js
狗哥哥16 小时前
Vite 插件实战 v2:让 keep-alive 的“组件名”自动长出来
前端·vue.js·架构
小黑的铁粉16 小时前
Vue2 vs Vue3
vue.js
AAA阿giao16 小时前
代码宇宙的精密蓝图:深入探索 Vue 3 + Vite 项目的灵魂结构
前端·javascript·vue.js
半桶水专家16 小时前
vue中的props详解
前端·javascript·vue.js
前端不太难16 小时前
RN 遇到复杂手势(缩放、拖拽、旋转)时怎么设计架构
javascript·vue.js·架构
白兰地空瓶16 小时前
一行 npm init vite,前端工程化的世界就此展开
前端·vue.js·vite
码力巨能编16 小时前
Markdown 作为 Vue 组件导入
前端·javascript·vue.js
仰望.17 小时前
vue 甘特图 vxe-gantt table 拖拽任务调整开始日期和结束日期的使用,拖拽任务调整日期
vue.js·甘特图·vxe-ui