title: HAP發(fā)貨單管理Demo
categories: 后端
tags:
- hap
整體效果
前端效果
發(fā)貨退貨單據(jù)界面:
頭行查詢出現(xiàn)的屬性:頭:1.單號(hào) 2.發(fā)貨時(shí)間 3.單據(jù)類型 4.倉(cāng)庫(kù) 5.接收倉(cāng)庫(kù) 6.發(fā)貨單狀態(tài) 7.司機(jī)姓名 8.司機(jī)電話 9.車牌號(hào)碼 10.運(yùn)費(fèi) 11.備注 12.創(chuàng)建人
單號(hào):DOC_NUMBER,必輸,編號(hào)規(guī)則:D+yyyyMMdd+(1-1000隨機(jī)整數(shù),不夠4位用0補(bǔ)齊)
發(fā)貨時(shí)間:大于當(dāng)前日期,必輸
單據(jù)類型:DOC_TYPE,ISSUED/RETURN,下拉列表
倉(cāng)庫(kù):ORGANIZATION_ID,LOV,必輸,從xxfnd_organization_access_b表中獲取,根據(jù)當(dāng)前角色來篩選組織 e.param['roleId'] =("${Session.roleId}");
接收倉(cāng)庫(kù):TO_ORGANIZATION_ID,LOV,當(dāng)DOC_TYPE=ISSUED時(shí),必輸,不可等于來源倉(cāng)庫(kù),否則灰掉不可錄入
發(fā)貨狀態(tài):顯示LOOKUP的MEANING
運(yùn)費(fèi):只錄入數(shù)字,ISSUED類型時(shí)必輸
行:1.行號(hào) 2.物料編碼 3.是否批次控制 4.物料說明 5.批次 6.行數(shù)量 7.待發(fā)貨數(shù)量 8.已發(fā)貨數(shù)量
物料編碼:LOV,字段對(duì)應(yīng)為INVENTORY_ITEM_ID,根據(jù)頭上的ORGANIZATION_ID作為篩選條件
是否批次控制:只讀,CHECKBOX,由"物料編碼LOV"帶出,物料TABLE:xxinv_material_item
物料說明:只讀,由"物料編碼LOV"帶出
批次:IF(LOT_CONTROL=Y)要錄入, 否則不用錄入
行數(shù)量:"PENDING"時(shí)必輸,其他狀態(tài)只讀顯示
待發(fā)貨數(shù)量:"PENDING,ISSUED"時(shí)只讀蝎亚,“COMFIRMED”默認(rèn)(行數(shù)量-已發(fā)貨數(shù)量)
已發(fā)貨數(shù)量(ISSUED_QTY):只讀根據(jù)xxinv_material_txns的SOURCE_TABLE,SOURCE_KEY1來匯總行的已發(fā)貨數(shù)量
單據(jù)查詢界面:
搜索條件:1.單號(hào) 2.倉(cāng)庫(kù) 3.單據(jù)狀態(tài) 4.物料編碼 5.是否存在未發(fā)貨行 6.單據(jù)類型
查詢結(jié)果:1.單據(jù)號(hào) 2.單據(jù)類型 3.單據(jù)狀態(tài) 4.倉(cāng)庫(kù) 5.目標(biāo)倉(cāng)庫(kù) 6.司機(jī) 7.創(chuàng)建人 (編輯與查看按鈕)
前端界面對(duì)應(yīng)邏輯
頭行界面邏輯:
單據(jù)查詢界面邏輯:
編碼描述與lov值準(zhǔn)備:
開發(fā)
數(shù)據(jù)庫(kù)準(zhǔn)備
創(chuàng)建數(shù)據(jù)庫(kù)
創(chuàng)建數(shù)據(jù)庫(kù)hap4_demo,把權(quán)限賦給hap_dev用戶
因?yàn)槲覀円呀?jīng)有了hap_dev用戶炫狱,這里就只是創(chuàng)建數(shù)據(jù)庫(kù)和刷新權(quán)限了魂务。
CREATE SCHEMA hap4_ship_order DEFAULT CHARACTER SET utf8mb4;
GRANT ALL PRIVILEGES ON hap4_ship_order.* TO hap_dev@'%';
FLUSH PRIVILEGES;
修改pom文件中的依賴與前端config.js
修改pom文件中的依賴
<dependency>
<groupId>io.choerodon</groupId>
<artifactId>hap-core</artifactId>
</dependency>
<dependency>
<groupId>io.choerodon</groupId>
<artifactId>hap-security-standard</artifactId>
</dependency>
修改config.js
modules: [
'../target/generate-react/choerodon-fnd-util',
'../target/generate-react/hap-core',
],
初始化數(shù)據(jù)庫(kù)表
修改initdatabse.sh腳本中的數(shù)據(jù)庫(kù)名稱和target.jar的名稱與項(xiàng)目名稱一致
再執(zhí)行該腳本sh init-database.sh
修改xlsx文件
將grid的demo路徑修改為項(xiàng)目路徑。就是將hap-demo替換為這里的ship-order又谋。修改這里是因?yàn)榍岸寺窂降膯栴}橘荠,路由的js中有${match.url}匹配的就是當(dāng)前項(xiàng)目名礁遣,xlsx中寫死了hap-demo雪侥,需要手動(dòng)修改碗殷。
打包并運(yùn)行
執(zhí)行如下命令腳本
mvn clean package
npm install --registry https://nexus.choerodon.com.cn/repository/choerodon-npm/
npm run build
mvn spring-boot:run
所需表初始化
添加groovy建表的腳本,這里給出一個(gè)實(shí)例:物料表速缨。
package script.db
databaseChangeLog(logicalFilePath: "hap4-ship-order.groovy") {
changeSet(author: "lth", id: "2019-08-26-hap4_ship_order") {
if (helper.dbType().isSupportSequence()) {
createSequence(sequenceName: 'XXINV_MATERIAL_ITEM_S', startValue: "100")
}
createTable(tableName: "XXINV_MATERIAL_ITEM", remarks: "物料信息表") {
if (helper.dbType().isSupportAutoIncrement()) {
column(name: "ITEM_ID", type: "BIGINT", autoIncrement: "true", startWith: "10001", remarks: "PK") {
constraints(nullable: "false", primaryKey: "true", primaryKeyName: "XXINV_MATERIAL_ITEM_PK")
}
} else {
column(name: "ITEM_ID", type: "BIGINT", remarks: "PK") {
constraints(nullable: "false", primaryKey: "true", primaryKeyName: "XXINV_MATERIAL_ITEM_PK")
}
}
column(name: "INVENTORY_ITEM_ID", type: "BIGINT(20)", remarks: "ERP物料ID") {
constraints(nullable: "false")
}
column(name: "ITEM_NUMBER", type: "VARCHAR(60)", remarks: "物料編碼") {
constraints(nullable: "false")
}
column(name: "ORGANIZATION_ID", type: "BIGINT(20)", remarks: "庫(kù)存組織ID") {
constraints(nullable: "false")
}
column(name: "DESCRIPTION", type: "VARCHAR(240)", remarks: "物料說明")
column(name: "LOT_CONTROL", type: "VARCHAR(10)", remarks: "是否批次控制")
column(name: "UOM_CODE", type: "VARCHAR(30)", remarks: "單位") {
constraints(nullable: "false")
}
column(name: "ITEM_STATUS", type: "VARCHAR(30)", remarks: "物料狀態(tài) ACTIVE/INACTIVE") {
constraints(nullable: "false")
}
//必輸字段
column(name: "OBJECT_VERSION_NUMBER", type: "BIGINT", defaultValue: "1")
column(name: "REQUEST_ID", type: "bigint", defaultValue: "-1")
column(name: "PROGRAM_APPLICATION_ID", type: "BIGINT(11)")
column(name: "PROGRAM_ID", type: "bigint", defaultValue: "-1")
column(name: "PROGRAM_UPDATE_DATE", type: "DATE")
column(name: "CREATED_BY", type: "bigint", defaultValue: "-1")
column(name: "CREATION_DATE", type: "datetime", defaultValueComputed: "CURRENT_TIMESTAMP")
column(name: "LAST_UPDATED_BY", type: "bigint", defaultValue: "-1")
column(name: "LAST_UPDATE_DATE", type: "datetime", defaultValueComputed: "CURRENT_TIMESTAMP")
column(name: "LAST_UPDATE_LOGIN", type: "bigint", defaultValue: "-1")
column(name: "ATTRIBUTE_CATEGORY", type: "varchar(30)")
column(name: "ATTRIBUTE1", type: "varchar(240)")
column(name: "ATTRIBUTE2", type: "varchar(240)")
column(name: "ATTRIBUTE3", type: "varchar(240)")
column(name: "ATTRIBUTE4", type: "varchar(240)")
column(name: "ATTRIBUTE5", type: "varchar(240)")
column(name: "ATTRIBUTE6", type: "varchar(240)")
column(name: "ATTRIBUTE7", type: "varchar(240)")
column(name: "ATTRIBUTE8", type: "varchar(240)")
column(name: "ATTRIBUTE9", type: "varchar(240)")
column(name: "ATTRIBUTE10", type: "varchar(240)")
column(name: "ATTRIBUTE11", type: "varchar(240)")
column(name: "ATTRIBUTE12", type: "varchar(240)")
column(name: "ATTRIBUTE13", type: "varchar(240)")
column(name: "ATTRIBUTE14", type: "varchar(240)")
column(name: "ATTRIBUTE15", type: "varchar(240)")
}
//判斷是不是postgresql數(shù)據(jù)庫(kù)锌妻,并且添加唯一約束。我們是mysql數(shù)據(jù)庫(kù)旬牲,
if (!helper.isPostgresql()) {
addUniqueConstraint(columnNames: "INVENTORY_ITEM_ID,ORGANIZATION_ID", tableName: "XXINV_MATERIAL_ITEM", constraintName: "XXINV_MATERIAL_ITEM_U1")
} else {
addUniqueConstraint(columnNames: "INVENTORY_ITEM_ID", tableName: "XXINV_MATERIAL_ITEM", constraintName: "FXXINV_MATERIAL_ITEM_U1")
}
}
}
順便提一句:創(chuàng)建索引的方法如下:
createIndex(tableName: "XXINV_SHIPED_DOC_LINES", indexName: "XXINV_SHIPED_DOC_LINES_N1") {column(name: "INVENTORY_ITEM_ID", type: "BIGINT(20)");column(name: "ORGANIZATION_ID",type: "BIGINT(20)")}
建好groovy腳本之后仿粹,如果之前運(yùn)行過initdatabase腳本,需要?jiǎng)h除數(shù)據(jù)庫(kù)表databasechangelog
中之前的操作記錄引谜,否則可能會(huì)腳本運(yùn)行之后沒有插入數(shù)據(jù)庫(kù)牍陌。
后端開發(fā)
建立對(duì)應(yīng)的mapper dto service 包,然后創(chuàng)建實(shí)體類 mapper類 service類员咽。這些上一篇的demo開發(fā)中有解釋實(shí)體類中注解的使用和這些類或者接口應(yīng)該繼承或者實(shí)現(xiàn)什么類或者接口,這里就不再贅述了贮预。
代碼維護(hù)狀態(tài)創(chuàng)建和lov的創(chuàng)建
代碼維護(hù)創(chuàng)建:在后臺(tái)的代碼維護(hù)頁(yè)面創(chuàng)建相應(yīng)的Lookup Type贝室。
lov創(chuàng)建
首先我們知道,在后端定義lov時(shí)會(huì)指定一個(gè)sql.id,這個(gè)東西指的就是我們mapper接口名+對(duì)應(yīng)方法装蓬。當(dāng)我們?cè)诤笈_(tái)調(diào)用值集框時(shí)怖糊,就會(huì)自動(dòng)創(chuàng)建一個(gè)mapper對(duì)象。
不過僅僅這樣還不夠峡迷,mapper中方法的定義很有講究银伟。
我這里拿物料來舉例,這個(gè)接口里面有兩個(gè)lov的查詢绘搞。發(fā)現(xiàn)有沒有特別之處彤避?最特殊的就是其中的參數(shù),傳遞的是一個(gè)完整的物料對(duì)象夯辖。這個(gè)對(duì)象中有我們的篩選條件琉预。這里就是尤其要注意的地方。
public interface MaterialItemMapper extends Mapper<MaterialItem> {
/**
* 通過倉(cāng)庫(kù)id模糊查詢出倉(cāng)庫(kù)(這里沒有倉(cāng)庫(kù)表)
* @param materialItem
* @return
*/
List<MaterialItem> selectOrganizationLov(MaterialItem materialItem);
/**
* 通過頭的倉(cāng)庫(kù)Id(不用手動(dòng)輸入)找對(duì)應(yīng)的物料蒿褂,描述作為再篩選的條件(需要手動(dòng)輸入)
* @param materialItem
* @return
*/
List<MaterialItem> selectMaterialItemLov(MaterialItem materialItem);
}
現(xiàn)在在后臺(tái)創(chuàng)建對(duì)應(yīng)的描述:注意我在圖中的解釋圆米,這里就不再拿出來敘述了,在圖上解釋更為直觀啄栓。
物料對(duì)應(yīng)的mapper.xml文件:上面的參數(shù)是對(duì)象娄帖,在xml中的寫法又與以往的寫法要變化一些。
- ResultMap中需要繼承
io.choerodon.mybatis.mapper.StdMapper.STD
昙楚。 - 寫的查詢方法標(biāo)簽中需要指定resultMap近速。不能用resultType來代替resultMap的定義,而且還要指定parameterType來指定方法傳來的參數(shù)桂肌。
- select的參數(shù)需要指定数焊,不能用*來代替。
- 如果只有一個(gè)if標(biāo)簽崎场,也需要用<\where>來包裹佩耳。后臺(tái)值集查詢時(shí),會(huì)先執(zhí)行一個(gè)查詢總數(shù)的sql谭跨,如果只用where會(huì)使動(dòng)態(tài)生成的sql多一個(gè)where干厚,會(huì)失敗。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="hap.demo.core.order.mapper.MaterialItemMapper">
<resultMap id="baseMaterial" type="hap.demo.core.order.dto.MaterialItem" extends="io.choerodon.mybatis.mapper.StdMapper.STD">
<id property="itemId" column="ITEM_ID" jdbcType="DECIMAL"/>
<result property="inventoryItemId" column="INVENTORY_ITEM_ID" jdbcType="DECIMAL"/>
<result property="itemNumber" column="ITEM_NUMBER" jdbcType="VARCHAR"/>
<result property="organizationId" column="ORGANIZATION_ID" jdbcType="DECIMAL"/>
<result property="description" column="DESCRIPTION" jdbcType="VARCHAR"/>
<result property="lotControl" column="LOT_CONTROL" jdbcType="VARCHAR"/>
<result property="uomCode" column="UOM_CODE" jdbcType="VARCHAR"/>
<result property="itemStatus" column="ITEM_STATUS" jdbcType="VARCHAR"/>
</resultMap>
<select id="selectOrganizationLov" resultMap="baseMaterial" parameterType="hap.demo.core.order.dto.MaterialItem">
SELECT distinct item.ORGANIZATION_ID FROM
xxinv_material_item item
<where>
<if test="organizationId != null">
<bind name="pattern" value="'%' + organizationId + '%'"/>
item.ORGANIZATION_ID LIKE #{pattern}
</if>
</where>
</select>
<select id="selectMaterialItemLov" resultMap="baseMaterial" parameterType="hap.demo.core.order.dto.MaterialItem">
SELECT item.INVENTORY_ITEM_ID,item.ITEM_NUMBER,item.DESCRIPTION,item.ORGANIZATION_ID
FROM xxinv_material_item item
<where>
<if test="organizationId != null">
item.ORGANIZATION_ID = #{organizationId}
</if>
<if test="description != null">
<bind name="pattern" value="'%' + description + '%'"/>
and item.DESCRIPTION LIKE #{pattern}
</if>
</where>
</select>
</mapper>
訂單頭和行查詢 (增刪改也補(bǔ)充上了)
頭:創(chuàng)建VO類螃宙,整理sql語(yǔ)句
先寫出條件查詢訂單頭蛮瞄,因?yàn)橛胁皇穷^表中的列作為條件,所以我使用了一個(gè)OrderHeaderVO來包裹條件字段和結(jié)果字段谆扎。注意其中的shippedTime屬性挂捅,它來自ShipDoc類。①這個(gè)屬性在name為OrderHeader的DataSet中堂湖,對(duì)應(yīng)字段的type是datetime類型闲先。②shippedTime的java類型是java.util.Date状土。③OrderHeaderVO的resultMapper中shippedTime對(duì)應(yīng)的jdbctype為TIMESTAPE,對(duì)應(yīng)的javatype是java.util.Date伺糠。還有這里繼承了BaseDTO是因?yàn)榍岸说脑鰟h改查操作會(huì)傳一個(gè)status值蒙谓,只有繼承了BaseDTO之后,在寫service的實(shí)現(xiàn)類并重寫方法時(shí)训桶,才能拿到狀態(tài)值累驮,進(jìn)行對(duì)應(yīng)的操作。
這里需要注意數(shù)據(jù)中的字段是datetime類型的舵揭,講道理對(duì)應(yīng)的java中類型為TIMESTAPE谤专,那么jdbctype是它可以理解;那為啥實(shí)體類的字段不使用TIMESTAPE而使用Date呢琉朽?通過實(shí)踐毒租,如果使用TIMESTAPE,前端的DataSet轉(zhuǎn)化為OrderHeaderVO就會(huì)報(bào)錯(cuò)箱叁,不能轉(zhuǎn)化成TIMESTAPE墅垮;如果使用@JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
能夠轉(zhuǎn)化成對(duì)象了。不過我看BaseDTO的源碼中耕漱,它的創(chuàng)建與更新時(shí)間屬性都是java.util.Date類型算色,數(shù)據(jù)庫(kù)中也是datetime類型,在mapper.xml中用的是jdbctype="TIMESTAPE"螟够;這就省略了使用注解灾梦。這里兩種方式應(yīng)該都是能行的。我當(dāng)時(shí)時(shí)間查詢之后沒有在前端顯示出來是因?yàn)槲姨孛磗elect語(yǔ)句的時(shí)間字段沒有對(duì)應(yīng)上resultMap中的列妓笙,真是難受若河。
public class OrderHeaderVO extends BaseDTO {
private Long shipDocId;
//結(jié)果字段
private String docNumber;
private String docType;
private String shippmentStatus;
private Long organizationId;
private Long toOrganizationId;
private String driverName;
private String driverPhone;
private Double freight;
private String memo;
private Date shippedTime;
private Long createdBy;
//條件字段
private Long inventoryItemId;
private String issuedFlag;
private List<OrderLineVO> lines;
//省略getter和setter
}
下面給出基本的連接,沒有添加條件寞宫。這條sql我改了三次萧福,第一次select的值只寫了頭界面展示的;第二次由于行上需要展示頭界面未包含的辈赋,就添加了隱藏的創(chuàng)建時(shí)間等字段鲫忍;第三次由于是左連接,如果一個(gè)頭對(duì)應(yīng)多個(gè)行钥屈,那么頭就會(huì)顯示多次悟民,為了不重復(fù)顯示頭就添加了DISTINCT。
SELECT DISTINCT
doc.SHIP_DOC_ID,
doc.DOC_NUMBER,
doc.DOC_TYPE,
doc.SHIPPMENT_STATUS,
doc.ORGANIZATION_ID,
doc.TO_ORGANIZATION_ID,
doc.DRIVER_NAME,
doc.DRIVER_PHONE,
doc.FREIGHT,
doc.MEMO,
doc.CREATED_BY,
doc.SHIPPED_TIME
FROM
xxinv_shiped_doc doc
LEFT JOIN xxinv_shiped_doc_lines line ON (
doc.SHIP_DOC_ID = line.SHIP_DOC_ID
)
LEFT JOIN xxinv_material_item item ON (
line.INVENTORY_ITEM_ID = item.INVENTORY_ITEM_ID
AND line.ORGANIZATION_ID = item.ORGANIZATION_ID
)
對(duì)應(yīng)的mybatis中的語(yǔ)句:
<resultMap id="baseOrderHeader" type="hap.demo.core.order.dto.vo.OrderHeaderVO">
<result property="shipDocId" column="SHIP_DOC_ID" jdbcType="DECIMAL"/>
<result property="createdBy" column="CREATED_BY" jdbcType="DECIMAL"/>
<result property="docNumber" column="DOC_NUMBER" jdbcType="VARCHAR"/>
<result property="docType" column="DOC_TYPE" jdbcType="VARCHAR"/>
<result property="driverName" column="DRIVER_NAME" jdbcType="VARCHAR"/>
<result property="driverPhone" column="DRIVER_PHONE" jdbcType="VARCHAR"/>
<result property="inventoryItemId" column="INVENTORY_ITEM_ID" jdbcType="DECIMAL"/>
<result property="issuedFlag" column="ISSUED_FLAG" jdbcType="VARCHAR"/>
<result property="organizationId" column="ORGANIZATION_ID" jdbcType="DECIMAL"/>
<result property="shippmentStatus" column="SHIPPMENT_STATUS" jdbcType="VARCHAR"/>
<result property="toOrganizationId" column="TO_ORGANIZATION_ID" jdbcType="DECIMAL"/>
<result property="freight" column="FREIGHT" jdbcType="DECIMAL"/>
<result property="memo" column="MEMO" jdbcType="VARCHAR"/>
<result property="shippedTime" column="SHIPPED_TIME" javaType="java.util.Date" jdbcType="TIMESTAMP"/>
<collection property="lines" javaType="ArrayList" column="shipDocId" ofType="hap.demo.core.order.dto.vo.OrderLineVO"
select="hap.demo.core.order.mapper.ShipDocLinesMapper.selectOrderLine"/>
</resultMap>
<select id="selectOrderHeader" resultMap="baseOrderHeader" >
SELECT DISTINCT
doc.SHIP_DOC_ID,doc.DOC_NUMBER,doc.DOC_TYPE,doc.SHIPPMENT_STATUS,doc.ORGANIZATION_ID,
doc.TO_ORGANIZATION_ID,doc.DRIVER_NAME,doc.DRIVER_PHONE,doc.FREIGHT,doc.MEMO,doc.CREATED_BY,doc.SHIPPED_TIME
FROM
xxinv_shiped_doc doc
LEFT JOIN xxinv_shiped_doc_lines line ON (
doc.SHIP_DOC_ID = line.SHIP_DOC_ID
)
LEFT JOIN xxinv_material_item item ON (
line.INVENTORY_ITEM_ID = item.INVENTORY_ITEM_ID
AND line.ORGANIZATION_ID = item.ORGANIZATION_ID
)
<where>
<if test="orderHeaderVO.docNumber != null">
doc.DOC_NUMBER =#{orderHeaderVO.docNumber}
</if>
<if test="orderHeaderVO.docType != null">
AND doc.DOC_TYPE = #{orderHeaderVO.docType}
</if>
<if test="orderHeaderVO.shippmentStatus != null">
AND doc.shippment_status =#{orderHeaderVO.shippmentStatus}
</if>
<if test="orderHeaderVO.organizationId != null">
AND doc.organization_id =#{orderHeaderVO.organizationId}
</if>
<if test="orderHeaderVO.inventoryItemId != null">
AND item.INVENTORY_ITEM_ID =#{orderHeaderVO.inventoryItemId}
</if>
<if test="orderHeaderVO.issuedFlag != null">
AND line.ISSUED_FLAG =#{orderHeaderVO.issuedFlag}
</if>
</where>
</select>
行:對(duì)應(yīng)的VO類和sql語(yǔ)句
創(chuàng)建行OrderLineVO類篷就,主要就是包含在前端顯示的字段射亏,或者是需要行實(shí)體類需要用到的字段。 上面頭的實(shí)體中之所以要加行的list,是因?yàn)檠挥荆笮陆^同時(shí)插入行 或者有頭但 更新行的時(shí)候银锻,能夠從重寫的mutations方法中的headerList參數(shù)中永品,header對(duì)象中能拿到對(duì)應(yīng)的行l(wèi)ist做鹰,從而拿到行數(shù)據(jù)。
下面加了一個(gè)@JsonIgnoreProperties(ignoreUnknown = true)
注解是因?yàn)榍岸说男蠨ataSet轉(zhuǎn)化為行實(shí)體的時(shí)候會(huì)把當(dāng)中定義的lov的對(duì)象也傳進(jìn)來鼎姐。這個(gè)注解能讓不是實(shí)體中的字段被忽略钾麸。
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderLineVO extends BaseDTO {
private Long lineNum;
private Long inventoryItemId;
private String itemNumber;
//物料表中
private String lotControl;
private String description;
//行表
private String lotNumber;
private Double lineQty;
private Double issueReqQty;
//已發(fā)貨數(shù)量
private Double shippedQty;
//省略getter和setter
}
前端行對(duì)應(yīng)的mybatis中的sql語(yǔ)句
<resultMap id="baseOrderLineVO" type="hap.demo.core.order.dto.vo.OrderLineVO">
<result property="description" column="DESCRIPTION" jdbcType="VARCHAR"/>
<result property="lineNum" column="LINE_NUM" jdbcType="DECIMAL"/>
<result property="inventoryItemId" column="INVENTORY_ITEM_ID" jdbcType="DECIMAL"/>
<result property="itemNumber" column="ITEM_NUMBER" jdbcType="VARCHAR"/>
<result property="lotControl" column="LOT_CONTROL" jdbcType="VARCHAR"/>
<result property="lotNumber" column="LOT_NUMBER" jdbcType="VARCHAR"/>
<result property="lineQty" column="LINE_QTY" jdbcType="DECIMAL"/>
<result property="issueReqQty" column="ISSUE_REQ_QTY" jdbcType="DECIMAL"/>
</resultMap>
<select id="selectOrderLine" resultMap="baseOrderLineVO">
SELECT
line.LINE_NUM,
item.ITEM_NUMBER,
item.INVENTORY_ITEM_ID,
item.LOT_CONTROL,
item.DESCRIPTION,
line.LOT_NUMBER,
line.LINE_QTY,
line.ISSUE_REQ_QTY
FROM
xxinv_shiped_doc_lines line
LEFT JOIN xxinv_material_item item ON (
line.INVENTORY_ITEM_ID = item.INVENTORY_ITEM_ID
AND line.ORGANIZATION_ID = item.ORGANIZATION_ID
)
WHERE line.SHIP_DOC_ID=#{shipDocId}
</select>
創(chuàng)建對(duì)應(yīng)的Service和Impl類
Service類不說了,Impl類說一下:這個(gè)OrderHeaderVO沒有對(duì)應(yīng)的數(shù)據(jù)庫(kù)表炕桨,那么就不用繼承BaseServiceImpl了饭尝,Service類也不用繼承BaseService類。不過還是需要實(shí)現(xiàn)IDatasetService接口的献宫,這樣前端的dataset的請(qǐng)求才能有對(duì)應(yīng)的操作钥平。
queries方法中的參數(shù)body中包裹的就是dataset.js中的query fields屬性;前端編輯了哪些查詢條件姊途,把他的name與value作為body的k-v涉瘾。例如前端,我前端有一個(gè)如下查詢字段的代碼捷兰,那么我如果在前端進(jìn)行了物料lov的選擇立叛,隨便選一個(gè)物料,點(diǎn)擊查詢贡茅;這個(gè)接收到的body中會(huì)包含了什么呢秘蛇?看下面的圖就知道了,會(huì)把這兩個(gè)屬性查到的值,和它的name作為鍵值對(duì)傳入body顶考。知道這個(gè)了赁还,我后面通過shopDocId查行就能通過前端拿到shopDocId了。
{ name: 'materialItem4', type: 'object',textField: 'itemNumber', label: '物料編碼', lovCode: 'XXINV_ITEMS' },
{ name: 'inventoryItemId', type: 'number', label: 'ERP物料ID', bind: 'materialItem4.inventoryItemId' },
下面是初步的查詢的Service驹沿,并沒有測(cè)試是否能增刪改艘策。這里面有很多錯(cuò)誤。
@Service
@Transactional(rollbackFor = Exception.class)
@Dataset("OrderHeader")
public class OrdreHeaderServiceImpl implements OrderHeaderService, IDatasetService<OrderHeaderVO> {
@Autowired
private ShipDocMapper shipDocMapper;
@Autowired
private ShipDocLinesMapper shipDocLinesMapper;
@Override
public List<OrderHeaderVO> listOrderHeader(OrderHeaderVO orderHeaderVO) {
return shipDocMapper.selectOrderHeader(orderHeaderVO);
}
@Override
public List<?> queries(Map<String, Object> body, int page, int pageSize, String sortname, boolean isDesc) {
try {
OrderHeaderVO orderHeaderVO = new OrderHeaderVO();
BeanUtils.populate(orderHeaderVO, body);
PageHelper.startPage(page, pageSize);
return shipDocMapper.selectOrderHeader(orderHeaderVO);
} catch (Exception e) {
throw new DatasetException("dataset.error", e);
}
}
@Override
public List<OrderHeaderVO> mutations(List<OrderHeaderVO> list) {
for (OrderHeaderVO header : list) {
switch (header.get__status()) {
case ADD:
insertOrderHeader(header);
break;
case DELETE:
deleteOrderHeader(header);
break;
case UPDATE:
updateOrderHeader(header);
break;
default:
break;
}
}
return list;
}
private ShipDoc headerToShipDoc(OrderHeaderVO header) {
return new ShipDoc(header.getOrganizationId(),
header.getDocNumber(),
header.getToOrganizationId(),
header.getShippedTime(),
header.getDocType(),
header.getShippmentStatus(),
header.getCreatedBy(),
header.getDriverName(),
header.getDriverPhone(),
header.getFreight(),
header.getMemo());
}
private ShipDocLines orderLineToShipDocLines(OrderHeaderVO header,OrderLineVO orderLine) {
return new ShipDocLines(header.getShipDocId(),
orderLine.getLineNum(),
orderLine.getInventoryItemId(),
header.getOrganizationId(),
orderLine.getIssueReqQty(),
orderLine.getLineQty(),
orderLine.getLotNumber(),
header.getIssuedFlag());
}
private void insertOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = shipDocLinesMapper.selectOrderLine(header.getShipDocId());
ShipDoc shipDoc = headerToShipDoc(header);
shipDocMapper.insert(shipDoc);
if (orderLines.size() != 0) {
for (OrderLineVO line:orderLines
) {
ShipDocLines shipDocLine = orderLineToShipDocLines(header, line);
shipDocLinesMapper.insert(shipDocLine);
}
}
}
private void deleteOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = shipDocLinesMapper.selectOrderLine(header.getShipDocId());
ShipDoc shipDoc = headerToShipDoc(header);
shipDocMapper.delete(shipDoc);
if (orderLines.size() != 0) {
for (OrderLineVO line:orderLines
) {
ShipDocLines shipDocLine = orderLineToShipDocLines(header, line);
shipDocLinesMapper.delete(shipDocLine);
}
}
}
private void updateOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = shipDocLinesMapper.selectOrderLine(header.getShipDocId());
ShipDoc shipDoc = headerToShipDoc(header);
shipDocMapper.updateByPrimaryKey(shipDoc);
if (orderLines.size() != 0) {
for (OrderLineVO line:orderLines
) {
ShipDocLines shipDocLine = orderLineToShipDocLines(header, line);
shipDocLinesMapper.updateByPrimaryKey(shipDocLine);
}
}
}
}
下面給出比較完善的頭的實(shí)現(xiàn)類:基本實(shí)現(xiàn)了單次插入頭和行甚负,或者在頭的基礎(chǔ)上修改或者插入行柬焕,也實(shí)現(xiàn)了頭行一起刪除。
@Service
@Transactional(rollbackFor = Exception.class)
@Dataset("OrderHeader")
public class OrdreHeaderServiceImpl implements OrderHeaderService, IDatasetService<OrderHeaderVO> {
@Autowired
private ShipDocMapper shipDocMapper;
@Autowired
private ShipDocLinesMapper shipDocLinesMapper;
@Override
public List<OrderHeaderVO> listOrderHeader(OrderHeaderVO orderHeaderVO) {
return shipDocMapper.selectOrderHeader(orderHeaderVO);
}
@Override
public List<?> queries(Map<String, Object> body, int page, int pageSize, String sortname, boolean isDesc) {
try {
OrderHeaderVO orderHeaderVO = new OrderHeaderVO();
BeanUtils.populate(orderHeaderVO, body);
PageHelper.startPage(page, pageSize);
return shipDocMapper.selectOrderHeader(orderHeaderVO);
} catch (Exception e) {
throw new DatasetException("dataset.error", e);
}
}
@Override
public List<OrderHeaderVO> mutations(List<OrderHeaderVO> list) {
for (OrderHeaderVO header : list) {
switch (header.get__status()) {
case ADD:
insertOrderHeader(header);
break;
case DELETE:
deleteOrderHeader(header);
break;
case UPDATE:
updateOrderHeader(header);
break;
default:
break;
}
}
return list;
}
/**
* 將前端的header轉(zhuǎn)化為訂單頭
*
* @param header
* @return
*/
private ShipDoc headerToShipDoc(OrderHeaderVO header) {
ShipDoc frontShipDoc = new ShipDoc();
frontShipDoc.setOrganizationId(header.getOrganizationId());
frontShipDoc.setDocNumber(header.getDocNumber());
frontShipDoc.setToOrganizationId(header.getToOrganizationId());
frontShipDoc.setShippedTime(header.getShippedTime());
frontShipDoc.setDocType(header.getDocType());
frontShipDoc.setShippmentStatus(header.getShippmentStatus());
frontShipDoc.setCreatedBy(header.getCreatedBy());
frontShipDoc.setDriverName(header.getDriverName());
frontShipDoc.setDriverPhone(header.getDriverPhone());
frontShipDoc.setFreight(header.getFreight());
frontShipDoc.setMemo(header.getMemo());
return frontShipDoc;
}
/**
* 將前端的line轉(zhuǎn)化為訂單行
*
* @param header
* @param orderLine
* @return
*/
private ShipDocLines orderLineToShipDocLines(OrderHeaderVO header, OrderLineVO orderLine) {
ShipDocLines frontShipDocLine = new ShipDocLines();
frontShipDocLine.setShipDocId(header.getShipDocId());
frontShipDocLine.setLineNum(orderLine.getLineNum());
frontShipDocLine.setInventoryItemId(orderLine.getInventoryItemId());
frontShipDocLine.setOrganizationId(header.getOrganizationId());
frontShipDocLine.setIssueReqQty(orderLine.getIssueReqQty());
frontShipDocLine.setLineQty(orderLine.getLineQty());
frontShipDocLine.setLotNumber(orderLine.getLotNumber());
frontShipDocLine.setIssuedFlag(header.getIssuedFlag());
return frontShipDocLine;
}
private void insertOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = header.getLines();
ShipDoc shipDoc = headerToShipDoc(header);
shipDocMapper.insert(shipDoc);
if (orderLines.size() != 0) {
Long i =Long.valueOf("1") ;
for (OrderLineVO line : orderLines
) {
line.setLineNum(i);
Long docId = shipDocMapper.selectShipDocId(shipDoc.getOrganizationId(), shipDoc.getDocNumber());
header.setShipDocId(docId);
ShipDocLines shipDocLine = orderLineToShipDocLines(header, line);
shipDocLinesMapper.insert(shipDocLine);
i++;
}
}
}
private void deleteOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = shipDocLinesMapper.selectOrderLine(header.getShipDocId());
ShipDoc shipDoc = headerToShipDoc(header);
shipDocMapper.delete(shipDoc);
if (orderLines.size() != 0) {
for (OrderLineVO line : orderLines
) {
ShipDocLines shipDocLine = orderLineToShipDocLines(header, line);
shipDocLinesMapper.delete(shipDocLine);
}
}
}
/**
* @param shipDoc 新
* @param shipDoc1 原始
* @return
*/
private ShipDoc mergeShipDoc(ShipDoc shipDoc, ShipDoc shipDoc1) {
if (shipDoc.getShippedTime() != null && !shipDoc.getShippedTime().equals(shipDoc1.getShippedTime())) {
shipDoc1.setShippedTime(shipDoc.getShippedTime());
}
if (shipDoc.getDocType() != null && !shipDoc.getDocType().equals(shipDoc1.getDocType())) {
shipDoc1.setDocType(shipDoc.getDocType());
}
if (shipDoc.getOrganizationId() != null && !shipDoc.getOrganizationId().equals(shipDoc1.getOrganizationId())) {
shipDoc1.setOrganizationId(shipDoc.getOrganizationId());
}
if (shipDoc.getToOrganizationId() != null && !shipDoc.getToOrganizationId().equals(shipDoc1.getToOrganizationId())) {
shipDoc1.setToOrganizationId(shipDoc.getToOrganizationId());
}
if (shipDoc.getDriverName() != null && !shipDoc.getDriverName().equals(shipDoc1.getDriverName())) {
shipDoc1.setDriverName(shipDoc.getDriverName());
}
if (shipDoc.getDriverPhone() != null && !shipDoc.getDriverPhone().equals(shipDoc1.getDriverPhone())) {
shipDoc1.setDriverPhone(shipDoc.getDriverPhone());
}
if (shipDoc.getFreight() != null && !shipDoc.getFreight().equals(shipDoc1.getFreight())) {
shipDoc1.setFreight(shipDoc.getFreight());
}
if (shipDoc.getMemo() != null && !shipDoc.getMemo().equals(shipDoc1.getMemo())) {
shipDoc1.setMemo(shipDoc.getMemo());
}
return shipDoc1;
}
/**
* @param shipDocLines 新
* @param shipDocLines1 數(shù)據(jù)庫(kù)中原數(shù)據(jù)
* @return
*/
private ShipDocLines mergeShipDocLines(ShipDocLines shipDocLines, ShipDocLines shipDocLines1) {
if (shipDocLines.getInventoryItemId() != null && !shipDocLines.getInventoryItemId().equals(shipDocLines1.getInventoryItemId())) {
shipDocLines1.setInventoryItemId(shipDocLines.getInventoryItemId());
}
if (shipDocLines.getLotNumber() != null && !shipDocLines.getLotNumber().equals(shipDocLines1.getLotNumber())) {
shipDocLines1.setLotNumber(shipDocLines.getLotNumber());
}
if (shipDocLines.getLineQty() != null && !shipDocLines.getLineQty().equals(shipDocLines1.getLineQty())) {
shipDocLines1.setLineQty(shipDocLines.getLineQty());
}
if (shipDocLines.getIssueReqQty() != null && !shipDocLines.getIssueReqQty().equals(shipDocLines1.getIssueReqQty())) {
shipDocLines1.setIssueReqQty(shipDocLines.getIssueReqQty());
}
return shipDocLines1;
}
private void updateOrderHeader(OrderHeaderVO header) {
List<OrderLineVO> orderLines = header.getLines();
//shipDoc是新修改數(shù)據(jù)
ShipDoc shipDoc = headerToShipDoc(header);
//shipDoc1是原數(shù)據(jù)
ShipDoc shipDoc1 = shipDocMapper.selectByPrimaryKey(header.getShipDocId());
ShipDoc mergeShipDoc1 = mergeShipDoc(shipDoc, shipDoc1);
shipDocMapper.updateByPrimaryKey(mergeShipDoc1);
//已經(jīng)存在行增加或修改的情況下
if (orderLines.size() != 0) {
for (OrderLineVO line : orderLines
) {
//轉(zhuǎn)化為行梭域,再查出原來的行斑举,合并,更新
ShipDocLines newShipDocLine = orderLineToShipDocLines(header, line);
Long docLineId = shipDocLinesMapper.selectShipDocLineId(newShipDocLine.getOrganizationId(),
newShipDocLine.getInventoryItemId(),
newShipDocLine.getShipDocId());
if (null != docLineId) {
ShipDocLines shipDocLine = shipDocLinesMapper.selectByPrimaryKey(docLineId);
ShipDocLines mergeShipDocLine = mergeShipDocLines(newShipDocLine, shipDocLine);
//在同倉(cāng)庫(kù)和同物料的情況下判斷是不是新建的行病涨,如果是則拋出異常
if (shipDocLine.getLineNum().equals(newShipDocLine.getLineNum())) {
shipDocLinesMapper.updateByPrimaryKey(mergeShipDocLine);
}else {
throw new DatasetException("所屬倉(cāng)庫(kù)與物料已經(jīng)存在",newShipDocLine.getLineNum());
}
} else {
Long lineNum = shipDocLinesMapper.selectShipDocLineNum(newShipDocLine.getShipDocId());
if (lineNum != null) {
Long i=lineNum+1;
newShipDocLine.setLineNum(i);
shipDocLinesMapper.insert(newShipDocLine);
}else {
newShipDocLine.setLineNum(Long.valueOf("1"));
shipDocLinesMapper.insert(newShipDocLine);
}
}
}
}
}
}
在行的編輯頁(yè)面要實(shí)現(xiàn)單個(gè)刪除行:需要自己重寫刪除方法
@Service
@Transactional(rollbackFor = Exception.class)
@Dataset("OrderLine")
public class OrderLineServiceImpl implements OrderLineService, IDatasetService<OrderLineVO> {
@Autowired
private ShipDocLinesMapper shipDocLinesMapper;
@Autowired
private ShipDocMapper shipDocMapper;
private Long id;
@Override
public List<?> queries(Map<String, Object> body, int page, int pageSize, String sortname, boolean isDesc) {
Object shipDocId = body.get("shipDocId");
id =Long.valueOf(shipDocId.toString());
return shipDocLinesMapper.selectOrderLine(id);
}
@Override
public List<OrderLineVO> mutations(List<OrderLineVO> list) {
for (OrderLineVO line : list) {
switch (line.get__status()) {
case DELETE:
deleteOrderLine(line);
break;
default:
break;
}
}
return list;
}
private void deleteOrderLine(OrderLineVO line) {
ShipDoc shipDoc = shipDocMapper.selectByPrimaryKey(id);
Long id1 = shipDocLinesMapper.selectShipDocLineId(shipDoc.getOrganizationId(), line.getInventoryItemId(), id);
if (id1 != null) {
shipDocLinesMapper.deleteByPrimaryKey(id1);
}
}
}
創(chuàng)建OrderHeader的DataSet.js和OrderLine的DataSet.js
注意要對(duì)其中fields和queries fields屬性中的lov進(jìn)行數(shù)據(jù)綁定(bind)富玷,不然在行的頁(yè)面不知道加載什么數(shù)據(jù)。注意在這里fields中的兩個(gè)lov,他們都綁定了organizationId赎懦;但是我在頭對(duì)應(yīng)的react組件中用來展示的是綁定的數(shù)據(jù)雀鹃,就沒有用這個(gè)lov對(duì)象。但是在行的DataSet中励两,也有一個(gè)lov黎茎,只是因?yàn)檫@里不光展示數(shù)據(jù),還要能通過lov編輯數(shù)據(jù)当悔,所以就設(shè)置與前面的lov的name相同的行name傅瞻。
function generateCode() {
let date = new Date();
let number = Math.round((Math.random()*1000));
var month = ("0" + (date.getMonth() + 1)).slice(-2);
while(number.toString().length<4){
number ="0"+number;
}
return "D"+date.getFullYear()+""+month+""+date.getDate()+""+number;
}
export default {
//主鍵字段名,一般用作級(jí)聯(lián)行表的查詢字段
primaryKey: 'shipDocId',
autoQuery: true,
pageSize: 20,
//對(duì)應(yīng)后臺(tái)ds的name盲憎,自動(dòng)生成約定的submitUrl, queryUrl, tlsUrl
name: 'OrderHeader',
//與后端對(duì)應(yīng)的列的描述
fields: [
{name: 'docNumber', type: 'string', label: '單據(jù)號(hào)', defaultValue: generateCode()},
{name: 'docType', type: 'string', label: '單據(jù)類型', lookupCode: 'XXFND_DOC_TYPE'},
{name: 'shippmentStatus', type: 'string', label: '單據(jù)狀態(tài)', lookupCode: 'XXFND_SHIPPMENT_STATUS'},
{name: 'materialItem1', type: 'object', textField:'organizationId', label: '倉(cāng)庫(kù)ID',lovCode: 'XXINV_ISSUE_ORGANIZATION'},
{ name: 'organizationId', type: 'number', label: '倉(cāng)庫(kù)ID', bind: 'materialItem1.organizationId' },
{name: 'materialItem2', type: 'object',textField:'organizationId', label: '目標(biāo)倉(cāng)庫(kù)ID',lovCode: 'XXINV_ISSUE_ORGANIZATION'},
{ name: 'toOrganizationId', type: 'number', label: '倉(cāng)庫(kù)ID', bind: 'materialItem2.organizationId' },
{name: 'driverName', type: 'string', label: '司機(jī)姓名'},
{name: 'driverPhone', type: 'string', label: '司機(jī)電話'},
{name: 'createdBy', type: 'string', label: '創(chuàng)建人number'},
{name: 'freight', type: 'string', label: '運(yùn)費(fèi)'},
{name: 'memo', type: 'string', label: '備注'},
{name: 'shippedTime', type: 'datetime', label: '發(fā)貨時(shí)間'},
],
//查詢字段嗅骄,自動(dòng)生成查詢組件
queryFields: [
{ name: 'shipDoc', type: 'object', textField: 'docNumber', label: '單據(jù)號(hào)', lovCode: 'XXINV_SHIP_DOC' },
{ name: 'docNumber', type: 'string', label: '單據(jù)號(hào)', bind: 'shipDoc.docNumber' },
{ name: 'materialItem3', type: 'object',textField:'organizationId', label: '倉(cāng)庫(kù)ID', lovCode: 'XXINV_ISSUE_ORGANIZATION' },
{ name: 'organizationId', type: 'number', label: '倉(cāng)庫(kù)ID', bind: 'materialItem3.organizationId' },
{ name: 'shippmentStatus', type: 'string', label: '單據(jù)狀態(tài)', lookupCode: 'XXFND_SHIPPMENT_STATUS'},
{ name: 'materialItem4', type: 'object',textField: 'itemNumber', label: '物料編碼', lovCode: 'XXINV_ITEMS' },
{ name: 'inventoryItemId', type: 'number', label: 'ERP物料ID', bind: 'materialItem4.inventoryItemId' },
{ name: 'issuedFlag', type: 'string', label: '行發(fā)貨狀態(tài)', lookupCode: 'XXFND_SHIPLINE_ISSUED_FLAG' },
{ name: 'docType', type: 'string', label: '單據(jù)類型', lookupCode: 'XXFND_DOC_TYPE' },
],
};
行的字段顯示就比較簡(jiǎn)單了,不過也是需要數(shù)據(jù)綁定的:
export default {
name: 'OrderLine',
fields: [
{ name: 'lineNum', type: 'string', label: '行號(hào)'},
{ name: 'materialItem', type: 'object',textField: 'itemNumber', required: true , label: '物料', lovCode: 'XXINV_ITEMS'},
{ name: 'inventoryItemId', type: 'number', label: 'ERP物料ID', bind: 'materialItem.inventoryItemId' },
{ name: 'itemNumber',type: 'string', label: '物料編碼', bind: 'materialItem.itemNumber'},
{ name: 'lotControl', type: 'string', label: '批次控制',},
{ name: 'description', type: 'string', label: '物料描述'},
{ name: 'lotNumber', type: 'string', label: '批次' },
{ name: 'lineQty', type: 'number', label: '行數(shù)量'},
{ name: 'issueReqQty', type: 'number', label: '待發(fā)貨數(shù)量'},
{ name: 'shippedQty', type: 'number', label: '已發(fā)貨數(shù)量' },
],
};
開發(fā)頭和行react組件
先開發(fā)頭的饼疙,其中我把編輯和查看作為參數(shù)寫死(0和1)傳入
import React from 'react';
import {Button, IntlField, Modal, Table, Tooltip} from 'choerodon-ui/pro';
import OrderLineModal from './OrderLineModal';
const { Column } = Table;
const modalKey = Modal.key();
export default ({ headerDS, lineDS }) => {
let isCancel;
let created;
/**
* 編輯修改
* 數(shù)據(jù)校驗(yàn)成功時(shí)保存
*/
async function handleOnOkOrderLineModal() {
isCancel = false;
if (await headerDS.current.validate()) {
await headerDS.submit();
} else {
return false;
}
}
function handleOnCancelOrderLineModal() {
isCancel = true;
}
/**
* 關(guān)閉編彈窗.
*
*/
function handleOnCloseOrderLineModal() {
if (isCancel) {
// 新建時(shí)取消溺森,移除dataSet記錄
if (created) {
headerDS.remove(created);
} else {
// 修改時(shí)取消 重置當(dāng)前記錄數(shù)據(jù)
headerDS.current.reset();
lineDS.reset();
}
}
// 重置新建記錄標(biāo)記
created = null;
}
/**
* 打開彈窗.
* @param shipDocId 頭Id
* @param enabled
*/
function openOrderLineModal(shipDocId,enabled) {
if (!shipDocId) {
created = headerDS.create();
}
// 如果是編輯狀態(tài) 單號(hào)不可編輯
const isEditDisabled = !!shipDocId;
// 如果為啟用狀態(tài) 只可以進(jìn)行查看 不能編輯數(shù)據(jù)
const isEnableDisabled = (isEditDisabled) && (enabled === 1);
// 如果為啟用狀態(tài) 編碼規(guī)則行,不可被選中
lineDS.selection = isEnableDisabled ? false : 'multiple';
Modal.open({
//唯一鍵窑眯, 當(dāng)destroyOnClose為false時(shí)屏积,必須指定key。
// 為了避免與其他modal的key重復(fù)伸但,可通過Modal.key()來獲取唯一key肾请。
key: modalKey,
//標(biāo)題
title: shipDocId ? '編輯' : '添加',
//抽屜模式
drawer: true,
//關(guān)閉時(shí)是否銷毀
destroyOnClose: true,
//同時(shí)顯示ok和cancel按鈕,false的時(shí)候只顯示ok按鈕
okCancel: !isEnableDisabled,
//確認(rèn)按鈕文字
okText: !isEnableDisabled ? '保存' : '關(guān)閉',
//點(diǎn)擊確定回調(diào)更胖,返回false Promise.resolve(false)或
// Promise.reject()不會(huì)關(guān)閉铛铁, 其他自動(dòng)關(guān)閉
onOk: !isEnableDisabled ? handleOnOkOrderLineModal : handleOnCancelOrderLineModal,
//點(diǎn)擊取消回調(diào),返回false Promise.resolve(false)或
// Promise.reject()不會(huì)關(guān)閉却妨, 其他自動(dòng)關(guān)閉
onCancel: handleOnCancelOrderLineModal,
//關(guān)閉后回調(diào)
afterClose: handleOnCloseOrderLineModal,
children: (
<OrderLineModal headerDS={headerDS} lineDS={lineDS} isEditDisabled={isEditDisabled} isEnableDisabled={isEnableDisabled} />
),
style: {
width: 1100,
},
});
}
const addBtn = (
<Button
icon="playlist_add"
funcType="flat"
color="blue"
onClick={() => openOrderLineModal(null, null)}
>
{'添加'}
</Button>
);
const excelBtn = (
<Button
icon="format_align_justify"
funcType="raised"
color="blue"
>
{'Excel導(dǎo)出'}
</Button>
);
/**
* 渲染表格內(nèi)容.
*/
return (
<Table buttons={[excelBtn,'delete',addBtn]} dataSet={headerDS} queryFieldsLimit={8}>
<Column name="docNumber" />
<Column name="docType" />
<Column name="shippmentStatus" />
<Column name="organizationId" />
<Column name="toOrganizationId" />
<Column name="driverName" />
<Column name="driverPhone" />
<Column name="createdBy" />
<Column header={'編輯'} align="center" width={120}
renderer={({ record})=>{
return (
<Button
funcType="flat"
icon={'mode_edit'}
onClick={() => openOrderLineModal(record.get('shipDocId'),0)}
/>
);
}}/>
<Column
header={'查看'}
align="center"
width={120}
renderer={({ record}) => {
return (
<Button
funcType="flat"
icon={'visibility'}
onClick={() => openOrderLineModal(record.get('shipDocId'),1)}
/>
);
}}
/>
</Table>
);
};
再開發(fā)行的react組件饵逐。行中form標(biāo)簽中的就是頭傳過來的字段,其中的時(shí)間 代碼維護(hù) lov的標(biāo)簽需要使用對(duì)應(yīng)的彪标。 注意名稱必須對(duì)應(yīng)倍权。時(shí)間空間有個(gè)import moment from 'moment';
import React from 'react';
import {
Button,
CheckBox,
DatePicker,
DateTimePicker,
Form,
Lov,
NumberField,
Select,
Table,
TextField
} from 'choerodon-ui/pro';
import moment from 'moment';
const { Column } = Table;
export default ({ headerDS, lineDS, isEditDisabled, isEnableDisabled }) => {
let btnGroup = [];
if (!isEnableDisabled) {
btnGroup = ['add', 'delete'];
}
return (
<div>
<Form
columns={3}
abelWidth={100}
>
<TextField name="docNumber" label={'單號(hào)'} dataSet={headerDS} required disabled={isEditDisabled}/>
<DateTimePicker name="shippedTime" label={'發(fā)貨時(shí)間'} dataSet={headerDS} disabled={isEnableDisabled} min={moment()}/>
<Select name="docType" label={'單據(jù)類型'} dataSet={headerDS} required disabled={isEnableDisabled}/>
<Lov name="materialItem1" label={'倉(cāng)庫(kù)'} dataSet={headerDS} required disabled={isEnableDisabled} />
<Lov name="materialItem2" label={'接收倉(cāng)庫(kù)'} dataSet={headerDS} disabled={isEnableDisabled} />
<Select name="shippmentStatus" label={'發(fā)貨單狀態(tài)'} dataSet={headerDS} required disabled={isEditDisabled} />
<TextField name="driverName" label={'司機(jī)姓名'} dataSet={headerDS} disabled={isEnableDisabled} />
<TextField name="driverPhone" label={'司機(jī)電話'} dataSet={headerDS} disabled={isEnableDisabled} />
<TextField name="freight" label={'運(yùn)費(fèi)'} dataSet={headerDS} disabled={isEnableDisabled} />
<TextField name="memo" label={'備注'} dataSet={headerDS} disabled={isEnableDisabled} />
<TextField name="createdBy" label={'創(chuàng)建人'} dataSet={headerDS} disabled={isEditDisabled} />
</Form>
<Table
buttons={btnGroup}
dataSet={lineDS}
header={'行'}
>
<Column name="lineNum" label={'行號(hào)'} />
<Column name="materialItem" label={'物料編碼'} editor={<Lov />}/>
<Column name="lotControl" label={'批次控制'} />
<Column name="description" label={'物料描述'} />
<Column name="lotNumber" label={'批次'} editor={<NumberField/>}/>
<Column name="lineQty" label={'行數(shù)量'} editor={<NumberField/>}/>
<Column name="issueReqQty" label={'待發(fā)貨數(shù)量'} editor={<NumberField/>}/>
<Column name="shippedQty" label={'已發(fā)貨數(shù)量'} editor={<NumberField/>}/>
</Table>
<div>
<Button
icon="format_align_justify"
funcType="raised"
color="blue"
>
{'打印'}
</Button>
<Button
icon="format_align_justify"
funcType="raised"
color="blue"
>
{'單據(jù)確認(rèn)'}
</Button>
<Button
icon="format_align_justify"
funcType="raised"
color="blue"
>
{'確認(rèn)發(fā)貨'}
</Button>
</div>
</div>
);
};
編輯xlsx,添加路由
這里的頭與行的順序最好不要打亂捞烟,我之前亂了一行薄声,初始化表,插入不了/ship-order/order下面的數(shù)據(jù)