当前位置: 首页 > article >正文

简易记事本前端开发(初步)

目录

简介

1. 创建Vue3项目和导入依赖

创建Vue3项目

安装依赖

2. 登录注册页面的编写

登录页面

注册页面

3. 首页仪表盘的编写

4. 事件分类的编写

5. 事件管理的编写

结语


简介

在本篇博客中,我们将一起探索如何使用Vue3框架,结合ECharts图表库和Element-Plus UI组件库,来构建一个简易记事本应用的前端部分。我们将涵盖从项目创建到各个功能模块的前端代码编写过程。

1. 创建Vue3项目和导入依赖

首先,我们需要创建一个Vue3项目,并导入必要的依赖。

创建Vue3项目

打开终端,运行以下命令来创建一个新的Vue3项目:

 

bash

npm install -g @vue/cli
vue create simple-notebook
cd simple-notebook

选择Vue 3作为项目的基础,并安装所需的配置。

安装依赖

接下来,我们需要安装ECharts和Element-Plus。

 

bash

npm install echarts element-plus

2. 登录注册页面的编写

我们将使用Element-Plus组件库来快速构建登录和注册页面。

登录页面

src/views目录下创建Login.vueRegister.vue文件,并使用Element-Plus的表单组件。

 

vue

<template>
  <div class="login-container">
    <div class="login-box">
      <div class="login-header">
        <div class="logo-container">
          <svg class="logo" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
            <path fill="#1890ff" d="M64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm32 98.7c0 3.5-2.8 6.3-6.3 6.3H38.3c-3.5 0-6.3-2.8-6.3-6.3V29.3c0-3.5 2.8-6.3 6.3-6.3h51.4c3.5 0 6.3 2.8 6.3 6.3v69.4z"/>
            <path fill="#fff" d="M45 41h38v6H45zm0 20h38v6H45zm0 20h38v6H45z"/>
          </svg>
        </div>
        <h2>简易记事本</h2>
        <p class="subtitle">记录生活,规划未来</p>
      </div>
      <el-form :model="loginFormData" :rules="rules" ref="loginForm">
        <el-form-item prop="username">
          <el-input v-model="loginFormData.username" placeholder="请输入账户名" size="large" />
        </el-form-item>
        <el-form-item prop="password">
          <el-input v-model="loginFormData.password" type="password" placeholder="请输入密码" size="large" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleLogin" style="width: 100%" size="large">
            登录
          </el-button>
        </el-form-item>
      </el-form>
      <div class="register-link">
        <router-link to="/register">没有账户?点击注册</router-link>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'

const router = useRouter()
const loginForm = ref(null)

const loginFormData = reactive({
  username: '',
  password: ''
})

const rules = {
  username: [
    { required: true, message: '请输入账户名', trigger: 'blur' }
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
    { min: 6, message: '密码长度不能小于6位', trigger: 'blur' }
  ]
}

const handleLogin = () => {
  if (!loginForm.value) return

  loginForm.value.validate((valid) => {
    if (valid) {
      // 这里可以添加登录逻辑,比如调用 API
      ElMessage.success('登录成功!')
      router.push('/dashboard') // 确保这里的路径是正确的
    }
  })
}
</script>

<style scoped>
.login-container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background: linear-gradient(135deg, #1890ff 0%, #36cfc9 100%);
}

.login-box {
  width: 420px;
  padding: 40px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(10px);
}

.login-header {
  text-align: center;
  margin-bottom: 40px;
}

h2 {
  margin: 0;
  font-size: 28px;
  color: #1890ff;
  margin-bottom: 8px;
}

.subtitle {
  margin: 0;
  color: #666;
  font-size: 16px;
}

:deep(.el-input__wrapper) {
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

:deep(.el-button) {
  border-radius: 8px;
  font-size: 16px;
  height: 44px;
}

:deep(.el-form-item) {
  margin-bottom: 24px;
}

.register-link {
  text-align: center;
  margin-top: 20px;
}

.register-link a {
  color: #1890ff;
  text-decoration: none;
}

.logo-container {
  display: flex;
  justify-content: center;
  margin-bottom: 16px;
}

.logo {
  width: 80px;
  height: 80px;
  animation: float 6s ease-in-out infinite;
}

@keyframes float {
  0% {
    transform: translateY(0px);
  }
  50% {
    transform: translateY(-10px);
  }
  100% {
    transform: translateY(0px);
  }
}
</style> 

注册页面

Register.vue的编写与登录页面类似,只是表单字段不同。

3. 首页仪表盘的编写

首页仪表盘主要展示用户的基本信息和事件统计。

 

vue

<template>
  <div class="home-container">
    <!-- 数据概览卡片 -->
    <el-row :gutter="20">
      <el-col :span="6" v-for="card in dataCards" :key="card.title">
        <el-card class="data-card" shadow="hover">
          <div class="data-header">
            <div class="data-title">
              <el-icon class="icon"><component :is="card.icon" /></el-icon>
              <span>{{ card.title }}</span>
            </div>
            <div class="data-value">{{ card.value }}</div>
          </div>
          <div class="data-footer">
            <span>{{ card.footerLabel }}</span>
            <span :class="card.trend">{{ card.footerValue }}</span>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 图表区域 -->
    <el-row :gutter="20" class="charts-container">
      <el-col :span="12">
        <el-card class="chart-card" shadow="hover">
          <template #header>
            <div class="chart-header">
              <span>事件分类统计</span>
            </div>
          </template>
          <div ref="pieChart" class="chart"></div>
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card class="chart-card" shadow="hover">
          <template #header>
            <div class="chart-header">
              <span>近7天事件趋势</span>
            </div>
          </template>
          <div ref="lineChart" class="chart"></div>
        </el-card>
      </el-col>
    </el-row>

    <!-- 最近事件列表 -->
    <el-card class="recent-events" shadow="hover">
      <template #header>
        <div class="recent-header">
          <span>最近事件</span>
          <el-button type="primary" link @click="$router.push('/dashboard/event-management')">
            查看更多<el-icon><ArrowRight /></el-icon>
          </el-button>
        </div>
      </template>
      <el-table 
        :data="recentEvents" 
        style="width: 100%"
        :row-class-name="tableRowClassName">
        <el-table-column prop="title" label="事件标题">
          <template #default="scope">
            <div class="event-title">{{ scope.row.title }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="category" label="分类" width="120">
          <template #default="scope">
            <el-tag size="small" effect="plain">{{ scope.row.category }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态" width="120">
          <template #default="scope">
            <el-tag :type="getStatusType(scope.row.status)" size="small">
              {{ scope.row.status }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" width="180" />
      </el-table>
    </el-card>
  </div>
</template>

<script setup>
import { ref, onMounted, reactive } from 'vue'
import * as echarts from 'echarts'
import { Calendar, Check, Warning, Folder, ArrowRight } from '@element-plus/icons-vue'

// 数据卡片
const dataCards = reactive([
  {
    title: '总事件数',
    value: 156,
    icon: 'Calendar',
    footerLabel: '较上周',
    footerValue: '+12%',
    trend: 'up'
  },
  {
    title: '已完成事件',
    value: 89,
    icon: 'Check',
    footerLabel: '完成率',
    footerValue: '57%',
    trend: 'up'
  },
  {
    title: '待处理事件',
    value: 67,
    icon: 'Warning',
    footerLabel: '紧急事件',
    footerValue: '5',
    trend: 'warning'
  },
  {
    title: '事件分类',
    value: 8,
    icon: 'Folder',
    footerLabel: '本月新增',
    footerValue: '+2',
    trend: 'up'
  }
])

// 最近事件
const recentEvents = ref([
  {
    title: '完成项目文档',
    category: '工作',
    status: '进行中',
    createTime: '2024-03-01 10:00:00'
  },
  {
    title: '团队会议',
    category: '会议',
    status: '已完成',
    createTime: '2024-03-01 09:30:00'
  },
  {
    title: '健身计划',
    category: '生活',
    status: '待开始',
    createTime: '2024-03-01 09:00:00'
  }
])

const getStatusType = (status) => {
  const types = {
    '已完成': 'success',
    '进行中': 'primary',
    '待开始': 'info'
  }
  return types[status] || 'info'
}

// 图表相关
const pieChart = ref(null)
const lineChart = ref(null)

onMounted(() => {
  // 初始化饼图
  const pieChartInstance = echarts.init(pieChart.value)
  pieChartInstance.setOption({
    tooltip: {
      trigger: 'item'
    },
    legend: {
      orient: 'vertical',
      left: 'left'
    },
    series: [{
      type: 'pie',
      radius: '50%',
      data: [
        { value: 35, name: '工作' },
        { value: 30, name: '生活' },
        { value: 25, name: '学习' },
        { value: 20, name: '会议' },
        { value: 15, name: '娱乐' }
      ]
    }]
  })

  // 初始化折线图
  const lineChartInstance = echarts.init(lineChart.value)
  lineChartInstance.setOption({
    tooltip: {
      trigger: 'axis'
    },
    xAxis: {
      type: 'category',
      data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
    },
    yAxis: {
      type: 'value'
    },
    series: [{
      data: [8, 12, 15, 9, 11, 13, 10],
      type: 'line',
      smooth: true,
      areaStyle: {
        opacity: 0.3
      }
    }]
  })

  // 监听窗口大小变化
  window.addEventListener('resize', () => {
    pieChartInstance.resize()
    lineChartInstance.resize()
  })
})

const tableRowClassName = ({ rowIndex }) => {
  return 'table-row-' + rowIndex
}
</script>

<style scoped>
.home-container {
  padding: 20px;
}

.data-card {
  height: 120px;
  margin-bottom: 20px;
}

.data-header {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.data-title {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #666;
}

.icon {
  font-size: 20px;
}

.data-value {
  font-size: 24px;
  font-weight: bold;
  color: #303133;
}

.data-footer {
  margin-top: 10px;
  display: flex;
  justify-content: space-between;
  color: #909399;
  font-size: 14px;
}

.up {
  color: #67c23a;
}

.down {
  color: #f56c6c;
}

.warning {
  color: #e6a23c;
}

.charts-container {
  margin-top: 20px;
}

.chart-card {
  margin-bottom: 20px;
}

.chart {
  height: 300px;
}

.chart-header {
  font-size: 16px;
  font-weight: 500;
}

.recent-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

:deep(.el-card__header) {
  padding: 15px 20px;
  border-bottom: 1px solid #ebeef5;
}

.el-row {
  margin-bottom: 20px;
}

.recent-events {
  transition: all 0.3s;
}

.recent-events:hover {
  transform: translateY(-5px);
}

:deep(.el-table) {
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

:deep(.el-table__header) {
  background-color: #f5f7fa;
}

:deep(.el-table__row) {
  transition: all 0.3s;
}

:deep(.el-table__row:hover) {
  transform: translateZ(20px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}

.event-title {
  font-weight: 500;
  color: #303133;
}

:deep(.table-row-0) {
  background-color: rgba(24, 144, 255, 0.05);
}

:deep(.table-row-1) {
  background-color: rgba(54, 207, 201, 0.05);
}

:deep(.el-card) {
  border-radius: 12px;
  overflow: hidden;
}

.recent-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 0;
}

:deep(.el-card__header) {
  border-bottom: 1px solid #f0f0f0;
  padding: 0 20px;
}
</style> 

4. 事件分类的编写

src/views目录下创建EventCategory.vue文件。

 

vue

<template>
  <div class="category-container">
    <div class="category-header">
      <h3>事件分类管理</h3>
      <el-button type="primary" @click="handleAdd">
        <el-icon><Plus /></el-icon>新增分类
      </el-button>
    </div>

    <el-table :data="categories" style="width: 100%" border stripe>
      <el-table-column prop="id" label="ID" width="80" align="center" />
      <el-table-column prop="name" label="分类名称" />
      <el-table-column prop="count" label="事件数量" width="100" align="center" />
      <el-table-column prop="createTime" label="创建时间" width="180" align="center" />
      <el-table-column label="操作" width="200" align="center">
        <template #default="scope">
          <div class="operation-buttons">
            <el-button type="primary" size="small" @click="handleEdit(scope.row)">
              <el-icon><Edit /></el-icon>
              <span>编辑</span>
            </el-button>
            <el-button type="danger" size="small" @click="handleDelete(scope.row)">
              <el-icon><Delete /></el-icon>
              <span>删除</span>
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>

    <!-- 新增/编辑对话框 -->
    <el-dialog
      :title="dialogType === 'add' ? '新增分类' : '编辑分类'"
      v-model="dialogVisible"
      width="30%">
      <el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
        <el-form-item label="分类名称" prop="name">
          <el-input v-model="form.name" placeholder="请输入分类名称"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete } from '@element-plus/icons-vue'

// 模拟数据
const categories = ref([
  { id: 1, name: '工作', count: 35, createTime: '2024-03-01 10:00:00' },
  { id: 2, name: '生活', count: 30, createTime: '2024-03-01 10:30:00' },
  { id: 3, name: '学习', count: 25, createTime: '2024-03-01 11:00:00' },
  { id: 4, name: '会议', count: 20, createTime: '2024-03-01 11:30:00' },
  { id: 5, name: '娱乐', count: 15, createTime: '2024-03-01 12:00:00' }
])

const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const currentId = ref(null)

const form = reactive({
  name: ''
})

const rules = {
  name: [
    { required: true, message: '请输入分类名称', trigger: 'blur' },
    { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
  ]
}

const handleAdd = () => {
  dialogType.value = 'add'
  form.name = ''
  dialogVisible.value = true
}

const handleEdit = (row) => {
  dialogType.value = 'edit'
  currentId.value = row.id
  form.name = row.name
  dialogVisible.value = true
}

const handleDelete = (row) => {
  ElMessageBox.confirm(
    '此操作将永久删除该分类,是否继续?',
    '提示',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }
  ).then(() => {
    const index = categories.value.findIndex(item => item.id === row.id)
    categories.value.splice(index, 1)
    ElMessage.success('删除成功')
  })
}

const handleSubmit = () => {
  formRef.value?.validate((valid) => {
    if (valid) {
      if (dialogType.value === 'add') {
        const newCategory = {
          id: categories.value.length + 1,
          name: form.name,
          count: 0,
          createTime: new Date().toLocaleString()
        }
        categories.value.push(newCategory)
        ElMessage.success('新增成功')
      } else {
        const index = categories.value.findIndex(item => item.id === currentId.value)
        categories.value[index].name = form.name
        ElMessage.success('编辑成功')
      }
      dialogVisible.value = false
    }
  })
}
</script>

<style scoped>
.category-container {
  padding: 20px;
  background-color: #fff;
  border-radius: 4px;
}

.category-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.category-header h3 {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
}

.el-button {
  display: flex;
  align-items: center;
  gap: 5px;
}

.operation-buttons {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.el-button {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

:deep(.el-button .el-icon) {
  margin: 0;
}
</style> 

5. 事件管理的编写

src/views目录下创建EventManagement.vue文件。

 

vue

<template>
  <div class="event-container">
    <div class="event-header">
      <h3>事件管理</h3>
      <el-button type="primary" @click="handleAdd">
        <el-icon><Plus /></el-icon>新增事件
      </el-button>
    </div>

    <!-- 搜索栏 -->
    <div class="search-bar">
      <el-form :inline="true" :model="searchForm">
        <el-form-item>
          <el-input
            v-model="searchForm.keyword"
            placeholder="搜索事件标题"
            clearable
          />
        </el-form-item>
        <el-form-item>
          <el-select v-model="searchForm.category" placeholder="选择分类" clearable>
            <el-option
              v-for="item in categories"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-select v-model="searchForm.status" placeholder="选择状态" clearable>
            <el-option
              v-for="item in statusOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSearch">搜索</el-button>
          <el-button @click="resetSearch">重置</el-button>
        </el-form-item>
      </el-form>
    </div>

    <!-- 事件列表 -->
    <el-table :data="events" style="width: 100%" border stripe>
      <el-table-column prop="title" label="事件标题" />
      <el-table-column prop="category" label="分类" width="120" />
      <el-table-column prop="priority" label="优先级" width="100" align="center">
        <template #default="scope">
          <el-tag :type="getPriorityType(scope.row.priority)">
            {{ scope.row.priority }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="status" label="状态" width="100" align="center">
        <template #default="scope">
          <el-tag :type="getStatusType(scope.row.status)">
            {{ scope.row.status }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="createTime" label="创建时间" width="180" align="center" />
      <el-table-column label="操作" width="250" align="center">
        <template #default="scope">
          <div class="operation-buttons">
            <el-button type="primary" size="small" @click="handleEdit(scope.row)">
              <el-icon><Edit /></el-icon>
              <span>编辑</span>
            </el-button>
            <el-button 
              type="success" 
              size="small" 
              @click="handleComplete(scope.row)"
              v-if="scope.row.status !== '已完成'">
              <el-icon><Check /></el-icon>
              <span>完成</span>
            </el-button>
            <el-button type="danger" size="small" @click="handleDelete(scope.row)">
              <el-icon><Delete /></el-icon>
              <span>删除</span>
            </el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页 -->
    <div class="pagination">
      <el-pagination
        v-model:current-page="currentPage"
        v-model:page-size="pageSize"
        :page-sizes="[10, 20, 30, 50]"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </div>

    <!-- 新增/编辑对话框 -->
    <el-dialog
      :title="dialogType === 'add' ? '新增事件' : '编辑事件'"
      v-model="dialogVisible"
      width="40%">
      <el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
        <el-form-item label="事件标题" prop="title">
          <el-input v-model="form.title" placeholder="请输入事件标题"></el-input>
        </el-form-item>
        <el-form-item label="所属分类" prop="category">
          <el-select v-model="form.category" placeholder="请选择分类">
            <el-option
              v-for="item in categories"
              :key="item.id"
              :label="item.name"
              :value="item.name"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="优先级" prop="priority">
          <el-select v-model="form.priority" placeholder="请选择优先级">
            <el-option label="高" value="高" />
            <el-option label="中" value="中" />
            <el-option label="低" value="低" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input
            v-model="form.remark"
            type="textarea"
            rows="3"
            placeholder="请输入备注信息"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确定</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Edit, Delete, Check } from '@element-plus/icons-vue'

// 分类数据
const categories = ref([
  { id: 1, name: '工作' },
  { id: 2, name: '生活' },
  { id: 3, name: '学习' },
  { id: 4, name: '会议' },
  { id: 5, name: '娱乐' }
])

// 状态选项
const statusOptions = [
  { value: '待开始', label: '待开始' },
  { value: '进行中', label: '进行中' },
  { value: '已完成', label: '已完成' }
]

// 搜索表单
const searchForm = reactive({
  keyword: '',
  category: '',
  status: ''
})

// 模拟事件数据
const events = ref([
  {
    id: 1,
    title: '完成项目文档',
    category: '工作',
    priority: '高',
    status: '进行中',
    createTime: '2024-03-01 10:00:00',
    remark: '需要完成项目相关文档的编写工作'
  },
  {
    id: 2,
    title: '团队会议',
    category: '会议',
    priority: '中',
    status: '已完成',
    createTime: '2024-03-01 09:30:00',
    remark: '讨论本周工作进展'
  },
  {
    id: 3,
    title: '健身计划',
    category: '生活',
    priority: '低',
    status: '待开始',
    createTime: '2024-03-01 09:00:00',
    remark: '每周三次健身计划'
  }
])

// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(100)

// 对话框相关
const dialogVisible = ref(false)
const dialogType = ref('add')
const formRef = ref(null)
const currentId = ref(null)

const form = reactive({
  title: '',
  category: '',
  priority: '',
  remark: ''
})

const rules = {
  title: [
    { required: true, message: '请输入事件标题', trigger: 'blur' },
    { min: 2, max: 50, message: '长度在 2 到 50 个字符', trigger: 'blur' }
  ],
  category: [
    { required: true, message: '请选择所属分类', trigger: 'change' }
  ],
  priority: [
    { required: true, message: '请选择优先级', trigger: 'change' }
  ]
}

// 处理函数
const handleSearch = () => {
  // 实现搜索逻辑
  console.log('搜索条件:', searchForm)
}

const resetSearch = () => {
  Object.keys(searchForm).forEach(key => {
    searchForm[key] = ''
  })
}

const handleSizeChange = (val) => {
  pageSize.value = val
  // 重新加载数据
}

const handleCurrentChange = (val) => {
  currentPage.value = val
  // 重新加载数据
}

const handleAdd = () => {
  dialogType.value = 'add'
  Object.keys(form).forEach(key => {
    form[key] = ''
  })
  dialogVisible.value = true
}

const handleEdit = (row) => {
  dialogType.value = 'edit'
  currentId.value = row.id
  Object.keys(form).forEach(key => {
    form[key] = row[key]
  })
  dialogVisible.value = true
}

const handleDelete = (row) => {
  ElMessageBox.confirm(
    '此操作将永久删除该事件,是否继续?',
    '提示',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }
  ).then(() => {
    const index = events.value.findIndex(item => item.id === row.id)
    events.value.splice(index, 1)
    ElMessage.success('删除成功')
  })
}

const handleComplete = (row) => {
  const index = events.value.findIndex(item => item.id === row.id)
  events.value[index].status = '已完成'
  ElMessage.success('事件已完成')
}

const handleSubmit = () => {
  formRef.value?.validate((valid) => {
    if (valid) {
      if (dialogType.value === 'add') {
        const newEvent = {
          id: events.value.length + 1,
          ...form,
          status: '待开始',
          createTime: new Date().toLocaleString()
        }
        events.value.push(newEvent)
        ElMessage.success('新增成功')
      } else {
        const index = events.value.findIndex(item => item.id === currentId.value)
        events.value[index] = {
          ...events.value[index],
          ...form
        }
        ElMessage.success('编辑成功')
      }
      dialogVisible.value = false
    }
  })
}

// 工具函数
const getPriorityType = (priority) => {
  const types = {
    '高': 'danger',
    '中': 'warning',
    '低': 'info'
  }
  return types[priority]
}

const getStatusType = (status) => {
  const types = {
    '已完成': 'success',
    '进行中': 'primary',
    '待开始': 'info'
  }
  return types[status]
}
</script>

<style scoped>
.event-container {
  padding: 20px;
  background-color: #fff;
  border-radius: 4px;
}

.event-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.event-header h3 {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
}

.search-bar {
  margin-bottom: 20px;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.pagination {
  margin-top: 20px;
  display: flex;
  justify-content: flex-end;
}

.operation-buttons {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.el-button {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

:deep(.el-button .el-icon) {
  margin: 0;
}
</style> 

结语

一天把记事本项目前端样式简单写一下,目前只是初版,后面可能会迭代,需要的小伙伴不要老老实实复制代码,联系作者,自然会有全套代码


http://www.kler.cn/a/413349.html

相关文章:

  • Java中的线程池使用详解
  • el-tree的使用及控制全选、反选、获取选中
  • OpenAI Whisper 语音识别 模型部署及接口封装
  • node.js基础学习-http模块-创建HTTP服务器、客户端(一)
  • LeetCode 0632.最小区间:优先队列
  • 【VRChat 全身动捕】VIVE 手柄改 tracker 定位器教程,低成本光学动捕解决方案(持续更新中2024.11.26)
  • 分布式系统RPC原理面试题及参考答案
  • 解决stuid项目类爆炸问题
  • 矩阵/矩阵乘法/特征值/特征向量的讲解
  • Docker 启动和停止的精准掌舵:操控指南
  • 学习JavaEE的日子 Day09 一维数组
  • 全景图像(Panorama Image)向透视图像(Perspective Image)的跨视图转化(Cross-view)
  • Paddle Inference部署推理(七)
  • QT 中 SQLite 使用方法
  • 第二节——计算机网络(四)物理层
  • Docker 容器隔离的关键技术:Namespace
  • PAT甲级 1056 Mice and Rice(25)
  • vue2 - 20.json-server
  • 优化DevOps环境中的容器化交付流程:实践指南
  • SpringBoot+Vue3+Element Plus实现图片上传和预览
  • k8s运行运行pod报错超出文件描述符表限制
  • BERT简单理解;双向编码器优势
  • Leetcode 131 Palindrome Partition
  • 使用 exe4j 将 Spring Boot 项目打包为 EXE 可执行文件
  • 前端面试笔试(六)
  • Ubuntu20.04安装kalibr