Commit b3226990 by zhangliding

Merge remote-tracking branch 'origin/master'

parents f9843fb7 6f0054cd
# 公共面板
# 公共面板
路径:vue-gjjs/src/views/Public
## 1、公共面板
### 1.引入
部分面板在许多交易中出现,已提为公共页面,路径:vue-gjjs/src/views/public
例如:Detopn中的账务、附言、报文及面函、统一授信
![](../assets/frontEndImg/publicPanel.png)
例如:"账务" 可通过以下方式引入
1、import Setpan from "~/views/Public/Setpan";
2、在components中添加:"m-setpan": Setpan
3、使用
<el-tab-pane label="费用及账务" name="setpan">
<c-content>
<m-setpan :model="model" :codes="codes" />.
</c-content>
</el-tab-pane>
4、其他公共页面引入方式类似
### 2、补充额外字段
##### 1、面函
后端:
1)在对应的实体类中,如ditopn.class,找到注释为://XMLPanel ...的内置block(可能存在多个)
的字段,在Vo和前端model中补充相应字段
2)Vo中额外补充:
@SimpleType(type = SimpleDoceot.class)
private List<SimpleDoceot> trnmod_trndoc_doceot;
前端:
对应面板:docpan
在对应的index.js中将trnmod属性改为:trnmod: new Pub().data.Trnmod,
##### 2、账务
后端:
1)Vo中额外补充:
private String setmod_msgmod_docpth;@SimpleType(type = SimpleSetfol.class)
private List<SimpleSetfol> setmod_setfog_setfol;
@SimpleType(type = SimpleSetfel.class)
private List<SimpleSetfel> setmod_setfeg_setfel;
@SimpleType(type = SimpleSetgll.class)
private List<SimpleSetgll> setmod_setglg_setgll;
前端:
对应面板:setpan
在对应的index.js中将setmod属性改为:setmod: new Pub().data.Setmod,
##### 3、表外/或有
后端:
1)Vo中额外补充:
@SimpleType(type = SimpleLiaccvg.class)
private List<SimpleLiaccvg> liaall_liaccv_liaccvg;
@SimpleType(type = SimpleLiaallg.class)
private List<SimpleLiaallg> liaall_liaallg;
@RelPath(value="",dir=DirType.OUT)
private IStream liaall_liaccv_stgstm;
前端:
对应面板:engp
在对应的index.js中将liaall属性改为:liaall: new Pub().data.Liaall,
##### 4、分录
后端:
1)Vo中额外补充:
@RelPath(value="",dir=DirType.OUT)
private IStream setmod_glemod_gleshwstm;
前端:
对应面板:glepan
在对应的index.js中将setmod属性改为:setmod: new Pub().data.Setmod,
##### 5、保证金
前端:
对应面板:ccvpan
##### 6、附言
后端:
1)Vo中额外补充:
@RelPath(value="",dir=DirType.BOTH)
@JsonDeserialize(using=IStreamDeSerialized.class)
private IStream mtabut_coninf_oitinf_oit_inftxt;
@RelPath(value="",dir=DirType.BOTH)
@JsonDeserialize(using=IStreamDeSerialized.class)
private IStream mtabut_coninf_oitset_oit_inftxt;
前端:
对应面板:coninfp
在对应的index.js中将mtabut属性改为:mtabut: new Pub().data.Mtabut,
##### 7、授信额度
前端:
对应面板:limitbody
在对应的index.js中将liaall属性改为:liaall: new Pub().data.Liaall,
##### 8、附件
前端:
对应面板:doctre
在对应的index.js中将trnmod属性改为:trnmod: new Pub().data.Trnmod,
## 2、面板内模板引用
仅列举部分,其余可查看vue-gjjs/src/views/Public内的公共模板
### 1、ptap模板
例如detopn/ovwp中的受益人引用了ptap模板
![](../assets/frontEndImg/detopnCommonPtap.png)
1、此模块已提取为公共模块,导入:import Ptap from "~/views/Public/Ptap";
2、在components中添加:"c-ptap": Ptap
3、使用:
<c-col :span="24">
<c-ptap
:model="model"
:argadr="{
title: '受益人',
grp: 'dedgrp',
rol: 'ben',
}"
:disabled="true"
:isAdrblk="false"
>
</c-ptap>
</c-col>
### 2、表格公共模板
请参照*[表格公共模板](../../../../../../assets/images/03-新国结产品开发/pdf/表格公共模板.pdf)
![](../assets/frontEndImg/docpre.jpg)
## 3、复核面板引用
\#复核 交易完成后添加 "复核" 操作
#### 1、在 "Review/Business" 建立相应的vue页面
#### ![img](../assets/frontEndImg/trnrelNewPanel.png)2、在 "Review/ReviewRouter.js" 配置相应路由
#### ![img](../assets/frontEndImg/trnrelRouter.png) 3、在对应交易的 "index.vuw" 页面初始化后加入读取快照操作 ![img](../assets/frontEndImg/trnrelDisplay.png)
## 4、开发规范说明
### 1.交易录入
#### 入口文件
每个交易的入口文件都是其文件夹下的 index.vue。src/views/Bussiness/交易代码/index.vue
![img](../assets/frontEndImg/交易录入_入口文件.jpg)
### 2.页面布局排版
#### 大体结构
![img](../assets/frontEndImg/交易录入_页面大体结构.png)
![img](../assets/frontEndImg/交易录入_组件结构.png)
每个标签页tab下的内容,建议都加上 eibs-tab 的class样式,统一间距。若使用折叠面板,则折叠面板内的所有页面使用 eibs 的class样式。
![img](file:///G:/XinChen/gjjs/gjjs-lessons/assets/images/03-%E6%96%B0%E5%9B%BD%E7%BB%93%E4%BA%A7%E5%93%81%E5%BC%80%E5%8F%91/image/%E5%89%8D%E7%AB%AF%E8%A7%84%E8%8C%83/%E4%BA%A4%E6%98%93%E5%BD%95%E5%85%A5_%E6%A0%87%E7%AD%BE%E9%A1%B5%E5%86%85%E5%AE%B9%E5%B8%83%E5%B1%80.png) ![img](../assets/frontEndImg/交易录入_标签页内容布局_1.png)
### 3.内容格式
每个tab页面为左右布局,若一行只有一个,那就全部占满;若一行有多个,则自行控制每个的宽度,但需要保证该行与其他行是右对齐的。 ![img](../assets/frontEndImg/交易录入_标签页内容格式_1.png) ![img](../assets/frontEndImg/交易录入_标签页内容格式.png)
### 4.查询页
#### 查询页整体布局
查询页布局以汇款查询(Infcpd)为例,如下图所示,主入口组件为Infcpd下的index.vue,查询页面为infsea.vue组件,整体布局分为三部分,查询条件、按钮区和查询表格,下面对这三部分进行详细说明。
![img](../assets/frontEndImg/searchpage1.png)
#### 查询条件
查询条件整体为一个form表单,代码如下所示,其他查询条件的表单基本都是采用这个规范,label为右对齐,宽度度110px,表单样式一般写在主入口组件(index.vue)中,主要约束了表单中组件的浮动方式,代码如下所示。
```vue
<el-form
class="m-table-search-form"
ref="paramsForm"
label-position="right"
label-width="110px"
size="small"
>
...
</el-form>
.m-table-search-form {
position: flex;
flex-direction: row;
}
.m-table-search-form .el-form-item__content {
width: calc(100% - 110px);
}
```
表单内为栅格布局,每行分为三列,每列的span值为8,查询条件超过三行时设置收起展开功能,默认为收起状态,不超过三行时不用设置此功能,如下图所示。通过点击展开或收起按钮改变可控展示区v-show的布尔值来实现可控展示区的显示和隐藏,一般把业务编号和查询起止时间这两个最常用的条件放在第一行的前两列,把较为常用放在第三列,在不展开状态下方便查询。
![img](../assets/frontEndImg/fold.png)
![img](../assets/frontEndImg/unfold.png)
点击按钮修改searchToggle的值 ,通过标识位和v-show控制 可控展示区的展示与隐藏
```vue
<el-button type="text" @click="searchToggle = false">
展开
<i class="el-icon-arrow-down"></i>
</el-button>
<el-button type="text" @click="searchToggle = true">
收起
<i class="el-icon-arrow-up"></i>
</el-button>
<c-row v-show="!searchToggle">
...........
</c-row>
```
#### 按钮区
查询条件下面的按钮区布局如下图所示,一般交易入口按钮放置在左侧,操作按钮放置在右侧。
![img](../assets/frontEndImg/searchpagebutton.png)
按钮区的按钮为交易入口按钮,按钮的尺寸比查询条件中的查询按钮尺寸要大一些,和查询列表左侧对齐
```vue
<c-col style="margin-top: 10px">
<c-button class="medium_bcs" size="medium" type="primary" style="margin-left: 0"
@click="toCptopn">swift汇入</c-button
>
<c-button class="medium_bcs" size="medium" type="primary" style="margin-left: 0"
@click="toCptadv">swift汇出</c-button
>
<c-button class="medium_bcs" size="medium" type="primary" style="margin-left: 0"
>境内外币汇入</c-button
>
<c-button class="medium_bcs" size="medium" type="primary" style="margin-left: 0"
>境内外币汇出</c-button
>
<c-button class="medium_bcs" size="medium" type="primary" style="float:right;margin-right:10px;"
>导Excel</c-button
>
</c-col>
<style>
.el-dialog__body {
padding: 10px 5px 50px;
}
</style>
```
#### 查询表格
下方的表格显示查询结果的数据,后端查询返回的是IStream类型数据,前端使用全局组件IStreamTable对返回值处理,代码如下所示。其中表头数据从父组件的data里的stmData.columns传入,子组件通过props接收columns,表格数据从父组件的data里的stmData.data传入,子组件通过props接收list,
```vue
<c-istream-table :list="stmData.data" :columns="stmData.columns" :showButtonFlg="true">
...
</c-istream-table>
```
showButtonFlg是控制显示自定义列属性弹窗的齿轮按钮,默认为false不显示,需要此功能时设置为true,可自定义表格中各列。点击齿轮按钮后弹出面板,通过勾选需要显示的列进行自定义列属性
![image20220214151019438](../assets/frontEndImg/20220214151019438.png)
表头数据通过数组传入IStreamTable组件中,代码如下所示。数组中有字符串和对象两种类型数据,
1、一般使用字符串类型,以'12 3 "PYE NO." 100 '为例,3表示表格第三列,"PYE NO."表示列名,100表示列宽,而12表示本列存放的数据在后台返回的IStream的索引,即以/t为分隔从0开始,索引为12的数据存放在本列,数据与列的对应关系参照td。
2、数组中的对象类型是实现对存入的数据进行处理,以'{index: 3,position: 15,width: 100,pattern: "date",label: "Opened",},'为例,pattern为date,是去掉日期的时分秒毫秒保留年月日的处理方法,还有查出的数据在td上对应码表的值,pattern设为"code",code可对数据进行码表映射。其他常用处理方法也都封装在IStreamTable里,只需设置对应的pattern即可。
```vue
stmData: {
columns: [
'1 1 "Reference" 150 ',
'2 2 "Resp. User" 100 ',
'12 3 "PYE NO." 100 ',
'9 4 "Payee.Party Number" 150',
'10 5 "Payee Customer" 250',
'11 6 "PYE.Customer CN" 130',
'13 7 "Ord.Party Number" 150',
'14 8 "Ord.Customer" 250',
'15 9 "Ord.Customer CN" 130',
'16 10 "1.Party Number" 150',
'17 11 "Ord.Institution" 200',
'12 12 "ORC NO." 150',
'18 13 "2.Party Number" 150',
'19 14 "Paying Bank" 150',
//'3 15 "Opened" 140',
{index: 3,position: 15,width: 100,pattern: "date",label: "Opened",},
//'4 16 "Value" 140',
{index: 4,position: 16,width: 100,pattern: "date",label: "Value",},
//'5 17 "Closed" 140',
{index: 5,position: 17,width: 100,pattern: "date",label: "Closed",},
'20 18 "1.Cur" 80',
'22 19 "2.Cur" 80',
'21 20 "Paym.Amount" 120',
'23 21 "Amount rcvd." 120',
'6 22 "Pyectycod" 100',
'7 23 "Orcctycod" 100',
],
data: [],
},
```
#### 操作按钮
操作按钮的个数根据实际业务设置,以infcpd为例,操作有两个按钮,【详情】和【处理】
点击【详情】按钮后弹出历史信息列表(其中包含另一个【详情】按钮),非业务按钮,白底
![image20220214162113742](../assets/frontEndImg/20220214162113742.png)
点击【处理】按钮会弹出交易的后续可操作的业务按钮,业务按钮,蓝底 type="primary"
![image20220214162145836](../assets/frontEndImg/20220214162145836.png)
```vue
<c-istream-table :list="stmData.data" :columns="stmData.columns" :showButtonFlg="true">
<el-table-column fixed="right" prop="op" label="操作" width="140px">
<template slot-scope="scope">
<el-popover
placement="top-start"
title="历史信息"
width="800"
trigger="click"
:ref="'popover_' + scope.row.IDX"
>
<div
style="
text-align: right;
margin-top: -30px;
margin-right: 5px;
font-size: 16px;
"
>
<span
class="el-icon-close"
@click="closeTrn('popover_' + scope.row.IDX)"
/>
</div>
<c-istream-table :list="trnData.data" :columns="trnData.columns">
<el-table-column prop="op" label="操作" width="0">
<template slot-scope="scope">
<c-button
style="margin-left: 0"
size="small"
@click="display(scope.$index, scope.row)"
>
详情
</c-button>
</template>
</el-table-column>
</c-istream-table>
<c-button
style="margin-left: 0"
size="small"
@click="getTrnInfo(scope.$index, scope.row)"
slot="reference"
>
详情
</c-button>
</el-popover>
<c-button
style="margin-left: 0"
size="small"
type="primary"
@click="getButtons(scope.row['Reference'])"
>
处理
</c-button>
</template>
</el-table-column>
</c-istream-table>
```
## 5、界面组件规范
```
路径:vue-gjjs/src/components
```
自定义组件里有很大一部分是对Element-UI组件的包装([组件 | Element](https://element.eleme.cn/#/zh-CN/component/installation)
### 1.Layout 布局
通过基础的 24 分栏,迅速简便地创建布局。https://element.eleme.cn/#/zh-CN/component/layout
#### c-row
行布局
| 属性 | 说明 | 默认值 |
| ------- | ------------------------------------- | ------ |
| gutter | 栅格间隔 | 0 |
| type | 布局模式,可选 flex,现代浏览器下有效 | |
| justify | flex 布局下的水平排列方式 | start |
| align | flex 布局下的垂直排列方式 | |
```vue
<c-row>
<!-- 摘要 -->
<c-col :span="24">
<el-form-item label="Name" prop="bpdgrp.rec.pntnam">
<c-input
v-model="model.bpdgrp.rec.pntnam"
maxlength="40"
style="width:90%"
placeholder="请输入摘要"
></c-input>
</el-form-item>
</c-col>
</c-row>
```
#### c-col
列布局
| 属性 | 说明 | 默认值 |
| ------ | ------------------------------ | ------ |
| span | 栅格占据的列数,24表示全部占满 | 24 |
| offset | 栅格左侧的间隔格数 | 0 |
| push | 栅格向右移动格数 | 0 |
| pull | 栅格向左移动格数 | 0 |
示例:
```vue
<c-col :span="11" :offset="1">
<el-form-item label="摘要" prop="didgrp.rec.nam">
<c-input
align="middle"
v-model="model.didgrp.rec.nam"
maxlength="40"
disabled
placeholder="请输入Externally Displayed Name to Identify the Contract"
></c-input>
</el-form-item>
</c-col>
```
### 2.表单项:c-form-item
对表单里面的表单项做了一层封装,用于统一处理表单项里的 i18n 转换以及交易在复核页面时表单项点击高亮的操作。
示例:
```vue
<c-form-item label="邮编" prop="didgrp.apl.pts.youzbm">
<c-input
v-model="model.didgrp.apl.pts.youzbm"
maxlength="6"
placeholder="请输入邮编"
></c-input>
</c-form-item>
previewLabel 用于在复核时标注的显示
<c-form-item
previewLabel="信用证金额"
style="text-align: left;"
label-width="5px"
prop="didgrp.cbs.nom1.amt"
>
<c-input-currency
v-model="model.didgrp.cbs.nom1.amt"
placeholder="请输入信用证金额"
@keyup.enter.native="defaultFunction('didgrp.cbs.nom1.amt', model.didgrp.cbs.nom1.amt)"
></c-input-currency>
</c-form-item>
```
### 3.Tabs标签页
分隔内容上有关联但属于不同类别的数据集合。详细配置参见 https://element.eleme.cn/#/zh-CN/component/tabs
示例:
```vue
<c-tabs :value="tabVal" ref="elment" type="card" @tab-click="tabClick">
<el-tab-pane label="其他当事人" name="detp1">
<!--PD000452 -->
<c-content>
<m-detp1 :model="model" :codes="codes" />
</c-content>
</el-tab-pane>
<el-tab-pane label="详细信息" name="detp">
<!--PD000077 -->
<m-detp :model="model" :codes="codes" />
</el-tab-pane>
</c-tabs>
```
### 4.滚动条
在页面上添加滚动条,使用 c-content 组件,有个height属性,默认是250
height:指的是页面document的高度与自身dom元素高度的差值。
示例:
```vue
<c-content :height="300">
<m-ovwp :model="model" :codes="codes" />
</c-content>
```
### 5.文本输入框
示例:
```vue
<c-input
v-model="model.cpdgrp.rec.othbch"
maxlength="8"
placeholder="请输入所属行">
</c-input>
```
### 6.文本域框
在c-input 组件添加type="textarea" 属性
示例:
```vue
<c-input
type="textarea"
v-model="model.mtabut.coninf.oitinf.oit.inftxt"
maxlength="60"
show-word-limit
placeholder="请输入Infotext" >
</c-input>
```
### 7.金额输入框
在c-input 组件添加class="m-input-currency" 样式,会限定保留三位小数,靠右显示。 示例:
```vue
<c-input
class="m-input-currency"
v-model="model.cpdgrp.cbs.nom1.amt"
style="text-align: left; width: 100%"
placeholder="请输入汇款金额"
@change="commonExecuteNotify()">
</c-input>
```
常用:1、非负金额输入框:用c-inpu-currency标签,只能输入非负数,会自动限定保留两位小数,靠右显示。 示例:
```vue
<c-col :span="12">
<el-form-item label="" prop="trnmod.swiadd.newamt">
<c-input-currency
v-model="model.trnmod.swiadd.newamt"
placeholder="请输入修改后金额"
></c-input-currency>
</el-form-item>
</c-col>
```
因c-input-currency标签限定了非负及保留两位小数,故在pattern.js中此字段
```html
{type: "string", required: false, message: "必输项"},
{max: 18,message:"整数位不能超过14位"},
{pattern: /(^\d+$)|(^\.\d{1,3}$)|(^\d+\.\d{1,3}$)/, message: "小数位不能超过3位" }`
```
应调为整:
```html
{type: "string", required: false, message: "必输项"},
{max: 17,message:"整数位不能超过14位"}`
```
常用: 2、正负金额输入框:用c-input-currency-min标签,正负及0都可输,会自动限定保留两位小数,靠右显示。 示例:
```vue
<c-col :span="12">
<el-form-item label="" prop="trnmod.swiadd.ameamt">
<c-input-currency-min
v-model="model.trnmod.swiadd.ameamt"
placeholder="请输入增减金额."
></c-input-currency-min>
</el-form-item>
</c-col>
```
### 8.按钮
```vue
<c-button
style="margin: 0 10px 0 10px; padding: 0 12px; height: 32px"
size="small"
type="primary"
@click="onSeainf"
icon="el-icon-search"
>
</c-button>
```
### 9.单选框
示例:
```vue
<c-radio v-model="params.partInoutCrClrFlag" label="2">SWIFT</c-radio>
```
### 10.多选框
示例:
```vue
<c-checkbox v-model="model.bcdgrp.rec.focflg">Free of Payment</c-checkbox>
```
由于TD中的多选框常使用X、Y、C等值来表示勾选状态,对应的""、O等值来表示未勾选状态,而checkbox中默认绑定变量的值会是Boolean,选中为true,未选为false,因此需要通过computed计算属性来实现勾选状态。
```vue
computed:{
colinsflg:{
get(){
return this.model.bodgrp.blk.colinsflg === "X";
},
set(val){
this.model.bodgrp.blk.colinsflg=val ? "X":"";
},
},
}
```
### 11.日期选择框
使用c-date-picker,之前有用el-date-picker需要改成c-date-picker,el-date-picker会造成传到后台日期不准确。
示例:
```vue
<c-date-picker
type="date"
v-model="model.didgrp.rec.opndat"
value-format="yyyy-MM-dd"
placeholder="请选择Date"
style="width:100%">
</c-date-picker>
```
### 12.下拉选择框
#### 使用静态码表
index.vue父组件data里的codes:{...CodeTable}传入,子组件通过props: [ "codes"]接收。
```vue
<c-select
v-model="model.didgrp.rec.guaflg"
style="width: 100%"
placeholder="请选择货押标识"
>
<el-option
v-for="item in codes.guaflg"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</c-select>
```
或者简写成:
常用:
```vue
<c-select
v-model="model.didgrp.rec.guaflg"
style="width: 100%"
placeholder="请选择货押标识"
:code="codes.guaflg">
</c-select>
```
#### 使用动态码表:使用后台setvalues/setCodeValues传送
写成:code="getValues(key,tableName)"形式,(切记,该字段一定要在后端JAVA vo中存在,例如示例中的btdgrp.rec.docprbrolbe1)
key:为后端传来的CodeSet的字段,如btdgrp.rec.docprbrolbe1。
tableName:src下的全局静态码表中的码表名称,如rolall
如后端传来的CodeSet下该字段值为"value+lable",则不用传参数tableName 如后端传来的CodeSet下该字段值仅有"value",则需传参数tableName,以便去全局静态码表中找到相应码表,根据value值找到lable值
```vue
<c-col :span="24">
<el-form-item label="收款人" prop="btdgrp.rec.docprbrolbe1">
<c-select
v-model="model.btdgrp.rec.docprbrolbe1"
style="width: 100%"
placeholder="请选择收款人"
:code="getValues('btdgrp.rec.docprbrolbe1', 'rolall')"
@change="selectOrCheckboxRule('btdgrp.rec.docprbrolbe1')"
></c-select>
</el-form-item>
</c-col>
```
### 13.FunctionBtn
通用的方法按钮组,内置交易开证的提交、检核、暂存、退出这4个按钮,还可自行添加其他的事件按钮显示在右边。
示例:
```vue
<c-function-btn
:handleSubmit="handleSubmit"
:handleCheck="handleCheck"
:handleStash="handleStash"
>
</c-function-btn>
```
![img](../assets/frontEndImg/function-button_1.png)
### 14.FullBox
用于表单项的布局排版,将容器内的组件对齐排列。多用于FormItem内部
示例:
```vue
<el-form-item
label="所属客户经理"
prop="ditp.usr.extkey"
style="width: 100%"
>
<c-fullbox>
<c-input
v-model="model.ditp.usr.extkey"
maxlength="8"
placeholder="请输入User ID"
disabled
></c-input>
<template slot="footer">
<c-button
style="margin-left:10px;padding: 0 10px;"
size="small"
icon="el-icon-search"
type="primary"
@click="onExtkey"
></c-button>
</template>
</c-fullbox>
</el-form-item>
```
![FullBox](../assets/frontEndImg/full-box_1.png)
### 15.streamtable
最简单形式:
```vue
<c-istream-table
:list="trnData.data"
:columns="trnData.columns"
>
</c-istream-table>
```
如果列表后有操作项,则添加el-table-column标签
```vue
<c-istream-table
:list="trnData.data"
:columns="trnData.columns"
>
<el-table-column prop="op" label="操作" width="0">
<template slot-scope="scope">
<c-button
style="margin-left: 0"
size="small"
@click="display(scope.$index, scope.row)"
>
详情
</c-button>
</template>
</el-table-column>
</c-istream-table>
```
streamtable目前日期格式化处理和码值展示描述信息,例如:
```vue
trnData: {
columns: [
'1 1 "编号" 200',
'2 2 "交易名称" 120',
{index:3,position:3,width:110,pattern:'date',label:'日期'},
{index:4,position:4,width:100,pattern:'code',label:'状态',code:this.codes.relstaEN},
'5 5 "币种" 80',
'6 6 "金额" 110',
],
data: [],
},
```
上面在定义columns时日期和状态字段
index:表示后台返回数据在stream中的索引 ,以'/t'分隔 ,从0开始
position:在table中展示的列
width: 字段宽度
pattern:转义的类型 date表示转义为日期类型
label:表头
code:pattern为code时,转为对应码表值
### 16.弹出回填组件
可以在文本框输入字符,然后回车弹出选项列表,双击选择某个选项后回填到父页面,例如,选择申请人、收益人、开户行、国家代码等
以信用证开立其他当事人页签选择通知行联行行号为例,输入303100,点击回车,然后双击一条记录,弹出框关闭,页面回填信息 ![img](../assets/frontEndImg/tckht0.png) ![img](../assets/frontEndImg/tckht2.png) ![img](../assets/frontEndImg/tckht3.png)
开发步骤:
1、先在交易index.vue,添加c-grid-ety-prompt-dialog标签 ![img](../assets/frontEndImg/tckht1.png)
```
<c-grid-ety-prompt-dialog ref="etyDialog" :promptData="promptData" v-on:select-ety="selectEty">
</c-grid-ety-prompt-dialog>
```
2、然后在c-input组件里添加@keyup.enter.native="showGridPromptDialog('xxx')"属性,xxx是该input框的model值
```vue
<c-input
v-model="model[argadr.grp][argadr.rol].pts.bankno"
maxlength="20"
:disabled="disabledBankno"
:placeholder="'请输入' + argadr.title + '联行行号'"
@keyup.enter.native="showGridPromptDialog(`${argadr.grp}.${argadr.rol}.pts.bankno`)"
>
</c-input>
```
3、整个过程:先通过c-input中的showGridPromptDialog 模糊查询出匹配的数据,数据在c-grid-ety-prompt-dialog展示,选择对应的数据后,调用selectEty,将选择的数据回填到关联的多个c-input中,如果模糊查询的数据只有一条将不会弹出选择框。
```vue
<c-input
v-model="model[argadr.grp][argadr.rol].pts.bankno"
maxlength="20"
:disabled="disabledBankno"
:placeholder="'请输入' + argadr.title + '联行行号'"
@keyup.enter.native="showGridPromptDialog(`${argadr.grp}.${argadr.rol}.pts.bankno`)"
>
</c-input>
<c-input
type="textarea"
:rows="2"
v-model="model[argadr.grp][argadr.rol].pts.jigomc"
maxlength="35"
show-word-limit
:placeholder="'请输入' + argadr.title + '联行名称'"
:disabled="disabledJigomc"
>
</c-input>
<c-input
type="textarea"
:rows="2"
v-model="model[argadr.grp][argadr.rol].pts.dizhii"
maxlength="35"
show-word-limit
:placeholder="'请输入' + argadr.title + '地址'"
disabled
>
</c-input>
```
### 17.文本回填组件
- ···
-
请参照*[文本回填组件](file:///G:/XinChen/gjjs/gjjs-lessons/assets/images/03-新国结产品开发/pdf/文本回填公共模板.pdf) ![img](../assets/frontEndImg/faeea-selectMsg.jpg)
### 18.ListSearch
多条件查询,条件项的收缩与展开。
![ListSearhClose](../assets/frontEndImg/list-search_1.png)
![ListSearhOpen](../assets/frontEndImg/list-search_2.png)
示例:
```vue
<c-list-search @form-reset="handleReset" @form-search="handleSearch">
<template v-slot="searchSlot">
<el-form
class="m-table-search-form"
ref="paramsForm"
:inline="true"
label-position="right"
label-width="110px"
size="small"
>
<el-row>
<c-col :span="24">
<c-col :span="8">
<el-form-item
label="Own Reference"
prop="infcon.seaownref"
style="width: 100%"
>
<c-input
v-model="model.infcon.seaownref"
maxlength="16"
placeholder="请输入Own Reference"
></c-input>
</el-form-item>
</c-col>
</c-col>
</el-row>
</el-form>
</template>
</c-list-search>
```
### 19.BusNavbar
在查询交易infsea.vue中引入,点击业务查询界面的数据列表中的【处理】按钮后,弹出的交易列表
![image20220214172133239](../assets/frontEndImg/20220214172133239.png)
交易按钮组件封装在src/views/Bussiness/查询业务交易代码/BusNavbar.vue中,ref="childs" 用于infsea调用子组件BusNavbar中的方法
```vue
<el-dialog :visible.sync="initdialog" :title="'交易列表'" append-to-body>
<div class="m-list-btns">
<m-busbtn ref="childs" :ownref="ownref" @onChoose="onChoose"
></m-busbtn
>
</div>
</el-dialog>
import BusNavbar from "~/views/Business/Infcpd/BusNavbar";
export default {
components: { "m-busbtn": BusNavbar },
}
```
点击【处理】按钮,调用getButtons方法,触发BusNavbar中方法加载业务按钮
```vue
getButtons(ownref){
this.initdialog = true
this.ownref = ownref
setTimeout(()=>{
//调用子组件中的方法
this.$refs.childs.$emit("childmethods")
},10)
},
```
先置空按钮数据,从后台加载按钮数据,根据业务需要筛选需要的按钮数据,
```vue
mounted(){
//加载交易按钮数据
this.$nextTick(function(){
this.$on('childmethods',async function(){
this.navcode = []
//请求按钮数据
this.model.cpdgrp.rec.ownref = this.ownref
//部分查询交易 ,可能需要执行多个rule才能获取到数据(如infbdd)
let rtnmsg = await this.executeRule("cpdgrp.rec.ownref");//didgrp_rec_ownref
if(rtnmsg.respCode == SUCCESS){
//重置数组
this.navcode = []
this.updateModel(rtnmsg.data)
//this.model.cfgfil.btnstm = rtnmsg.data.cfgfil_btnstm.rows
//给inr赋值,后面弹窗里面的按钮请求会用到
//this.model.didgrp.rec.inr = rtnmsg.data.didgrp_rec_inr
const length = this.model.cfgfil.btnstm.rows.length
let btnStr = this.model.cfgfil.btnstm.rows
//汇入汇款(包含payment)、汇出汇款(包含payment)、境内外币 已经在查询界面做成了入口按钮,这里不需要展示
//根据具体的业务需求 可对按钮进行过滤 、 排序等处理 、添加处理 等---------start
let m = 0;
for(let i=0; i < length; i++){
//获取数组中每行的数据
if(!( btnStr[i].indexOf("payment") >= 0) && !(btnStr[i].indexOf("境内外币") >= 0)){
let arr = btnStr[i].split("\t");
let newList = {
code:arr[0],
label:arr[1],
isDis:arr[2],
title:arr[3]
}
m++;
this.navcode.splice(m,0,newList)
}
}
this.navcode.push({code:"",label:"退汇",isDis:"N",title:""})
//屏蔽cptsel sptcpt
this.navcode.splice(1,2)
//根据具体的业务需求 可对按钮进行过滤 、 排序等处理 、添加处理 等---------end
}else{
this.navcode = []
this.$notify.error({ title: "错误", message: "服务请求失败!" });
}
})
})
},
```
通过codeList将按钮数组转为数组
```vue
computed:{
codeList(){
//将model中的数据映射成数组
return this.navcode.map(item=>{
let entireItem = {...item}
this.navcode = [];
//TODO 根据数据判断当前的code,是否可以继续
// entireItem.enable = item.isDis
return entireItem
})
}
},
```
渲染到界面,并控制 infsea中的initdialog为true,展示交易按钮组件
```vue
<template>
<div class="busnavbar">
<div class="busnavbar-items">
<c-button style="margin-left:7px;" size="medium" type="primary" class="medium_bcs" v-for="(item,index) in codeList" v-bind:key="index" @click.native="onNarBtnClick(item.code,index)" :title="item.title" :disabled="item.isDis==='N'">{{item.label}}</c-button>
</div>
</div>
</template>
```
点击业务按钮时调用onNarBtnClick,调用父组件的方法,进入对应业务的处理
```vue
methods:{
//各入口按钮请求
async onNarBtnClick(code,i){
this.model.cfgfil.subtrn1= code
let rtnmsg = await this.executeRule("cfgfil.hotsub1")
if(rtnmsg.respCode == SUCCESS){
this.navcode = []
//调用父组件的onChoose方法
this.$emit("onChoose",code.toLowerCase());
}else{
this.$notify.error({ title: "错误", message: "服务请求失败!" });
}
},
},
```
## 前端开发调试文档
## 前端开发调试文档
#### 前端调试
***视频教程***
http://114.115.138.98:9497/gjjs-book/assets/videos/fore-end-debug.mp4
##### 1.观察XHR(异步请求)(TODO)
F12打开开发者工具,选中Network,可看到当前页面的所有资源请求。我们只需关注XHR请求,故在过滤条件中选中Fetch/XHR选项,剩下的就是XHR请求了。
![查看请求](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_1.png)
单击其中的某一个请求,可以看到该请求的详细信息,如下所示
![查看请求](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_2.png)
##### 2.观察响应数据
请求响应的结果在Preview和Response栏里,二者展示的形式不一样。
Preview模式
![响应结果预览](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_3.png)
Response模式
![响应结果1](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_4.1.png)
![响应结果2](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_4.2.png)
响应数据的属性:
![响应结果属性](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_5.png)
观察Response请求
##### 3.如何打前端断点
前端项目是通过Webpack进行加载的,我们编写的源文件在 webpack:// 目录下。其中 .vue 文件都在 webpack:///src下,.js文件都在 webpack:///./src 目录下
![源文件](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_6.png)
在需要调试的代码位置点一下,断点就标记完成,后面程序在执行到这一步时会停下来。
![标记断点](../../gjjs-lessons/assets/images/03-新国结产品开发/image/front_debug_7.png)
调试的常用按钮
![断点调试](../../../../../assets/images/03-新国结产品开发/image/front_debug_8.png)
\ No newline at end of file
## 后端项目下载运行 ## 后端项目下载运行
...@@ -81,43 +81,45 @@ servers元素中配置如下 ...@@ -81,43 +81,45 @@ servers元素中配置如下
</servers> </servers>
``` ```
mirrors元素中配置如下 mirrors元素中配置如下
```xml ```xml
<mirrors> <mirrors>
<!-- mirror <!-- mirror
| Specifies a repository mirror site to use instead of a given repository. The | Specifies a repository mirror site to use instead of a given repository. The
repository that repository that
| this mirror serves has an ID that matches the mirrorOf element of this | this mirror serves has an ID that matches the mirrorOf element of this
mirror. IDs are used mirror. IDs are used
| for inheritance and direct lookup purposes, and must be unique | for inheritance and direct lookup purposes, and must be unique
across the set of mirrors. across the set of mirrors.
| |
<mirror> <mirror>
<id>mirrorId</id> <id>mirrorId</id>
<mirrorOf>repositoryId</mirrorOf> <mirrorOf>repositoryId</mirrorOf>
<name>Human Readable Name for this Mirror.</name> <name>Human Readable Name for this Mirror.</name>
<url>http://my.repository.com/repo/path</url> <url>https://my.repository.com/repo/path</url>
</mirror> </mirror>
--> -->
<mirror> <mirror>
<id>brilliance-virtual</id> <id>brilliance-virtual</id>
<mirrorOf>*</mirrorOf> <mirrorOf>*</mirrorOf>
<name>brilliance-virtual</name> <name>brilliance-virtual</name>
<url>http://114.115.138.98:9620/artifactory/brilliance-virtual/</url> <url>http://114.115.138.98:9620/artifactory/brilliance-virtual/</url>
</mirror> </mirror>
<!-- <mirror> <!-- <mirror>
<id>aliyunmaven</id> <id>aliyunmaven</id>
<mirrorOf>*</mirrorOf> <mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name> <name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url> <url>https://maven.aliyun.com/repository/public</url>
</mirror> --> </mirror> -->
<!-- <mirror> <!-- <mirror>
<id>maven-default-http-blocker</id> <id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf> <mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name> <name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url> <url>http://0.0.0.0/</url>
<blocked>true</blocked> <blocked>true</blocked>
</mirror> --> </mirror> -->
</mirrors> </mirrors>
``` ```
编译内存设置,建议根据自己电脑内存实际情况进行配置,推荐2048 编译内存设置,建议根据自己电脑内存实际情况进行配置,推荐2048
......
# 后端项目代码调试
# 后端项目代码调试
## 项目开发调试
***视频教程***
http://114.115.138.98:9497/gjjs-book/assets/videos/rear-end-debug.mp4
以执行一个rule为例,讲解前端请求到后端的跟踪debug过程,供大家参考。
### 前端请求
前端信用证开立Exteky字段输入2000,然后回车,触发executeRule事件(“didgrp.apl.pts.extkey”)到后端
![](../assets/images/hddebug0.png)
![](../assets/images/hddebug1.png)
![](../assets/images/hddebug2.png)
### Resource断点
后端AbstractCommonResource executeRule方法接收到请求
![](../assets/images/hddebug3.png)
### Service断点
resource executeRule代码执行到service层
![](../assets/images/hddebug5.png)
![](../assets/images/hddebug6.png)
### Emitter断点
service executeRule代码执行到emitter层处理,AbstractRuleEmitter缓存有每个rule所对应的执行方法,通过反射去找到具体对应emitter的相应方法,然后去执行该方法
![](../assets/images/hddebug7.png)
![](../assets/images/hddebug8.png)
![](../assets/images/hddebug12.png)
### Rule层级断点
emitter作为rule的执行入口,里面按照顺序再去执行具体的业务逻辑代码
![](../assets/images/hddebug13.png)
### 返回结果断点
rule执行完回到service层进行数据的赋值封装,返回给前端
![](../assets/images/hddebug14.png)
![](../assets/images/hddebug15.png)
### debug调试技巧(drop frame)
在调试过程中,对于之前走过的代码想重新走一遍,不用把这次请求走完然后重新触发前端调用到后端再进行调试,这样会浪费时间影响效率,可以使用drop frame按钮,让断点回到上个断点位置重新步入。
如下图,断点已经走到了AbstractRuleEmitter executeRule方法,点击drop frame按钮,断点重新回到了AbstractRouteService executeStepWithRuleList方法
![](../assets/images/hddebugdrop1.png)
![](../assets/images/hddebugdrop2.png)
## 常见缺陷解决
### check隐藏字段
check校验时,浏览器控制台上filederror中报隐藏/不存在的字段的check错误:
对比td和新国结,找到为什么不一样,先找到原因,一般情况为invisible/visible的问题
#### 出现原因
td代码中的invisible/visible面板,有使该面板上的所有字段置为disabled/enable的功能,但在新国结后端代码中未实现invisible/visible置对应字段为disabled/enable的功能,而校验时很多check方法的进入条件有判断字段是否为enable,当字段隐藏时td自动置字段为disabled,因check进入条件判断enable为假,不进入check此字段,而新国结上字段隐藏时未置字段为disabled,check进入条件判断为真,进入了check方法,导致校验时报隐藏字段的check错误。
![check](../assets/images/check1.png)
#### 解决方案
在进入此check前加标志位判断,判断是否为xxx交易,且是否满足xx标志位条件,如:满足为gitopn交易,且开立方式为否时,不进入此check,否则按其原来的判断条件正常走check方法。
```java
//check了隐藏字段,加标志位条件。如gitopn开立方式为否时check了此隐藏字段,进入check方法的条件再加判断交易为gitopn时,且开立方式不为否时进入此check,否则按其原来的判断条件走此check
```
![check2](../assets/images/check2.png)
代码中 ctx.getTransName().equals("GITOPN") 可替换为 MdaUtils.compareTo(ctx.getTransName(),"GITOPN") == 0
验证代码逻辑正确后,在bdproject项目中对应的script文件中修改代码,重新编译生成后端代码,检查生成的新代码是否正确:
bdproject代码:
![check3](../assets/images/check3.png)
### 必输项
#### 1、金额输入框有值,进入交易后仍报红
前端:在此交易的pattern.js中找到该字段的type: "number"改为 "string";
(注意:金额输入框参照前端界面组件规范中使用的标签c-input-currency/c-input-currency-min,标签自动限定了输入数字,且保留两位小数,注意pattern的修改)
#### 2、天数输入框有值,进入交易后仍报红
前端:在此交易的pattern.js中找到该字段的type: "string"改为 "number",max为最大值;
示例:gitcrq交易的pattern.js
```html
"payday":[ "payday":[
{type: "string", required: false, message: "必输项"}, 改为 {type: "number", required: false, message: "请输入数字"},
{max: 2,message:"长度不能超过2"} {type: "number", max: 99,message:"不能超过99"}
], ],
```
前端页面该字段处v-model改为v-model.number
(**注意:**当字段有自动触发默认方法时,在浏览器控制台检查下更改后是否仍能触发默认方法或在后端代码打断点检查)
```html
<c-col :span="24">
<c-col :span="12">
<el-form-item label="我行将于" prop="payday">
<c-input v-model.number="model.payday" placeholder=""> </c-input>
</el-form-item>
</c-col>
<c-col :span="12">
<el-form-item label="个工作日后付款" label-width="120px">
</el-form-item>
</c-col>
</c-col>
```
### 字数超过限制
#### 输入框字数限制
1、在TD上查看该输入框字数限制,在前端标签中调整maxlength长度限制,或pattern.js中该字段的长度限制(二选一即可,如两者都加,注意对应)
![debug1](../assets/images/debug1.png)
![debug2](../assets/images/debug2.png)
#### 文本框字数限制
名称地址栏等多行文本框中英文字数限制问题:
使用提供的4x35这种格式的基础控件<c-mul-row-input>,支持过滤纯英文,swift、swiftz字符集,默认中文算两个长度,
达到每行规定输入的字符数后会自动换行。
*传参:*
`:rows`:可输入行数;
`:cols`:每行最多字符数,中文占两个字符,空格及标点符号占一个字符;
示例:
```
<c-col :span="24">
<el-form-item label="地址信息" prop="cpdgrp.orc.pts.adrblk">
<c-mul-row-input
v-model="model.cpdgrp.orc.pts.adrblk"
:rows="4"
:cols="35"
placeholder="请输入地址信息"
></c-mul-row-input>
</el-form-item>
</c-col>
```
### 输入框是否可编辑(灰显)
1、在TD上查看对应的输入框
![disabled1](../assets/images/disabled1.png)
2、在前端对应输入框加上disabled属性
![disabled2](../assets/images/disabled2.png)
### check检验不通过
#### check检验无提示
通不过,在浏览器控制台查看哪些字段check未通过,在该字段的前端页面用el-form-item标签包起来,且检查是否有prop.
![check4](../assets/images/check4.png)
![check5](../assets/images/check5.png)
#### check隐藏的字段
td上找到该字段的check方法
![check6](../assets/images/check6.png)
![check7](../assets/images/check7.png)
![check8](../assets/images/check8.png)
在TD及新国结进入此check方法的入口条件处打断点,新国结与TD都触发,走到断点处,对比新国结和TD不同之处,为什么新国结进入了此check方法,常见有invisable在TD上有置不可见的字段为disabled功能,而新国结上此功能未实现。
### 金额输入框
1、金额输入框只能输入非负数且靠右显示,保留两位小数:前端标签用`c-input-currency`
若要靠左显示,加`class="input-currency-left"`
示例:(`maxlength="xx"`可根据Td上的长度限制自己调整,或可在pattern.js中调整max,二选一即可,如两者都加,注意对应)
```html
<c-col :span="24">
<el-form-item label="承兑金额" prop="cnybop.fexchangeamt">
<c-input-currency
v-model="model.cnybop.fexchangeamt"
maxlength="20"
placeholder="请输入承兑金额"
></c-input-currency>
</el-form-item>
</c-col>
```
(因`c-input-currency`标签限定了非负及保留两位小数,故在pattern.js中此字段
```html
{type: "string", required: false, message: "必输项"},
{max: 18,message:"整数位不能超过14位"},
{pattern: /(^\d+$)|(^\.\d{1,3}$)|(^\d+\.\d{1,3}$)/, message: "小数位不能超过3位" }`
```
应调为整:
```html
{type: "string", required: false, message: "必输项"},
{max: 17,message:"整数位不能超过14位"}`
```
2、金额输入框可输入正负及0且靠右显示,保留两位小数:前端标签用`c-input-currency-min`
若要靠左显示,加`class="input-currency-left"`
3、金额输入框失去焦点会自动触发默认default方法,想要其回车时也触发:
若直接在前端页面该字段手动加回车触发default,当回车后会触发,但失去焦点后又会重复触发,为避免重复触发,可用
`@keyup.enter.native="$event.target.blur()"` :回车触发失去焦点发生的事件(若失去焦点手动触发其他事件,可再加`@blur="xxxxxxx"`)
示例:
```html
<c-col :span="12">
<c-form-item previewLabel="信用证金额" style="text-align: left" label-width="5px" prop="gcdgrp.cbs.max.amt">
<c-input-currency v-model="model.gcdgrp.cbs.max.amt" placeholder="请输入信用证金额" @keyup.enter.native="
defaultFunction('gcdgrp.cbs.max.amt', model.gcdgrp.cbs.max.amt)
"></c-input-currency>
</c-form-item>
</c-col>
上面加了回车手动触发自己字段的默认default方法,当失去焦点后会重复出发。改为使用@keyup.enter.native="$event.target.blur()",如下:
<c-col :span="12">
<c-form-item previewLabel="信用证金额" style="text-align: left" label-width="5px" prop="gcdgrp.cbs.max.amt">
<c-input-currency v-model="model.gcdgrp.cbs.max.amt" placeholder="请输入信用证金额" @keyup.enter.native="$event.target.blur()"></c-input-currency>
<!-- @keyup.enter.native="$event.target.blur()" :回车触发失去焦点发生的事件 -->
</c-form-item>
</c-col>
```
4、金额修改时输入一个数后,自动补齐小数点,且光标立即跳到输入框最后面,输入不正常:
一般为同一个交易中,同一页面或不同页面有两个一样的此金额字段,一个能输入修改,另一个为disabled,两个都用了`c-input-currency``c-input-currency-min`标签
将disabled的那个金额输入框改用`c-input`标签,加`class="m-input-currency"`,如:
```html
<c-col :span="9">
<c-form-item previewLabel="信用证金额" style="text-align: left" label-width="5px" prop="gcdgrp.cbs.max.amt">
<c-input disabled v-model="model.gcdgrp.cbs.max.amt" placeholder="请输入" class="m-input-currency"></c-input>
</c-form-item>
</c-col>
```
### 数据丢失
#### 交易数据丢失
新国结进入交易后,切换page页,进入交易携带的数据丢失:在index.vue中加name值
![进入交易后缓存数据](../assets/images/进入交易后缓存数据.png)
#### 输入框数据丢失
检查控制台该字段是否有值
![dataloss1](../assets/images/dataloss1.png)
若是前端未将后端返回的数据更新到页面上:检查方法是否缺少updateModel方法;检查前端该字段是否写错,该交易的index.js中是否正确定义了该字段
![dataloss2](../assets/images/dataloss2.png)
若是控制台上后端返回的该字段的数据不正确,检查后端VO,前端页面及index.js该字段是否写错;对照TD找到该字段的值是什么时机出现的,找到触发的方法,
哪句代码给该字段赋值,在新国结后端代码上找到对应代码,打上断点,debug模式下,触发该方法,对照TD看新国结后端代码该处哪个数据和TD对不上,往回找值的源头,
为什么对不上,找到新国结上哪行代码,哪个方法出了问题,然后解决,改正后,验证是否解决问题。
**注意:**由转换工具生成且会覆盖的代码修改时,在bdproject中找到对应的script文件,在script文件中修改,具体参考:
* 修改代码位置参考
![修改代码位置参考](../assets/images/修改代码位置参考.png)
* TD上定位该字段值什么时候赋值,哪行代码赋的值:
![dataloss3](../assets/images/dataloss3.png)
![dataloss4](../assets/images/dataloss4.png)
![dataloss5](../assets/images/dataloss5.png)
![dataloss6](../assets/images/dataloss6.png)
![dataloss7](../assets/images/dataloss7.png)
![dataloss8](../assets/images/dataloss8.png)
![dataloss9](../assets/images/dataloss9.png)
![dataloss10](../assets/images/dataloss10.png)
* 后端debug模式下调试代码
![dataloss11](../assets/images/dataloss11.png)
This source diff could not be displayed because it is too large. You can view the blob instead.
## 后端项目整体介绍 # 后端项目整体介绍
## 后端项目整体介绍 # 后端项目整体介绍
#### 项目结构介绍 ## 项目结构介绍
gjjs-business模块文件结构 gjjs-business模块文件结构
![backenddev1](../assets/images/backenddev1.png) ![backenddev1](../assets/images/backenddev1.png)
#### 项目流程介绍 ## 项目流程介绍
##### 1.请求流程 ### 1.请求流程
![image-20210918165941920](../assets/images/gjjs-common2.png) ![image-20210918165941920](../assets/images/gjjs-common2.png)
...@@ -17,7 +17,7 @@ gjjs-business璅∪辣蝏 ...@@ -17,7 +17,7 @@ gjjs-business璅∪辣蝏
##### 2.Service与Rule如何调用 ### 2.Service与Rule如何调用
1)AbstractRouteService是service层最上层抽象类,对一些基本公共方法(init、executeRule、executeDefault等,这些方法基本每个交易都会去调用)做了实现,保证执行流程的统一,通过getEmitter这个抽象方法来实现多态(子类通过实现这个方法来处理不同业务逻辑,不用去关心具体的执行流程) 1)AbstractRouteService是service层最上层抽象类,对一些基本公共方法(init、executeRule、executeDefault等,这些方法基本每个交易都会去调用)做了实现,保证执行流程的统一,通过getEmitter这个抽象方法来实现多态(子类通过实现这个方法来处理不同业务逻辑,不用去关心具体的执行流程)
...@@ -31,7 +31,7 @@ gjjs-business璅∪辣蝏 ...@@ -31,7 +31,7 @@ gjjs-business璅∪辣蝏
![](../assets/images/hdservicerule1.png) ![](../assets/images/hdservicerule1.png)
##### 3.Emitter的方法分类 ### 3.Emitter的方法分类
RuleEmitter大概有4类方法,分别是 RuleEmitter大概有4类方法,分别是
...@@ -43,9 +43,9 @@ executeDefault 嚗efault rule嚗 ...@@ -43,9 +43,9 @@ executeDefault 嚗efault rule嚗
executeCheck (参数、数据校验类rule) executeCheck (参数、数据校验类rule)
##### 4.消息体格式说明 ### 4.消息体格式说明
###### 请求消息体 #### 请求消息体
请求消息体是一个json格式数据,数据格式形如 请求消息体是一个json格式数据,数据格式形如
![](../assets/images/qqxxt2.png) ![](../assets/images/qqxxt2.png)
...@@ -63,7 +63,7 @@ executeCheck (撉掩rule) ...@@ -63,7 +63,7 @@ executeCheck (撉掩rule)
![请求实体类](../assets/images/请求实体类.png) ![请求实体类](../assets/images/请求实体类.png)
###### 响应消息体 #### 响应消息体
响应消息体是一个json格式数据 响应消息体是一个json格式数据
结果成功响应数据格式形如 结果成功响应数据格式形如
...@@ -101,7 +101,7 @@ executeCheck (撉掩rule) ...@@ -101,7 +101,7 @@ executeCheck (撉掩rule)
##### 5.VO的规范 ### 5.VO的规范
VO类是前后端数据请求和响应的实体类,VO有一个共同父类VO(BaseVO),字段说明如下: VO类是前后端数据请求和响应的实体类,VO有一个共同父类VO(BaseVO),字段说明如下:
...@@ -110,9 +110,9 @@ VO蝐餅垢霂瑟掩嚗O銝芸蝐蓆O嚗 ...@@ -110,9 +110,9 @@ VO蝐餅垢霂瑟掩嚗O銝芸蝐蓆O嚗
VO按照交易进行划分,一个交易对应一个VO(比如信用证开证交易对应VO是DitopnVO),VO类使用了lombok插件,不需要set get方法,字段用RelPath注解区分是请求字段还是响应字段(默认没有注解,代表dir属性值是DirType.BOTH,及请求和响应都需要该字段;如果只是请求字段,dir属性值是DirType.IN;如果是相应字段,dir属性值是DirType.OUT),如图: VO按照交易进行划分,一个交易对应一个VO(比如信用证开证交易对应VO是DitopnVO),VO类使用了lombok插件,不需要set get方法,字段用RelPath注解区分是请求字段还是响应字段(默认没有注解,代表dir属性值是DirType.BOTH,及请求和响应都需要该字段;如果只是请求字段,dir属性值是DirType.IN;如果是相应字段,dir属性值是DirType.OUT),如图:
![](../assets/images/vogf1.png) ![](../assets/images/vogf1.png)
##### 6.前后台事件关联方式 ### 6.前后台事件关联方式
###### 调用普通Module下事件 #### 调用普通Module下事件
例如: 例如:
...@@ -128,7 +128,7 @@ if (rtnmsg.respCode == SUCCESS) { ...@@ -128,7 +128,7 @@ if (rtnmsg.respCode == SUCCESS) {
(2) 同样的,账务面板中的”细节”按钮,对应(Module)setmod中的det事件。使用··``` await this.executeRule(“setmod.det”)```方式调用。 (2) 同样的,账务面板中的”细节”按钮,对应(Module)setmod中的det事件。使用··``` await this.executeRule(“setmod.det”)```方式调用。
###### 调用ModuleList选中行事件 #### 调用ModuleList选中行事件
例如:账务 Own Commission/Charges 列表,对应模型setmod/setfeg/setfel(ModuleList)。每行数据对应ModuleList中的一个setfel实例。 例如:账务 Own Commission/Charges 列表,对应模型setmod/setfeg/setfel(ModuleList)。每行数据对应ModuleList中的一个setfel实例。
...@@ -136,8 +136,8 @@ if (rtnmsg.respCode == SUCCESS) { ...@@ -136,8 +136,8 @@ if (rtnmsg.respCode == SUCCESS) {
前后台对应关系: 前后台对应关系:
| 前台: | VO | Module | | 前台: | VO | Module |
| :---------------------------------------: | :------------------------------------------: | :------------------: | |:-------------------------------------:|:-------------------------------------------:|:--------------------:|
| Setpan.Vue:账务Own Commission/Charges列表 | DitopnVO:List<Setfel> setmod_setfeg_setfel; | setmod/setfeg/setfel | | Setpan.Vue:账务Own Commission/Charges列表 | DitopnVO:List<Setfel> setmod_setfeg_setfel; | setmod/setfeg/setfel |
Details按钮在后台对应的事件rule 为”del”,当按钮被点击时,应当通过以下方式触发相应事件: Details按钮在后台对应的事件rule 为”del”,当按钮被点击时,应当通过以下方式触发相应事件:
...@@ -151,14 +151,14 @@ if (rtnmsg.respCode == SUCCESS) { ...@@ -151,14 +151,14 @@ if (rtnmsg.respCode == SUCCESS) {
} }
``` ```
###### 事件在普通模型下,但实际处理ModuleList选中行 #### 事件在普通模型下,但实际处理ModuleList选中行
例如:保证金模块中的保证金列表。对应数据模型为:(ModuleList)liaall/liaccv/liaccvg ;但删除操作按钮的对应事件是在(Module)liaall/liaccv模型下的del 例如:保证金模块中的保证金列表。对应数据模型为:(ModuleList)liaall/liaccv/liaccvg ;但删除操作按钮的对应事件是在(Module)liaall/liaccv模型下的del
![](../assets/images/delete.png) ![](../assets/images/delete.png)
| 前台: | VO | Module | | 前台: | VO | Module |
| :--------: | :-------------------------------------------: | :-------------------: | |:----------:|:--------------------------------------------:|:---------------------:|
| Ccvpan.vue | DitopnVO:List<Setfel> liaall_liaccv_liaccvg; | liaall/liaccv/liaccvg | | Ccvpan.vue | DitopnVO:List<Setfel> liaall_liaccv_liaccvg; | liaall/liaccv/liaccvg |
删除按钮事件调用方式: 删除按钮事件调用方式:
...@@ -173,7 +173,345 @@ if (rtnmsg.respCode == SUCCESS) { ...@@ -173,7 +173,345 @@ if (rtnmsg.respCode == SUCCESS) {
} }
``` ```
###### 事件在普通模型下,但实际处理IStream选中行 #### 事件在普通模型下,但实际处理IStream选中行
此种情况参考"ModuleList选中行"的处理,只需把selDst的值指向IStream即可。 此种情况参考"ModuleList选中行"的处理,只需把selDst的值指向IStream即可。
## 运行机制介绍
### 1、缓存
​ MdaContext作为交易的上下文,在交易初始化时生成,在页面中一个交易的初始化后,后面的请求操作都应使用该MdaContext,故而将MdaContext在生成时放入缓存中,key是UUID生成的随机字符串串pageId。在后续的进入交易时,会先根据pageId取出context,并将context放入ThreadLocal,供后续的方法使用;若取出的context为空,则为执行init初始化交易,生成context并放入ThreadLocal。
### 2、Context
​ MdaContext实现IContext接口,每个交易都有一个MdaContext,在页面初始化时,会执行init操作,生成一个MdaContext,该context存有交易的根模块、交易名、配置信息、快照、错误信息等,通过ThreadLocal来传递。
### 3、sysStream
​ SysStream是一个StreamImpl实例,StreamImpl实现了IStream接口,IStream接口主要是控制字节数组的输入流和输出流。sysStream存放的交易中涉及到的各个模块。
### 4、init
#### (1)初始化规则
​ 在系统尝试执行可选全局过程`EnterTransaction`之后和执行可选全局过程`InitTransaction`之前,在事务启动时执行此类规则。
事务中所有模块实例的 INIT 规则都是递归执行的。每个模块首先执行所有相关模块的 INIT 规则(只有当底层模块中的所有 INIT 都被调用时才会执行),然后是它自己的。因此,事务的 INIT 规则在相关模块的所有其他 INIT 规则之后执行。
#### (2)事务启动期间规则的执行顺序
1.如果存在,则调用全局过程“SUB EnterTransaction”。
2.执行事务中所有模块实例的 INIT 规则。
3.如果已定义,则调用全局过程“SUB InitTransaction”
4.执行事务中所有对象的 DEFAULT 规则。
即:EnterTransaction -> Module Inits -> InitTransaction -> Defaults
### 5、executeCheck
#### (1)检查规则
​ executeCheck用于验证字段字和内容的一致性。可以为(列表的)字段或模块定义检查规则。
#### (2)触发时机
​ 1.当使用键盘按下"Enter"或者失去焦点时
​ 2.当为(列表)模块或字段调用 CheckAll 函数时
#### (3)其他规则
​ 一般情况下,检查规则不能修改任何字段的值。
### 6、executeRule
#### (1)触发时机
​ 前端事件执行executeRule时触发,需要至少提供一个路径,后端根据此路径执行相应的rule后返回。若存在多个路径,则顺序执行
#### (2)执行顺序
​ EVENT --> DEFAULT(s) --> CHECK(s)。当存在多个路径时,每个路径都属于独立的模块,只有一个路径的所有EVENT、DEFAULT、CHECK执行完成后下一路径才会顺序被执行。
### 7、executeDefault
#### (1)默认规则
​ 所有Default规则在事务开始时执行3遍(作为事务启动序列的最后一步)。此外,只要前端任意字段的值发生改变,就会执行默认规则
### 8、set方法触发defaultRule机制
​ 执行任意字段的set方法时,若传过来的新值与旧值不同,则在部分情况下需要执行对该字段进行了引用的所有default规则。
​ 1.该机制是否触发由DCR开关控制,详情请见`DCR说明`
​ 2.字段被引用的default规则由`resources/defaultRule`中定义的码表获取
### 9、队列执行
#### invokeExpress产生的队列
##### (1)产生
​ 由invokeExpress方法产生。当invokeExpress方法被调用且delay参数值不小于0时,该方法中需要被执行的rule会被加入到"tdContextPOSTQUEUE"队列中。
##### (2)执行清空
​ 1.Init过程产生的队列,会在初始化结束前作为最后一个步骤被执行,且执行完成后清空
​ 2.Vo给模型赋值产生的队列,在赋值完成后被立即执行,且执行完成后清空
​ 3.执行Rule产生的队列,会在执行Rule过程结束前作为最后一个步骤被执行(若存在多个Rule,则在每个Rule的最后均会执行),且执行完成后清空
#### set方法触发的DefaultRule队列
##### (1)产生
​ 详情请看`set方法触发defaultRule机制`,该机制产生的方法不会被立即执行
##### (2)执行
​ 1.请求为executeCheck,则作为每个executeCheck方法的最后一个步骤被执行
​ 2.请求为executeDefault,则作为每个executeDefault方法的最后一个步骤被执行
​ 3.请求为executeRule,则作为每个executeRule方法中invokeExpress产生的队列被执行前的前一个步骤执行
## 核心类介绍
### 1、DCR说明
#### (1)默认说明
​ DCR开关用于控制set方法是否会触发相应的defaultRule。DCR开关默认情况下为关闭状态,
#### (2)开关状态
​ 1.Init结束后,DCR开关打开
​ 2.Vo向模型赋值时将DCR开关打开
​ 3.执行executeDefault时,若DCR开关为打开状态,则需要将开关临时关闭。结束后将开关恢复成执行前状态
​ 4.进行数据库查询操作时,若DCR开关为打开状态,则需要将开关临时关闭。结束后将开关恢复成执行前状态
​ 5.调用copyValues方法实现模型深拷贝时,若DCR开关为打开状态,则需要将开关临时关闭。结束后将开关恢复成执行前状态
​ 6.调用ObjectMapper.readValue方法实现json字符串转Java对象时,若DCR开关为打开状态,则需要将开关临时关闭。结束后将开关恢复成执行前状态
### 2、MdaDriver说明
| 函数 | 描述 |
|----------------------------------------------------------------------------------------------------------|--------------------------------------|
| IBaseObject getBaseObject(IModule root, String target, boolean helpLoad) | 通过路径获取上下文中的IBaseObject 对象 |
| IBaseObject getBaseObject(IModule root,String target) | 通过路径获取上下文中的IBaseObject 对象 |
| DatafieldImpl getDatafield(IModule root, String target) | 通过路径获取上下文中的DatafieldImpl 对象 |
| DatafieldImpl getDatafield(String target) | 通过路径获取上下文中的DatafieldImpl 对象 |
| IModule getModule(IModule root,String target) | 通过路径获取上下文中的IModule 对象 |
| IModule getModule(String target) | 通过路径获取上下文中的IModule 对象 |
| T getModule(String target,Class<T> clazz) | 通过路径获取上下文中的clazz对象 |
| IModuleList getModuleList(IModule root,String target) | 通过路径获取上下文中的IModuleList 对象 |
| IModuleList getModuleList(String target) | 通过路径获取上下文中的IModuleList 对象 |
| void copyValues(Object target,Object src) | 深拷贝src 到target |
| void clearModule(IModule module) | 清空模型信息 |
| Object zero(Class<?> clazz) | 清空基本类型和BigDecimal |
| String getModuleType(IModule m) | 获取模型类型 |
| void setFieldValue(Field field,Object value) | 空方法 |
| void setValueFromVO(IContext ctx,T vo) | 将VO中的值设置到上下文 |
| setValueFromVoByClass(IModule root,Object vo,Class clazz,String parent) | 根据class将VO的值赋予IModule |
| void setValueFromVO(IModule root,Object vo,String parent) | 将VO中的值赋予IModule |
| Field getParentField(Object parent,String fieldstr) | 获取parent字段中的fieldstr字段 |
| List<String> getSubModuleTypes(IModule module) | 获取模型中所有属于自己子类的类型 |
| setFieldValue(Field from,Object fromObj,Field to,Object toObj, boolean voToMod) | 将对象字段设置到对应的字段中,true 表示从VO到ctx(写入上下文) |
| T getFieldValue(Object o,String fieldName) | 获取对应字段的值 |
| void setValueToVO(IContext ctx,T vo) | 将ctx内容写入到VO |
| void setValueToVoByClass(IModule root,Object vo,Class clazz,String parent) | 根据class将IModule的值赋予VO |
| void setValueToVO(IModule root,Object vo,String parent) | 将IModule的值赋予VO |
| Map<String,T> translateMapByVoAnotation(String transKey, boolean pathToAlias, Map<String,T> map) | 将map中所有键转化为别名 |
| String getPathAlias(String trnnam,String path) | 获取路径别名 |
| String getAliasPath(String trnnam,String aliasName) | 根据别名获取路径 |
| void createVoSetterAndGetter(Set<Class<?>> clsSet) | 根据交易上的注解,生成别名与长路径的映射 |
| void processTransAnotion(Class<?> trnCls) | 根据交易上的注解,生成别名与长路径的映射 |
| void processTransAnotion(Class<?> trnCls,Class<?> voCls,String modPath,String voPath) | 根据交易上的注解,生成别名与长路径的映射 |
| boolean isFieldPathExist(Class<?> trnCls,String path) | 空方法 |
| String getTransName(Class<?> trnCls) | 获取交易名 |
| String firstUpper(String s) | 将首字母大写 |
| Map<String,String> getErrorMap(IContext ctx,Class voClazz) | 获取错误信息map |
| String getModuleInfo(IModule module, int getterType) | 获取模型信息 |
| void getModuleInfoStream(IStream out,IModule module,int getterType) | 将模型信息写入IStream |
| void getModuleInfoStream(IStream infostream, IModule mod, int type, String match) | 将模型信息写入IStream |
| void getModuleInfoStreamMethodWalk(IStream infostream, Class moduleClass,String prefixPath,String match) | 将模型信息写入IStream |
### 3、MdaEnv说明
| 函数 | 描述 |
|----------------------------------------------------|-----------------|
| T getBean(String beanId,Class<T> clazz) | 根据类型和名称获取对应Bean |
| T getBean(Class<T> clazz) | 根据类型获取Bean |
| Object getBean(String beanId) | 根据名称获取Bean |
| void setContext(IContext ctx) | 设置上下文 |
| IContext getContext() | 获取上下文 |
| void rmContext() | 删除上下文 |
| void clearContext() | 清空所有上下文和认证信息 |
| void clear(Object object) | 清空对象 |
| boolean isEmpty(Object obj) | 判空 |
| void setAuthInfo(IAuthInfo authInfo) | 设置认证信息 |
| IAuthInfo getAuthInfo() | 获取认证信息 |
| String getLoginUser() | 获取登录用户信息 |
| String getEncoding() | 获取编码格式 |
| void setEncoding(String encoding) | 设置编码格式 |
| void setLang(String lang) | 设置语言 |
| String getLang() | 获取语言 |
| T getSessionContextValue(String key) | 获取用户上下文 |
| void setSessionContext(String key , Object... obj) | 设置用户会话上下文 |
| void clearSessionContext(String uid) | 清空指定用户会话上下文 |
| String getRootPath() | 获取根路径 |
| void removeAuthInfo() | 移除认证信息 |
| void removeAttrs() | 移除所有属性 |
| void setAttribute(String key,Object obj) | 设置属性 |
| Object getAttribute(String key) | 获取对应属性值 |
| String getSessionId() | 获取会话id |
### 4、自定义注解使用说明
#### Init
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Init {
int order() default 100;
}
```
##### 使用说明
@Init 用于修饰模块中的方法,表明该方法执行于初始化,order表示初始化的顺序。
#### Check
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
int order() default 100;
String target() default "";
String[] value() default {};
}
```
##### 使用说明
@Check 用于修饰模块中的方法,表明该方法执行于校验阶段,验证修改的字段属性是否合法,order表示校验的顺序,target、value表示验证的属性,
#### Default
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Default {
int order() default 100;
String target() default "";
String[] value() default {};
}
```
##### 使用说明
@Default 用于修饰模块中的方法,表明该方法执行于默认规则阶段,模块指定的字段值发生改变时会触发,order表示执行的顺序,target、value表示指定的属性,
#### Rule
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Rule {
String target() default "";
int order() default 100;
String[] value() default {};
}
```
##### 使用说明
@Rule 用于修饰模块中的方法,表明该方法执行于触发事件阶段,order表示执行的顺序,target、value表示执行的的属性。
#### RelPath
##### 定义
```java
@Documented
@Retention(RUNTIME)
@Target({TYPE,FIELD})
public @interface RelPath {
String value() default ""; //路径
DirType dir() default DirType.BOTH ; //输入输出方向
boolean recursion() default false; //是否递归关联
}
```
##### 使用说明
@RelPath 用于修饰VO中的字段,value表明该字段对应交易模块下的属性,dir声明该字段是否能被读取或是赋值。
#### TDMethod
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TDMethod {
boolean value() default true;
}
```
##### 使用说明
@TDMethod 用于修饰模块中的方法,表明该方法是TD的上Method
#### TDStatic
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TDStatic {
boolean value() default true;
}
```
##### 使用说明
@TDStatic 用于修饰模块中的方法,表明该方法是TD的上Static
#### Transaction
##### 定义
```java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Transaction {
String value() default "";
Class<?> vo() default EmptyVO.class;
}
```
##### 使用说明
@Transaction 修饰于模块类上,表明该类是个交易类
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment