Aurora开发备忘
Aurora开发备忘
Aurora框架主要编辑的文件包括bm数据库操作文件(类比mapper文件)、oracle数据库包pkg文件(类比java文件)、screen界面展示文件(类比jsp文件)。学习中,持续更新…
1 screen文件
一个screen文件的基本的格式如下:
<?xml version="1.0" encoding="UTF-8"?>
<a:screen xmlns:a="http://www.aurora-framework.org/application" trace="true">
<a:init-procedure>
<!--界面显示前,服务器端执行查询,结果放在rootPath里面,界面可通过/model/acc_entity路径取值-->
<a:model-query fetchAll="true" model="hec_util.gld_accounting_entities_vl_lov" rootPath="acc_entity"/>
</a:init-procedure>
<a:view>
<a:link id="CON2000_req_detail_show_link" url="${/request/@context_path}/modules/pur/PUR7010/pur_requisition_view_main.screen"/>
<script><![CDATA[
//此处是写前端js脚本的位置,语法遵循Ext框架以及,Aurora对Ext的扩展
]]></script>
<a:dataSets>
<!--dataSets下面配置界面上要用到的数据源,一般有3种来源:指向某个bm文件、前文提到”init-procedure“查询结果、系统描述”lookupCode“(数据来源是类似项目国际化的配置文件,不过这里的国际化数据是存到数据库里面的)-->
<a:dataSet id="CON2000_accEntityDs">
<a:datas dataSource="/model/acc_entity"/>
</a:dataSet>
<a:dataSet id="CON2000_yes_no_ds" lookupCode="YES_NO"/>
<a:dataSet id="CON2000_typeChoiceAccEntityDs" loadData="true" model="hec_util.gld_accounting_entities_vl_lov"/>
</a:dataSets>
<a:screenTopToolbar>
<!--界面按钮:增删查改、导出、打印等-->
<a:gridButton bind="CON2000_grid" type="save"/>
</a:screenTopToolbar>
<!--可提交的表单-->
<!-- bindTarget:(官网注释:需要绑定的DataSet的ID)组件展示数据的数据来源ds,会作为查询条件; resultTarget:(官网注释:映射的DataSet)表单查询结果映射到的目标结果集,其实也是一个ds,查询结果刷新这个ds的值-->
<a:queryForm bindTarget="CON2000_con_contract_query_ds" resultTarget="CON2000_con_contract_query_result_ds">
<!--表单元素(查询条件)-->
<a:formToolBar>
<a:textField name="partner_name" bindTarget="CON2000_con_contract_query_ds"/>
</a:formToolBar>
<!--扩展元素(查询条件)-->
<a:formBody column="4">
<a:multiComboBox name="contract_status_name" bindTarget="CON2000_con_contract_query_ds"/>
</a:formBody>
</a:queryForm>
<!--动态表格-->
<a:grid id="CON2000_grid" bindTarget="CON2000_con_contract_query_result_ds" marginHeight="115" marginWidth="3" navBar="true">
<!--底部表格工具-->
<a:toolBar>
<a:button type="delete"/>
</a:toolBar>
<!-- 表格列 -->
<a:columns>
<a:column name="contract_number" align="center" renderer="CON2000_conRenderer" sortable="true" width="120"/>
<a:column name="stamp_duty_type_name" align="center" editorFunction="CON2000_stampDutyTypeEditorFunc" width="120"/>
<a:columns>
<!--为表格中可编辑的列,增加编辑组件-->
<a:editors>
<a:textArea id="CON2000_ta"/>
</a:editors>
</a:grid>
</a:view>
</a:screen>
更多界面标签组件描述可参见官方文档:Aurora官方tag文档
1.1 字段只读
为字段标签加上readOnly="true"属性。可以加到dataSet里面,也可直接加到界面组件上。如果界面组件是column,默认是不可编辑的,readOnly="true"可以加到column的editor上。
加到数据源dataSet上:
<a:dataSet id="SEL0010_receiptHeaderDs" submitUrl="${/request/@context_path}/modules/sel/SEL0010/sel_negotiate_report_save.svc">
<a:datas dataSource="/model/headerInfo"/>
<a:fields>
<a:field name="sel_type_desc" prompt="BGT_BALANCE_RUNNING_PARAMETERS.DOCUMENT_TYPE" readOnly="true"/>
</a:fields>
</a:dataSet>
界面组件是表单form,加到界面组件上:
<a:screenBody>
<a:form id="SEL0010_receiptMainForm" column="1" marginWidth="0" title="${/model/headerInfo/record/@item_type_name}">
<a:box column="4" style="width:100%">
<a:textField name="sel_type_desc" bindTarget="SEL0010_receiptHeaderDs" readOnly="true"/>
</a:box>
</a:form>
</a:screenBody>
界面组件是表格grid的列,加到editor上。editor相当于是在列上定义一个表单组件,用于编辑单元格。
在js中处理只读:
var h_info = $au('header_info_ds').getAt(0);
h_info.getMeta().getField('description').setReadOnly(false);
//似乎也可以这样
h_info.getField('description').setReadOnly(false);
1.2 lov 弹出式选择框,带查询按钮和查询条件
动态设置查询条件
<style><![CDATA[
.reqnumberlov {
color: #005a78;
text-decoration: none;
cursor: pointer;
}
.reqnumberlov:hover {
color: #ff9900;
text-decoration: none;
}
]]></style>
...
...
<!--className属性同html标签添加class样式一样-->
<a:lov name="source_contract_number" id="source_contract_number_lov" bindTarget="CON1050_contract_header_maintain_ds" className="reqnumberlov" prompt="CON.MAIN_CONTRACT">
<a:events>
<a:event name="focus" handler="source_contract_number_func2"/>
</a:events>
</a:lov>
function source_contract_number_func2(){
var record = $au('CON1050_contract_header_maintain_ds').getAt(0);
record.getField('source_contract_number').setLovPara('acc_entity_id', record.get('acc_entity_id'));
if('${/model/header_info/record/@contract_attribute}'=='MATERIAL'){
//修改查询用的bm
record.getField('source_contract_number').setLovService('cont.CON1050.con_contract_source_headers_infor_lov2');
//设置bm中的查询参数
record.getField('source_contract_number').setLovPara('partner_id', record.get('partner_id'));
//设置lov弹出框的标题
record.getField('source_contract_number').setTitle('主合同编号');
}
}
注意:此处lov组件是位于表单控件内的,即xxx_ds作为一个form的数据源,一个field对应的值只有一个。还有种情况是,xxx_ds 作为一个grid的数据源,一个field对应一个grid的列,field对应的值是一个集合,lov嵌入到这一列的每一行的column中。那么,通过$au{‘xxx_ds’).getAt(0),只能获取到第一行的数据。如何获取当前行的其它列的值作为查询条件呢?
1、通过查阅Aurora-all.js 。上面handler方法中可以加一个入参,参数是当前组件Component即当前lov。我们可以从当前组件中获取到当前行的record。也可以通过当前组件更新lov入参。
界面代码:
<a:grid id="doctype_relation_grid" bindtarget="doctype_relation_result_ds">
<a:columns>
...
<a:column name="hec_doc_code" align="center" editor="hec_doc_code_lov"/>
...
</a:columns>
<a:editors>
<a:lov id="hec_doc_code_lov">
<a:events>
<a:event name="focus" handler="ACP3101_onDocTypeFocusFun"/>
</a:events>
</a:lov>
</a:editors>
</a:grid>
js代码
function ACP3101_onDocTypeFocusFun(cmp){
var hec_doc_type_code=cmp.record.get('hec_doc_type_code');
if(hec_doc_type_code){
cmp.para.hec_doc_category=hec_doc_type_code;
}
}
2、将focus事件改成cellclick事件,加到grid上。在handler中通过行列的判断,cellclick事件的入参带record(行数据)、row(行)等。拿到了当前行的record,就可以按1.2中最开始的方法处理了。
<a:grid id="CSH5010_csh_payment_requisition_grid" autoAdjustHeight="true" bindTarget="CSH5010_pay_req_create_line_ds" gridskin="gridskin" marginHeight="350" marginWidth="12" navBar="true" style="margin-top:-4px;">
<a:columns>
</a:columns>
<a:editors>
...
</a:editors>
<a:events>
<a:event name="cellclick" handler="CSH5010_onPaymentReqLineCellClickFun"/>
</a:events>
</a:grid>
通过js除了可以动态处理lov的查询语句、查询参数、查询弹出框的标题等。还可以设置查询结果,字段的对应关系。
function CSH5010_onPaymentReqLineCellClickFun(grid, row, name, record) {
//这里是在grid的cellclick事件方法中,入参带有当前行的record数据
var payment_req_type_code = '${/model/header_info/record/@payment_req_type_code}';
if (name == 'acc_entity_name' && payment_req_type_code == 'WCSH0020'){
var account_mapping = [{
from: 'acc_entity_id',
to: 'acc_entity_id'
}, {
from: 'acc_entity_code',
to: 'acc_entity_code'
},
...
{
from: 'gl_account_name',
to: 'gl_account_name'
}
];
record.getField('acc_entity_name').setLovService('hec_util.gld_acc_entities_payee_vl_lov');
record.getField('acc_entity_name').setLovPara('company_id', record.get('company_id'));
//设置查询结果字段和field字段的映射关系
record.getField('acc_entity_name').setMapping(account_mapping);
}
}
1.3 通过 js手动执行dataSet中的查询
通过js手动执行一个dataSet的查询,此操作方便手动改变查询条件。引用此数据源的界面也会随查询结果动态变化。
$au('SEL0010_attach_record_ds').setQueryParameter('sel_negotiate_type_id', record.get('sel_negotiate_type_id'));
$au('SEL0010_attach_record_ds').setQueryParameter('enable_flag', 'Y');
$au('SEL0010_attach_record_ds').query();
关于dataSet的方法,可参见Aurora官方文档:Aurora官方js文档 当然有时候他们官网会挂。。。那就直接翻源码吧:Aurora-all.js
1.4 在js中获取系统描述
系统描述,是系统框架集成的,类似国际化配置,也可以当作字典。通过:${l:key} key为系统描述中的描述字段
if (typeId && record.get('requirement_source_type') != 'MANUAL') {
return '<a href="javascript:CON1010_assign_req_typeInfo(' + typeId + ')">${l:CON_MO_CONTRACT_TYPES_VL.ASSIGN_REQ_TYPE}</a>';
}
1.5 自定义数据校验
主要参考校验函数的写法
组件上加validator属性,值是校验函数的名字
<a:dataSet id="SEL0010_assets_discard_line_ds" autoQuery="true" bindName="assets_discard_lines" bindTarget="SEL0010_receiptHeaderDs" model="sel.SEL0010.sel_assets_discard_lines" queryUrl="${/request/@context_path}/autocrud/sel.SEL0010.sel_assets_discard_lines/query?sel_negotiate_header_id=${/model/headerInfo/record/@sel_negotiate_header_id}" selectable="true" submitUrl="${/request/@context_path}/autocrud/sel.SEL0010.sel_assets_discard_lines/batch_update">
<a:fields>
<a:field name="assets_number" lovService="sel.SEL0010.sel_asset_number_no_ref_query_lov" required="true" title="资产编号选择" validator="numsRepeatValidator"/>
</a:fields>
</a:dataSet>
在js里面增加校验函数,返回字符串,会提示到界面,返回true会校验成功,校验函数会在控件失去焦点和表单提交时触发。如果校验失败(返回非true),失去焦点触发->悬停提示框提示。表单提交触发->弹框提示,表单提交会被终止。
function numsRepeatValidator(record, name, value){
var records = $au('SEL0010_assets_discard_line_ds').getAll();
if(records.length>1){
for(var i=0;i<records.length;i++){
if(records[i].get('assets_number')==value&&records[i].get('line_number')!=record.get('line_number')){
return 'xxxx有重复';
}
}
}
return true;
}
1.6 通过Aurora发起ajax请求
首先在顶部添加链接地址
<a:link id="CON1050_contrac_donate_sum_amount" model="cont.CON1050.sel_donate_req_header_lov" modelaction="query"/>
在js中编写调用方法
function amountValidator(record, name, value){
Aurora.request({
url: $au('CON1050_contrac_donate_sum_amount').getUrl(),
sync:true,
para: {
relation_donate_num: relation_donate_num,
employee_id:record.get('employee_id')
},
success: function (resp) {
if (resp && resp.result && resp.result.record) {
var amount=resp.result.record.donate_sum_amount;
if(amount<value){
debugger;
return '原币金额必须小于等于“关联捐赠申请”的单据头总金额!';
}
}
}
return true;
}
注意,我在validator里面加的ajax,即使此处加了sync:true 。也会异步返回true。 导致校验失败。
1.7 js中设置必输校验
js中使用setRequired(true)需要放在handler里面。如果放到Aurora.onReady()里面,可能不会生效哦。
<a:dataSets>
<a:dataSet id="CON1050_contract_header_maintain_ds" >
<a:fields>
<a:field name="description" prompt="CON_CONTRACT_HEADERS.DESCRIPTION"/>
</a:fields>
<a:events>
<a:event name="load" handler="CON1050_loadHandler"/>
</a:events>
</a:dataSet>
</a:dataSets>
function CON1050_onMaintainReady() {
var record = $au('CON1050_contract_header_maintain_ds').getAt(0);
record.getMeta().getField('description').setRequired(true);
}
Aurora.onReady(CON1050_onMaintainReady);
function CON1050_loadHandler() {
var record = $au('CON1050_contract_header_maintain_ds').getAt(0);
record.getMeta().getField('description').setRequired(true);
}
1.8 界面的field添加renderer
在<a:form>内的表单元素中增加 renderer属性。
<a:view>
<a:form id="CON1050_view_form_place_id0" column="1" title="CON_CONTRACT_HEADERS_APPLY_INFOR">
<a:formToolbar>
<!--表单工具按钮之类的-->
...
</a:formToolbar>
<!--增加一个box标签,方便排版表单元素排版,当然也可以增加多个box-->
<a:box column="4" id="jq_resort_box_h" labelWidth="115" style="width:100%">
<a:textField name="document_desc" bindTarget="CON1050_contract_header_maintain_ds"/>
...
<!--当某个表单元素需要通过条件判断,是否存在时,可以在这里增加<a:placeHolder>标签,相当于一个预留位。在后面的config标签里面来判断此处该渲染成什么-->
<a:placeHolder id="CON1050_purchaseColumns"/>
</a:box>
</a:form>
</a:view>
<a:view-config>
<c:create-config targetId="CON1050_purchaseColumns">
<!--这里的/model/.../record/@...是固定写法。header_info是后台返回给前端的对象的名字,@contract_attribute是取对象里面的contract_attribute字段的值-->
<p:switch test="/model/header_info/record/@contract_attribute">
<p:case value="PURCHASE">
<c:process-config>
<!--此处增加了renderer-->
<a:numberField name="wired_ratio" allowDecimals="false" bindTarget="CON1050_contract_header_maintain_ds" max="100" min="0" renderer="CON1050_wired_ratio"/>
</c:process-config>
</p:case>
<!--这个case没有加条件,表示其它-->
<p:case>
<c:process-config>
<a:comboBox name="acc_entity_name" bindTarget="CON1050_contract_header_maintain_ds"/>
</c:process-config>
</p:case>
</p:switch>
</c:create-config>
</a:view-config>
1.9 prompt 属性添加
prompt 属性,①可以加到<a:field>标签上,②也可以加到具体组件,如<a:textField>上。方式①影响界面显示和缓存中的prompt值,方式②只影响界面显示。所以,如果要校验该field。因为表单校验失败时,提示框的消息是取自缓存中的prompt,所以需要将prompt加到<a:field>上。综上,就统一加<a:field>上吧!
1.10 js 添加ds数据
关键词 create 。create后ds绑定的界面(通常是表格)会联动增加行。
js中的写法:
let data = {};
data.seq_number=10;
data.employee_name=cur.get('employee_name');
...
data.position_desc=cur.get('position_desc');
$au('group_ref_emp_result_ds').create(data);
标签中的写法:
<a:dataSet id="group_ref_emp_result_ds" autoQuery="true" model="wfl.WFL4100...." queryUrl="${/request/@context_path}/autocrud/.../query" queryDataSet="..." selectable="true">
<a:fields>
<a:field name="seq_number" prompt="..." required="true" validator="..."/>
</a:fields>
...
</a:dataSet>
另外,判断一行数据是否是新建:isNew属性。
function editfunc(record, name) {
return record.isNew ? 'WFL4100_approver_group_code_tf' : '';//保存后不运行修改
}
1.11数据导出excel
1、一般导出,导出某个grid内的数据
添加导出按钮
<a:screenTopToolbar>
<!-- export_grid是导出表格的id -->
<a:gridButton bind="export_grid" type="excel" text="导出查询结果"/>
</a:screenTopToolbar>
...
<!-- 是将query_result_ds中查询出来的数据导出 -->
<a:grid id="export_grid" bindTarget="query_result_ds" ...>
...
</a:grid>
2、任意导出,导出任意查询结果集。
通过翻阅Aurora-all.js代码。可以发现,导出excel实际是调用的的$A.doExport方法
//Aurora-all.js
$A.doExport=function(dataset,cols,mergeCols,type,separator,filename,generate_state,param){
...
}
...
其中要传入好几个参数。从方法内容不难看出,dataset是查询结果数据集,cols是导出的字段名和字段的对应关系。最后一个参数是查询参数数据集。从param的使用可以看出param传入的是一个json。其它参数可以暂时置空,不重要。
首先要确定导出哪些列,cols是一个固定格式的json。然后确定数据集和参数。
function export_detail(){
//name字段填query_result_ds中的field的name属性。prompt填导出后的列名
var cols=[
{
"prompt": "单据号",
"width": 100,
"name": "exp_report_number",
"align": "center"
},
...
{
"prompt": "单据名称",
"width": 100,
"name": "exp_report_type_name",
"align": "center"
}
];
var r=$au('query_result_ds');//需要导出的数据集
var params=$au('query_ds').getAt(0).data||{};//查询参数数据集转成json格式
$A.doExport(r,cols,undefined,undefined,undefined,undefined,undefined,params);
}
在界面中添加按钮,绑定按钮点击事件。
<a:screenTopToolbar>
<a:gridButton text="导出查询结果明细" click="export_detail"/>
</a:screenTopToolbar>
1.12 界面弹窗参数传递
1、参数如果写在url后面:
var url='.../b.screen?enable_flag=Y&header_id=1...';
在b.screen中取值enable_flag、header_id等
//b.screen
var to_url='${/parameter/@enable_flag}';
var to_header_id='${/parameter/@header_id}';
2、如果参数写到para 里面:
Aurora.request({
url: '.../b.screen',
sync:true,
para: {
enable_flag: 'Y',
header_id:1,
...
},
...
});
在b.screen中取值enable_flag、header_id等
//b.screen
var to_url='${@enable_flag}';
var to_header_id='${@header_id}';
此处取值方式有待确认
1.13 comboBox对应值列表的书写方式
首先界面需要一个<a:comboBox>标签
<a:dataSets>
<!-- 自定义值列表的数据源 -->
<a:dataSet id="FND4000_progress_status_ds">
<a:datas>
<!--status_name、status_code可以自定义-->
<a:record status_name="全部" status_code=""/>
<a:record status_name="提交之后的单据" status_code="AFTER_SUBMIT"/>
<a:record status_name="提交之前的单据" status_code="BEFORE_SUBMIT"/>
</a:datas>
</a:dataSet>
<!--表单的数据源 -->
<a:dataSet id="query_ds">
<a:field name="progress_status"/>
<a:field name="progress_status_desc" displayField="status_name" options="FND4000_progress_status_ds" prompt="单据状态" returnField="progress_status" valueField="status_code"/>
...
</a:dataSet>
</a:dataSets>
<!-- 这是一个作为查询条件的表单控件,查询结果将为grid提供数据 -->
<a:queryForm bindTarget="query_ds" ...>
<a:formToolBar>
...
</a:formToolBar>
<a:formBody column="3">
<a:comboBox name="progress_status_desc"/>
...
</a:formBody>
</a:queryForm>
1.14 grid合并单元格写法
<a:grid id="query_result_ds" bindTarget="xxx">
<a:columns>
<a:column name="acc_entity_name" align="center" width="120"/>
...
<a:column name="actual_line" prompt="xxx" width="660">
<a:column name="jan_actual" align="center" width="50"/>
....
<a:column name="nov_actual" align="center" width="50"/>
<a:column name="dece_actual" align="center" width="50"/>
</a:column>
</a:columns>
</a:grid>
1.15 Aurora中判断组件是否存在
错误的方式:
//通过$au取值,如果不存在,直接就报错。
if($au('xxx_lov')){
...
}
正确的处理方式:
//未验证过这种方式
if ($A.CmpManager.get('CON1050_expRelNumberLov')) {
...
}
//验证有效的方式:应该和上面这种等效的,及$A 和 Aurora 等效
var signDs=Aurora.CmpManager.get('con_sigin_lines_ds');
if(signDs){
}
2 lov书写格式
lov我的理解是,Aurora框架实现的一个弹出式选择框。涉及弹出框界面组件和数据查询bm。我们要实现自己的lov可以有两种方式,
1、使用系统自带的lov组件。我们只需要加查询bm就可以了。省去了写lov界面。
界面上写法:
<!--需要添加自定义的lov.bm,通过lovService属性指定-->
<a:field name="..." lovService="hec_util...._lov?dimension_id=${@dimension_id}&company_level=${@company_level}" >
<a:mapping>
<a:map from="..._name" to=".._name}"/>
<a:map from="..._id" to=".._id"/>
</a:mapping>
</a:field>
bm写法。此bm与普通bm稍有不同。增加了一些属性。
<?xml version="1.0" encoding="UTF-8"?>
<bm:model xmlns:f="aurora.database.features" xmlns:bm="http://www.aurora-framework.org/schema/bm">
<bm:operations>
<bm:operation name="query">
<bm:query-sql><![CDATA[
SELECT
v.*
FROM
(
--sql语句
....
) v #WHERE_CLAUSE#
]]></bm:query-sql>
</bm:operation>
</bm:operations>
<bm:query-fields>
<bm:query-field name="tax_type_code" queryExpression="v.tax_type_code like '%' || ${@tax_type_code} || '%'"/>
<bm:query-field name="tax_type_name" queryExpression="v.tax_type_name like '%' || ${@tax_type_name} || '%'"/>
</bm:query-fields>
<bm:fields>
<bm:field name="tax_type_id"/>
<bm:field name="tax_type_code" forDisplay="true" forQuery="true" prompt="VAT_INVOICE_TAX_RATE_TYPES.TAX_RATE_TYPE_CODE"/>
<bm:field name="tax_type_name" forDisplay="true" forQuery="true" prompt="VAT_INVOICE_LINES.TAX_RATE"/>
<bm:field name="tax_type_rate"/>
</bm:fields>
<bm:data-filters>
<bm:data-filter name="query" expression="v.tax_type_id not in (select vv.tax_type_id from vat_invoice_rate_assign vv where vv.invoice_category_id = ${@invoice_category_id})"/>
</bm:data-filters>
</bm:model>
2、第二种方式是自定义弹出框的界面。写一个screen界面。添加界面需要的查询bm
<!--需要添加自定义的screen,通过lovUrl属性指定-->
<a:field name="default_object_code" lovGridHeight="320" lovHeight="460" lovUrl="${/request/@context_path}/modules/exp/EXP4020/..._lov.screen?mag_org_id=${/parameter/@mag_org_id}" lovWidth="500">
<a:mapping>
<a:map from="code" to="default_object_code"/>
<a:map from="description" to="default_object_desc"/>
<a:map from="id" to="default_mo_object_id"/>
</a:mapping>
</a:field>
下面是js的写法
//这里material_description是一个lov组件(单选)
...
record.getField('material_description').setLovUrl('${/request/@context_path}/modules/fnd/FND8030/fnd_computer_choose_lov.screen');
record.getField('material_description').setLovPara('pur_type_code', pur_type_code);
record.getField('material_description').setLovPara('fnd_computer_info_id', fnd_computer_info_id);
record.getField('material_description').setLovWidth('1300');
record.getField('material_description').setLovHeight('550');
record.getField('material_description').setTitle('xx信息');
var mapping = [{
from: 'fnd_computer_info_id',
to: 'fnd_computer_info_id'
}, {
from: 'name_model',
to: 'material_description'
}, {
from: 'amount',
to: 'business_price'
}];
record.getField('material_description').setMapping(mapping);
...
在fnd_computer_choose_lov.screen页面里面,加一个行双击事件:FND8030_dblClick,在函数里面提交目标行数据,固定的写法。record里面字段值就会按mapping传到父页面对应的字段上。
<?xml version="1.0" encoding="UTF-8"?>
<a:screen xmlns:a="http://www.aurora-framework.org/application">
<a:init-procedure>
...
</a:init-procedure>
<a:view>
<script><![CDATA[
function FND8030_dblClick(grid,record,row){
$au('${/parameter/@lovid}').commit(record);
}
...
]]></script>
<a:dataSets>
<a:dataSet id="FND8030_chooseComputerDs">
<a:fields>
<a:field name="choosed_seq_number" defaultValue="${/model/choosed_computer/record/@seq_number}"/>
...
</a:fields>
</a:dataSet>
<a:dataSet id="FND8030_chooseComputerResultDs" autoQuery="true" model="fnd.FND8030.fnd_computer_info_query" queryUrl="${/request/@context_path}/autocrud/fnd.FND8030.fnd_computer_info_query/query?pur_type_code=${/parameter/@pur_type_code}" queryDataSet="FND8030_chooseComputerDs"/>
</a:dataSets>
<a:screenBody>
<span>
<a:queryForm bindTarget="FND8030_chooseComputerDs" resultTarget="FND8030_chooseComputerResultDs" style="width:100%;border:none">
<a:formToolBar labelWidth="100">
<a:textField name="product_model" bindTarget="FND8030_chooseComputerDs"/>
...
</a:formToolBar>
</a:queryForm>
</span>
<a:grid bindTarget="FND8030_chooseComputerResultDs" height="450" navBar="true" width="1280">
<a:columns>
<a:column name="seq_number" align="center" width="50"/>
...
</a:columns>
<a:events>
<a:event name="dblclick" handler="FND8030_dblClick"/>
</a:events>
</a:grid>
</a:screenBody>
</a:view>
</a:screen>
3 bm技巧
3.1 bm传入数组参数
bm是没法输入数组作为查询条件的。通过带分隔符的字符串来转换。如下。
<bm:query-sql><![CDATA[
SELECT
h.req_number,
h.req_header_id,
pur_util_pkg.get_mo_req_type_name(p_mo_req_type_id => h.mo_req_type_id) req_type_name,
hec_util_pkg.get_employee_name(p_employee_id => h.employee_id) employee_name,
h.description,
TO_CHAR(h.requisition_date, 'YYYY-MM-DD') requisition_date,
sys_code_pkg.get_sys_code_value_name(p_code => 'PUR_PR_STATUS', p_code_value => h.status) status_name
FROM
pur_requisition_headers h
WHERE
h.req_number IN (
(SELECT
*
FROM
TABLE(hec_util_pkg.parse_multi_param(p_parameter_value => ${@pur_req_num}, p_split_chars => ';'))
))
]]></bm:query-sql>
存储过程parse_multi_param的写法:
/* =============================================
* FUNCTION
* NAME : PARSE_MULTI_PARAM
* DESCRIPTION: MulitComboBox 查询条件转换
* ARGUMENT:
*
* RETURN:
* character_table -- 参数表
* HISTORY:
* 1.00 11/1/2017 12:09:23 PM Tagin
* Creation Description
* 1.01 yyyy/mm/dd Author Name
* Changes Description
* =============================================*/
FUNCTION parse_multi_param(p_parameter_value IN VARCHAR2,
p_split_chars IN VARCHAR2 DEFAULT NULL)
RETURN character_table
PIPELINED IS
v_character_record character_record := character_record(NULL);
v_index NUMBER;
v_split VARCHAR(30) := ';';
v_content VARCHAR2(32767) := TRIM(v_split FROM
p_parameter_value);
BEGIN
IF v_content IS NULL THEN
RETURN;
END IF;
IF p_split_chars IS NOT NULL THEN
v_split := p_split_chars;
END IF;
LOOP
v_index := instr(str1 => v_content, str2 => v_split);
EXIT WHEN v_index = 0;
v_character_record.value := substr(str1 => v_content,
pos => 1,
len => v_index - 1);
v_content := substr(str1 => v_content,
pos => v_index + 1);
PIPE ROW(v_character_record);
END LOOP;
v_character_record.value := v_content;
PIPE ROW(v_character_record);
RETURN;
END parse_multi_param;
即通过存储过程,将传入字符串参数,转化为临时表
3.2 往sql中拼接sql语句段
类似mybatis中的${}标签,这里是截取的lov中的一段写法
<bm:features>
<s:bm-script><![CDATA[
var objectMap = $bm('expm.EXP5110.exp_mo_expense_object_types_query').queryAsMap();
var objectArr = objectMap.getChildren();
if (objectArr && objectArr.length == 1) {
if (objectArr[0].expense_object_method == 'VALUE_LIST') {
var sqlText = 'select v.mo_expense_object_id as id,v.mo_expense_object_code as code,v.mo_expense_object_name as name from exp_mo_expense_object_value_vl v where v.mo_exp_obj_type_id =' + $ctx.parameter.mo_exp_obj_type_id;
$ctx.parameter.sqltext = sqlText;
} else if (objectArr[0].expense_object_method == 'SQL_TEXT') {
var sqlText = 'select id,code,name from (' + objectArr[0].sql_query + ')';
$ctx.parameter.sqltext = sqlText;
}
}
]]></s:bm-script>
</bm:features>
<bm:operations>
<!--${:参数的路径}-->
<bm:operation name="query">
<bm:query-sql><![CDATA[
select * from (${:/parameter/@sqltext}) #WHERE_CLAUSE#
]]></bm:query-sql>
</bm:operation>
</bm:operations>
所以把3.1中数组传入改成逗号拼接字符串传入可能更方便。不过这里是有注入风险的。