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

需求:需要将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){
            // 拼接sql
            String 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{
            // 拼接sql
            String querySql = "EXEC ["+xinxiShituzhu.getName()+"]";
            List<XinxiShitucongEntity> congdatas = xinxiShituzhu.getCanshu();
            List<String> canshus = new ArrayList<>();
            // 遍历所有参数
            for(XinxiShitucongEntity data: congdatas){
                // 视图必要参数添加
                if(Objects.equals(data.getZdtype(), "1")){
                    if(!Objects.equals(data.getZdzhi(), "")&& data.getZdzhi()!=null){
                    	canshus.add(" @"+data.getName()+"= '"+data.getZdzhi()+"'");
                        // querySql = querySql + " @"+data.getName()+"= '"+data.getZdzhi()+"'";
                    }else{
                        return R.error("必要参数不能为空");
                    }
                }
            }
            if(canshus.size()>0){
                querySql = querySql + StringUtils.join(canshus, ",");
            }
            // 获取所有数据
            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())){
                                // 如果被其中一个条件筛选出来就给整条数据标记true
                                biaojis.add(true);
                            }else{
                                // 如果被其中一个条件没有筛选出来就给整条数据标记false
                                biaojis.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-option
                    v-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-option
                    v-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-option
                    v-for="item in renyuanlist"
                    :key="item.yg"
                    :label="item.yg"
                    :value="item.yg">
                  </el-option>
                </el-select>

                <el-date-picker
                  v-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-pagination
        style="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-pagination
        style="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 = val
        this.getList(2);
      },
      handleCurrentChange(val) {
        this.mapdatas.pageNum = val
        this.getList(2);
      },

      getList(type){
        if(type==1){
          this.mapdatas.pageNum = 1
          this.mapdatas.pageSize = 100;
        }

        this.mapdatas['canshu'] = this.canshulist
        
        this.$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 = 0
            this.mapdatas.pageNum = 1
            this.mapdatas.pageSize = 100;
          }
        }).catch((error) =>{
          console.log(error)       //请求失败返回的数据
          
        })
      },
      chongzhi(){
        for(let data of this.canshulist){
            data.zdzhi=""
        }

        this.mapdatas.pageNum = 1
        this.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.canshu

                    if(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实现不了的我才自己写后台接口和前端页面,这次说要全部迁移,我看一下几十个报表,如果像原来那样一个个写后台接口和前端页面的话不知道要写到什么时候,于是花了两天写了这个功能出来,目前正常使用没问题(因为存储过程必须要填参数才可以出数据,所以存储过程的展示页面需要输入必填参数以后点查询出数据,视图则是可以直接出数据)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Which local search operator best 4 SPVRPTW:or and 2-opt*

这篇文献的研究背景是对车辆路径问题&#xff08;VRP&#xff09;的局部搜索移动算子进行测试&#xff0c;其中包括分割配送和时间窗口的车辆路径问题。 VRP涉及根据各种约束条件为客户提供货物的最优路线。当配送的时间窗口和分割配送选项被引入时&#xff0c;问题变得更加复…

Kotlin 笔记 -- Kotlin 语言特性的理解(一)

函数引用、匿名函数、lambda表达式、inline函数的理解 双冒号对函数进行引用的本质是生成一个函数对象只有函数对象才拥有invoke()方法&#xff0c;而函数是没有这个方法的kotlin中函数有自己的类型&#xff0c;但是函数本身不是对象&#xff0c;因此要引用函数类型就必须通过双…

arcgis javascript api4.x加载天地图cgs2000坐标系

需求&#xff1a;arcgis javascript api4.x加载天地图cgs2000坐标系 效果&#xff1a; 示例代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"wid…

vscode使用remote ssh到server上 - Node进程吃满CPU

起因&#xff1a;Node进程吃满CPU 分析 我发现每次使用vscode的remote插件登陆到server后&#xff0c;就会出现node进程&#xff0c;不太清楚干什么用的&#xff0c;但是绝对和它有关。 查找原因 首先找到了这篇文章&#xff0c;解决了rg进程的问题&#xff1a; https://blo…

克服端口顺序影响,使用PCAN实现固定设备ID/通道分配

来源&#xff1a;虹科智能互联 虹科干货 | 克服端口顺序影响&#xff0c;使用PCAN实现固定设备ID/通道分配 原文链接&#xff1a;https://mp.weixin.qq.com/s/Ik2fp9sWyI9MiQOOHO1dCA 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 导读 多设备协同工作是常见的需求…

Mac managing Multiple Python Versions With pyenv 【 mac pyenv 管理多个python 版本 】

文章目录 1. 简介2. 安装2.1 brew 安装 pyenv2.2 脚本安装 3. pyenv 安装 Python4. 卸载 python5. 管理 python 1. 简介 Pyenv 是一个用于管理和切换多个 Python 版本的工具。它允许开发人员在同一台计算机上同时安装和使用多个不同的 Python 版本&#xff0c;而无需对系统进行…

Apache Seatunnel本地源码构建编译运行调试

Apache Seatunnel本地源码构建编译运行调试 文章目录 1. 环境准备1.1 Java环境1.2 Maven1.3 IDEA1.4 Docker环境1.5 Mysql8.0.281.6 其它环境准备 2. 源码包下载3. idea项目配置3.1 项目导入3.2 maven配置3.3 项目JDK配置3.4 项目启动参数配置3.4.1 seatunnel项目启动参数配置3…

SpringBoot+WebSocket

SpringBootWebSocket 1.导入依赖&#xff1a; -- Spring Boot 2.x 使用 javax.websocket-- Spring Boot 3.x 使用 jakarta.websocket<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId&g…

git基础命令(小白适合看)

作者&#xff1a;爱塔居 欢迎大佬指正 1.git add 跟上文件地址 要注意斜杆&#xff0c;然后文件地址就是我们修改文件的地址。 就比如git add xx/xx/xx.x&#xff0c;记得加后缀&#xff0c;然后如果是几个文件&#xff0c;就加空格 例如 git add xx/xx/xx.x yy/yy/yy.y 2.…

机器翻译:跨越语言边界的智能大使

导言 机器翻译作为人工智能领域的瑰宝&#xff0c;正在以前所未有的速度和精度&#xff0c;为全球沟通拓展新的可能性。本文将深入研究机器翻译的技术原理、应用场景以及对语言交流未来的影响。 1. 简介 机器翻译是一项致力于通过计算机自动将一种语言的文本翻译成另一种语言的…

BearPi Std 板从入门到放弃 - 先天神魂篇(3)(RT-Thread I2C设备 读取光照强度BH1750)

简介 使用BearPi IOT Std开发板及其扩展板E53_SC1&#xff0c; SC1上有I2C1 的光照强度传感器BH1750 和 EEPROM AT24C02&#xff0c; 本次主要就是读取光照强度; 主板: 主芯片: STM32L431RCT6LED : PC13 \ 推挽输出\ 高电平点亮串口: Usart1I2C使用 : I2C1E53_SC1扩展板 : LE…

Linux服务器性能优化小结

文章目录 生产环境监测常见专业名词扫盲服务器平均负载服务器平均负载的定义如何判断平均负载值以及好坏情况如果依据平均负载来判断服务器当前状况系统平均负载和CPU使用率的区别 CPU上下文切换基本概念3种上下文切换进程上下文切换线程上下文切换中断上下文切换 查看上下文切…

视频号链接提取器详细使用指南,教你轻松下载号视频!

视频号下载提取器的使用方法会因不同工具而略有差异&#xff0c;但大体上可以按照以下步骤进行操作&#xff1a; 1. 找到一个适合的视频号下载提取器&#xff1a;可以在微信搜一搜中输入关键词“超级短视频去水印解析助手”&#xff0c;选择进入公众号、获取在线视频下载提取工…

12.18_黑马数据结构与算法笔记Java

目录 thinking:orElse? thinking:map.computerifabsent? thinking&#xff1a;subString&#xff1f; 184 哈希表 问2 解释拆分 185 哈希算法 概述 186 哈希算法 Object.hashCode 187 哈希算法 String.hashCode 188 哈希算法 冲突测试 189 哈希算法 MurmurHash 190…

【轮式移动机器人课程笔记3】移动机器人运动学简介

文章目录 写在前面L3 移动机器人运动学简介3.1 运动学概述3.2 研究机器人运动学的意义3.3 机器人运动的描述3.4 机器人正微分运动学3.5 机器人逆微分运动学3.6 总结 写在前面 前两节课介绍了移动机器人、机械手、类型&#xff0c;本节课重点讲解移动机器人运动学相关知识&…

hive的分区表和分桶表详解

分区表 Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录&#xff0c;每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区&#xff0c;这样的查询效率会提高很多。 静态分区表基本语法 创建分区表 create table dept_p…

数据安全无阻,轻松远程工作!迅软DSE出差加密指南,让你出差更放心!

文件加密软件是确保内网文件安全使用的重要工具&#xff0c;但在终端脱离内部网络、面对外出或居家办公等情境时&#xff0c;文件加密的挑战也相应增加。为解决这一问题&#xff0c;迅软DSE文件加密软件提供了离线授权功能&#xff0c;确保在终端脱离公司网络后的设定时间内&am…

使用Docker运行Nacos并安装cpolar内网穿透工具实现远程访问

文章目录 1. Docker 运行Nacos2. 本地访问Nacos3. Linux安装Cpolar4. 配置Nacos UI界面公网地址5. 远程访问 Nacos UI界面6. 固定Nacos UI界面公网地址7. 固定地址访问Plik Nacos是阿里开放的一款中间件,也是一款服务注册中心&#xff0c;它主要提供三种功能&#xff1a;持久化…

openwrt 搭建web

折腾 软路由 有几年了&#xff0c;最近试了下 移动的 IPV6, 既然可以拿到 公网的 IPV6&#xff0c; 所以想折腾下, 经过不懈努力 实现了&#xff1a;通过 ipv4/ipv6 地址访问我的 web站点 (白飘不花钱的方式) 1 动态DNS 折腾 DDNS 无非是想 白飘 公网IP&#xff0c;但是 仅仅…

一个企业为什么要数字化转型?答案在这里!

一个企业为什么要数字化转型&#xff1f; 先简单说说原因。 因为很多行业现在存在大量的产能过剩、产品过剩、服务过剩&#xff0c;经营维度低、行业竞争激烈......企业生存困难&#xff0c;必须改变经营维度才能活下来&#xff0c;才能变现。 单方面举个例子&#xff0c;可…