Loading...
墨滴

简简单单

2021/07/04  阅读:76  主题:草原绿

苍穹开发笔记

苍穹日常学习知识库

(一)开发技巧

1.实现苍穹跳转页面

通过代码打开新页面需要用的方法是showform方法,需要用到的参数时FormShowParameter,这里要注意的是打开不同类型的页面要构建的FormShowParameter

PC 端

  • 打开动态表单 页面:FormShowParameter

  • 打开单据 页面:BillShowParameter

  • 打开基础资料 页面:BaseShowParameter

  • 打开报表 页面:ReportShowParameter

  • 打开标准列表 页面:ListShowParameter

通过代码打开页面

FormShowParameter showParameter = new FormShowParameter();
showParameter.setFormId("表单标识");
showParameter.getOpenStyle().setShowType(ShowType.Modal);//打开方式
this.getView().showForm(showParameter);
ListShowParameter showParameter = new ListShowParameter();
showParameter.setBillFormId("单据标识");//注意这里是billFormId,指的是列表对应的单据标识
showParameter.getOpenStyle().setShowType(ShowType.Modal);
this.getView().showForm(showParameter);

代码打开页面并向下传递参数

通过代码打开页面需要构建showparamter,如果需要 传递参数到下一个页面需要setCustomParam即可,

formShowParameter.setCustomParam("key","testkey")

FormShowParameter formShowParameter = new FormShowParameter();
formShowParameter.setFormId("zvhm_test");
formShowParameter.setCustomParam("key","testkey");
formShowParameter.getOpenStyle().setShowType(ShowType.Modal);//打开方式
this.getView().showForm(formShowParameter);

在子页面可以通过formShowParameter.getCustomParam("key");来取值

FormShowParameter formShowParameter = this.getView().getFormShowParameter();
String key = formShowParameter.getCustomParam("key");

代码打开页面回传参数到父页面

通过代码打开页面需要构建showparamter,如果需要获取到子页面传回的参数,需要在构建showparamter中添加setCloseCallBack,这样在父页面的closedCallBack才能捕获事件,如formShowParameter.setCloseCallBack(new CloseCallBack(this,"zvhm_test"));

FormShowParameter formShowParameter = new FormShowParameter();
formShowParameter.setFormId("zvhm_test");
formShowParameter.setCustomParam("key","testkey");
formShowParameter.setCloseCallBack(new CloseCallBack(this,"zvhm_test"));
formShowParameter.getOpenStyle().setShowType(ShowType.Modal);//打开方式
this.getView().showForm(formShowParameter);

父页面closedCallBack

 @Override
    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
        super.closedCallBack(closedCallBackEvent);
        String actionId = closedCallBackEvent.getActionId();
        if (actionId.equals("zvhm_test")){
            String returnData = (String) closedCallBackEvent.getReturnData();
            System.out.println(returnData);
        }
    }

子页面需要调用returnDataToParent将参数传递回父页面,子页面代码:

@Override
public void beforeClosed(BeforeClosedEvent e) {
        super.beforeClosed(e);
        //返回数据给父页面
        this.getView().returnDataToParent("testreturndata");
    }

详细代码

父单据

package test.dev;

import io.swagger.models.parameters.FormParameter;
import kd.bos.bill.AbstractBillPlugIn;
import kd.bos.form.CloseCallBack;
import kd.bos.form.FormShowParameter;
import kd.bos.form.ShowType;
import kd.bos.form.control.Button;
import kd.bos.form.control.Control;
import kd.bos.form.events.ClosedCallBackEvent;

import java.util.EventObject;

/**
 * @program:
 * @description:
 * @author: zhangchunli
 * @create: 2021-06-02 11:16
 **/

public class TestShowForm extends AbstractBillPlugIn {
    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        Button button =this.getView().getControl("zvhm_buttonap");//获取按钮
        button.addClickListener(this);//给点击按钮注册监听
    }

    @Override
    public void click(EventObject evt) {
        super.click(evt);
       Control control = (Control)evt.getSource();//获取事件源
        String key = control.getKey();
        if (key.equals("zvhm_buttonap")){
            FormShowParameter formShowParameter = new FormShowParameter();
            formShowParameter.setFormId("zvhm_test");//zvhm_test是单子id
            formShowParameter.setCustomParam("key","testkey");
            formShowParameter.setCloseCallBack(new CloseCallBack(this,"zvhm_test"));
            formShowParameter.getOpenStyle().setShowType(ShowType.Modal);//打开方式
            this.getView().showForm(formShowParameter);
        }
    }

    @Override
    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
        super.closedCallBack(closedCallBackEvent);
        String actionId = closedCallBackEvent.getActionId();
        if (actionId.equals("zvhm_test")){
            String returnData = (String) closedCallBackEvent.getReturnData();
            System.out.println(returnData);
        }
    }
}

子单据

package test.dev;

import kd.bos.form.FormShowParameter;
import kd.bos.form.events.BeforeClosedEvent;
import kd.epm.eb.formplugin.AbstractFormPlugin;

import java.util.EventObject;

/**
 * @program: node-debug-mservice
 * @description:
 * @author: zhangchunli
 * @create: 2021-06-02 12:59
 **/

public class BybillPlugin extends AbstractFormPlugin {

    @Override
    public void beforeBindData(EventObject e) {
        super.beforeBindData(e);
        FormShowParameter formShowParameter = this.getView().getFormShowParameter();
        //获取子页面穿过了的数据
        String key = formShowParameter.getCustomParam("key");
        //将传过来的值赋值给子页面
        this.getModel().setValue("zvhm_textfield",key);
    }
    @Override
    public void beforeClosed(BeforeClosedEvent e) {
        super.beforeClosed(e);
        //返回数据给父页面
        this.getView().returnDataToParent("testreturndata");
    }
}

移动端

  • 移动表单:MobileFormShowParameterFormShowParameter类似
  • 移动单据:MobileBillShowParameterBillShowParameter类似
  • 移动基础资料:MobileBaseShowParameterBaseShowParameter 相同
  • 移动列表:MobileListShowParameterListShowParameter类似

注:

移动端的实体是 PC 端,但是标识是移动端的标识,这里有一个特例,如果你想要打开 PC 端单据页面中对应的移动列表的话,billFormId还是要传单据的标识,然后showParameterMobileListShowParameter

参考链接

2.苍穹徽标使用

1、徽标一般都很简洁, 所以我们在不区分中英文的情况, 文本允许显示的最大长度为 4, 超出会被截断。

2、支持徽标的控件: 按钮, 标签, 图片控件, 页签, 工具栏。

3、代码里的BadgeInfo对象方法有以下几种:

方法名 参数 说明 场景
setCount integer 设置数量 未读的消息数量
setDot boolean 设置是否显示成点,默认为 false 表示收到的新消息
setColor String 设置显示颜色,如(#aaaaaa) 徽标背景色
setShowZero boolean 设置数量为 0 的时候是否显示,默认为false 想要消息的数量一直显示,不论有没有未读消息
setOverflowCount Integer 超过overflowCount的会显示$(overflowCount)+默认的overflowCount为99 100 条消息,最多只能显示 99
setOffset String[] 设置显示的偏移修正量[right,top],如[10,10] 根据自己的布局调整徽标位置
setBadgeText String 设置显示文本 徽标上显示文本
image-20210603095255377
image-20210603095255377
  • 红点型徽标

@Override
public void afterCreateNewData(EventObject e) {
    Button zvhm_testbadge = this.getView().getControl("zvhm_testbadge");
    BadgeInfo badgeInfo = new BadgeInfo();
    badgeInfo.setDot(true);//设置徽标为一个点
    zvhm_testbadge.setBadgeInfo(badgeInfo);
}
  • 数字型徽标

@Override
public void afterCreateNewData(EventObject e) {
    Button zvhm_testbadge = this.getView().getControl("zvhm_testbadge");
    BadgeInfo badgeInfo = new BadgeInfo();
    badgeInfo.setCount(100);//设置徽标显示数字为100
    zvhm_testbadge.setBadgeInfo(badgeInfo);
}
  • 设置数字上限,超出上限显示“xx+”的效果

@Override
public void afterCreateNewData(EventObject e) {
    Button zvhm_testbadge = this.getView().getControl("zvhm_testbadge");
    BadgeInfo badgeInfo = new BadgeInfo();
    badgeInfo.setCount(100);//设置徽标显示数字为100
    badgeInfo.setOverflowCount(90);//当数字超过90时将显示90+
    zvhm_testbadge.setBadgeInfo(badgeInfo);
}
  • 文本徽标

@Override
public void afterCreateNewData(EventObject e) {
    Button zvhm_testbadge = this.getView().getControl("zvhm_testbadge");
    BadgeInfo badgeInfo = new BadgeInfo();
    badgeInfo.setBadgeText("文本徽标");
    zvhm_testbadge.setBadgeInfo(badgeInfo);
}

3. F7 的理解

对于 F7,对于初学来说,是很难理解的一个知识点,其实 F7 相当于一个基础资料,而你点击基础资料控件会弹出基础资料列表

image-20210604102120930
image-20210604102120930

而在苍穹中常用的就是BeforeF7SelectListener, AfterF7SelectListener这两个接口,通过实现这两个接口,然后重写方法,进而对基础资料的选择进行干预,对于BeforeF7SelectListener,它的方法是beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent),而对于AfterF7SelectListener接口,他的方法是afterF7Select(AfterF7SelectEvent afterF7SelectEvent),你可以在方法中分别书写自己的逻辑

package test.dev.f7;

import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.form.field.OrgEdit;
import kd.bos.form.field.events.AfterF7SelectEvent;
import kd.bos.form.field.events.AfterF7SelectListener;
import kd.bos.form.field.events.BeforeF7SelectEvent;
import kd.bos.form.field.events.BeforeF7SelectListener;
import kd.bos.form.plugin.AbstractFormPlugin;

import java.util.EventObject;

/**
 * @program: node-debug-mservice
 * @description:
 * @author: zhangchunli
 * @create: 2021-06-04 09:44
 **/

public class ExampleFormPlugin extends AbstractFormPlugin implements BeforeF7SelectListenerAfterF7SelectListener {
    @Override
    public void registerListener(EventObject e) {
        super.registerListener(e);
        OrgEdit orgEdit =  this.getView().getControl("zvhm_orgfield");
        orgEdit.addBeforeF7SelectListener(this);
    }


    @Override
    public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
         String fieldKey = beforeF7SelectEvent.getProperty().getName();

        if (StringUtils.equals(fieldKey, "shkd_module")) {
            // 获取问题详情分录选中行
            int index = this.getModel().getEntryCurrentRowIndex("shkd_entryentity");
            //获取产品
            DynamicObject productDo = (DynamicObject) this.getModel().getValue("shkd_product", index);
            //构建模块过滤条件
            QFilter qFilter = new QFilter("shkd_product.fbasedataid.name", QCP.equals, productDo.getString("name"));
            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
            showParameter.getListFilterParameter().setFilter(qFilter);


    }

    @Override
    public void afterF7Select(AfterF7SelectEvent afterF7SelectEvent) {

    }
}

(二)业务笔记

1.询价与竞价

询价采购是指对几个供货商(通常至少三家)的报价进行比较以确保价格具有竞争性的一种采购方式。 竞争性谈判,是指采购人或者采购代理机构直接邀请三家以上供应商就采购事宜进行谈判的方式。

2.名词

SOW

工作说明书(Statement of Work,简称 SOW)是对项目所要提供的产品或服务的叙述性的描述。

PCR

需求变更申请单

UAT

用户测试阶段

PMP

项目管理专业人士资格认证

RFI

request for information(信息邀请书)。

(三)其他知识

2021/6/1

1.在根节点中可以批量设置属性

2.样式中扩展比率为 0

3.锁定性的优先级大于界面规则

4.插件的运行原理

image-20210531135035136
image-20210531135035136
image-20210623092858452
image-20210623092858452

5.插件开发过程

FormView单据试图类,负责界面显示,控件属性设置

FormDataModel单据数据类,负责界面数据的增删改查以及数据对象的存放

DynamicObject从持久层取出的数据,封装成动态数据对象,传递给前端

BusinessDataReader/BusinessDataServiceHelper

持久层对象查询类,负责持久层数据查询,然后将数据封装成 DynamicObject

  1. 选择插件基类
    • 根据业务需求,分析应用场景
    • 确定页面类型(动态表单、单据、基础资料、单据列表、移动布局、报表等
    • 确定插件基类
  2. 选用合适的事件源、事件
    • 表单在运行时,会提供各种插件事件
    • 各种不同的控件、字段、都有自己的用途,也会提供相应的插件事件
    • 根据业务需求,选用合适的控件、字段
  3. 选用上下文,开发插件代码,实现特定业务逻辑
    • 利用插件基类提供上下文对象,事件参数,封装好的服务,实现特定的业务逻辑
  4. 绑定到页面

6.FormServiceImpl.class

FormServiceImpl.classinvokeMethod方法会拦截所有按钮事件,可以在此debug调试

7. 苍穹显示异常堆栈信息

st=>start: 管理员登陆
e=>end
op1=>operation: 系统参数
op2=>operation: 参数配置
op3=>operation: 公共参数
op4=>operation: 打开显示异常堆栈信息
st(right)->op1(right)->op2(right)->op3(right)->op4(right)
image-20210603095842466
image-20210603095842466

8.格式化

日期格式化

如果同时选择了日期格式化和掩码,那么优先显示日期格式化

9.单价需要关联币别

如果表单中出现了单价字段,那么就需要添加币别字段,同时单价关联币别

10 动态表单界面事件如下

(按触发先后顺序列出):

分类 事件 触发时机
界面显示前 setPluginName 显示界面,准备构建界面显示配置 formConfig 前,构建插件时触发此事件,传入脚本名称;
preOpenForm 显示界面前,准备构建界面显示参数时,触发此事件;
loadCustomControlMetas 显示界面前,构建界面显示参数时,触发此事件;
界面初始化 setView 表单视图模型初始化,创建插件时,调用此方法,向插件传入表单视图模型 IFormView 实例;
initialize 表单视图模型初始化,创建插件后,触发此事件;
registerListener 用户与界面上的控件交互时,触发此事件;
getEntityType 表单基于实体模型,创建数据包之前,触发此事件;
createNewData 界面初始化或刷新,开始新建数据包时触发此事件;
afterCreateNewData 界面初始化或刷新,新建数据包完毕后,触发此事件
beforeBindData 界面数据包构建完毕,开始生成指令,刷新前端字段值、控件状态之前,触发此事件;
afterBindData 界面数据包构建完毕,生成指令,刷新前端字段值、控件状态之后,触发此事件;
用户交互事件 beforeItemClick 用户点击界面菜单按钮时,执行绑定的操作前,触发此事件;
itemClick 用户点击界面菜单按钮时触发此事件;
beforeDoOperation 用户点击按钮、菜单,执行绑定的操作前,触发此事件;
afterDoOperation 用户点击按钮、菜单,执行完绑定的操作后,不论成功与否,均会触发此事件;
confirmCallBack 前端交互提示确认后,通知插件进行后续处理;
closedCallBack 子界面关闭时,如果回调函数由父界面处理,则会触发父界面的此事件;
flexBeforeClosed 弹性域维护界面关闭时,触发父界面此事件;
onGetControl 在有代码尝试获取控件的编程模型时,触发此事件;
customEvent 触发自定义控件的定制事件;
TimerElapsed 定时触发此事件;
界面关闭 beforeClosed 界面关闭之前触发此事件;
destory 界面关闭后,释放资源时,触发此事件
pageRelease 界面关闭后,释放资源时,触发此事件;

idea 快速去除没有使用的引用

ctrl + alt + o

采购模块开发总结

2021年5月20日

今天进行了第三次采购模块的开发,今天的开发是按照需求文档的描述进行了开发,屏蔽掉了指南,这次的独立开发,让我对对以往的疑惑有了新的理解和认识

  1. 基础资料属性的使用。

在一个系统预置的基础资料控件中,比如物料这个控件,在一个单据体中,不同的属性是有联系的,当我在单据体中加了物料这个属性,我试图通过物料的引用属性把计量单位和规格型号自动携带到指定列,使用这种方法,虽然可以满足需求,但是在接下来数量关联计量单位的时候出现了找不到计量单位的问题,原来,在一个单据列表中,数量关联的计算单位并不是独立存在的,如果你需要使用数量这个控件,那么最好单据体中添加计量单位,另外,使用基础资料属性引用物料的确能带出计量单位,但是不推荐使用,因为一旦你使用了自动携带,那么你的数量将无法找到计量单位的引用。

  1. 单据体中最好加一个单据状态

比如,未下达下达已关闭,可以通过下游单据配置反写时进行关闭状态的转换

  1. 单据体也有自己的业务规则配置

单据体的业务规则配置往往是最容易忽略的,因为往往我们只关注单据头上的配置,导致我们在配置界面规则和业务规则时,不能及时找到我们想要的字段,所以,在进行单据界面规则和业务规则配置的时候,要注意,单据体的配置单据头,单据头的配置单据头上

  1. 一个应用的首页是在 home 图标中配置的

在我们配置了应用之后,往往点击进来发现是空白的,但是可以通过在 home 图标中,配置自己想要展示的内容,但是值得注意的是,我们配置的类型需要在单据列表的查询方案中配置然后引用。

(四)代码段

1.propertyChanged

@Override
public void propertyChanged(PropertyChangedArgs e) {
 // TODO Auto-generated method stub
 super.propertyChanged(e);
 //获取属性名
 String name = e.getProperty().getName();

 if("ali_userfield".equals(name)) {
  DynamicObject value = (DynamicObject)this.getModel().getValue("ali_userfield");
  if(value!=null) {
  String number = value.getString("number");
  if (number!=null) {
   QFilter filter = new QFilter("number", QCP.equals, number);
   DynamicObject queryOne = QueryServiceHelper.queryOne("bos_user""id,name,number", filter.toArray());
   Long id = (Long)queryOne.get("id");
   long mainOrgId = UserServiceHelper.getUserMainOrgId(id);
   this.getModel().setValue("createorg", mainOrgId);
  }
  }
 }
}

2.应用参数代码

public class TestBill0106Plugin extends AbstractBillPlugIn {

    @Override
    public void afterBindData(EventObject e) {
        super.afterBindData(e);

        //获取公共参数
        Object hideHomeTab = SystemParamServiceHelper.getPublicParameter("hidehometab");
        System.out.println(hideHomeTab);


        //获取应用参数
        //获取当前登录业务单元id
        long orgId = RequestContext.get().getOrgId();
        //从缓存中获取应用信息
        AppInfo ptstDemo = AppMetadataCache.getAppInfo("ptst_demo");
        //获取应用的主键
        String appId = ptstDemo.getId();
        //获取应用参数
        Object count = SystemParamServiceHelper.getAppParameter(appId, orgId, "count");
        System.out.println(count);


        //获取单据参数
        //获取单据参数的dynamicObject对象
        DynamicObject ptstTestbill0106 = ParameterReader.getBillParameter("ptst_testbill0106");
 //获取指定标识的参数值
        Object billCount = ptstTestbill0106.get("billcount");
        System.out.println(billCount);


        //获取单据类型参数
        List<String> appIds = new ArrayList<>();
        appIds.add(appId);
        //通过应用id集合获取单据类型
        List<Map<String, Object>> billTypesByAppId = BillTypeServiceHelper.getBillTypesByAppId(appIds);
        if (null != billTypesByAppId && billTypesByAppId.size() > 0) {
            //获取单据类型的主键id
            long billTypeId = (long) billTypesByAppId.get(0).get("id");
            //获取单据类型参数,formId为单据的标识,paramFormId为单据类型参数页面的标识
            DynamicObject billTypeParameter = (DynamicObject) SystemParamServiceHelper.getBillTypeParameter("ptst_testbill0106""ptst_billtypeparam0106", billTypeId);
            int count1 = billTypeParameter.getInt("count");
            String textfield = billTypeParameter.getString("textfield");
            System.out.println(textfield + "------" + count1);
        }
//获取列表参数
        //获取上下文信息
        RequestContext requestContext = RequestContext.get();
        //获取当前登陆用户的id
        String userId = requestContext.getUserId();
        //获取列表选项参数的DynamicObject对象,formId是列表对应的单据的标识,listOption是列表选项参数页面的标识
        DynamicObject listOptionParameter = ParameterReader.getListOptionParameter(Long.parseLong(userId), "ptst_testbill0106""ptst_listparam0106", null);
        //获取整数控件的值
        int count2 = listOptionParameter.getInt("count");
        System.out.println(count2);
    }

3.控制台输出执行 sql

DebugServer类添加

   DB.setSqlLogger(new SqlLogger() {
            @Override
            public void log(String s, Object... objects) {
                System.out.println(s);
            }
        });

4.sql 激活用户

激活张三、李四、王五、赵六员工账号设置密码为 1234567

UPDATE t_sec_user_u
SET FPASSWORD = '8HrquJnZfyOkmmHkpGLXfg==',
FIsRegisted = '1',
fisactived = '1'
WHERE
 FID IN ( SELECT FID FROM t_sec_user WHERE FPHONE IN ( 16675152021166751520221667515202316675152025,18739527714 ) );
扩展比率压缩比率 快速了解“扩展比率”和“压缩比率” (kingdee.com)
自定义图标 学完这波操作,我当场成为了斗“图”王者 (qq.com)
苍穹自定义打印 关于苍穹套打/打印开发的样例 (kingdee.com)

简简单单

2021/07/04  阅读:76  主题:草原绿

作者介绍

简简单单