【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇

概述:

本篇是接着上一篇,细分出说明书的编写部分,实现这个功能的需求,是内部很多同事反馈,需要有个地方存工具,并且可以写说明书,如果需要的人,那么可以在界面上直接下载工具和查看工具的说明,这样就不用每次都找人发文档,各种本地找,很浪费时间,故此需要实现这样的一个功能

新建说明书表

CREATE TABLE IF NOT EXISTS `manual` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`tool_id` int(11) NOT NULL COMMENT '关联的工具ID',`version` varchar(20) NOT NULL DEFAULT '1.0' COMMENT '版本号',`title` varchar(255) NOT NULL COMMENT '说明书标题',`content` text COMMENT '富文本内容',`file_path` varchar(255) DEFAULT NULL COMMENT '附件存储路径',`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `idx_tool_version` (`tool_id`, `version`) COMMENT '工具ID和版本号的唯一索引',KEY `idx_tool_id` (`tool_id`) COMMENT '工具ID索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='工具说明书表';
验证数据表
-- 给 manual 表添加缺失的 version 和 file_path 字段
ALTER TABLE manual
ADD COLUMN version VARCHAR(20) NOT NULL DEFAULT '1.0' COMMENT '版本号',
ADD COLUMN file_path VARCHAR(255) NULL COMMENT '文件路径';-- 验证字段是否添加成功
DESCRIBE manual;  -- 应显示所有字段:id, tool_id, title, content, version, file_path, created_at

建立数据表模型

# app/models.py(Manual 模型定义)
from datetime import datetime
from extensions import dbclass Manual(db.Model):__tablename__ = 'manual'  # 表名必须与数据库一致id = db.Column(db.Integer, primary_key=True)tool_id = db.Column(db.Integer, nullable=False, comment='工具ID')title = db.Column(db.String(255), nullable=False, comment='标题')  # 确保表中有 title 字段content = db.Column(db.Text, comment='富文本内容')version = db.Column(db.String(20), default='1.0', comment='版本号')  # 新增字段file_path = db.Column(db.String(255), nullable=True, comment='文件路径')  # 新增字段created_at = db.Column(db.DateTime, default=datetime.now, comment='创建时间')# 确保没有其他多余字段(如 updated_at 若表中不存在需删除)__table_args__ = (db.Index('idx_tool_id', 'tool_id'),  # 添加索引)

新增保存说明书的接口和获取说明书的接口

保存说明书的接口开发

@tool_bp.post('/manual/save')
def save_manual():try:data = request.get_json()if not data:return jsonify({"code": 40000,"message": "请求数据不能为空","data": None,"total": 0})# 强制校验字段required = ['tool_id', 'title', 'content']if not all(k in data for k in required):return jsonify({"code": 40000,"message": f"缺少必填字段: {', '.join(required)}","data": None,"total": 0})# 类型检查try:tool_id = int(data['tool_id'])except ValueError:return jsonify({"code": 40000,"message": "tool_id必须为整数","data": None,"total": 0})# 数据库操作manual = Manual.query.filter_by(tool_id=tool_id).first()if manual:manual.title = data['title']manual.content = data['content']else:manual = Manual(tool_id=tool_id,title=data['title'],content=data['content'])db.session.add(manual)db.session.commit()return jsonify({"code": 20000,"message": "保存成功","data": {"id": manual.id},"total": 1})except Exception as e:db.session.rollback()current_app.logger.error(f"保存失败: {str(e)}")  # 记录详细错误return jsonify({"code": 40000,"message": f"保存失败: {str(e)}",  # 返回具体错误信息"data": None,"total": 0})

验证接口是不是可以保存数据成功,接口成功,至于前端界面的集成编辑器功能,我们在前面的文章中有提到,如何在vue2.x中集成编辑器,可以往上看上一篇文章;

另外这里的说明书我在此基础上增加了一个PDF导出的功能,说明书如果想发送给别人,那么这里可以直接导出,这样就可以在本地看到一个文件,也可以发送给其他人员

目前我们说明书部分可以保存了,接下来需要实现一个接口,从数据库中读取我们的数据展示,这样每次点击查看说明书时,默认展示存储的说明书数据

开发接口

@tool_bp.route('/info/<int:tool_id>', methods=['GET']) 
def get_tool_info(tool_id):"""获取工具基本信息(原接口,包含 toolId、toolName 等)"""tool = Tool.query.get(tool_id)  return jsonify({"code": 20000,"data": {"toolId": tool.id,"toolName": tool.name,"manuals": []  }})

获取指定工具说明书,点击后自动获取工具关联的说明书数据

@tool_bp.route('/manual/<int:tool_id>', methods=['GET'])  # 说明书回显接口(专属)
def get_manual(tool_id):"""获取指定工具的说明书(仅返回 title 和 content)"""manual = Manual.query.filter_by(tool_id=tool_id).first()return jsonify({"code": 20000,"data": {"title": manual.title if manual else "","content": manual.content if manual else ""}})

验证下效果,点击查看说明书后跳转如下

至此,说明书关联部分开发完成,完整前端代码如下

<template><div class="manual-edit-container"><el-card><!-- 标题区域 --><div slot="header" class="card-header"><el-breadcrumb separator="/"><el-breadcrumb-item>工具管理</el-breadcrumb-item><el-breadcrumb-item>编辑说明书</el-breadcrumb-item></el-breadcrumb></div><!-- 表单内容 --><el-form ref="form" :model="form" label-width="120px"><!-- 说明书标题 --><el-form-item label="说明书标题" required><el-inputv-model="form.title"placeholder="请输入标题"maxlength="200"show-word-limitstyle="width: 600px"/></el-form-item><!-- 富文本编辑器 --><el-form-item label="说明书内容" required><TinymceEditorv-model="form.content":height="500":disabled="loading"/></el-form-item><!-- 操作按钮 --><el-form-item><el-buttontype="primary"@click="handleSave":loading="loading"><i class="el-icon-check"></i> 保存</el-button><el-buttontype="success"@click="handleExportPDF":disabled="!form.content.trim()"><i class="el-icon-download"></i> 导出PDF</el-button><el-button @click="handleCancel">取消</el-button></el-form-item></el-form></el-card></div>
</template><script>
import TinymceEditor from '@/components/TinymceEditor.vue' // 富文本编辑器组件
import axios from 'axios' // HTTP请求库
import html2pdf from 'html2pdf.js' // PDF导出库export default {name: 'ManualEdit',components: { TinymceEditor },data() {return {form: {tool_id: this.$route.params.id, // 从路由获取工具ID(例如31)title: '', // 存储数据库中的标题content: '' // 存储数据库中的富文本内容},loading: false // 保存按钮加载状态}},created() {// 页面加载时立即从数据库获取数据this.loadManualFromDatabase()},methods: {/*** 从数据库加载说明书数据(核心方法)*/async loadManualFromDatabase() {// 1. 显示加载提示this.$message.info('正在加载说明书数据...')try {// 2. 调用后端回显接口(已验证返回正确数据)const response = await axios.get(`http://172.16.60.60:5000/api/tool/manual/${this.form.tool_id}`)// 3. 验证接口响应格式if (response.data.code === 20000) {const manualData = response.data.data || {}// 4. 赋值到表单(覆盖默认空值)this.form.title = manualData.title || '未命名说明书'this.form.content = manualData.content || '<p>请输入说明书内容...</p>'this.$message.success('加载成功!')} else {this.$message.warning('未找到说明书数据')}} catch (error) {// 5. 捕获网络错误this.$message.error(`加载失败: ${error.message || '网络异常'}`)}},/*** 保存数据到数据库*/async handleSave() {// 1. 基础校验if (!this.form.title.trim()) {this.$message.warning('请输入说明书标题')return}if (!this.form.content.trim()) {this.$message.warning('请输入说明书内容')return}this.loading = truetry {// 2. 调用保存接口(确保后端保存接口路径正确)const response = await axios.post('http://172.16.60.60:5000/api/tool/manual/save', this.form)// 3. 处理响应if (response.data.code === 20000) {this.$message.success('保存成功!')} else {this.$message.error(`保存失败: ${response.data.message || '未知错误'}`)}} catch (error) {this.$message.error(`请求失败: ${error.message}`)} finally {this.loading = false}},/*** 导出PDF(保留功能)*/handleExportPDF() {const opt = {margin: 15,filename: `${this.form.title || '说明书'}.pdf`,image: { type: 'jpeg', quality: 0.98 },html2canvas: { scale: 2, useCORS: true },jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }}// 导出当前编辑器内容html2pdf().from(document.querySelector('.tox-edit-area__iframe').contentDocument.body).set(opt).save()},/*** 取消编辑返回上一页*/handleCancel() {this.$router.go(-1)}}
}
</script><style scoped>
.card-header {background-color: #f5f7fa;padding: 10px 20px;
}
.manual-edit-container {padding: 20px;
}
</style>

 

 

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

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

相关文章

Mac设置中的安全性缺少“任何来源”

问题&#xff1a;用Mac安装软件&#xff0c;隐私性与安全性&#xff0c;想切换“任何来源”用来下载网站的app&#xff0c;但是菜单栏找不到“任何来源”选项&#xff0c;无法安装dmg的文件终端中一行代码设置出来&#xff1a;sudo spctl --global-disable &#xff08;禁用Mac…

uniapp开发小程序,列表 点击后加载更多数据

一、需求 1.初始显示限制:将每页条数limit改为5,确保初始只显示5条数据 2.查看更多功能:添加了loadMore方法,点击"查看更多"时加载下一页数据 3.实现查看更多功能,点击后加载更多数据 4.添加loading状态防止重复请求 添加hasMore状态判断是否还有更多数据 …

Windows 部署 Gerrit 与 Apache24 配置

Windows 部署 Gerrit 与 Apache24 并配置反向代理 准备工作 下载并安装 Java JDK 确保配置 JAVA_HOME 环境变量博主这里安装openjdk21 https://jdk.java.net/archive/下载所需软件 Apache24&#xff1a;https://httpd.apache.org/download.cgi Gerrit&#xff1a;https://www.g…

从 Excel 趋势线到机器学习:拆解 AI 背后的核心框架​

引言&#xff1a;你其实早就 “玩转” 过机器学习&#xff1f;提到 “机器学习”&#xff0c;你是不是第一时间联想到复杂的代码、密密麻麻的公式&#xff0c;还有那些让人头晕的 “算法”“模型”“训练” 术语&#xff1f;仿佛它是高高在上的技术&#xff0c;离我们的日常无比…

Lenovo联想YOGA Pro 16 IAH10 2025款笔记本电脑(83L0)开箱状态预装OEM原厂Win11系统

适用机型(MTM)&#xff1a;【83L0】 链接&#xff1a;https://pan.baidu.com/s/1tDpeBb93t1u0XIgqAZ3edg?pwdqy2r 提取码&#xff1a;qy2r 联想原装系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想浏览器、电脑管家、…

Android 开发 - 一些画板第三方库(DrawBoard、FingerPaintView、PaletteLib)

一、DrawBoard 1、Dependencies 模块级 build.gradle implementation com.github.jenly1314:drawboard:1.1.02、Test &#xff08;1&#xff09;Activity Layout activity_draw_board.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout …

捷多邦揭秘超厚铜板:从制造工艺到设计关键环节​

一、超厚铜板制造工艺要点超厚铜板&#xff08;3oz 及以上&#xff09;的制造工艺对精度和稳定性要求严苛&#xff0c;核心环节需突破多重技术壁垒。蚀刻工艺中&#xff0c;因铜箔厚度达 105μm 以上&#xff0c;需采用高浓度酸性蚀刻液&#xff08;氯化铜浓度控制在 180-220g/…

【MYSQL | 高级篇 MyCat实现分库分表】

摘要&#xff1a;本文围绕分库分表展开&#xff0c;先分析单库性能瓶颈&#xff0c;介绍垂直与水平拆分策略及实现技术&#xff0c;再详述 MyCat 中间件的概述、环境准备、目录结构&#xff0c;讲解其入门配置与测试&#xff0c;深入说明核心配置文件&#xff0c;最后演示垂直和…

Docker部署Drawnix开源白板工具

Drawnix简介 Drawnix 是一款开源的在线白板工具&#xff08;SaaS&#xff09;&#xff0c;集思维导图、流程图绘制、自由画图等多种功能于一体&#xff0c;支持协作与插件扩展&#xff0c;适用于个人创作、团队协作和远程办公场景。它完全免费且开源&#xff0c;提供丰富的编辑…

Griffin|增强现实数据集|无人机数据集

Griffin|增强现实数据集|无人机数据集 数据来源&#xff1a;huggingface 百度网盘 构建方式 Griffin数据集的构建采用了模块化架构&#xff0c;结合了CARLA和AirSim平台&#xff0c;通过模拟真实世界中的无人驾驶环境和无人机动态&#xff0c;收集了超过30,000帧图像数据&am…

力扣.1054距离相等的条形码力扣767.重构字符串力扣47.全排列II力扣980.不同路径III力扣509.斐波那契数列(记忆化搜索)

目录 力扣.1054距离相等的条形码 力扣767.重构字符串 力扣47.全排列II 力扣980.不同路径III 力扣509.斐波那契数列&#xff08;记忆化搜索) 力扣.1054距离相等的条形码 是否策略正确 但是假如 1 2 2 此时 1_2 此时中间只能填写2&#xff0c;但是就不对了&#xff0c;所…

「docker」二、3分钟快速理解docker核心要素

上一节中我们知道docker的作用&#xff0c;这节我们介绍一下docker的要素。 镜像 docker的核心要素里面有个叫镜像&#xff08;images&#xff09;的概念&#xff0c;镜像的作用就类似我们安装虚拟机用到的iso镜像文件。镜像里包含了我们要运行的应用&#xff0c;如&#xff…

搭建基于 Solon AI 的 Streamable MCP 服务并部署至阿里云百炼

一、快速搭建 Solon 项目&#xff0c;引入 Solon AI 1. 开发环境准备 JDK 8 或以上版本。Maven 3.8.6 或以上版本。通义千问 API Key&#xff08;用于模型调用&#xff09;。 2. 创建名为 mcp-server-demo 的项目 创建时选择 Archetype 为 Solon AI&#xff08;可以减少些活&am…

免费的SSL和付费SSL 证书差异

免费的 SSL 和付费的 SSL&#xff08;TLS 证书&#xff09;本质上提供的加密能力是一样的&#xff0c;因为 SSL/TLS 协议本身是开放标准&#xff0c;核心加密算法不会因为是否收费而不同。主要区别在于以下几个方面&#xff1a;&#x1f511; 1. 加密强度免费 SSL&#xff1a;一…

代码随想录算法训练营第六天 -- 字符串1 || 344.反转字符串I / 541.反转字符串II / kamacoder54.替换数字--第八期模拟笔试

代码随想录算法训练营第六天 -- 字符串1 || 344.反转字符串I / 541.反转字符串II / kamacoder54.替换数字--第八期模拟笔试344.反转字符串I思路541.反转字符串II题目理解解题思路边界细节reverse()函数的实现[kamacoder54.替换数字 -- 第八期模拟笔试](https://kamacoder.com/p…

计算机视觉——光流法

系列文章目录 本系列开篇文章&#xff0c;暂时没有目录啦&#xff5e; 文章目录系列文章目录前言一、问题假设二、方程推导三、计算Ix,Iy,ItI_x,I_y,I_tIx​,Iy​,It​四、计算光流u,vu,vu,v4.1 传统算法Lucas-Kanade算法五、孔径问题5.1 直观理解5.2 数学角度5.3 解决方法总结…

前端安全攻防:XSS, CSRF 等防范与检测

前端安全攻防&#xff1a;XSS, CSRF 等防范与检测在Web应用日益普及的今天&#xff0c;前端安全已经成为一个不容忽视的重要环节。随着攻击技术的不断演进&#xff0c;各种前端安全漏洞&#xff08;如跨站脚本攻击 XSS、跨站请求伪造 CSRF 等&#xff09;层出不穷&#xff0c;它…

03OpenCV图像处理

参考课程&#xff1a; 【黑马程序员 OpenCV入门教程】 [https://www.bilibili.com/video/BV1Fo4y1d7JL] ZZHow(ZZHow1024) 1.1几何变换 图像缩放 对图像的大小进行调整&#xff0c;即使图像放大或缩小 cv2.resize(src, dsize, fx0, fy0, interpolationcv2.INTER_LINEAR)参数…

UE5 C++ 第三方动态库的使用

一. 首先要拷贝对应的 第三方库 bin里有dll动态库&#xff0c;include里有动态库需要的头文件。 二.在Target.cs里&#xff0c;进行设置 头文件前面的路径为公共路径 设置需要一起打包的三方库文件 三.加载这个库 FPlatformProcess::GetDllHandle将他解析为 任意类型&#x…

C++进阶——多态

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 个人主页&#xff1a;励志不掉头发的内向程序员&#xff1b; 专栏主页&#xff1a;C语言&#xff1b; 文章目录 前言 一、多态的概念 二、多态的定义及实现 2.1、多态的构成条件 &#xff08;1&#xff09;虚函…