从0开始搭建vue + flask 旅游景点数据分析系统(九):旅游景点管理之增删改查

这一期来做旅游景点数据的增删改查

先看下我们做好的效果是这样的:
在这里插入图片描述## 1 后台接口

这里的接口已经考虑到了分页的情况,因为前端的表格是带有分页的,接受的前端传过来的get参数为 title 、page、 limit ,titie是查询的关键词,会根据景点的title去模糊查询。

@main.route('/tours', methods=['GET'])
def get_tours():try:title = request.args.get('title', '')  # 获取查询参数中的 titlepage = int(request.args.get('page', 1))  # 获取当前页码,默认为 1limit = int(request.args.get('limit', 10))  # 获取每页显示的记录数,默认为 10# 根据 title 进行模糊搜索query = Tour.query.filter(Tour.title.like(f'%{title}%'))# 计算总数和获取当前页数据total = query.count()  # 总记录数tours = query.offset((page - 1) * limit).limit(limit).all()  # 当前页的数据result = tours_schema.dump(tours)  # 使用你的序列化方案处理数据return make_response(data={'total': total, 'records': result})except Exception as e:return make_response(code=1, message=str(e))

2 前端表格

前端表格分为表头、表格数据部分、分页,放在一个el-card中,注意到表格栏中有景点图片的处理,可以在表格中直接展示图片。

<el-card class="box-card"><div slot="header" class="header"><span class="header-title">旅游景点管理</span><div class="header-controls"><el-input v-model="searchTitle" placeholder="输入标题进行搜索" class="search-input"></el-input><el-button type="primary" @click="fetchData">搜索</el-button><el-button type="success" @click="handleAddTour">添加景点</el-button></div></div><el-table :data="tours" style="width: 100%"><el-table-column label="图片" width="120"><template slot-scope="scope"><el-image:src="scope.row.img"class="tour-image":alt="scope.row.title"fit="cover"lazy/></template></el-table-column><el-table-column prop="title" label="景点名称" min-width="180"></el-table-column><el-table-column prop="title_en" label="别名" min-width="180"></el-table-column><el-table-column prop="comments" label="评论数" min-width="100"></el-table-column><el-table-column prop="score" label="评分" min-width="100"></el-table-column><el-table-column prop="nation" label="国家" min-width="120"></el-table-column><el-table-column prop="city" label="城市" min-width="120"></el-table-column><el-table-column label="操作" min-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-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-size="pageSize":total="totalItems"layout="total, sizes, prev, pager, next, jumper"/></el-card>

数据部分是这样的,原先的静态数据改成[]就行了,通过后台接口来获取数据:

data() {return {searchTitle: '',tours: [],// 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: {},formLabelWidth: '100px',totalItems: 0,currentPage: 1,pageSize: 10,};},

在页面加载的时候默认让它显示第一页,进行搜索的时候,会根据关键词去查询后台接口:

mounted() {this.currentPage = 1this.loadData()},methods: {fetchData() {this.loadData()},//加载数据loadData() {tours(this.searchTitle, this.currentPage, this.pageSize).then(res => {// console.log(res.data.data.records);this.tours = res.data.data.recordsthis.totalItems = res.data.data.total})},handleCurrentChange(page) {this.currentPage = page;this.loadData();},handleSizeChange(size) {this.pageSize = size;this.loadData();},
}

还有两个分页相关的方法也可以注意下,因为分页控件可以调整页数、每页显示的数量,点击之后也需要加载数据,而且假如说这时候是有搜索关键词的,关键词也需要保持。

样式部分

.tours-container {padding: 20px;
}.header {display: flex;justify-content: space-between;align-items: center;padding: 10px 20px;
}.dialog-footer {text-align: right;
}.header-title {font-size: 18px;font-weight: bold;
}.header-controls {display: flex;align-items: center;
}.search-input {width: 300px;margin-right: 10px; /* Adjust spacing between input and buttons */
}

在tour.js中需要添加新的接口:

export function  tours(title,page=1,limit=10){return request({url:  '/tours',method: 'get',params: {title, page, limit}})
}

3 搜索效果测试

在这里插入图片描述

4 新增景点

先增加后端方法:

@main.route('/tour', methods=['POST'])
def add_tour():data = request.json  # 获取JSON数据# 这里可以进行数据验证,例如检查必填字段是否存在required_fields = ['img', 'title', 'title_en', 'comments', 'score', 'select_comment', 'nation', 'city']for field in required_fields:if field not in data:return make_response(code=1, message= f'错误,缺少字段: {field}')# 创建新的景点对象new_tour = Tour(img=data['img'],title=data['title'],title_en=data['title_en'],comments=data['comments'],score=data['score'],select_comment=data['select_comment'],nation=data['nation'],city=data['city'] )

前端部分我们先增加一个接口,使用的是POST请求:

export function  addTour(data){return request({url:  '/tour',method: 'post',data})
}

页面部分是先点击添加景点,触发handleAddTour,打开对话框:

handleAddTour() {this.dialogTitle = '新增景点'this.dialogVisible = true;this.form = {img: '',title: '',title_en: '',comments: 0,score: 0,select_comment: '',nation: '',city: ''};},<el-dialog :title="dialogTitle" :visible.sync="dialogVisible"><el-form :model="form"><el-form-item label="景点图片地址" :label-width="formLabelWidth"><el-input v-model="form.img"></el-input></el-form-item><el-form-item label="景点名称" :label-width="formLabelWidth"><el-input v-model="form.title"></el-input></el-form-item><el-form-item label="别名" :label-width="formLabelWidth"><el-input v-model="form.title_en"></el-input></el-form-item><el-form-item label="评论数" :label-width="formLabelWidth"><el-input v-model="form.comments" type="number"></el-input></el-form-item><el-form-item label="评分" :label-width="formLabelWidth"><el-input v-model="form.score" type="number"></el-input></el-form-item><el-form-item label="精选评论" :label-width="formLabelWidth"><el-input v-model="form.select_comment"></el-input></el-form-item><el-form-item label="国家" :label-width="formLabelWidth"><el-input v-model="form.nation"></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>

对话框填写完毕后,点击handleSaveTour,有后台交互,这里为了偷懒,这个对话框我们打算既支持新增也支持编辑,所以对话框的标题也是动态的数据:

 handleSaveTour() {if (this.form.id) {//更新景点信息的逻辑} else {addTour(this.form).then(res=>{console.log(res.data.message)const messageType = res.data.code === 0 ? 'success' : 'error';Message({message: res.data.message,type: messageType, // 'success' 或者 'error' 根据需要duration: 2000 // 消息框显示的时长(毫秒)});})}this.dialogVisible = false;},

根据返回code,弹出不同的消息框(elmentui的Message)。

我们添加了一个测试景点:

在这里插入图片描述

返回消息框:
在这里插入图片描述
在这里插入图片描述

5 修改景点

先新增前后端的接口:

@main.route('/tour/<int:id>', methods=['PUT'])
def update_tour(id):data = request.json  # 获取JSON数据tour = Tour.query.get(id)  # 根据ID查找景点if not tour:return make_response(code=1, message='景点不存在')# 更新景点的字段for field in ['img', 'title', 'title_en', 'comments', 'score', 'select_comment', 'nation', 'city']:if field in data:setattr(tour, field, data[field])db.session.commit()return make_response(code=0, message='修改景点成功')

tour.js

// 修改现有景点
export function updateTour(id, data) {return request({url: `/tour/${id}`,method: 'put',data});
}

然后就很容易,修改补全刚才未完成的*handleSaveTour 就行了,基本上和新增的都一样。逻辑就是如果form.id 存在,说明是一个修改操作,如果不存在,说明是一个新增操作。*

 handleSaveTour() {if (this.form.id) {updateTour(this.form.id, this.form).then(res=>{console.log(res.data.message)const messageType = res.data.code === 0 ? 'success' : 'error';Message({message: res.data.message,type: messageType, // 'success' 或者 'error' 根据需要duration: 2000 // 消息框显示的时长(毫秒)});})} else {addTour(this.form).then(res=>{console.log(res.data.message)const messageType = res.data.code === 0 ? 'success' : 'error';Message({message: res.data.message,type: messageType, // 'success' 或者 'error' 根据需要duration: 2000 // 消息框显示的时长(毫秒)});})}this.dialogVisible = false;},

在这里插入图片描述
在这里插入图片描述

6 删除景点

先增加后端接口

@main.route('/tour/<int:id>', methods=['DELETE'])
def delete_tour(id):tour = Tour.query.get(id)  # 根据ID查找景点if not tour:return make_response(code=1, message='景点不存在')db.session.delete(tour)db.session.commit()return make_response(code=0, message='删除景点成功')

然后修改前端tour.js

// 删除景点
export function deleteTour(id) {return request({url: `/tour/${id}`,method: 'delete'});
}

最后就是完善一下 *handleDeleteTour*这个方法就是点击每行上的删除按钮触发的:

handleDeleteTour(tour) {deleteTour(tour.id).then(res=>{const messageType = res.data.code === 0 ? 'success' : 'error';Message({message: res.data.message,type: messageType, // 'success' 或者 'error' 根据需要duration: 2000 // 消息框显示的时长(毫秒)});})},

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/401128.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab绘制像素风字母颜色及透明度随机变化动画

本文是使用 Matlab 绘制像素风字母颜色及透明度随机变化动画的教程 实现效果 实现代码 如果需要更改为其他字母组合&#xff0c;在下面代码的基础上简单修改就可以使用。 步骤&#xff1a;(1) 定义字母形状&#xff1b;(2) 给出字母组合顺序&#xff1b;(3) 重新运行程序&#…

iPhone 16 机模视频曝光,五种颜色各有千秋

科技博主的最新视频分享了苹果 iPhone 16 标准版的机模上手体验。 视频中展示了五种颜色的 iPhone 16&#xff1a;深邃的蓝色、柔和的粉色、纯净的白色、经典的黑色和生机勃勃的绿色。 与 iPhone 15 相比&#xff0c;iPhone 16 弃用了黄色&#xff0c;新增了白色&#xff0c;…

地质灾害评估和治理工程勘查设计资质乙级资质办理标准

地质灾害评估和治理工程勘查设计资质乙级资质的办理标准主要包括单位条件、专业技术人员条件、仪器设备要求以及申请材料等方面。以下是详细的办理标准&#xff1a; 一、单位条件 **1、法人资格&#xff1a;**申请单位应具有企业法人或者事业单位法人资格。 **2、管理体系&a…

奥运内容碎片化传播下,品牌营销开始要讲究“性价比”

8月12日凌晨&#xff0c;随着孙颖莎和其他代表各洲的运动员们一起熄灭了圣火&#xff0c;巴黎奥运会终于落下帷幕。 本届奥运会上&#xff0c;中国体育代表团表现出色&#xff0c;共获得40枚金牌&#xff0c;金牌总数位居全球榜首&#xff0c;创下了中国在境外奥运会上的最佳成…

人工智能领域颠覆性技术创新,数字人泛化AI时代来临

是先有鸡还是先有蛋&#xff0c;这个问题人类还没有搞清楚&#xff0c;这次又有一个新的问题产生了&#xff0c;是算法进化了AI&#xff0c;还是AI进化了算法。我们知道直播平台都是利用算法对数字人直播进行斟别&#xff0c;但这一次被数字人泛化技术颠覆了&#xff0c;AI回复…

报错解决——苹果电脑mac装windows10,总是提示“启动转换”安装失败:拷贝Windows安装文件时出错

报错原因&#xff1a; 所安装的镜像文件大于4GB。 解决办法一&#xff1a; 使用小于4GB的镜像文件。 参考文章&#xff1a; 安装小于4GB的windows系统镜像 小于4GB的windows10镜像下载&#xff1a; 系统库官网 解决办法二&#xff1a; 参考文章&#xff1a; Mac air装…

VS实用调试技巧(程序员的必备技能)

调试的重要性 在我们写代码的时候&#xff0c;如果程序出现了bug&#xff0c;那么下一步就是找到bug并修复bug!而这个找问题的过程就被称为调试&#xff08;英文叫debug&#xff0c;消灭bug的意思&#xff09;。 调试能观察到程序内部执行的细节&#xff0c;可以增加程序员对…

Kafka系列之:Kafka Connect深入探讨 - 错误处理和死信队列

Kafka系列之&#xff1a;Kafka Connect深入探讨 - 错误处理和死信队列 一、快速失败二、YOLO&#xff1a;默默忽略坏消息三、如果一条消息掉在树林里&#xff0c;会发出声音吗&#xff1f;四、将消息路由到死信队列五、记录消息失败原因&#xff1a;消息头六、记录消息失败原因…

什么是数据仓库ODS层?为什么需要ODS层?

在大数据时代&#xff0c;数据仓库的重要性不言而喻。它不仅是企业数据存储与管理的核心&#xff0c;更是数据分析与决策支持的重要基础。而在数据仓库的各个层次中&#xff0c;ODS层&#xff08;Operational Data Store&#xff0c;操作型数据存储&#xff09;作为关键一环&am…

【6大设计原则】代码的艺术:深入探索单一职责原则

1. 引言&#xff1a;理解软件设计的艺术 软件设计&#xff0c;如同艺术创作&#xff0c;需要遵循一定的原则和规则。设计模式六大原则&#xff0c;是软件设计中不可或缺的指导方针。它们为软件开发者提供了一种思考问题的方法&#xff0c;帮助我们编写出更加优雅、高效和可维护…

Rocky系统部署k8s1.28.2单节点集群(Containerd)+Kuboard

目录 Kubernetes介绍 Kubernetes具备的功能 Kubernetes集群角色 Master管理节点组件 Node工作节点组件 非必须的集群插件 Kubernetes集群类型 Kubernetes集群规划 集群前期环境准备 开启Bridge网桥过滤 关闭SWAP交换分区 安装Containerd软件包 K8s集群部署方式 集…

Type-C接口取电芯片-LDR6500

取电芯片&#xff0c;特别是针对Type-C接口的取电芯片&#xff0c;如LDR6328系列&#xff0c;是近年来电子设备领域的一个重要技术组件。这些芯片通过智能协议控制&#xff0c;实现高效、安全的充电过程&#xff0c;并广泛应用于智能手机、平板电脑、笔记本电脑、小家电等各类需…

骗水技巧!怎么让猫咪多喝水?热门补水猫罐头推荐

我家一开始喂的是猫粮&#xff0c;买的还是进口牌子。然后发现团团有很多眼屎&#xff0c;泪痕也很重&#xff0c;我一度怀疑是这个牌子的猫粮不太好&#xff0c;后来就换成了国产的&#xff0c;价格确实少了一半&#xff0c;但是问题还是没有改善&#xff0c;而且吃完以后&…

HarmonyOS应用二之代办事项案例

目录&#xff1a; 1、代码分析2、ArkTS的基本组成3、重点扩展 1、代码分析 1.1代码&#xff1a; 在鸿蒙&#xff08;‌HarmonyOS&#xff09;‌的ArkTS框架中&#xff0c;‌aboutToAppear() 是一个自定义组件的生命周期函数&#xff0c;‌它在组件即将显示时被系统自动调用1。…

多条折线图修改图例以及自定义tooltip

在图例后面添加所有数据之和修改之后 series 中的name之后导致tooltip也加上了重新自定义tooltip&#xff0c;去掉总量统计 核心代码 监听数据改变计算总量修改name字段自定义 tooltip // 计算每条线的总和 const sum1 this.VALUE1.reduce((acc, val) > acc val, 0); co…

应急响应:Linux 入侵排查思路.

什么是应急响应. 一个组织为了 应对 各种网络安全 意外事件 的发生 所做的准备 以及在 事件发生后 所采取的措施 。说白了就是别人攻击你了&#xff0c;你怎么把这个攻击还原&#xff0c;看看别人是怎么攻击的&#xff0c;然后你如何去处理&#xff0c;这就是应急响应。 目录&…

Python OpenCV 影像处理:边缘检测

►前言 上篇介绍使用OpenCV Python findContours() 函数用于在二值化影像中寻找连通的白色区域&#xff0c;并返回一系列点的集合来表示找到的轮廓。本篇将介绍基于计算影像的梯度&#xff0c;通过在影像中找到梯度值的变化来识别边缘&#xff0c;边缘检测通常用于预处理步骤&…

【区块链+食品安全】湖南省食品行业联合会:溯链中国—基于区块链的食品安全可信追溯平台 | FISCO BCOS应用案例

食品安全追溯体系的建设&#xff0c;能够切实加强食品安全监管&#xff0c;确保人民群众饮食安全和身体健康&#xff0c;是创建食品安全城市必不可少的一部分。然而&#xff0c;中心化存储、信息孤岛、窜货是传统溯源行业最大痛点。区块链技术的快速发展&#xff0c; 使得防伪溯…

文案二创app下载,为你轻松生成原创文案

在当今数字化的时代&#xff0c;各种应用软件如雨后春笋般涌现&#xff0c;为我们的生活和工作带来了极大的便利。而其中&#xff0c;有一款特别的短剧文案二创app&#xff0c;它以其独特的功能和优势&#xff0c;为文案创作者们打开了一扇全新的大门&#xff0c;让生成原创文案…

电子电气架构 --- 智能驾驶域控制器供应商简介

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…