大连市冷链食品安全追溯系统

项目使用公司自研A6框架书写

项目展示

首页

数据上报

数据查询

基本信息

其中我负责数据上报的进口产品上报功能

进口产品上报功能分为三个模块,分别为:查询展示页面查看页面新增页面

进口产品上报——查询展示

查询展示页面包括四个输入数据框

  1. 入库开始日期
  2. 入库结束日期
  3. 冷库名称
  4. 入库单号

这四个数据要实现组合查询,其实最好还要实现模糊查询

搜索查询——日期

日期一开始我选择的是A6封装的日期段,可以直接选择一个时间段,即实现了需求文档要求的选择一个时间段,不可以在开始日期选择结束日期之后的日期,不可以在结束日期选择开始日期

注意:这里如果使用时间段,那么传输到后台的是一个List集合,集合内包含两个字符串

后端接受数组——前后端数据的接收

在这里我的同学丁遇到一个很奇怪的问题,他在前端的数组在后端接受不到,经过各种调试后实现了接收,代码如下:

控制层

@GetMapping(value = "/ckList", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
@DataTranslate // 此注解用于翻译实体类中的单值代码,组织机构数据
@ExceptionTips("加载数据失败") // 此注解用于后台报错了给前台的提示信息
public ArteryPageableData<List<ExpressExport>> selectCkByForm(@RequestParam(value="date[]",required=false)String[] date, String exportCode, String warehouseName, Integer offset, Integer limit) {
    //获取对应单号和名称的数据
    List<ExpressExport> jg = expressExportService.selectAllDate(exportCode,warehouseName);

js

condition: {
    exportDate: [new Date()],
}
    Artery.ajax.get('jkcpcksb/ckList', {
        params: {
            date: _this.condition.exportDate,

他在后端加入了中括号之后才实现了数据的接收,这让我感觉有些疑惑,因为毕竟前端定义的参数名字是date,我仔细查阅了资料

>
>

如果 JQuery 要往服务端传递一个数组参数,请求的方式如下

$.ajax({
url : ${yourURL},
data: {yourParam:[1,2,3,4]},
success:function(data){
}
});

或者:

$.ajax({
url : ${yourURL},
data: {"yourParam[]":[1,2,3,4]},
success:function(data){
}
});

前端传递参数这两种写法都可以,建议写成第二种,而服务端的接收参数对应起来。

那么在服务端的 Controller怎么接收这个参数?

@RequestMapping("/save")
public void save(@RequestParam(value="yourParam[]" String[] yourParam){
// do Something...
}

注意: @RequestParam 一定要用数组的形式 “yourParam[]” 作为接收参数, 这样的话才能够正确的接收到前端传递的数组, 如果前端的数组为空,接收到的也是空串。 比如:前端传递的参数: data:{"yourParam[]":[null,null,null]} 那么服务端接收到的参数将会是 [“”,””,””] 无需担心空指针问题。

如果不用 “yourParam[]” 作为接收参数的话,将会发生莫名的错误。

最好在前端和后端定义数组的时候都加上[ ]

最后我决定使用两个日期框,因为需要跟其他人的样式合并,但这样就需要实现之前提到的日期选择问题:

不可以在开始日期选择结束日期之后的日期,不可以在结束日期选择开始日期

实现这个问题的解决办法其实也很简单,就是在A6的日期选择框里设置一个禁止选择日期事件,但是这里其实有个问题:

vue无法在Data的return里使用同级数据,var命令会发生”变量提升“现象,因为变量可以在声明之前使用,值为undefined,这导致在Data里调用同级数据是拿不到的,解决方案也很简单:使用Let关键字

let——解决Data内同级调用

es6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

pickerOptionsStart: {
    disabledDate: time => {
        let endTime = this.queryConditions.endTime;
        if (endTime) {

            return time.getTime() > new Date(endTime.replace(/-/g,"/")).getTime();
        }

    }
},
pickerOptionsEnd: {
    disabledDate: time => {
        let startTime = this.queryConditions.startTime;
        if (startTime) {

            return time.getTime() < new Date(startTime.replace(/-/g,"/")).getTime();
        }

    }
},

JS时区问题

但只是这样问题还没有解决,由于js在es5标准中的Date构造函数中识别字符串的间隔符如果为‘-’,则会选择格林威治标准时间来设置日期,这时候我们选择的时间是某一天的零点,而在东8区,得到的时间会是0点,这导致我们的 日期选择器不能选择当前日期(今天)。

解决方案也很简单,将字符串的‘-’连接符全部换成‘/’就可以了

endTime.replace(/-/g,"/")

至此基本问题已经解决,只等向后台传输数据

搜索查询——冷库名称

在页面开始之前,我们需要先从后台得到数据,从后台拿到冷库列表,这里有一个小知识点

Created/Mounted——Vue不同的生命周期

  • 在created的时候,视图中的html并没有渲染出来,所以此时如果直接去操作html的dom节点,一定找不到相关的元素

  • 而在mounted中,由于此时html已经渲染出来了,所以可以直接操作dom节点

A6框架数据传输

冷库向后端传输的是冷库的ID,根据ID获得一个集合

控制层

    @GetMapping("getWareHouseList")
    @ResponseBody
    public List<ExpressWarehouse> getWareHouseList() {
        return expressWarehouseService.selectAll();
    }

这里我们看一下注解

  • @GetMapping("getWareHouseList")
    • 这个注解的意思很好理解,它使前端的ajax请求直接找到对应的controller方法
    • 注意是Get方法,其实更多使用@RequestMapping
  • @ResponseBody
    • @ResponseBody 支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)
    • 本来控制层如果进行了映射,返回值其实会根据mv返回一个页面,如果加上这个注解,数据将会返回成JSON格式给前端

JS

Artery.ajax.get('jkcprksb/getWareHouseList').then(function (result) {
    _this.wareHouseList = result;
});

前端接受后端参数

查询列表——分页

js

<aty-table border :pageable-data="queryList" @load-data="query" ref="table1"
           empty-text="未查询到数据" limit-opts-transfer :limit="10" :limit-opts="[10]" stripe>
    <aty-table-column type="index" label="序号" :index="indexIncrement"></aty-table-column>
    <aty-table-column label="入库单号" prop="c_order_code"></aty-table-column>
    <aty-table-column label="冷库名称" prop="c_warehouse_name"></aty-table-column>
    <aty-table-column label="入库日期" prop="dt_storage_date"></aty-table-column>
    <aty-table-column label="流入地分类" prop="n_origin_type"></aty-table-column>
    <aty-table-column label="操作">
        <template slot-scope="props">
            <aty-link text="查看" @click="view(props.row.c_order_code)"></aty-link>
        </template>
    </aty-table-column>
</aty-table>

js

Artery.loadPageData('jkcprksb/getQueryList', queryInfo, _this.queryConditions
).then(function (result) {
    _this.queryList = result;
});

控制层

@PostMapping("getQueryList")
@ResponseBody
@DataTranslate
@ExceptionTips("获取查询结果失败")
public ArteryPageableData<List<ExpressImportVo>> getQueryList(
    IQueryInfo queryInfo,
    @RequestParam("startTime") String startTime,
    @RequestParam("endTime") String endTime,
    @RequestParam("importCode") String importCode,
    @RequestParam("wareHouseNameSelected") String wareHouseNameSelected) {

    ExpressImportDto expressImportDto = expressOrderImportedService.encapsulation(
        startTime, endTime, importCode, wareHouseNameSelected);
    return expressOrderImportedService.select(queryInfo, expressImportDto);
}

A6自己封装的分页数据已经非常强大,实现了很多功能,也省略了很多BUG,但有一个地方需要注意

A6JS封装的loadPageData方法自动接收一个参数queryInfo(分页信息),这个queryInfo只 有 在 loadDate方法中可以拿到,如果你没有让他拿到queryInfo,它会去自己创建一个默认的queryInfo,这里queryInfo的默认limit是15

换句话说,如果你将loadDate事件绑定成一个,它是无法拿到queryInfo的,没法拿到就会自动创建一个默认的queryInfo,这也造成了我们点击查询之后数据会无法正常分页,解决方案也很简单,将点击事件和LoadDate方法区分开

点击事件

loadDate事件

进口产品上报——查看页面

查看页面分为两部分,涉及了两张表,分别是EOI(进口产品入库表)表和EOP(进口产品出入库详情表)

分两个部分实现:查看入库和入库明细,上方是不可写入的文本框,较容易实现,下方是一个表格,需要之前实现的分页

这里一个很蛋疼的小问题,回显

数据回显——单值列表是有用的

我们需要在类型这个地方显示具体的类型,但是实际上数据库中存储的是类型Id,同理,在流入地分类,入境口岸,口岸/流入地,是否核酸检测,是否消杀等等这些地方我们都会遇到这个很纠结的数据回显问题。

查看入库中,我使用了超哥的解决方案,与单值代码表做子查询

   select
        eoi.c_order_code,
        ew.c_warehouse_name,
        eoi.dt_storage_date,
        eoi.n_origin_type,
        (select c_name from db_llkf.express_code where n_type = #{ntype} and c_value = eoi.c_origin_area)
        as c_origin_area,
        (select c_name from db_llkf.express_code where n_type = 5 and c_value = eoi.c_origin_port)
        as c_origin_port,
        (select c_name from db_llkf.express_code where n_type = 4 and c_value = eoi.c_native_country)
        as c_native_country,

这样我们可以直接根据数据库中的单值代码得到单值代码表中的实际数据

入库明细中,我使用了比较笨的方法

image-20210416175825531

手动将值解析(那时候超哥还没跟我讲单值代码表),这种方法需要我的实体类的属性类型为String,否则是无法对应上的,对应不上就只能手动加入字段


醉后不知天在水,满船清梦压星河