首页 > 其他分享 >从0开始搭建vue + flask 旅游景点数据分析系统( 五):【用户管理页面、 景点管理页面、个人设置页面编写】

从0开始搭建vue + flask 旅游景点数据分析系统( 五):【用户管理页面、 景点管理页面、个人设置页面编写】

时间:2024-07-31 13:28:02浏览次数:15  
标签:vue name form true tours 数据分析系统 id 页面

  • 本期任务是编写数据用户管理页面(Users)。
  • 编写数据景点管理页面(Tours)页面。
  • 编写数据个人设置页面(Profile)页面。

1 编写用户管理页面

修改Users.vue:

<template>
  <div class="users-container">
    <el-card class="box-card">
      <div slot="header" class="header">
        <span>用户管理</span>
        <el-button style="float: right; " type="primary" @click="handleAddUser">添加用户</el-button>
      </div>
      <el-table :data="users" style="width: 100%">
        <el-table-column prop="id" label="ID" width="50"></el-table-column>
        <el-table-column prop="name" label="姓名" width="180"></el-table-column>
        <el-table-column prop="email" label="邮箱"></el-table-column>
        <el-table-column label="操作" width="180">
          <template slot-scope="scope">
            <el-button @click="handleEditUser(scope.row)" type="text" size="small">编辑</el-button>
            <el-button @click="handleDeleteUser(scope.row)" type="text" size="small">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <el-dialog title="添加用户" :visible.sync="dialogVisible">
      <el-form :model="form">
        <el-form-item label="姓名" :label-width="formLabelWidth">
          <el-input v-model="form.name"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" :label-width="formLabelWidth">
          <el-input v-model="form.email"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSaveUser">保存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      users: [
        { id: 1, name: '张三', email: '[email protected]' },
        { id: 2, name: '李四', email: '[email protected]' },
        { id: 3, name: '王五', email: '[email protected]' }
      ],
      dialogVisible: false,
      form: {
        name: '',
        email: ''
      },
      formLabelWidth: '80px'
    };
  },
  methods: {
    handleAddUser() {
      this.dialogVisible = true;
      this.form = { name: '', email: '' };
    },
    handleEditUser(user) {
      this.dialogVisible = true;
      this.form = { ...user };
    },
    handleDeleteUser(user) {
      this.users = this.users.filter(u => u.id !== user.id);
    },
    handleSaveUser() {
      if (this.form.id) {
        // Edit existing user
        const index = this.users.findIndex(u => u.id === this.form.id);
        if (index !== -1) {
          this.$set(this.users, index, { ...this.form });
        }
      } else {
        // Add new user
        const newUser = { ...this.form, id: this.users.length + 1 };
        this.users.push(newUser);
      }
      this.dialogVisible = false;
    }
  }
};
</script>

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

.header{
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>

效果:

在这里插入图片描述

2 编写景点管理页面

新建Tours.vue:

<template>
  <div class="tours-container">
    <el-card class="box-card">
      <div slot="header" class="header">
        <span>旅游景点管理</span>
        <el-button type="primary" @click="handleAddTour">添加景点</el-button>
      </div>
      <el-table :data="tours" style="width: 100%">
        <el-table-column prop="name" label="景点名称" width="180"></el-table-column>
        <el-table-column prop="alias" label="别名" width="180"></el-table-column>
        <el-table-column prop="reviewCount" label="评论数" width="100"></el-table-column>
        <el-table-column prop="rating" label="评分" width="100"></el-table-column>
        <el-table-column prop="featuredReview" label="精选评论"></el-table-column>
        <el-table-column prop="country" label="国家" width="120"></el-table-column>
        <el-table-column prop="city" label="城市" width="120"></el-table-column>
        <el-table-column label="操作" width="180">
          <template slot-scope="scope">
            <el-button @click="handleEditTour(scope.row)" type="text" size="small">编辑</el-button>
            <el-button @click="handleDeleteTour(scope.row)" type="text" size="small">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <el-dialog title="编辑景点" :visible.sync="dialogVisible">
      <el-form :model="form">
        <el-form-item label="景点名称" :label-width="formLabelWidth">
          <el-input v-model="form.name"></el-input>
        </el-form-item>
        <el-form-item label="别名" :label-width="formLabelWidth">
          <el-input v-model="form.alias"></el-input>
        </el-form-item>
        <el-form-item label="评论数" :label-width="formLabelWidth">
          <el-input v-model="form.reviewCount" type="number"></el-input>
        </el-form-item>
        <el-form-item label="评分" :label-width="formLabelWidth">
          <el-input v-model="form.rating" type="number"></el-input>
        </el-form-item>
        <el-form-item label="精选评论" :label-width="formLabelWidth">
          <el-input v-model="form.featuredReview"></el-input>
        </el-form-item>
        <el-form-item label="国家" :label-width="formLabelWidth">
          <el-input v-model="form.country"></el-input>
        </el-form-item>
        <el-form-item label="城市" :label-width="formLabelWidth">
          <el-input v-model="form.city"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSaveTour">保存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      tours: [
        { id: 1, name: '东京迪士尼度假区', alias: 'Tokyo Disney Resort', reviewCount: 1500, rating: 4.8, featuredReview: '非常美丽的景点', country: '日本', city: '东京' },
        { id: 2, name: '东京塔', alias: 'Tokyo Tower', reviewCount: 2500, rating: 4.9, featuredReview: '历史悠久,气势恢宏', country: '日本', city: '东京' },
        { id: 3, name: '三鹰之森吉卜力美术馆', alias: 'Ghibli Museum', reviewCount: 1800, rating: 4.7, featuredReview: '象征自由的地标', country: '日本', city: '东京' }
      ],
      dialogVisible: false,
      form: {
        name: '',
        alias: '',
        reviewCount: 0,
        rating: 0,
        featuredReview: '',
        country: '',
        city: ''
      },
      formLabelWidth: '100px'
    };
  },
  methods: {
    handleAddTour() {
      this.dialogVisible = true;
      this.form = { name: '', alias: '', reviewCount: 0, rating: 0, featuredReview: '', country: '', city: '' };
    },
    handleEditTour(tour) {
      this.dialogVisible = true;
      this.form = { ...tour };
    },
    handleDeleteTour(tour) {
      this.tours = this.tours.filter(t => t.id !== tour.id);
    },
    handleSaveTour() {
      if (this.form.id) {
        const index = this.tours.findIndex(t => t.id === this.form.id);
        if (index !== -1) {
          this.$set(this.tours, index, { ...this.form });
        }
      } else {
        const newTour = { ...this.form, id: this.tours.length + 1 };
        this.tours.push(newTour);
      }
      this.dialogVisible = false;
    }
  }
};
</script>

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

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

.dialog-footer {
  text-align: right;
}
</style>

效果:

在这里插入图片描述

3 编写个人设置页面

新建Profile.vue:

<template>
  <div class="profile-settings">
    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>个人设置</span>
      </div>
      <el-form :model="form" label-width="100px" :rules="rules" ref="profileForm">
        <el-form-item label="用户名" prop="username">
          <el-input v-model="form.username"></el-input>
        </el-form-item>
        <el-form-item label="年龄" prop="age">
          <el-input v-model="form.age" type="number"></el-input>
        </el-form-item>
        <el-form-item label="职业" prop="profession">
          <el-input v-model="form.profession"></el-input>
        </el-form-item>
        <el-form-item label="签名" prop="signature">
          <el-input type="textarea" v-model="form.signature"></el-input>
        </el-form-item>
        <el-form-item label="地址" prop="address">
          <el-input v-model="form.address"></el-input>
        </el-form-item>
        <el-form-item label="手机" prop="phone">
          <el-input v-model="form.phone"></el-input>
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="form.email"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">保存</el-button>
          <el-button @click="onReset">重置</el-button>
        </el-form-item>
      </el-form>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    return {
      form: {
        username: '',
        age: '',
        profession: '',
        signature: '',
        address: '',
        phone: '',
        email: ''
      },
      rules: {
        username: [
          { required: true, message: '请输入用户名', trigger: 'blur' }
        ],
        age: [
          { required: true, message: '请输入年龄', trigger: 'blur' }
        ],
        profession: [
          { required: true, message: '请输入职业', trigger: 'blur' }
        ],
        phone: [
          { required: true, message: '请输入手机号码', trigger: 'blur' },
          { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur' }
        ],
        email: [
          { required: true, message: '请输入邮箱地址', trigger: 'blur' },
          { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
        ]
      }
    };
  },
  methods: {
    onSubmit() {
      this.$refs.profileForm.validate((valid) => {
        if (valid) {
          alert('保存成功');
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    onReset() {
      this.$refs.profileForm.resetFields();
    }
  }
};
</script>

<style scoped>
.profile-settings {
  padding: 20px;
}
</style>

效果:

在这里插入图片描述

4 修改router文件

修改router/index.js ,优化了一下之前的导入方式改为使用箭头函数来动态引入,这样项目消耗的资源更少:

const routes = [
    {
        path: '/',
        component: Layout,
        redirect: '/dashboard',
        children: [
            {
                path: 'dashboard',
                component:()=> import('@/views/Dashboard'),
                name: 'Dashboard'
            },
            {
                path: 'users',
                component:()=>  import('@/views/Users'),
                name: 'Users'
            },
            {
                path: 'profile',
                component:()=>  import('@/views/Profile'),
                name: 'Users'
            },
            {
                path: 'tours',
                component:()=>  import('@/views/Tours'),
                name: 'Tours'
            }
            // 其他子路由
        ]
    },
    // 其他路由
];

5 修改Layout.vue

由于新增了页面,因此菜单也需要修改

 <el-menu-item index="/dashboard" @click="navigateTo('/dashboard')">
          <i class="el-icon-s-marketing"></i>
          数据驾驶舱</el-menu-item>
        <el-menu-item index="/tours" @click="navigateTo('/tours')">
          <i class="el-icon-s-promotion"></i>
          景点管理</el-menu-item>
        <el-menu-item index="/users" @click="navigateTo('/users')">
          <i class="el-icon-s-custom"></i>
          用户管理</el-menu-item>
        <el-menu-item index="/profile" @click="navigateTo('/profile')">
          <i class="el-icon-s-tools"></i>
          个人设置</el-menu-item>

前端整体效果:

在这里插入图片描述

6 美化按钮,自定义按钮的颜色

为了酷炫(帅是一辈子的事),我们修改el-button=primary的配色为黑金色,

在assets/styles下新建global.css:

/* 全局覆盖 Element UI 按钮样式 */
.el-button--primary {
    background-color: #545c64 !important; /* 黑色背景 */
    border-color: #000000 !important; /* 黑色边框 */
    color: #ffd04b !important; /* 金色文字 */
}

.el-button--primary:hover, .el-button--primary:focus {
    background-color: #333333 !important; /* 深黑色背景 */
    border-color: #333333 !important; /* 深黑色边框 */
    color: #ffd04b !important; /* 金色文字 */
}

在main.js中引入上述文件

import './assets/styles/global.css'; // 引入全局样式覆盖文件

修改后的按钮效果:

在这里插入图片描述

7 修复BUG

  • 打开对话框可以明显发现页面右侧会有抖动

    导致这个问题的原因是页面body样式有一个margin 8px的样式,修改方法也是非常简单,在index.html中修改:

      <body style="margin: 0;">
    
  • 菜单栏边缘有一侧白色的边距,这个是由于我们之前设置container的时候有一个1px 的边框颜色,使用深色的菜单栏背景就能看出来了,所以删掉下面的样式:

    .container{
      height: 100vh;
      /*border: 1px solid #eee;*/
    }
    
  • 菜单栏active的问题,我们点击用户管理,然后再刷新页面,发现激活的菜单栏变成数据驾驶舱了,其实就是activeIndex 这个变量刷新页面后变成初始值了,所以修改方式也非常简单,在页面加载完成后给他赋予当前的路由就可以了:

     mounted() {
        console.log('当前路径:', this.$route.path)
        this.activeIndex = this.$route.path
      },
    

标签:vue,name,form,true,tours,数据分析系统,id,页面
From: https://blog.csdn.net/roccreed/article/details/140804831

相关文章

  • 【面试题一】 2024 大厂进阶Vue2面试题及答案(10道)
    Vue2进阶面试题及答案1.Vue2的数据响应原理是什么?答案概要:Vue2使用了观察者模式和发布订阅模式来实现数据的响应式。具体来说:当数据被初始化时,Vue会遍历数据对象的每一个属性,使用Object.defineProperty为每一个属性添加getter和setter。在getter中,会收集......
  • Vue3 - 最新详细实现网站内部打开预览 office 全套附件,在页面弹窗内解析预览 word文档
    前言如果您需要Vue2版本,请访问这篇文章。在vue3|nuxt3项目开发中,详解实现项目内部“打开解析预览各种office文档”通用预览插件,支持弹出一个窗口在弹框内预览或者直接显示在页面某个div容器里面,解析预览word文档、excel电子表格、ppt演示文稿、pdf文档、txt文......
  • Vue2 - 最新详细实现网站内部打开预览 office 全套附件,在页面弹窗内解析预览 word文档
    前言如果您需要Vue3版本,请访问在vue2|nuxt2项目开发中,详解实现项目内部“打开解析预览各种office文档”通用预览插件,解析预览word文档、excel电子表格、ppt演示文稿、pdf文档、txt文本等,支持弹出一个窗口在弹框内预览或者直接显示在页面某个div容器里面,让vue项......
  • vue基础知识总结(2)--- axios的使用
    一.下载Vue3:选择自己想要下载的项目文件夹,cmd回车打开命令栏,执行:cnpminitvue@latest然后等待一会就可以创建一个项目,并更改项目名:√请输入项目名称:...vue-project之后按照提示输入对应的语句:cdvue-projectcnpminstall我们等待几秒Vue3项目就成功创建出来了......
  • 五分钟,用flask做一个简单的交互页面
    Python作为一个万能且简单的编程语言,其在各个领域都有着很好的表现。其中在Web领域,也有大名鼎鼎的Django和Flask,今天我们就通过Flask,用五分钟写一个简单的交互页面!基本功能1、安装Flask在命令行中输入pipinstallflask即可安装Flask。2、创建Flask应用在P......
  • 计算机毕业设计django+vue“爱宠”宠物用品商店【开题+论文+程序】
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着社会经济的快速发展和人们生活水平的不断提升,宠物已成为越来越多家庭的重要成员,宠物经济的繁荣也随之而来。然而,传统的宠物用品购买方......
  • 基于Java+Vue的采购管理系统:降低采购成本,需求部门更低成本采购(整套源码)
    前言:采购管理系统是一个综合性的管理平台,旨在提高采购过程的效率、透明度,并优化供应商管理。以下是对各个模块的详细解释:一、供应商准入供应商注册:供应商通过在线平台进行注册,填写基本信息和资质文件。资质审核:系统对供应商提交的资质文件进行自动或人工审核,确保供应商符......
  • 封装Vue 的 SVG 组件
    svg静态资源在assets下新建一个svg文件夹,用于存放svg图片svgIcon组件在components下新建一个文件夹,包含两个文件index.ts和SvgIcon.vuevue.config.jsmain.ts需要引入组件svgIcon使用**.vue<svg-icon iconClass="invite" className="iconicon-invite" /> *......
  • 这本vue3编译原理开源电子书,初中级前端竟然都能看懂
    前言众所周知vue提供了很多黑魔法,比如单文件组件(SFC)、指令、宏函数、cssscoped等。这些都是vue提供的开箱即用的功能,大家平时用这些黑魔法的时候有没有疑惑过一些疑问呢。我们每天写的vue代码一般都是写在*.vue文件中,但是浏览器却只认识html、css、js等文件类型,明显是不认......
  • [vue3] Vue3源码阅读笔记 reactivity - collectionHandlers
    源码位置:https://github.com/vuejs/core/blob/main/packages/reactivity/src/collectionHandlers.ts这个文件主要用于处理Set、Map、WeakSet、WeakMap类型的拦截。拦截是为了什么?为什么要处理这些方法?Vue3实现响应式的思路是使用ProxyAPI在getter中收集依赖,在setter触发更新......