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

数据库动态视图和存储过程报表数据管理功能设计

需求:需要将ERP的报表数据挪到OA中,但是OA表单设计不支持存储过程动态传参,所以需要设计一个系统,可以手动配置,动态显示原本ERP的报表数据,ERP报表是存在数据库的视图和存储过程中

思路:因为ERP数据库只有一个,所以不需要考虑多数据源问题(当然这个也很好解决),动态sql拼接,存储过程原本想用临时表的方式解决结果集字段查询和分页问题,但是后来觉得太麻烦了,选择程序中解决,毕竟数据量最多的也就一两万条,使用list的截取实现分页

后端:spring
前端:element

效果截图:
管理界面:
在这里插入图片描述
新增界面:
在这里插入图片描述
修改界面:
视图没有必要参数,因为视图可以通过where查询,默认都是结果集筛选参数
在这里插入图片描述
展示页面效果(用于外挂在OA系统里):
(展示页面只有一个文件,动态展示数据,根据管理页面中注释字段区分)
在这里插入图片描述
所有筛选参数和展示字段也都是动态显示
在这里插入图片描述

针对不同字段的动态处理:
日期:
在这里插入图片描述
客户和供应商,采购员,员工,销售员都是对应数据的下拉带搜索:
在这里插入图片描述
在这里插入图片描述
后台配置筛选参数的时候,字段名叫日期会去调用日期选择,字段叫客户会调用所有客户信息选择,字段名叫供应商会去调用所有供应商信息,字段名带员的(人员,员工,采购员,销售员)会去调用员工信息选择(这些都是前端设置的,不想后端在加一个类型字段来区分了,直接用名字区分)

数据库表结构:
主表:
在这里插入图片描述
从表(用于筛选字段):
在这里插入图片描述
部分代码:
页面获取参数信息(根据展示页面url的参数):

@RequestMapping("/getcanshu")public R getcanshu(@RequestParam("name") String zhushi){QueryWrapper<XinxiShituzhuEntity> query = new QueryWrapper();query.eq("zhushi", zhushi);XinxiShituzhuEntity zhudata = xinxiShituzhuService.getOne(query);Integer zhuid = zhudata.getId();QueryWrapper<XinxiShitucongEntity> congquery = new QueryWrapper();congquery.eq("fatherid", zhuid);List<XinxiShitucongEntity> congdata = xinxiShitucongService.list(congquery);zhudata.setCanshu(congdata);return R.ok().put("data", zhudata);}

获取展示页面查询数据:

@RequestMapping("/getalldatas")public R getalldatas(@RequestBody XinxiShituzhuEntity xinxiShituzhu){// 视图if(xinxiShituzhu.getBtype()==1){// 拼接sqlString querySql = "SELECT * FROM "+xinxiShituzhu.getName() +" WHERE 1=1 ";String countsql = "SELECT COUNT(1) FROM "+xinxiShituzhu.getName() +" WHERE 1=1 ";List<XinxiShitucongEntity> congdatas = xinxiShituzhu.getCanshu();for(XinxiShitucongEntity data: congdatas){if(!Objects.equals(data.getZdzhi(), "")&& data.getZdzhi()!=null){querySql = querySql + " AND ["+data.getName()+"]= '"+data.getZdzhi()+"'";countsql = countsql + " AND ["+data.getName()+"]= '"+data.getZdzhi()+"'";}}// 添加分页querySql = querySql + " order by ["+ xinxiShituzhu.getPaixuzd() +"] offset "+(xinxiShituzhu.getPageNum()-1)*xinxiShituzhu.getPageSize()+" row fetch next "+xinxiShituzhu.getPageSize()+" row only;";List<Map<String, Object>> zhudatas = xinxiShituzhuService.getAllShituDatas(querySql);// 总数Integer zhucount = xinxiShituzhuService.getAllShituCount(countsql);// 获取所有表头,用于展示页表头信息List<Map<String, Object>> newdatas = new ArrayList<>();for(Map<String, Object> data : zhudatas){for(String key: data.keySet()){Map<String, Object> newmapdata = new LinkedHashMap<>();newmapdata.put("key", key);newdatas.add(newmapdata);}
//                Collections.reverse(newdatas);break;}return R.ok().put("count", zhucount).put("data", zhudatas).put("headdata", newdatas);}// 存储过程else{// 拼接sqlString querySql = "EXEC ["+xinxiShituzhu.getName()+"]";List<XinxiShitucongEntity> congdatas = xinxiShituzhu.getCanshu();// 遍历所有参数for(XinxiShitucongEntity data: congdatas){// 视图必要参数添加if(Objects.equals(data.getZdtype(), "1")){if(!Objects.equals(data.getZdzhi(), "")&& data.getZdzhi()!=null){querySql = querySql + " @"+data.getName()+"= '"+data.getZdzhi()+"'";}else{return R.error("必要参数不能为空");}}}// 获取所有数据List<Map<String, Object>> zhudatas = xinxiShituzhuService.getAllShituDatas(querySql);List<Map<String, Object>> newdatas = new ArrayList<>();// 遍历结果集,用于结果集的字段筛选for(Map<String, Object> dataxx: zhudatas){// 用于标记筛选字段有效性List<Boolean> biaojis = new ArrayList<>();for(XinxiShitucongEntity data: congdatas){if(Objects.equals(data.getZdtype(), "2")){if(!Objects.equals(data.getZdzhi(), "")&& data.getZdzhi()!=null){if(ObjectUtil.isNotNull(dataxx.get(data.getName())) && dataxx.get(data.getName()).equals(data.getZdzhi())){// 如果被其中一个条件筛选出来就给整条数据标记truebiaojis.add(true);}else{// 如果被其中一个条件没有筛选出来就给整条数据标记falsebiaojis.add(false);}}else{// 筛选条件没有填的是都要筛选的biaojis.add(true);}}}// 只有没有false标记的数据才是被筛选出来的if(!biaojis.contains(false)){newdatas.add(dataxx);}}// 总数Integer zhucount = newdatas.size();int pagenum = (xinxiShituzhu.getPageNum()-1)*xinxiShituzhu.getPageSize();int pagesize = pagenum + xinxiShituzhu.getPageSize();// list截取List<Map<String, Object>> newzhudatas = CollectionUtil.sub(newdatas, pagenum, pagesize);List<Map<String, Object>> newheaddatas = new ArrayList<>();// 获取表头信息for(Map<String, Object> data : newzhudatas){for(String key: data.keySet()){Map<String, Object> newmapdata = new LinkedHashMap<>();newmapdata.put("key", key);newheaddatas.add(newmapdata);}break;}return R.ok().put("count", zhucount).put("data", newzhudatas).put("headdata", newheaddatas);}}

sql拼接xml(要用LinkedHashMap类型,不然字段顺序不固定,数据展示就很难看):

 <select id="getAllShituDatas" resultType="java.util.LinkedHashMap">${shitusql}</select><select id="getAllShituCount" resultType="java.lang.Integer">${shitusql}</select>

主Entity:
在这里插入图片描述
从Entity:
在这里插入图片描述

展示页面的vue代码:

<template><div class="sanfangcangkuliang-main"><el-form :model="form" :inline="true" ><el-form-item :label="item.zdname" v-for="item of canshulist" :key="item.name" ><el-input v-model="item.zdzhi" v-if="item.zdname!='供应商' && item.zdname!='客户' && item.zdname.indexOf('员')==-1 && item.zdname!='日期'" :placeholder="item.zdtype==1?'必填':'选填'"></el-input><!-- <el-input v-model="item.zdzhi" v-if="item.zdtype==2" placeholder="选填"></el-input> --><el-select v-model="item.zdzhi" filterable clearable :placeholder="item.zdtype==1?'必填':'选填'" v-if="item.zdname=='供应商'"><el-optionv-for="item in gongyingshanglist":key="item.gys":label="item.gys":value="item.gys"></el-option></el-select><el-select v-model="item.zdzhi" filterable clearable :placeholder="item.zdtype==1?'必填':'选填'" v-if="item.zdname=='客户'"><el-optionv-for="item in kehulist":key="item.kh":label="item.kh":value="item.kh"></el-option></el-select><el-select v-model="item.zdzhi" filterable clearable :placeholder="item.zdtype==1?'必填':'选填'" v-if="item.zdname.indexOf('员')!=-1"><el-optionv-for="item in renyuanlist":key="item.yg":label="item.yg":value="item.yg"></el-option></el-select><el-date-pickerv-model="item.zdzhi"type="date"value-format="yyyy-MM-dd":placeholder="item.zdtype==1?'必填':'选填'"v-if="item.zdname=='日期'"></el-date-picker></el-form-item><el-form-item><el-button type="primary" style="display:inline-block; width: 80px;height: 40px;" @click="getList(1)">搜索</el-button><el-button style="display:inline-block; width: 80px;height: 40px;" @click="chongzhi()">重置</el-button><!-- <el-button type="success" style="display:inline-block; width: 100px;height: 40px;" @click="gengxin()">批量更新</el-button> --></el-form-item></el-form><el-paginationstyle="margin:30px"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="mapdatas.pageNum":page-sizes="[50, 100, 200, 500, 1000, 2000, 5000]":page-size="mapdatas.pageSize"layout="total, sizes, prev, pager, next, jumper":total=total></el-pagination><el-table style="width: 100%; margin-left:40px" :data="tableData"><template v-for="(item,index) in maphead"><el-table-column :prop="item.key" :label="item.key" :key="index"></el-table-column></template></el-table><el-paginationstyle="margin:30px"@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="mapdatas.pageNum":page-sizes="[50, 100, 200, 500, 1000, 2000, 5000]":page-size="mapdatas.pageSize"layout="total, sizes, prev, pager, next, jumper":total=total></el-pagination></div>
</template>
<script>export default {data () {return {renyuanlist:[],gongyingshanglist:[],kehulist:[],form:{},maphead:[],mapdatas:{pageNum:1,pageSize:100,},canshulist:[],pageSize:100,currentPage:1,total:0,tableData: [],xiangqingshow:false,xiangqingdatas:[],tableDatazong:[],ckmclist: [],ywymc:""}},mounted(){this.getTableCanshu();this.getRenyuanDatas();this.getGyingshangDatas();this.getKehuDatas();},methods: {handleSizeChange(val) {this.mapdatas.pageSize = valthis.getList(2);},handleCurrentChange(val) {this.mapdatas.pageNum = valthis.getList(2);},getList(type){if(type==1){this.mapdatas.pageNum = 1this.mapdatas.pageSize = 100;}this.mapdatas['canshu'] = this.canshulistthis.$axios({method:'post',url:"/renren-fast/xinxi/xinxishituzhu/getalldatas",data:JSON.stringify(this.mapdatas),headers:{"Content-Type": "application/json"}}).then((response) =>{          //这里使用了ES6的语法if(response.data.code==0 || response.data.code=='0'){this.tableData = response.data.data;this.total = response.data.count;this.maphead = response.data.headdata;}else{this.$message.error(response.data.msg);this.total = 0this.mapdatas.pageNum = 1this.mapdatas.pageSize = 100;}}).catch((error) =>{console.log(error)       //请求失败返回的数据})},chongzhi(){for(let data of this.canshulist){data.zdzhi=""}this.mapdatas.pageNum = 1this.mapdatas.pageSize = 100;this.tableData = []this.getList(1)},// 获取表的参数getTableCanshu(){this.$axios({url: '/xinxi/xinxishituzhu/getcanshu',method: 'GET',params: {name: this.$route.query.name}}).then((res) => {if(res.data.code==0 || res.data.code=='0'){this.mapdatas = {btype: res.data.data.btype,deleted: res.data.data.deleted,id: res.data.data.id,name: res.data.data.name,pageNum: res.data.data.pageNum || 1,pageSize: res.data.data.pageSize || 100,paixuzd: res.data.data.paixuzd,reationtime: res.data.data.reationtime,updatetime: res.data.data.updatetime,zhushi: res.data.data.zhushi}this.canshulist = res.data.data.canshuif(res.data.data.btype==1){this.getList(1);}}})},// 获取人员getRenyuanDatas(){this.$axios({url: '/xinxi/xinxishituzhu/getyuangongdatas',method: 'GET',// params: {//     name: this.$route.query.name// }}).then((res) => {if(res.data.code==0 || res.data.code=='0'){this.renyuanlist = res.data.data;}})},// 获取供应商getGyingshangDatas(){this.$axios({url: '/xinxi/xinxishituzhu/getgongyingshangdatas',method: 'GET',// params: {//     name: this.$route.query.name// }}).then((res) => {if(res.data.code==0 || res.data.code=='0'){this.gongyingshanglist = res.data.data;}})},// 获取客户getKehuDatas(){this.$axios({url: '/xinxi/xinxishituzhu/getkehudatas',method: 'GET',// params: {//     name: this.$route.query.name// }}).then((res) => {if(res.data.code==0 || res.data.code=='0'){this.kehulist = res.data.data;}})},}
}
</script>
<style scoped>
*{margin: 0;padding: 0;
}
</style>

因为ERP有几十个报表要迁移,之前领导都是上级领导想看报表但是他们不使用ERP只使用OA,就会我们做进OA报表,只有OA实现不了的我才自己写后台接口和前端页面,这次说要全部迁移,我看一下几十个报表,如果像原来那样一个个写后台接口和前端页面的话不知道要写到什么时候,于是花了两天写了这个功能出来,目前正常使用没问题(因为存储过程必须要填参数才可以出数据,所以存储过程的展示页面需要输入必填参数以后点查询出数据,视图则是可以直接出数据)

相关文章:

数据库动态视图和存储过程报表数据管理功能设计

需求&#xff1a;需要将ERP的报表数据挪到OA中&#xff0c;但是OA表单设计不支持存储过程动态传参&#xff0c;所以需要设计一个系统&#xff0c;可以手动配置&#xff0c;动态显示原本ERP的报表数据&#xff0c;ERP报表是存在数据库的视图和存储过程中 思路&#xff1a;因为E…...

css+js 选项卡动画效果

选项卡上下左右翻转动画效果 <template><div class"web-box"><div class"topTitle"><div class"topTitle1">标题标题</div></div><div class"info-wrap"><div style"width: 100%;h…...

[C错题本]转义字符/指针与首元素/运算

\a响铃 \b退格 \f换页 \r回车 \t水平制表 \v垂直制表 \单引号 \"双引号 \\反斜杠 \0dd八进制&#xff08;0-7&#xff09; \xdd(0-f)注意x一定不能大写 而且十六进制千万不能写\0xint main() {char s[]"ABCD", *p;for (p s 1; p < s 4; p)printf("%s…...

Layui继续学习

1、简单评论区代码&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>社区评论区</title> <link rel"stylesheet" href"https://cdn.staticfile.org/layui/2.6.8/css/…...

react+datav+echarts实现可视化数据大屏

&#x1f4d3;最近有点闲&#xff0c;就学习了下react&#xff0c;没想到就把react学完了&#xff0c;觉得还不错&#xff0c;就打算出一把reactdatav的简易版可视化数据大屏供大家做个参考。 &#x1f4d3;效果如下 1下载必要的框架 &#x1f4d3; react路由 npm install re…...

CSS新手入门笔记整理:CSS浮动布局

文档流概述 正常文档流 “文档流”指元素在页面中出现的先后顺序。正常文档流&#xff0c;又称为“普通文档流”或“普通流”&#xff0c;也就是W3C标准所说的“normal flow”。正常文档流&#xff0c;将一个页面从上到下分为一行一行&#xff0c;其中块元素独占一行&#xf…...

微服务组件Sentinel的学习(1)

Sentinel学习笔记&#xff08;1&#xff09; Sentinel基本概念Sentinel功能和设计理念流量控制熔断降级系统负载保护 Sentinel基本概念 资源 资源是Sentinel的关键概念。它可以是 ava应用程序中的任何内容&#xff0c;例如&#xff0c;由应用程序提供的服务&#xff0c;或由应…...

小程序 -网络请求post/get

1.1网络请求的概念(post和get) 1.2步骤 1.3 应用函数 js里面写&#xff0c;用bindtap绑在控件上&#xff0c;就不讲了 实例代码&#xff1a; //发起get数据请求get_info(){wx.request({url:https://www.escook.cn/api/get,//请求的接口地址,必须基于https协议//请求的方式met…...

Elasticsearch 8.10之前同义词最佳实践

1、同义词在搜索引擎领域用途 同义词在搜索引擎领域的用途可概括如下: 增强搜索的准确性——当用户输入一个关键词时,可能与他们实际意图相关的文档使用了一个不同的关键词或短语。同义词允许搜索引擎理解和识别这些情况,返回更准确的结果。如:“遥遥领先”和“华为Meta60…...

芯知识 | 什么是OTP语音芯片?唯创知音WTN6xxx系列:低成本智能语音解决方案

什么是OTP语音芯片&#xff1f; OTP&#xff0c;即一次性可编程&#xff08;One-Time Programmable&#xff09;&#xff0c;语音芯片是一类具有独特编程特性的嵌入式语音存储解决方案。与可重复擦写&#xff08;Flash型&#xff09;语音芯片不同&#xff0c;OTP语音芯片一经烧…...

Linux内核密钥环

Linux内核密钥环&#xff08;Linux Kernel Keyring&#xff09;是Linux内核中的一个机制&#xff0c;用于管理和存储各种类型的密钥和安全相关的数据。它是Linux内核提供的一种可编程的安全子系统&#xff0c;用于处理密钥的生成、存储、检索和删除等操作。 Linux内核密钥环的…...

web前端之正弦波浪动功能、repeat、calc

MENU 效果图htmlstylecalcrepeat 效果图 html <div class"grid"><span class"line"></span><span class"line"></span><span class"line"></span><span class"line"><…...

使用工具 NVM来管理不同版本的 Node.js启动vue项目

使用工具如 NVM&#xff08;Node Version Manager&#xff09;来管理不同版本的 Node.js。NVM 允许你在同一台计算机上安装和切换不同版本的 Node.js。以下是一些步骤&#xff0c;以便同时在你的系统中安装两个 Node.js 版本&#xff1a; 安装 NVM: 首先&#xff0c;你需要安装…...

Xcode编写基于C++的动态连接库(dylib)且用node-ffi-napi测试

创建一个dylib工程示例 在 Xcode 中创建一个动态链接库&#xff08;.dylib 文件&#xff09;的步骤如下&#xff1a; 打开 Xcode&#xff1a; 打开 Xcode 应用程序。 创建新的工程&#xff1a; 选择 "Create a new Xcode project"&#xff0c;或者使用菜单 File &g…...

WPF-UI HandyControl 简单介绍

文章目录 前言我的网易云专栏和Gitee仓库HandyControlHandyControl示例相关资源地址 我的运行环境快速开始和Material Design功能对比手风琴右键菜单自动补充滚动条轮播图消息通知步骤条托盘按钮 结尾 前言 最近我在研究如何使用WPF做一个比较完整的项目&#xff0c;然后我就先…...

golang学习笔记——数据结构进阶

文章目录 数据结构进阶mapmap示例sliceinterfaceembedded 数据结构进阶 常见数据结构实现原理 本章主要介绍常见的数据结构&#xff0c;比如channel、slice、map等&#xff0c;通过对其底层实现原理的分析&#xff0c;来加深认识&#xff0c;以此避免一些使用过程中的误区。 …...

TrustZone之总线请求

接下来&#xff0c;我们将查看系统中的总线请求者&#xff0c;如下图所示&#xff1a; 系统中的A型处理器具有TrustZone感知&#xff0c;并在每个总线访问中发送正确的安全状态。然而&#xff0c;大多数现代SoC还包含非处理器总线请求者&#xff0c;例如GPU和DMA控制器。 与完成…...

vue2+Echarts数据可视化 【帕累托图】

接口得到的数据如下 要经过排序 &#xff0c;计算累计百分比得到数据 蓝色 柱状图数据&#xff1a; 取count字段值 横坐标&#xff1a;取 id值 折线图&#xff1a;根据柱状图的数据计算累计百分比 getInterface(data) {getParetoChart(data).then((res) > {if (res) {thi…...

imazing 2.17.16中文版怎么备份iPhone手机照片

imazing 2.17.16中文版备份功能非常强大&#xff0c;在进行备份之前&#xff0c;需要对其进行设置&#xff0c;才能充分使用备份功能。当移动设备与电脑第一次连接成功后&#xff0c;会询问是否要立即备份&#xff0c;个人的建议是选择“稍后”&#xff0c;小伙伴可以先对软件进…...

05 python数据容器

5.1 数据容器认识 5.2 python列表 5.2.1 列表的定义 演示数据容器之&#xff1a;list 语法&#xff1a;[元素&#xff0c;元素&#xff0c;....] #定义一个列表List List [itheima,uityu,gsdfg] List1 [itheima,6666,True] print(List) print(List1) print(type(List)) pr…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...