From 8c141d70219d352f67066f0749de9e74980cbd11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=AB=E4=BF=9D=E9=87=91?= <8596067+benjamin-gong@user.noreply.gitee.com> Date: Sat, 3 Sep 2022 02:11:55 +0000 Subject: [PATCH 01/18] Initial commit --- README.en.md | 36 ++++++++++++++++++++++++++++++++++++ README.md | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 README.en.md create mode 100644 README.md diff --git a/README.en.md b/README.en.md new file mode 100644 index 00000000..f9caa0b2 --- /dev/null +++ b/README.en.md @@ -0,0 +1,36 @@ +# ui-model + +#### Description +前端UI模型。 + +#### Software Architecture +Software architecture description + +#### Installation + +1. xxxx +2. xxxx +3. xxxx + +#### Instructions + +1. xxxx +2. xxxx +3. xxxx + +#### Contribution + +1. Fork the repository +2. Create Feat_xxx branch +3. Commit your code +4. Create Pull Request + + +#### Gitee Feature + +1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md +2. Gitee blog [blog.gitee.com](https://blog.gitee.com) +3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) +4. The most valuable open source project [GVP](https://gitee.com/gvp) +5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) +6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md new file mode 100644 index 00000000..e03e2235 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# ui-model + +#### 介绍 +前端UI模型。 + +#### 软件架构 +软件架构说明 + + +#### 安装教程 + +1. xxxx +2. xxxx +3. xxxx + +#### 使用说明 + +1. xxxx +2. xxxx +3. xxxx + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 +4. 新建 Pull Request + + +#### 特技 + +1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md +2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) +3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 +4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 +5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) +6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) -- Gitee From 2d5f0a4b180d7e5057456706ea3f71035e6a747e Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 14 Dec 2022 10:22:57 +0000 Subject: [PATCH 02/18] =?UTF-8?q?initialize=20projects=20*=20Merge=20branc?= =?UTF-8?q?h=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20*=20=E5=9B=BA=E5=AE=9A=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=B8=BA1.8=20*=20=E8=B0=83=E6=95=B4api=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=80=BC=E7=BB=93=E6=9E=84=20*=20=E9=80=89=E4=BA=BA?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=92=8C=E9=80=89=E7=BB=84=E7=BB=87=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E6=8F=90=E5=8F=96title=20*=20=E8=B0=83=E6=95=B4pom=20?= =?UTF-8?q?*=20=E4=B8=8D=E5=BD=B1=E5=93=8D=E6=AD=A3=E5=B8=B8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=BF=90=E8=A1=8C=E7=9A=84=E5=89=8D=E6=8F=90=E4=B8=8B?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96=20*=20?= =?UTF-8?q?=E4=B8=8D=E5=BD=B1=E5=93=8D=E6=AD=A3=E5=B8=B8=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E7=9A=84=E5=89=8D=E6=8F=90=E4=B8=8B=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20=E4=B8=8D?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=E6=AD=A3=E5=B8=B8=E5=8A=9F=E8=83=BD=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E7=9A=84=E5=89=8D=E6=8F=90=E4=B8=8B=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96=20*=20=E4=B8=8D=E5=BD=B1?= =?UTF-8?q?=E5=93=8D=E6=AD=A3=E5=B8=B8=E5=8A=9F=E8=83=BD=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E5=89=8D=E6=8F=90=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BC=98=E5=8C=96=20*=20=E9=99=84=E4=BB=B6=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E9=A2=84=E8=A7=88=E9=BB=98=E8=AE=A4=E5=80=BC=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=9B=BD=E9=99=85=E5=8C=96=20*=20=E5=B8=AE=E5=8A=A9?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E5=85=83=E6=95=B0=E6=8D=AE=E6=94=AF=E6=8C=81=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20*=20=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=E7=AC=A6?= =?UTF-8?q?=E5=90=88=E8=A7=84=E8=8C=83=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B'=20into=20'dev'=20*=20=E8=B0=83=E6=95=B4=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E8=B7=AF=E5=BE=84=20*=20=E5=89=8D=E7=AB=AF=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=8F=98=E6=9B=B4=E6=94=AF=E6=8C=81=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=20*=20=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E6=94=AF=E6=8C=81=E7=A7=BB=E5=8A=A8=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=20*=20=E5=A2=9E=E5=8A=A0=E5=9B=BD=E9=99=85=E5=8C=96?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=8F=90=E5=8F=96=20*=20=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20Merge=20branch=20'Branch=5Fdev=5F?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B?= =?UTF-8?q?'=20into=20'dev'=20*=20=E5=B8=AE=E5=8A=A9=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=A0=E9=99=A4=E5=85=B3=E8=81=94=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=90=8C=E6=AD=A5=E5=88=A0=E9=99=A4=20*=20npm=20=20in?= =?UTF-8?q?stall=20=E5=A2=9E=E5=8A=A0legacy-peer-dependency=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E9=80=82=E5=BA=94=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BC=96=E8=AF=91=E8=B7=AF=E5=BE=84=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E6=97=B6=E9=9B=86=E6=88=90=E6=8E=88=E6=9D=83?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'?= =?UTF-8?q?=20*=20=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=9B=E5=BB=BA=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E5=A2=9E=E5=8A=A0=E6=8E=88?= =?UTF-8?q?=E6=9D=83=E6=8E=A7=E5=88=B6=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B'=20into=20'dev'=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20*=20Merge=20branch=20'dev-maf-authority'?= =?UTF-8?q?=20into=20'dev'=20*=20=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E5=90=8E=E7=AB=AF=E4=BA=A4=E4=BB=98=E7=89=A9?= =?UTF-8?q?=20*=20=E4=BF=9D=E5=AD=98=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6=20*=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9pom=20*=20=E4=BB=85=E4=BF=AE=E6=94=B9=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E6=A0=BC=E5=BC=8F=E4=BB=A3=E7=A0=81=20*=20Merge=20rem?= =?UTF-8?q?ote-tracking=20branch=20'origin'=20into=20dev-multiTenantMaf=20?= =?UTF-8?q?*=20=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E5=A4=9A=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=20*=20=E5=90=88=E5=B9=B6=E5=AE=A1=E6=89=B9=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BB=A3=E7=A0=81=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=86=B2?= =?UTF-8?q?=E7=AA=81=20*=20insuite=E6=96=B0=E5=BB=BA=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E6=97=B6=E7=A9=BA=E6=8C=87=E9=92=88=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E6=94=AF=E6=8C=81=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E9=83=A8=E7=BD=B2=20*=20=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E8=B0=83=E8=AF=95=E6=94=AF=E6=8C=81=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=20*=20=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84su=E4=BF=A1=E6=81=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20*=20=E6=97=A0=E9=A1=B5=E9=9D=A2=E6=B5=81=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=8F=91=E5=B8=83=E8=8F=9C=E5=8D=95=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20*=20=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20*=20=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20*=20=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=20*=20=E5=88=A0=E9=99=A4web=E6=9E=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E7=BA=A7=E8=81=94=E5=88=A0=E9=99=A4=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E7=9A=84ts=E6=96=87=E4=BB=B6=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E6=A3=80=E6=9F=A5=20*=20=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E5=AE=9A=E5=88=B6=E5=A2=9E=E5=8A=A0node=5Fmodules?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20*=20=E5=A2=9E=E5=8A=A0=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=20*=20Merge=20branch=20'Branch=5Fdev=5F?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B?= =?UTF-8?q?'=20into=20'dev'=20*=20Merge=20branch=20'dev'=20into=20Branch?= =?UTF-8?q?=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20*=20=E6=9B=B4=E6=94=B9=E5=91=BD=E4=BB=A4=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=20*=20ty?= =?UTF-8?q?pescipt=E4=BD=BF=E7=94=A8=E5=86=85=E7=BD=AE=20*=20Merge=20branc?= =?UTF-8?q?h=20'bizfieldnew'=20into=20'dev'=20*=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=E5=8E=9F=E7=94=9F?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E9=80=82=E9=85=8D=20*=20typescript=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=86=85=E7=BD=AEserver=20*=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B5=8C=E5=A5=97udt=20*=20=E4=BF=AE=E6=94=B9=20*=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E5=85=B3=E7=B3=BB=E6=94=B9=E9=80=A0=20*=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=E6=98=A0?= =?UTF-8?q?=E5=B0=84=E5=85=B3=E7=B3=BB=E6=94=B9=E9=80=A0=20*=20=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20*=20=E7=A7=BB=E9=99=A4RefElementId=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20Merge=20branch=20'dev'=20into=20'Branch=5Fdev=5F?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B?= =?UTF-8?q?'=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BB=A3=E7=A0=81=20*=20=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=20*=20=E6=8D=95=E8=8E=B7=E9=A1=B5=E9=9D=A2=E6=B5=81=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=89=BE=E4=B8=8D=E5=88=B0=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=EF=BC=8C=E4=BB=8E=E8=80=8C=E9=87=8D=E6=96=B0=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=AF=A5=E5=85=83=E6=95=B0=E6=8D=AE=20*=20=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E7=89=88=E6=9C=AC=20*=20Merge=20branch=20'bizfieldnew?= =?UTF-8?q?'=20into=20'dev'=20*=20pom,lib=E6=8F=90=E4=BA=A4=20*=20Merge=20?= =?UTF-8?q?branch=20'Branch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3?= =?UTF-8?q?=E6=9E=90'=20into=20'dev'=20*=20=E6=8D=95=E8=8E=B7=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E7=BC=96=E8=AF=91=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=8F=8B=E5=A5=BD=E7=9A=84?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=8F=90=E7=A4=BA=20*=20Merge=20branch=20'Br?= =?UTF-8?q?anch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90'=20i?= =?UTF-8?q?nto=20'dev'=20*=20=E6=81=A2=E5=A4=8D=E5=88=9D=E5=A7=8B=E7=8A=B6?= =?UTF-8?q?=E6=80=81=20*=20=E6=9B=B4=E6=96=B0pom=E7=89=88=E6=9C=AC=20*=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=A0=BC=E5=BC=8F=E5=88=A0=E9=99=A4=E7=9A=84?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=20*=20Merge=20branch=20'Branch=5FBranch=5Fde?= =?UTF-8?q?v=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=9D=83=E9=99=90=E8=B0=83=E6=95=B4=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90'=20into=20'dev'=20*=20=E6=9B=B4=E6=96=B0pom?= =?UTF-8?q?=E7=89=88=E6=9C=AC=20*=20=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2=E7=9A=84=E8=BD=AC=E6=8D=A2=E6=88=90=E5=B0=8F=E5=86=99?= =?UTF-8?q?=E5=BD=A2=E5=BC=8F=E6=88=96=E5=A4=A7=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=E7=9A=84method=20*=20Merge=20branch=20'bizfieldnew'=20into=20'?= =?UTF-8?q?dev'=20*=20=E4=BC=98=E5=8C=96=E7=94=9F=E6=88=90id=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=98=A0=E5=B0=84=20*=20Merge=20branch=20'web=5Fmafsu?= =?UTF-8?q?=5Fpatch'=20into=20web=5Fapproveformat=5Fpatch0817=20*=20Merge?= =?UTF-8?q?=20branch=20'BizFieldPatchFile'=20into=20'dev'=20*=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=94=9F=E6=88=90=E5=AD=97=E6=AE=B5=E6=98=A0=E5=B0=84?= =?UTF-8?q?=20*=20=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=E6=AF=94=E8=BE=83=E7=9A=84=E6=96=B9=E6=B3=95=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=8E=B7=E5=8F=96=E8=BF=90=E8=A1=8C=E6=97=B6?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E7=9A=84=E6=96=B9=E6=B3=95=20*=20Me?= =?UTF-8?q?rge=20branch=20'BizFieldPatchFile'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=A7=A3=E5=86=B3bug=EF=BC=9A=E9=9B=B6=E4=BB=A3=E7=A0=81=5F?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E8=AE=BE=E7=BD=AE=5F=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=E5=90=8E=E5=86=8D=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AD=97=E6=AE=B5=E7=BC=96=E5=8F=B7=EF=BC=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90=E7=9A=84=E5=85=B3=E8=81=94=E5=AD=97=E6=AE=B5=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=20*=20=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E8=B7=AF=E5=BE=84=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E6=94=B9=E4=B8=BAinfo=E7=BA=A7=E5=88=AB=20*?= =?UTF-8?q?=20=E6=B3=A8=E5=86=8C=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=94=B9=E4=B8=BAinfo=E7=BA=A7=E5=88=AB=20*=20Merge?= =?UTF-8?q?=20branch=20'BizFieldPatchFile'=20into=20'dev'=20*=20=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=EF=BC=8C?= =?UTF-8?q?vo=E8=BD=ACschema=20*=20Merge=20branch=20'dev'=20into=20Branch?= =?UTF-8?q?=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0web-logger=E6=97=A5=E5=BF=97=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0web-logger=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=80=89=E9=A1=B9=20*=20=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=85=B1lo?= =?UTF-8?q?gger=20*=20=E9=9B=86=E6=88=90=E8=BF=87=E6=BB=A4=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=8F=96=E6=95=B0=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20Branch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=20*=20Merge=20branch=20'Fix=5Fliyz'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=8E=A7=E5=88=B6=E5=8F=B0=E6=89=93=E5=8D=B0?= =?UTF-8?q?=20*=20=E8=B0=83=E6=95=B4=E8=84=9A=E6=9C=AC=E4=B8=8B=E8=BD=BDrp?= =?UTF-8?q?c=E6=9C=8D=E5=8A=A1=E5=BE=97applicationname=20*=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=88=86SU=E9=83=A8=E7=BD=B2=20*=20=E5=AF=B9eapi?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=5Fmaf=E5=90=8E=E7=BC=80=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E6=B5=8F=E8=A7=88=E5=99=A8=E6=97=A5=E5=BF=97=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20*=20=E7=9B=AE=E6=A0=87=E5=90=8D=E7=A7=B0=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E6=88=90=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch=5Fdev=5F?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E6=9B=B4=E6=96=B0rp?= =?UTF-8?q?c=20*=20=E6=9B=B4=E6=96=B0formurl=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E4=B8=8B=E8=BD=BDjs=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=20*=20=E9=A2=84=E8=A7=88=E6=97=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0gspapprovalformat=E8=A1=A8=E7=9A=84formurl?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=20*=20=E7=BC=93=E5=AD=98=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20*=20scriptcache=E5=A2=9E=E5=8A=A0rpc?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=9C=8D=E5=8A=A1=20*=20html=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=E5=8F=82=E6=95=B0=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6-=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=8F=90=E5=8F=96=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=98=AF=E8=A7=A3=E6=9E=90-=E6=9E=84=E9=80=A0namespace?= =?UTF-8?q?=E5=92=8Cjit=E4=B8=80=E8=87=B4=20*=20=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E7=BB=84=E5=90=88=E8=A1=A8=E5=8D=95=E7=9A=84namespace=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20=E6=B8=85=E9=99=A4=E6=97=A0=E7=94=A8=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=20*=20=E4=BF=AE=E6=AD=A3=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=BF=94=E5=9B=9E=E5=80=BC=E7=BB=93=E6=9E=84=E4=B8=8D?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E9=97=AE=E9=A2=98=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20npm=E9=85=8D=E7=BD=AE=E5=8F=82=E6=95=B0=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=A4=84=E7=90=86=20*=20=E5=B0=86=E6=98=8E=E6=96=87?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93=20*=20?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E6=96=B9=E6=A1=88=E5=8F=82=E6=95=B0=E6=8F=90?= =?UTF-8?q?=E5=8F=96=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch?= =?UTF-8?q?=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=8F=90=E5=8F=96=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=20*=20Merge=20remote-tracking=20branch=20'origin/approvalforma?= =?UTF-8?q?t-1224'=20into=20web=5Fapp=E2=80=A6=20*=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E4=BB=A5=E5=8F=8A=E5=BC=82=E5=B8=B8=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch?= =?UTF-8?q?=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E6=8F=90=E4=BE=9B=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E6=98=AF=E5=90=A6=E4=B8=BA=E8=A7=A3=E6=9E=90=E5=9E=8B?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E7=9A=84API=20*=20Merge=20remote-tracking=20?= =?UTF-8?q?branch=20'origin/dev'=20into=20dev=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E6=8F=90=E4=BE=9B=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E8=A7=A3=E6=9E=90=E5=9E=8B=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=9A=84API=20*=20=E7=BB=84=E5=90=88=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=AB=8B=E5=8A=A0=E8=BD=BDjs=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E7=94=9F=E6=88=90=E5=AF=B9=E5=BA=94service=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20*=20=E7=A7=BB=E9=99=A4html=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=BC=95=E5=8F=B7=20*=20Merge=20branch=20'de?= =?UTF-8?q?v-nocode-ts'=20into=20'dev'=20*=20=E4=B8=9A=E5=8A=A1=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=B7=BB=E5=8A=A0=E5=A4=9A=E9=80=89=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=EF=BC=9B=E6=94=AF=E6=8C=81=E5=BC=95=E7=94=A8web=E6=9E=84?= =?UTF-8?q?=E4=BB=B6=E5=86=85ts=E4=BB=A3=E7=A0=81=20*=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?pom=20*=20=E7=BB=9F=E4=B8=80=E8=B0=83=E6=95=B4=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E7=89=88=E6=9C=AC=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E5=90=88=E5=B9=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20*=20=E5=85=83=E6=95=B0=E6=8D=AE=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=B8=85=E7=90=86=E4=BC=98=E5=8C=96=20*=20=E8=BF=98=E5=8E=9Fsq?= =?UTF-8?q?l=E4=BB=A3=E7=A0=81=20*=20=E8=BF=98=E5=8E=9Fapi=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20*=20=E5=88=A0=E9=99=A4=E6=A0=BC=E5=BC=8F=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=AE=8C=E5=96=84=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E8=A1=A8=E5=8D=95--=E8=B4=9F=E8=BD=BD=E5=9D=87?= =?UTF-8?q?=E8=A1=A1=E9=85=8D=E7=BD=AE=20*=20=E6=8F=90=E4=BA=A4=E4=BE=9D?= =?UTF-8?q?=E8=B5=96jar=E5=8C=85=20*=20Merge=20branch=20'Branch=5Fdev=5Fnp?= =?UTF-8?q?m'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=20*=20=E4=BF=AE=E6=AD=A3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=8C=B9=E9=85=8D=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20=E6=9B=B4=E6=96=B0pom?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E5=91=BD=E4=BB=A4=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=A0=E9=99=A4=E8=B0=83=E6=95=B4=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0dbo=E7=BC=93=E5=AD=98=E6=B8=85=E7=90=86=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E8=B0=83=E6=95=B4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81url=E5=9C=B0=E5=9D=80=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=8A=A0=E8=B4=9F=E8=BD=BD=E5=9D=87=E8=A1=A1?= =?UTF-8?q?=20*=20=E6=89=8B=E5=B7=A5vo=E4=B8=8D=E4=BF=AE=E6=94=B9viewmodel?= =?UTF-8?q?=E8=A1=A8=20*=20Merge=20branch=20'dev-lyz'=20into=20'dev'=20*?= =?UTF-8?q?=20=E6=B8=85=E7=90=86=E5=A4=9A=E4=BD=99=E7=9A=84=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20*=20Merge=20branch=20'dev-jiwt-lookup'=20into=20'de?= =?UTF-8?q?v'=20*=20Merge=20branch=20'dev'=20into=20dev-jiwt-lookup=20*=20?= =?UTF-8?q?=E4=BA=BA=E5=91=98=E9=80=89=E6=8B=A9=E5=92=8C=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6=E6=94=AF=E6=8C=81=E5=90=91?= =?UTF-8?q?VO=E5=90=8C=E6=AD=A5=E5=B8=AE=E5=8A=A9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E3=80=82=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20=E4=BF=AE=E6=AD=A3=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E4=B8=AD=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E7=9B=B8?= =?UTF-8?q?=E5=AF=B9=E8=B7=AF=E5=BE=84=E5=9C=B0=E5=9D=80=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20udt=E6=89=A9=E5=B1=95=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=88=B0schema=EF=BC=9A=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B5=8C=E5=A5=97udt=20*=20=E6=8F=90=E5=8F=96udt=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=BF=A1=E6=81=AF=EF=BC=8C=E7=94=9F=E6=88=90=E5=88=B0?= =?UTF-8?q?=E8=A1=A8=E5=8D=95schema=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E7=A7=BB=E9=99=A4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81bean=E9=85=8D=E7=BD=AE=E4=BB=A3=E7=A0=81=20*=20'?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=81=E7=A8=8B=E4=B8=AD=E5=BF=83=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=9A=84=E8=A1=A8=E5=8D=95=E7=9A=84=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=B5=81=E6=95=B0=E6=8D=AE'=20*=20Merge=20branch=20'Branch=5Fd?= =?UTF-8?q?ev=5Fnpm'=20into=20'dev'=20*=20=E5=A2=9E=E5=8A=A0listener?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=20*=20Merge=20branch=20'nocode/approve-forma?= =?UTF-8?q?t'=20into=20'dev'=20*=20PC=E8=A1=A8=E5=8D=95=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E9=85=8D=E7=BD=AE=E7=94=9F?= =?UTF-8?q?=E6=88=90=E4=BB=A3=E7=A0=81=E5=B9=B6=E7=BC=96=E8=AF=91=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge?= =?UTF-8?q?=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20=E5=A2=9E=E5=8A=A0=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E6=BA=90=E4=BB=A3=E7=A0=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E6=81=A2=E5=A4=8D=E6=96=B9=E6=B3=95=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E7=A7=BB=E9=99=A4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BE=9D=E8=B5=96node=5Fmodules=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=EF=BC=8Cbabel=E7=BC=96=E8=AF=91=E5=A2=9E=E5=8A=A0isBabelCompil?= =?UTF-8?q?e=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Br?= =?UTF-8?q?anch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0?= =?UTF-8?q?=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E4=BE=9D=E8=B5=96=E5=A4=A7=E5=B0=8F=E5=86=99=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge?= =?UTF-8?q?=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=94=AF=E6=8C=81npm=E5=AE=89=E8=A3=85=20*?= =?UTF-8?q?=20Merge=20branch=20'nocode/isRuntime'=20into=20'dev'=20*=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9B=B6=E4=BB=A3=E7=A0=81=E8=8E=B7=E5=8F=96?= =?UTF-8?q?udt=E5=85=83=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98=EF=BC=9B?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9B=B6=E4=BB=A3=E7=A0=81schemaChangeListen?= =?UTF-8?q?er=20*=20=E5=88=9B=E5=BB=BAschema=E6=94=AF=E6=8C=81=E4=BC=A0?= =?UTF-8?q?=E9=80=92isRuntime=E5=8F=82=E6=95=B0=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=94=AF=E6=8C=81npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20=E5=85=BC=E5=AE=B9=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E7=BB=9D=E5=AF=B9=E8=B7=AF=E5=BE=84=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4?= =?UTF-8?q?=20=E7=BA=A7=E8=81=94=E5=88=A0=E9=99=A4=20*=20Merge=20branch=20?= =?UTF-8?q?'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=A7=86=E5=9B=BE=E5=AF=B9=E8=B1=A1=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=20*=20pom?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=E7=BB=9F=E4=B8=80=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20*=20=E5=A2=9E=E5=8A=A0=E7=A7=BB=E5=8A=A8npm?= =?UTF-8?q?=E5=8C=85=E5=88=A4=E6=96=AD=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E5=AF=B9=E5=85=B6dev=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=20*=20=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=85=B3=E9=97=AD=20*=20eapi=E5=8F=96=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E5=BC=80=E6=94=BEvoID=E5=8F=96=E6=95=B0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20*=20vo=E5=8F=98=E5=8C=96=E5=90=8C=E6=AD=A5=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=A1=A8=E5=8D=95=20*=20npm=E5=8C=85=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=9B=B4=E6=96=B0=E8=A1=A5=E4=B8=81-=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9D=83=E9=99=90=E8=AE=BE=E7=BD=AE=20*=20web=20*=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=A1=A5=E4=B8=81=E9=9B=86=E6=88=90=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=20*=20=E5=A2=9E=E5=8A=A0=E5=A4=8D=E5=88=B6package.jso?= =?UTF-8?q?n=20=E6=93=8D=E4=BD=9C=20*=20Merge=20branch=20'Branch=5Fdev=5Fn?= =?UTF-8?q?pm'=20into=20'dev'=20*=20Merge=20branch=20'nocode/approve-forma?= =?UTF-8?q?t'=20into=20'dev'=20*=20=E5=85=A8=E5=B1=80=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E9=9B=86=E6=88=90=E8=87=AA=E5=8A=A8=E5=AE=89=E8=A3=85=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20linux=20=E5=91=BD=E4=BB=A4=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90=20*=20linux=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=9B=AE=E5=BD=95=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=20*=20=E4=BF=AE=E6=AD=A3npm=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=97=B6=E4=BC=9A=E5=87=BA=E7=8E=B0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=EF=BC=8C=E5=AF=BC=E8=87=B4=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=90=8D=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=8E=AF=E5=A2=83=E5=BC=82=E5=B8=B8=E9=80=80=E5=87=BA?= =?UTF-8?q?=E6=97=B6=E7=BB=A7=E7=BB=AD=E5=AE=89=E8=A3=85=20*=20npm?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0=E9=9B=86=E6=88=90=E8=A1=A5?= =?UTF-8?q?=E4=B8=81=E5=B7=A5=E5=85=B7=20*=20=E5=85=A8=E5=B1=80=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E4=BD=BF=E7=94=A8=E7=B3=BB=E7=BB=9F=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=20*=20=E6=8C=89=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E7=94=9F?= =?UTF-8?q?=E6=88=90=E3=80=81=E7=BC=96=E8=AF=91=E3=80=81=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20br?= =?UTF-8?q?anch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20npm=E5=AE=89=E8=A3=85=E6=8F=90=E4=BA=A4=20*=20M?= =?UTF-8?q?erge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20npm?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=AE=89=E8=A3=85pom?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5Fdev=5F=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F'=20into=20'dev'=20*=20=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E6=8F=90=E5=8F=96=20*=20Merge=20branch=20'Branch=5F=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81'=20into=20'dev'=20*=20npm=20run=20command=20?= =?UTF-8?q?*=20Merge=20branch=20'Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81'=20i?= =?UTF-8?q?nto=20'dev'=20*=20Merge=20branch=20'dev'=20into=20Branch=5F?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E5=A2=9E=E5=8A=A0header?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=9B=BD=E9=99=85=E5=8C=96=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=8F=90=E5=8F=96=20*=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E9=9B=86=E6=88=90=E5=A2=9E=E5=8A=A0messagetype?= =?UTF-8?q?=E3=80=81id=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into?= =?UTF-8?q?=20'dev'=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2ng=20build=E4=B8=BA=20npm=20run=20build=20*?= =?UTF-8?q?=20=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20Merge=20branch=20'Branch?= =?UTF-8?q?=5F=E9=9B=B6=E4=BB=A3=E7=A0=81'=20into=20'dev'=20*=20Merge=20br?= =?UTF-8?q?anch=20'dev'=20into=20Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81=20*?= =?UTF-8?q?=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20M?= =?UTF-8?q?erge=20branch=20'Branch=5Fdev=5Fnpm'=20of=20https://git.iec.io/?= =?UTF-8?q?webadp/web=20into=20Br=E2=80=A6=20*=20Merge=20branch=20'dev'=20?= =?UTF-8?q?into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20'Branch=5Fdev=5Fnpm'=20*=20Merge=20branch=20'webdev0421'=20i?= =?UTF-8?q?nto=20'dev'=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=20*=20=E7=AC=AC=E4=B8=80=E7=BB=B4=E5=BA=A6=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E7=BB=B4=E5=BA=A6=E4=B8=8D=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=BF=94=E5=9B=9E=E5=85=AC=E6=9C=89=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E5=BC=80=E5=8F=91?= =?UTF-8?q?=20*=20FormProcessService=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20npm=E5=AE=89=E8=A3=85=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=8C=85=E7=89=88=E6=9C=AC=E6=A3=80=E6=B5=8B=20*=20np?= =?UTF-8?q?m=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=B7=A8=E7=9B=98=E7=AC=A6=20*=20Merge=20bra?= =?UTF-8?q?nch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20?= =?UTF-8?q?'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge=20branch=20'dev?= =?UTF-8?q?'=20into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20'dev'=20in?= =?UTF-8?q?to=20'Branch=5Fdev=5Fnpm'=20*=20Merge=20branch=20'webdev0421'?= =?UTF-8?q?=20into=20'dev'=20*=20=E6=9F=A5=E6=89=BE=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BC=98=E5=8C=96=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20of=20ssh://git.iec.io:6060/webadp/web=20into=20webdev0421?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20br?= =?UTF-8?q?anch=20'form-process'=20into=20'dev'=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=88=B0=E6=B5=81=E7=A8=8B=EF=BC=88=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=A0=BC=E5=BC=8F=EF=BC=89=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4=20*=20jit?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'dev'=20of=20ssh://gi?= =?UTF-8?q?t.iec.io:6060/webadp/web=20into=20webdev0421=20*=20npm=E5=8C=85?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=9B=86=E6=88=90=E8=A1=A5=E4=B8=81=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=20*=20=E6=B3=A8=E9=87=8A=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20*=20=E4=BF=AE=E6=AD=A3=E8=B7=AF=E7=94=B1=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E6=96=87=E4=BB=B6=E5=90=8D=E7=A7=B0=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E9=85=8D=E7=BD=AE=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=85=8D=E7=BD=AEconfiguration=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=80=81=E7=BC=96=E8=AF=91=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E7=A7=BB=E5=8A=A8=E7=8B=AC=E7=AB=8B=E7=9A=84node=5Fmo?= =?UTF-8?q?dules=20*=20npm=20install=20=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20package.json=E6=96=87=E4=BB=B6=20*=20Merge=20br?= =?UTF-8?q?anch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=E5=8C=85=20*=20=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E7=94=9F=E6=88=90UDT=20schema=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=97=B6=EF=BC=8CTypeContext=E9=83=BD=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=B8=BAisRuntime:true=20*=20=E6=9F=A5=E8=AF=A2sql=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20scriptcache=E6=94=AF=E6=8C=81oracle=2010g=20*?= =?UTF-8?q?=20Merge=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=89=A7=E8=A1=8Ccommand=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=8E=B7=E5=8F=96=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E8=B7=AF=E5=BE=84=E5=8F=8D=E6=96=9C=E7=BA=BF=20*=20Me?= =?UTF-8?q?rge=20branch=20'dev'=20of=20ssh://git.iec.io:6060/webadp/web=20?= =?UTF-8?q?into=20webdev0421=20*=20npm=20install=20=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=88=90=E4=B8=BA=E5=8D=95=E7=8B=AC=E7=9A=84?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=89=A7=E8=A1=8C=20*=20=E6=94=AF=E6=8C=81np?= =?UTF-8?q?m=E5=8C=85=E5=AE=89=E8=A3=85=20*=20npm=20install=20*=20npm=20?= =?UTF-8?q?=E9=9B=86=E6=88=90=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20=E8=AE=BE=E8=AE=A1=E6=97=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81linux=E9=83=A8=E7=BD=B2=20*=20Merge=20branch=20'dev'?= =?UTF-8?q?=20of=20ssh://git.iec.io:6060/webadp/web=20into=20webdev0421=20?= =?UTF-8?q?*=20=E8=B0=83=E6=95=B4command=E6=89=A7=E8=A1=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BD=8D=E7=BD=AE=E8=87=B3common=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=20*=20Merge=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*?= =?UTF-8?q?=20npm=E5=AE=89=E8=A3=85=20*=20=E6=97=A0=E6=95=88=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=96=87=E4=BB=B6=E6=B8=85=E7=90=86=20*=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=E6=94=AF=E6=8C=81linux=20=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F=20*=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E3=80=81=E9=A2=84=E8=A7=88url=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E8=BD=AC=E5=B0=8F=E5=86=99=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6?= =?UTF-8?q?=E5=AE=9A=E5=88=B6=E7=8A=B6=E6=80=81=E6=9C=BA=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20*=20=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=B7=A5=E5=85=B7=E7=9B=AE=E5=BD=95=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E6=94=AF=E6=8C=81=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=B7=A5=E5=85=B7=E8=B7=AF=E5=BE=84=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20pom=E8=B0=83=E6=95=B4=20*=20=E8=AF=BB=E5=8F=96=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=BA=E7=A9=BA=E6=97=B6=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=BC=82=E5=B8=B8=E6=8A=9B=E5=87=BA=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=AF=B9=E5=90=8E=E7=BB=AD=E6=93=8D=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=20*=20pom=E6=8F=90=E4=BA=A4jar=E5=8C=85?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E8=B0=83=E6=95=B4=20*=20=E8=B0=83=E6=95=B4ap?= =?UTF-8?q?i=E7=BC=96=E8=BE=91=E7=9A=84jar=E5=8C=85version=EF=BC=8C?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E7=9A=84jar=E5=8C=85=E7=A7=BB=E9=99=A4snapsh?= =?UTF-8?q?ot=20*=20=E4=BB=A3=E7=A0=81=E6=97=A0=E6=95=88=E5=BC=95=E5=85=A5?= =?UTF-8?q?=E6=B8=85=E9=99=A4=20*=20Merge=20branch=20'dev'=20of=20ssh://gi?= =?UTF-8?q?t.iec.io:6060/webadp/web=20into=20webdev0421=20*=20=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6service?= =?UTF-8?q?=E6=8B=B7=E8=B4=9D=20*=20Merge=20branch=20'dev'=20into=20'maste?= =?UTF-8?q?r'=20*=20=E8=B5=84=E6=BA=90=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E7=AD=96=E7=95=A5=20*=20=E8=8E=B7=E5=8F=96=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8F=96=E6=B6=88=E5=BC=82=E5=B8=B8=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=EF=BC=8C=E7=9B=B4=E6=8E=A5=E6=8A=9B=E5=87=BA=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BF=A1=E6=81=AF=20*=20bindingField=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=B8=BAnull=E5=88=A4=E6=96=AD=20*=20=E5=B0=86?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=A7=A3=E6=9E=90=E8=B0=83=E6=95=B4=E6=88=90?= =?UTF-8?q?code=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=20*=20Merge=20branch=20'dev'=20of?= =?UTF-8?q?=20https://git.iec.io/webadp/web=20into=20dev=20*=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E6=94=AF=E6=8C=81babel?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20=E5=88=9B=E5=BB=BAbindingField?= =?UTF-8?q?=E6=97=B6=E6=A3=80=E6=9F=A5=E4=B8=8A=E7=BA=A7bindingField?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20of=20https://git.iec.io/webadp/web=20into=20dev=20*=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6?= =?UTF-8?q?=E5=AE=8C=E5=96=84=20*=20j=E7=89=88=E5=BC=82=E5=B8=B8=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E6=95=88=E4=BB=A3=E7=A0=81=20*=20=E4=BF=AE=E6=AD=A3java?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=B8=8D=E7=AC=A6=E5=90=88=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E9=97=AE=E9=A2=98=20*=20Merge=20bra?= =?UTF-8?q?nch=20'dev'=20of=20https://git.iec.io/webadp/web=20into=20dev?= =?UTF-8?q?=20*=20j=E7=89=88=E4=BB=A3=E7=A0=81=E6=96=B9=E6=B3=95=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=86=99=E8=B0=83=E6=95=B4=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20'master'=20*=20fieldbuilder=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E7=94=9F=E6=88=90UDT=20schem?= =?UTF-8?q?a=E4=BF=A1=E6=81=AF=E6=97=B6=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E8=8E=B7=E5=8F=96=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E5=8F=A3=20*=20utility=20=20commit=20*=20bas?= =?UTF-8?q?e64=E5=8A=A0=E5=AF=86=E6=B5=8B=E8=AF=95=20*=20Merge=20branch=20?= =?UTF-8?q?'master'=20of=20ssh://git.iec.io:6060/webadp/web=20*=20base64?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0utf8=E8=AE=BE=E7=BD=AE=20*=20=E9=80=82?= =?UTF-8?q?=E5=BA=94localhost=E6=9B=B4=E6=94=B9=20*=20eapi=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E8=B0=83=E6=95=B4=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=88=90=E4=B8=BA=E9=A6=96=E5=AD=97=E6=AF=8D=E5=A4=A7=E5=86=99?= =?UTF-8?q?=E5=BD=A2=E5=BC=8F=20*=20=E8=A1=A8=E5=8D=95=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20=E5=A2=9E=E5=8A=A0=E7=BC=BA=E5=A4=B1class=20*=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6master=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9docker=E9=83=A8=E7=BD=B2=EF=BC=8Cformurl=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9docker=E9=83=A8=E7=BD=B2=E7=9B=B8=E5=85=B3=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=9A=E5=B7=A5=E7=A8=8B=E5=90=8D=EF=BC=8C=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=96=87=E4=BB=B6=E5=90=8D=E6=9B=B4=E6=94=B9=20*=20Me?= =?UTF-8?q?rge=20branch=20'master'=20of=20https://git.iec.io/webadp/web=20?= =?UTF-8?q?*=20=E8=A1=A8=E5=8D=95=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E8=AF=AD=20*=20=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=94=AF=E6=8C=81docker=E9=83=A8=E7=BD=B2=20*=20Merge=20branch?= =?UTF-8?q?=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20*=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9=E6=94=AF=E6=8C=81docker=20?= =?UTF-8?q?*=20Merge=20branch=20'b3580'=20into=20'master'=20*=20ts?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E8=B7=AF=E5=BE=84=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20ts=E6=96=87=E4=BB=B6=E4=B9=B1=E7=A0=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=A4=84=E7=90=86=20*=20=E8=A1=A8=E5=8D=95module?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=A2=9E=E5=8A=A0=20*=20Merge=20branch=20'ma?= =?UTF-8?q?ster'=20of=20https://git.iec.io/webadp/web=20*=20ts=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86?= =?UTF-8?q?=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81=E7=A7=BB=E9=99=A4=E7=BB=9D?= =?UTF-8?q?=E5=AF=B9=E8=B7=AF=E5=BE=84=20*=20Merge=20branch=20'master'=20o?= =?UTF-8?q?f=20ssh://git.iec.io:6060/webadp/web=20into=20b3580=20*=20?= =?UTF-8?q?=E7=BB=B4=E5=BA=A6=E7=BC=96=E5=8F=B7=E8=BD=AC=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20Merge=20branch=20'master'=20of=20ssh://git.iec.io:60?= =?UTF-8?q?60/webadp/web=20into=20b3580=20*=20=E8=8E=B7=E5=8F=96=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81=E8=B7=A8SU=20*=20?= =?UTF-8?q?Merge=20branch=20'b3580'=20into=20'master'=20*=20=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E6=9B=B4=E6=96=B0vo=20=20helpid=E5=8F=8C=E5=BC=95?= =?UTF-8?q?=E5=8F=B7=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86=20*=20Merge=20bra?= =?UTF-8?q?nch=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20into?= =?UTF-8?q?=20b3580=20*=20toout.bat=E4=BF=AE=E6=94=B9=20*=20=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E5=AE=A1=E6=89=B9=E9=A2=84=E8=A7=88=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E8=A1=A5=E5=85=A8=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9po?= =?UTF-8?q?pm=E4=BF=AE=E6=94=B9=20*=20Merge=20branch=20'master'=20of=20htt?= =?UTF-8?q?ps://git.iec.io/webadp/web=20*=20schema=20=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20=E8=B0=83=E6=95=B4=E4=BE=9D=E8=B5=96=20*=20Merge=20b?= =?UTF-8?q?ranch=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20into?= =?UTF-8?q?=20b3580=20*=20=E7=AD=BE=E5=85=A5=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E5=B7=A5=E7=A8=8B=20*=20Merge=20branch=20'F=5FWeb=5FF?= =?UTF-8?q?ormDel'=20into=20'master'=20*=20=E5=88=A0=E9=99=A4=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9B=B4=E6=96=B0=E9=A1=B5=E9=9D=A2=E6=B5=81=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=9F=A5=E6=89=BE=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E8=B7=AF=E5=BE=84=E7=9A=84=E6=96=B9=E6=B3=95?= =?UTF-8?q?=20*=20=E6=9B=B4=E6=96=B0=E7=BC=93=E5=AD=98code=20*=20=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E4=BF=AE=E6=94=B9=20*=20=E5=90=8C=E6=AD=A5sc?= =?UTF-8?q?hema=E6=9B=B4=E6=94=B9=20*=20Merge=20branch=20'webdev'=20into?= =?UTF-8?q?=20'master'=20*=20=E8=8E=B7=E5=8F=96=E6=96=87=E4=BB=B6=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=92=8C=E6=96=87=E4=BB=B6=E5=90=8D=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E8=8E=B7=E5=8F=96=E5=AE=89=E8=A3=85=E7=9B=98=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E9=97=AE=E9=A2=98=E4=BF=AE=E6=AD=A3=20*=20=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BC=A0=E8=BE=93=E5=BA=8F=E5=88=97=E5=8C=96?= =?UTF-8?q?=E5=99=A8=E8=B0=83=E6=95=B4=20*=20=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B1=9E=E6=80=A7=E6=A0=87=E8=AF=86=20*=20j?= =?UTF-8?q?=E7=89=88=E8=A1=A8=E5=8D=95schema=E5=90=8C=E6=AD=A5=20*=20Merge?= =?UTF-8?q?=20branch=20'webdev'=20into=20'master'=20*=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=8E=B7=E5=8F=96VO=E5=85=83=E6=95=B0=E6=8D=AE=E5=92=8C?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E5=85=83=E6=95=B0=E6=8D=AE=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E3=80=82=20*=20=E8=A1=A8=E5=8D=95=E5=8F=A6?= =?UTF-8?q?=E5=AD=98=E4=B8=BA=20*=20Merge=20branch=20'webdev'=20into=20'ma?= =?UTF-8?q?ster'=20*=20Merge=20branch=20'master'=20into=20'webdev'=20*=201?= =?UTF-8?q?.stateMachineId=202.TypeScriptFile=20Path=20*=201.stateMachineI?= =?UTF-8?q?d=202.TypeScriptFile=20Path=20*=201.stateMachineId=202.TypeScri?= =?UTF-8?q?ptFile=20Path=20*=20N=E8=BD=ACJ=E5=90=8C=E6=AD=A5=20*=201.?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=202.=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=89=A9=E5=B1=95=203.=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E7=BC=96=E8=AF=91=E6=8C=87=E5=AE=9A=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=20*=20=E4=B8=AD=E6=96=87=E8=B5=84=E6=BA=90=E9=A1=B9?= =?UTF-8?q?=E7=94=9F=E6=88=90=20*=20=E8=A1=A8=E5=8D=95=E9=A2=84=E8=A7=88--?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8=E7=BD=B2=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=8F=90=E4=BA=A4=20*=20=E5=90=91=E5=AF=BC?= =?UTF-8?q?=E5=88=9B=E5=BB=BAschema=20=20editor=E5=B1=9E=E6=80=A7=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E5=A2=9E=E5=8A=A0=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E9=A2=84=E8=A7=88=E5=B7=A5=E7=A8=8B=20*=20n=E8=BD=ACj?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20*=20N=E8=BD=ACJ=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=20*=20=E8=B7=AF=E5=BE=84=E4=BF=AE=E6=94=B9=20*=20java=E7=BC=96?= =?UTF-8?q?=E8=AF=91=20*=20Merge=20branch=20'master'=20of=20https://git.ie?= =?UTF-8?q?c.io/zhangweiqing/web=20*=20jar=E5=8C=85=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20*=20Merge=20branch=20'master'=20of=20https?= =?UTF-8?q?://git.iec.io/zhangweiqing/web=20into=20master=20*=20=E5=8E=BB?= =?UTF-8?q?=E6=8E=89System.out.println=20*=20j=E7=89=88=E7=BC=96=E8=AF=91?= =?UTF-8?q?=20*=20Merge=20branch=20'master'=20of=20https://git.iec.io/zhan?= =?UTF-8?q?gweiqing/web=20*=20=E7=BC=96=E8=AF=91=E6=8F=90=E4=BA=A4=20*=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0spring.factories=E6=96=87=E4=BB=B6=20*=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3ide=E6=8F=92=E4=BB=B6=E7=9A=84url=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=EF=BC=8C=E7=BC=BA=E5=B0=91index.html=E7=9A=84?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=E6=89=80=E5=9C=A8=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E6=8B=BC=E8=A3=85=E8=B7=AF=E5=BE=84=20*=20N=E8=BD=ACJ=E8=B0=83?= =?UTF-8?q?=E8=AF=95&=E5=91=BD=E5=90=8D=E8=B0=83=E6=95=B4=20*=20Merge=20br?= =?UTF-8?q?anch=20'master'=20of=20https://git.iec.io/zhangweiqing/web=20*?= =?UTF-8?q?=20=E8=BF=81=E7=A7=BB=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A?= =?UTF-8?q?=E5=88=B6java=20*=20sourcecode=20metadata=20serializer=20*=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=EF=BC=9B=E5=85=AC=E5=85=B1?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=B7=A5=E5=85=B7=20*=20ide?= =?UTF-8?q?=E8=AF=BB=E6=96=87=E4=BB=B6=EF=BC=9B=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81=20*=20pom=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=8F=90=E4=BA=A4=20*=20appconfig=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E7=BC=96=E8=AF=91=E6=8F=90=E4=BA=A4=20*=20Merg?= =?UTF-8?q?e=20branch=20'master'=20of=20https://git.iec.io/zhangweiqing/we?= =?UTF-8?q?b=20*=20=E4=BF=AE=E6=94=B9=20*=20=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E3=80=81ide=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=E6=94=B9=E5=90=8D=20*=20IDE=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E3=80=81TS=E4=BB=A3=E7=A0=81=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E3=80=81=E7=8A=B6=E6=80=81=E6=9C=BA=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=20*=20Merge=20branch=20'master'=20of=20https?= =?UTF-8?q?://git.iec.io/zhangweiqing/web=20*=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20=E6=B7=BB=E5=8A=A0toout.bat=20*=20pom?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=8F=90=E4=BA=A4=20*=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20*=20common=E7=BC=96=E8=AF=91=20*=20common=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20common=E5=B7=A5=E7=A8=8B=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20common=E5=B7=A5=E7=A8=8B=E7=BC=96=E8=AF=91=20*?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A=20*=20N=E7=89=88?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E8=BD=ACJ=E7=89=88=20*=20add=20restproject?= =?UTF-8?q?=20*=20form=20i18n=20*=20add=20web-form-jitengine=20*=20add=20w?= =?UTF-8?q?eb-frontendproject=20*=20add=20web-appconfig=20*=20add=20web-pa?= =?UTF-8?q?geflow-metadata=20*=20add=20web-sourcecode-metadata=20*=20?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8Dformmetadata=20*=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0webcomponent-api=20*=20init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 758 ++ .gitlab-ci.yml | 88 + .mvn/settings.xml | 113 + .mvn/wrapper/MavenWrapperDownloader.java | 111 + .mvn/wrapper/maven-wrapper.properties | 2 + jitengine-web-api/pom.xml | 20 + .../web/api/service/JitEngineService.java | 9 + .../service/MobileApproveReviewParameter.java | 65 + .../service/MobileApproveReviewResponse.java | 19 + .../api/webservice/JitEngineWebService.java | 27 + jitengine-web-core/pom.xml | 54 + .../config/JitEngineWebConfiguration.java | 28 + .../core/service/JitEngineServiceImpl.java | 25 + .../service/MobilEApprovePreviewImpl.java | 114 + .../web/core/service/MobileApproveDocker.java | 39 + .../webservice/JitEngineWebSericeImpl.java | 88 + .../main/resources/META-INF/spring.factories | 2 + mvnw | 286 + mvnw.cmd | 161 + pom.xml | 508 + runtime-api/pom.xml | 15 + .../api/entity/DeployTargetEnum.java | 16 + .../api/entity/JitBuildParameter.java | 332 + .../api/entity/JitBuildRefMetadata.java | 48 + .../api/entity/JitBuildResponse.java | 48 + .../api/entity/JitMetadataTypeEnum.java | 31 + .../api/entity/JitRuntimeConstant.java | 8 + .../api/service/JitBuildService.java | 17 + runtime-core/pom.xml | 60 + .../core/builddeploy/BuildDeployManager.java | 148 + .../JitBuildParameterGenerator.java | 108 + .../JitBuildParameterValidator.java | 74 + .../core/config/JitBuildConfiguration.java | 21 + .../constant/FormJsonFileSuffixConstant.java | 72 + .../AbstractFormJsonFileGenerator.java | 58 + .../CommandJsonFileGenerator.java | 57 + .../EapiJsonFileGenerator.java | 29 + .../FormJsonFileManager.java | 55 + .../FormModuleWithBuildParameter.java | 38 + .../FormModuleWithBuildParameterManager.java | 38 + .../FormRouteJsonFileGenerator.java | 72 + .../FormRuntimeMetadataEntity.java | 46 + .../FrmJsonFileGenerator.java | 290 + .../JsonFileGeneratorFactory.java | 40 + .../JsonFileGeneratorInterface.java | 11 + .../ResourceJsonFileGenerator.java | 22 + .../StateMachineJsonFileGenerator.java | 23 + .../formroute/FormRouteEntity.java | 52 + .../formroute/FormRoutePageEntity.java | 96 + .../formroute/FormRouteProjectEntity.java | 19 + .../core/i18n/GeneratedI18nResourceList.java | 35 + .../core/i18n/GeneratedI8nResource.java | 38 + .../core/service/JitBuildServiceImp.java | 145 + .../SourceCodeMetadataManager.java | 116 + .../core/utility/JitBuildUtility.java | 25 + .../main/resources/META-INF/spring.factories | 2 + runtime-scriptcache-api/pom.xml | 34 + .../api/entity/FormProjectCache.java | 148 + .../api/entity/FormScriptCache.java | 199 + .../api/entity/FormScriptCacheContent.java | 88 + .../api/entity/PublishScriptRequest.java | 100 + .../ScriptCacheCheckVersionRequest.java | 46 + .../api/entity/ScriptCacheResponse.java | 45 + .../api/service/ScriptCacheService.java | 25 + .../api/webservice/ScriptCacheWebService.java | 34 + .../src/main/resources/log4j2.properties | 7 + .../libs/bef-engine-core-0.1.12.jar | Bin 0 -> 80073 bytes runtime-scriptcache/libs/bef-engine-core.jar | Bin 0 -> 86961 bytes .../libs/bff-engine-core-0.1.4.jar | Bin 0 -> 80940 bytes runtime-scriptcache/libs/bff-engine-core.jar | Bin 0 -> 80162 bytes runtime-scriptcache/libs/cdp-sgf-api.jar | Bin 0 -> 33265 bytes runtime-scriptcache/libs/lcm-metadata-api.jar | Bin 0 -> 127802 bytes runtime-scriptcache/libs/task-api-0.3.11.jar | Bin 0 -> 76098 bytes .../web-jitengine-frontendproject-api.jar | Bin 0 -> 10469 bytes .../libs/web-jitengine-frontendproject.jar | Bin 0 -> 71908 bytes runtime-scriptcache/pom.xml | 70 + .../config/ScriptCacheConfiguration.java | 64 + .../constants/ScriptCacheDBTableConstant.java | 49 + .../converter/FormProjectCacheConverter.java | 67 + .../FormScriptCacheContentConverter.java | 67 + .../converter/FormScriptCacheConverter.java | 61 + .../domain/entity/FormProjectCacheEntity.java | 134 + .../entity/FormScriptCacheContentEntity.java | 83 + .../domain/entity/FormScriptCacheEntity.java | 61 + .../manager/FormProjectCacheManager.java | 81 + .../FormScriptCacheContentManager.java | 55 + .../manager/FormScriptCacheManager.java | 123 + .../FormProjectCacheRepository.java | 65 + .../FormScriptCacheContentRepository.java | 54 + .../repository/FormScriptCacheRepository.java | 112 + .../localserver/LocalServerFileOperation.java | 24 + .../localserver/LocalServerPathGenerator.java | 100 + .../LocalServerProjectVersion.java | 73 + .../localserver/LocalServerScriptVersion.java | 47 + .../LocalServerVersionFileContent.java | 43 + .../LocalServerVersionFileOperation.java | 163 + .../LocalServerVersionManager.java | 320 + .../rpc/LocalServerVersionRpcService.java | 50 + .../rpc/LocalServerVersionRpcServiceImpl.java | 75 + ...tomizationCacheServiceInstanceManager.java | 25 + .../manager/ScriptCacheVersionManager.java | 226 + .../service/ScriptCacheServiceImpl.java | 320 + .../utility/ScriptCacheContentEncrypt.java | 32 + .../webservice/ScriptCacheWebServiceImpl.java | 80 + .../main/resources/META-INF/spring.factories | 2 + .../src/main/resources/log4j2.properties | 7 + .../FormProjectCacheRepositoryTest.java | 15 + .../service/ScriptCacheServiceImpTest.java | 32 + .../ScriptCacheContentEncryptTest.java | 29 + toout.bat | 62 + web-appconfig-api/pom.xml | 20 + .../appconfig/api/entity/GspAppConfig.java | 109 + .../api/webservice/AppConfigWebService.java | 36 + web-appconfig-core/pom.xml | 32 + .../core/appconfig/AppConfigFileManager.java | 60 + .../appconfig/AppConfigFilePathGenerator.java | 24 + .../core/config/AppConfigConfiguration.java | 20 + .../core/constants/GspAppConfigConstants.java | 19 + .../core/service/GspAppConfigService.java | 204 + .../webservice/AppConfigWebServiceImpl.java | 33 + .../main/resources/META-INF/spring.factories | 2 + web-approval-format-api/pom.xml | 44 + .../entity/ApprovalFormUpdateRequestBody.java | 29 + .../api/entity/ApprovalFormat.java | 66 + .../ApprovalFormatCreateRequestBody.java | 72 + .../ApprovalFormatCreateResponseBody.java | 65 + ...rovalFormatDimensionUpdateRequestBody.java | 31 + .../api/entity/ApprovalFormatEnum.java | 59 + .../ApprovalFormatForestByDimension.java | 33 + .../ApprovalFormatQueryResponseBody.java | 76 + .../api/entity/ApprovalFormatTreeNode.java | 36 + .../ApprovalFormatUpdateRequestBody.java | 27 + .../ApprovalViewObjectUpdateRequestBody.java | 29 + .../entity/ApproveFormatPreviewParameter.java | 30 + .../api/entity/HelpMetadataSimpleContent.java | 27 + .../api/entity/HelpProviderResult.java | 15 + .../api/entity/schema/ComplexField.java | 16 + .../api/entity/schema/Entity.java | 17 + .../api/entity/schema/Field.java | 38 + .../api/entity/schema/FormSchema.java | 22 + .../api/entity/schema/SimpleField.java | 23 + .../api/entity/schema/editor/CheckBox.java | 16 + .../api/entity/schema/editor/DateBox.java | 20 + .../api/entity/schema/editor/EnumField.java | 17 + .../api/entity/schema/editor/FieldEditor.java | 25 + .../entity/schema/editor/LanguageTextBox.java | 16 + .../entity/schema/editor/MultiTextBox.java | 16 + .../api/entity/schema/editor/NumericBox.java | 17 + .../api/entity/schema/editor/TextBox.java | 16 + .../api/entity/schema/type/BooleanType.java | 16 + .../api/entity/schema/type/DateType.java | 16 + .../entity/schema/type/DynamicObjectType.java | 17 + .../api/entity/schema/type/EntityType.java | 27 + .../api/entity/schema/type/EnumItem.java | 18 + .../api/entity/schema/type/EnumType.java | 23 + .../api/entity/schema/type/FieldType.java | 32 + .../api/entity/schema/type/HierarchyType.java | 19 + .../api/entity/schema/type/NumericType.java | 21 + .../api/entity/schema/type/ObjectType.java | 27 + .../api/entity/schema/type/StringType.java | 19 + .../api/entity/schema/type/TextType.java | 19 + .../rpcservice/IApprovalFormatRpcService.java | 46 + .../service/ApprovalFormMetadataService.java | 52 + .../api/service/ApprovalFormatService.java | 185 + .../api/service/BusinessEntityService.java | 25 + .../api/service/DimensionService.java | 27 + .../api/service/IRuntimeMetadataService.java | 23 + .../ApprovalFormMetadataWebService.java | 52 + .../webservice/ApprovalFormatWebService.java | 238 + .../webservice/BusinessEntityWebService.java | 35 + .../api/webservice/DimensionWebService.java | 36 + web-approval-format-core/pom.xml | 81 + .../config/ApprovalFormatConfiguration.java | 127 + .../converter/ApprovalFormatConverter.java | 85 + .../core/domain/entity/ApprovalFormatDO.java | 26 + .../domain/manager/ApprovalFormatManager.java | 213 + .../repository/ApprovalFormatRepository.java | 92 + .../ApprovalFormatRpcServiceImpl.java | 95 + .../ApprovalFormMetadataServiceImpl.java | 107 + .../service/ApprovalFormatServiceImpl.java | 817 ++ .../service/BusinessEntityServiceImpl.java | 36 + .../core/service/DimensionServiceImpl.java | 43 + .../service/RuntimeMetadataServiceImpl.java | 29 + .../core/util/ApprovalFormSchemaUtil.java | 89 + .../core/util/ApprovalFormUtil.java | 394 + .../core/util/ApprovalFormatPermission.java | 23 + .../core/util/ApprovalFormatTreeUtil.java | 281 + .../core/util/ApprovalFormatUtil.java | 67 + .../core/util/ApproveFormatPreviewUtil.java | 52 + .../approvalformat/core/util/FieldUtil.java | 320 + .../core/util/HelpProviderUtil.java | 37 + .../core/util/TypeBuildingContext.java | 261 + .../ApprovalFormMetadataWebServiceImpl.java | 45 + .../ApprovalFormatWebServiceImpl.java | 149 + .../BusinessEntityWebServiceImpl.java | 32 + .../webservice/DimensionWebServiceImpl.java | 29 + .../main/resources/META-INF/spring.factories | 2 + web-approval-format-rpc/pom.xml | 48 + .../RtcDeployApprovalFormatConfiguration.java | 17 + .../RtcValidationApproveConfiguration.java | 59 + .../WebApprovalFormatRpcConfiguration.java | 14 + .../ApprovalFormatRpcServiceImpl.java | 123 + .../rpcservice/IApprovalFormatRpcService.java | 35 + .../DeployApprovalFormat.java | 9 + .../DeployApprovalFormatImpl.java | 32 + .../RtcValidationApproveWebService.java | 21 + .../RtcValidationApproveWebServiceImpl.java | 20 + .../main/resources/META-INF/spring.factories | 6 + web-common/pom.xml | 61 + .../inspur/edp/web/common/GSPException.java | 26 + .../inspur/edp/web/common/GspProjectUtil.java | 52 + .../edp/web/common/JITEngineConstants.java | 58 + .../constant/FrontendProjectConstant.java | 190 + .../web/common/constant/LanguageConstant.java | 21 + .../web/common/constant/MetadataConstant.java | 21 + .../web/common/core/EnumValueParsable.java | 73 + .../web/common/encrypt/EncryptConstant.java | 18 + .../web/common/encrypt/EncryptUtility.java | 335 + .../web/common/entity/NodeJsCommandEnum.java | 22 + .../edp/web/common/entity/ResultCode.java | 23 + .../edp/web/common/entity/ResultMessage.java | 52 + .../edp/web/common/entity/TerminalType.java | 115 + .../environment/EnvironmentException.java | 45 + .../environment/ExecuteEnvironment.java | 27 + .../environment/ExecuteEnvironmentEnum.java | 24 + .../ExecuteEnvironmentCheckResult.java | 40 + .../checker/ExecuteEnvironmentChecker.java | 163 + .../inspur/edp/web/common/io/FileUtility.java | 802 ++ .../web/common/io/NodeJsCommandResult.java | 23 + .../web/common/io/NodejsFunctionUtility.java | 217 + .../edp/web/common/logger/WebLogger.java | 188 + .../web/common/metadata/MetadataUtility.java | 471 + .../serialize/MyPropertyNamingStrategy.java | 33 + .../common/serialize/SerializeUtility.java | 279 + .../edp/web/common/utility/Base64Utility.java | 48 + .../utility/CommandExecuteInterceptor.java | 148 + .../common/utility/CommandExecuteResult.java | 50 + .../common/utility/CommandLineUtility.java | 137 + .../edp/web/common/utility/CommonUtility.java | 57 + .../utility/DesigntimeLoggerUtility.java | 7 + .../edp/web/common/utility/EqualsUtility.java | 76 + .../edp/web/common/utility/ListUtility.java | 30 + .../web/common/utility/LoggerLevelEnum.java | 13 + .../edp/web/common/utility/LoggerUtility.java | 120 + .../utility/OperatingSystemUtility.java | 42 + .../edp/web/common/utility/RandomUtility.java | 20 + .../common/utility/RuntimeLoggerUtility.java | 13 + .../edp/web/common/utility/StringUtility.java | 305 + .../edp/web/common/utility/TupleFour.java | 47 + .../edp/web/common/utility/TupleTwo.java | 20 + .../inspur/edp/web/common/OSHelperTest.java | 29 + .../ExecuteEnvironmentCheckerTest.java | 44 + .../edp/web/common/io/FileUtilityTest.java | 23 + .../edp/web/common/io/sourcefile/package.json | 212 + .../edp/web/common/io/targetfile/package.json | 212 + .../edp/web/common/logger/WebLoggerTest.java | 43 + .../utility/CommandLineUtilityTest.java | 20 + .../utility/OperatingSystemUtilityTest.java | 13 + web-designschema-api/pom.xml | 21 + .../api/entity/DesignSchemaCreateEntity.java | 28 + .../webservice/DesignSchemaWebService.java | 32 + web-designschema/libs/caf-cef-schema.jar | Bin 0 -> 14357 bytes .../com.inspur.edp.cef.designtime.api.jar | Bin 0 -> 295313 bytes .../libs/com.inspur.edp.das.commonmodel.jar | Bin 0 -> 138808 bytes .../com.inspur.edp.formserver.viewmodel.jar | Bin 0 -> 284199 bytes .../com.inspur.edp.udt.designtime.api.jar | Bin 0 -> 101129 bytes web-designschema/pom.xml | 82 + .../config/DesignSchemaConfiguration.java | 22 + .../designschema/elements/ComplexField.java | 11 + .../designschema/elements/DynamicField.java | 12 + .../edp/web/designschema/elements/Entity.java | 74 + .../edp/web/designschema/elements/Field.java | 123 + .../edp/web/designschema/elements/Schema.java | 93 + .../designschema/elements/SimpleField.java | 68 + .../web/designschema/elements/Variable.java | 47 + .../elements/editor/CheckBox.java | 11 + .../elements/editor/DataSource.java | 47 + .../designschema/elements/editor/DateBox.java | 21 + .../elements/editor/DefaultEditor.java | 11 + .../elements/editor/EnumField.java | 12 + .../elements/editor/FieldEditor.java | 21 + .../elements/editor/LanguageTextBox.java | 7 + .../elements/editor/LookupEdit.java | 112 + .../elements/editor/MultiTextBox.java | 7 + .../elements/editor/NumericBox.java | 7 + .../elements/editor/RadioGroup.java | 7 + .../elements/editor/SwitchField.java | 7 + .../designschema/elements/editor/TextBox.java | 8 + .../elements/type/BigNumericType.java | 56 + .../elements/type/BooleanType.java | 33 + .../elements/type/DateTimeType.java | 35 + .../designschema/elements/type/DateType.java | 35 + .../elements/type/DynamicObjectType.java | 22 + .../elements/type/EntityType.java | 48 + .../designschema/elements/type/EnumItem.java | 28 + .../designschema/elements/type/EnumType.java | 61 + .../designschema/elements/type/FieldType.java | 45 + .../elements/type/HierarchyType.java | 7 + .../elements/type/NumericType.java | 51 + .../elements/type/ObjectType.java | 38 + .../elements/type/StringType.java | 43 + .../designschema/elements/type/TextType.java | 41 + .../designschema/generator/EntityBuilder.java | 87 + .../designschema/generator/FieldBuilder.java | 630 + .../generator/FieldTypeBuilder.java | 229 + .../designschema/generator/SchemaBuilder.java | 33 + .../generator/TypeBuildingContext.java | 458 + .../generator/UdtExtBuildingContext.java | 15 + .../generator/UdtFieldTreeNode.java | 51 + .../generator/VariableBuilder.java | 28 + .../generator/VariableTypeBuilder.java | 37 + .../BaseDesignSchemaChangeHandler.java | 66 + .../DesignSchemaChangeListener.java | 34 + .../synchronization/FormMetadataUpdate.java | 54 + .../synchronization/LookupConfig.java | 33 + .../NocodeDesignSchemaChangeListener.java | 54 + .../synchronization/Synchronizer.java | 335 + .../udtextensiondef/FormUdtExtension.java | 33 + .../FormUdtExtensionDeserializer.java | 107 + .../FormUdtExtensionSerializer.java | 21 + .../web/designschema/utils/StringUtils.java | 29 + .../DesignSchemaWebServiceImpl.java | 61 + .../main/resources/META-INF/spring.factories | 2 + .../DesignSchemaChangeListenerTest.java | 27 + .../designschema/synchronization/help.json | 3563 ++++++ .../DesignSchemaWebServiceImplTest.java | 25 + web-form-jitengine/pom.xml | 45 + .../edp/web/jitengine/JITEngineManager.java | 733 ++ .../jitengine/NpmInstallBeforeGenerate.java | 24 + .../web/jitengine/ProjectCompileContext.java | 220 + .../babelgrnerate/GenerateForBabel.java | 67 + .../web/jitengine/constant/JitConstant.java | 11 + .../DynamicFormMetaFileNameGenerator.java | 19 + .../DynamicFormModuleOperation.java | 27 + .../expressions/DesignExpressionValue.java | 26 + .../ExpressionFormFieldExpression.java | 74 + .../ExpressionFormFieldJsonEntity.java | 69 + .../expressions/ExpressionFormGenerator.java | 97 + .../expressions/ExpressionFormJsonEntity.java | 40 + .../expressions/ExpressionManifest.java | 58 + .../ExpressionManifestJsonEntity.java | 36 + .../ExpressionManifestJsonItemEntity.java | 35 + .../ExpressionManifestManager.java | 109 + .../web/jitengine/expressions/FieldInfo.java | 46 + .../ModuleExpressionStatement.java | 66 + .../ModuleFormExpressionFieldItem.java | 58 + .../expressions/ModuleFormExpressionItem.java | 41 + .../expressions/ModuleFormExpressions.java | 52 + .../expressions/ModuleSchemaEntities.java | 56 + .../expressions/ModuleSchemaEntityType.java | 52 + .../DefaultFunctionExpressionParser.java | 64 + .../parser/EntityExpressionParser.java | 114 + .../parser/ExpressionParserManager.java | 50 + .../parser/FieldsExpressionParser.java | 69 + .../utility/ExpressionUtility.java | 220 + .../utility/FieldByIDAndVMIDResult.java | 52 + .../expressions/utility/TableFieldsInfo.java | 44 + .../i18nresource/GenerateResourceManager.java | 223 + .../GeneratedI18nResourceList.java | 33 + .../i18nresource/GeneratedI8nResource.java | 33 + .../i18nresource/I18nResourceLanguage.java | 15 + .../CommandServiceAnalysis.java | 143 + .../metadataanalysis/CommandsAnalysis.java | 262 + .../metadataanalysis/EapiAnalysis.java | 71 + .../metadataanalysis/FormAnalysis.java | 103 + .../StateMachineAnalysis.java | 43 + .../TsBuildConfigJsonGenerator.java | 56 + .../form/FormComponentParser.java | 109 + .../metadatamanager/BaseMetaDataManager.java | 75 + .../CommandExtendProperty.java | 17 + .../CommandServiceManager.java | 69 + .../CommandsMetadataManager.java | 23 + .../ComponentMetadataManager.java | 23 + .../metadatamanager/EapiMetadataManager.java | 27 + .../metadatamanager/FormMetadataManager.java | 53 + .../StateMachineMetadataManager.java | 17 + .../app/AppMetadataManager.java | 20 + .../metadatamodel/app/AppConfig.java | 40 + .../form/AnalysisExternalComponentResult.java | 62 + .../CommandServiceAnalysis.java | 44 + .../sourcecode/SourceCodeInFormManager.java | 124 + .../sourcecode/SourceCodeInFormRef.java | 46 + .../web/jitengine/utility/PathUtility.java | 43 + .../ExpressionFormGeneratorTest.java | 34 + .../expressions/SystemVariableTest.java | 23 + .../web/jitengine/expressions/bxd003.frm.json | 10384 ++++++++++++++++ .../expressions/expensemrgtxflcjt.frm.json | 4736 +++++++ .../NpmPacakgeWebServiceImplTest.java | 30 + web-form-metadata-api/pom.xml | 22 + .../api/FormMetadataCommonService.java | 12 + .../api/FormMetadataWebService.java | 79 + .../api/entity/FormSuInfoEntity.java | 24 + .../api/entity/ReplicateFormRequestBody.java | 68 + .../api/entity/SuInfoWithBizobjIdEntity.java | 14 + web-form-metadata/pom.xml | 67 + .../config/FormMetadataConfiguration.java | 33 + .../constant/ReplicationConstant.java | 8 + .../entity/FormRelateViewModelEntity.java | 87 + .../event/FormMetadataSaveEventListener.java | 270 + .../event/WebCommandMetadataDelete.java | 246 + .../i18n/FormMetadataI18nService.java | 289 + .../i18n/I18nResourceItemManager.java | 68 + .../web/formmetadata/i18n/II18nResource.java | 20 + .../i18n/component/BaseComponent.java | 49 + .../i18n/component/ComponentContext.java | 31 + .../i18n/component/ComponentUtility.java | 590 + .../I18nResourceStrategyContext.java | 44 + .../I18nResourceStrategyFactory.java | 120 + .../i18n/component/I18nResourceUtility.java | 117 + .../i18n/component/IComponent.java | 15 + .../i18n/component/II18nResourceStrategy.java | 20 + .../AbstractI18nResourceStrategy.java | 123 + .../ButtonI18nResourceStrategy.java | 22 + .../CalendarI18nResourceStrategy.java | 23 + .../CheckGroupI18nResourceStrategy.java | 93 + .../ComboListI18nResourceStrategy.java | 50 + .../ComboLookupI18nResourceStrategy.java | 48 + .../DataGridI18nResourceStrategy.java | 186 + .../DateBoxI18nResourceStrategy.java | 45 + .../DatePickerI18nResourceStrategy.java | 48 + .../DefaultComponentI18nResourceStrategy.java | 26 + .../EnumFieldI18nResourceStrategy.java | 63 + .../FieldSetI18nResourceStrategy.java | 74 + ...FileUploadPreviewI18nResourceStrategy.java | 80 + .../FooterI18nResourceStrategy.java | 70 + .../GridFieldI18nResourceStrategy.java | 154 + .../HeaderI18nResourceStrategy.java | 73 + .../HelpProviderI18nResourceStrategy.java | 78 + .../HtmlTemplateI18nResourceStrategy.java | 129 + .../InputGroupI18nResourceStrategy.java | 135 + .../LanguageTextBoxI18nResourceStrategy.java | 46 + .../ListFilterI18nResourceStrategy.java | 128 + .../ListNavI18nResourceStrategy.java | 25 + .../ListViewII18nResourceStrategy.java | 166 + .../LookupI18nResourceStrategy.java | 46 + .../MultiTextBoxI18nResourceStrategy.java | 50 + .../NavTabI18nResourceStrategy.java | 79 + .../NumberRangeI18nResourceStrategy.java | 44 + .../NumberSpinnerI18nResourceStrategy.java | 44 + .../NumericBoxI18nResourceStrategy.java | 47 + ...anizationSelectorI18nResourceStrategy.java | 45 + ...PersonnelSelectorI18nResourceStrategy.java | 45 + .../QueryFrameworkI18nResourceStrategy.java | 19 + .../QuerySchemeI18nResourceStrategy.java | 168 + .../RadioGroupI18nResourceStrategy.java | 94 + .../RichTextBoxI18nResourceStrategy.java | 44 + .../ScrollSpyI18nResourceStrategy.java | 67 + .../SectionI18nResourceStrategy.java | 54 + .../TagI18nResourceStrategy.java | 21 + .../TagsI18nResourceStrategy.java | 98 + .../TextBoxI18nResourceStrategy.java | 43 + .../TimePickerI18nResourceStrategy.java | 50 + .../TimeSpinnerI18nResourceStrategy.java | 48 + .../ToolBarItemI18nResourceStrategy.java | 19 + .../ViewChangeI18nResourceStrategy.java | 78 + .../WizardI18nResourceStrategy.java | 74 + .../AbstractComponentIdStrategy.java | 27 + .../idstrategy/ComponentIdFactory.java | 59 + .../strategy/idstrategy/ComponentIdType.java | 20 + .../idstrategy/DefaultIdStrategy.java | 11 + .../idstrategy/HtmlTemplateIdStrategy.java | 22 + .../idstrategy/IComponentIdStrategy.java | 19 + .../AbstractComponentNameStrategy.java | 22 + .../namestrategy/CaptionStrategy.java | 16 + .../namestrategy/ComponentNameFactory.java | 81 + .../namestrategy/ComponentNameType.java | 39 + .../namestrategy/DefaultNameStrategy.java | 9 + .../namestrategy/IComponentNameStrategy.java | 16 + .../strategy/namestrategy/LabelStrategy.java | 12 + .../PresetQuerySolutionNameStrategy.java | 15 + .../namestrategy/QueryNameStrategy.java | 12 + .../strategy/namestrategy/TextStrategy.java | 13 + .../strategy/namestrategy/TitleStrategy.java | 16 + .../i18n/constant/ComponentType.java | 218 + .../i18n/constant/I18nResourceConstant.java | 45 + .../FormMetadataInitialization.java | 24 + .../FormMetadataCreateLicControlListener.java | 63 + .../lic/ModuleWithMetadataType.java | 38 + .../manager/FormMetadataManager.java | 56 + .../metadata/FormMetadataContent.java | 101 + .../metadata/FormMetadataContentService.java | 64 + .../metadata/formdom/FormDOM.java | 34 + .../metadata/formdom/FormDomService.java | 47 + .../metadata/formdom/FormOptions.java | 50 + .../metadata/i18nsetting/I18nSetting.java | 45 + .../languagepackage/LanguagePackage.java | 9 + .../formmetadata/metadata/module/Module.java | 363 + .../metadata/module/ModuleService.java | 35 + .../replication/FormMetadataReplicator.java | 285 + .../replication/FormMetadataSmManager.java | 57 + .../replication/FormMetadataVoManager.java | 72 + .../replication/MetadataCloneManager.java | 268 + .../MetadataReplicationContext.java | 63 + .../MetadataReplicationContextService.java | 64 + .../ProjectInformationManager.java | 175 + .../FormMetadataContentSerializer.java | 45 + .../FormMetadataJsonSerializer.java | 55 + .../FormMetadataTransferSerializer.java | 46 + .../FormMetadataCommonServiceImpl.java | 36 + .../service/FormMetadataRTService.java | 80 + .../service/FormMetataService.java | 268 + .../FormMetadataWebServiceImpl.java | 92 + .../main/resources/META-INF/spring.factories | 2 + .../i18n/FormMetadataI18nServiceTest.java | 30 + .../formmetadata/i18n/HtmlTemplateTest.java | 25 + .../edp/web/formmetadata/i18n/form.json | 6558 ++++++++++ ...mMetadataCreateLicControlListenerTest.java | 37 + .../FormMetadataContentSerializerTest.java | 23 + web-form-process-api/pom.xml | 19 + .../api/service/FormProcessService.java | 5 + web-form-process/pom.xml | 58 + .../config/FormProcessConfiguration.java | 20 + .../service/FormProcessServiceImpl.java | 119 + web-frontendproject-api/pom.xml | 24 + .../entity/ChosenFormItem.java | 38 + .../entity/ChosenFormList.java | 138 + .../FrontendProjectGenerateParameter.java | 50 + .../frontendproject/entity/RestMessage.java | 61 + .../resolver/ResolveFormMetadataItem.java | 46 + .../resolver/ResolveFormMetadataList.java | 74 + .../webservice/FormDynamicParameter.java | 50 + .../FormMetadataDebugUriWebService.java | 32 + .../webservice/FrontendProjectWebService.java | 68 + .../webservice/ZeroCodeWebService.java | 22 + .../zerocode/ZeroCodeFormFormatParameter.java | 21 + .../zerocode/ZeroCodeFormParameter.java | 130 + .../ZeroCodeFormRefMetadataParameter.java | 34 + .../zerocode/ZeroCodeParameter.java | 135 + .../zerocode/ZeroCodeService.java | 37 + web-frontendproject/pom.xml | 64 + .../FrontendProjectCompiler.java | 170 + .../FrontendProjectDeployer.java | 310 + .../FrontendProjectExtractor.java | 156 + .../FrontendProjectManager.java | 122 + .../FrontendProjectService.java | 65 + .../FrontendProjectUtility.java | 184 + .../NpmPackageCheckUpdate.java | 12 + .../build/FrontendProjectBuild.java | 54 + .../ChangeDetectExecuteManager.java | 34 + .../ChangeDetectExecuteResult.java | 70 + .../ChangeDetectExecuteService.java | 27 + .../changedetect/ChangeDetectExecuteType.java | 76 + .../changedetect/ExcludePathEntity.java | 28 + ...CompileChangeDetectStepExecuteService.java | 17 + ...CompileChangeDetectExecuteServiceImpl.java | 61 + .../compile/CompileChangeDetectType.java | 55 + .../FileChangeStepExecuteImpl.java | 179 + .../context/ChangeDetectContext.java | 30 + ...enerateChangeDetectStepExecuteService.java | 24 + ...enerateChangeDetectExecuteServiceImpl.java | 67 + .../GenerateChangeDetectStepType.java | 58 + .../FileChangeStepExecuteImpl.java | 155 + .../MetadataChangeStepExecuteImpl.java | 248 + ...bstractChangeDetectStepExecuteService.java | 87 + .../step/ChangeDetectStepExecuteResult.java | 84 + .../step/ChangeDetectStepExecuteService.java | 27 + .../FormMetadataDebugUriConfiguration.java | 33 + .../config/FrontendProjectConfiguration.java | 21 + .../config/ZeroCodeConfiguration.java | 21 + .../SourceServicePathGenerator.java | 55 + .../AbstractFormMetadataDebugUri.java | 98 + .../debuguri/FormMetadataDebugUriService.java | 36 + .../FormMetadataDebugUriWithMobile.java | 85 + .../debuguri/FormMetadataDebugUriWithPC.java | 39 + .../deploy/FrontendProjectDeploy.java | 59 + .../deploy/SingleDynamicFormDeploy.java | 39 + .../FormDynamicMetadataResolver.java | 23 + .../FormDynamicParameterValidator.java | 28 + .../FormDynamicSourceCodeGenerate.java | 25 + .../formdynamic/FormDynamicTagGetter.java | 31 + .../generate/FrontendProjectGenerate.java | 108 + .../metadata/FormMetadataManager.java | 134 + .../pageflow/PageFlowMetadataManager.java | 178 + .../resolver/FormMetadataResolver.java | 116 + .../FormMetadataDebugUriWebServiceImpl.java | 34 + .../FrontendProjectWebServiceImpl.java | 118 + .../webservice/ZeroCodeWebServiceImpl.java | 73 + .../zerocode/ZeroCodeConstants.java | 17 + .../ZeroCodeParameterInitialization.java | 47 + .../zerocode/ZeroCodeParameterValidator.java | 35 + .../zerocode/ZeroCodeServiceImpl.java | 69 + .../operation/CommandMetadataOperation.java | 24 + .../operation/EapiMetadataOperation.java | 50 + .../operation/FormExpressionOperation.java | 31 + .../FormMetadataContentOperation.java | 111 + .../operation/MetaDataOperationManager.java | 24 + .../operation/PageFlowMetadataOperation.java | 13 + .../StateMachineMetadataOperation.java | 50 + .../zerocode/operation/ZeroCodeManager.java | 173 + .../services/ServicePathGenerator.java | 13 + .../AbstractSourceCodeOperation.java | 10 + .../sourcegenerate/ISourceCodeOperation.java | 7 + .../sourcegenerate/SourceCodeManager.java | 23 + .../SourceCodeMobileOperation.java | 28 + .../sourcegenerate/SourceCodePCOperation.java | 44 + .../SourceCodePathGenerator.java | 46 + .../AbstractWebDevJsonOperation.java | 51 + .../webdevjson/IWevDevJsonOperation.java | 11 + .../webdevjson/WebDevJsonManager.java | 34 + .../webdevjson/WebDevJsonPathGenerator.java | 38 + .../webdevjson/WebDevMobileJsonOperation.java | 22 + .../operation/webdevjson/WebDevPCJson.java | 4 + .../webdevjson/WebDevPCJsonOperation.java | 23 + .../main/resources/META-INF/spring.factories | 4 + .../MetadataChangeStepExecuteImplTest.java | 31 + .../zerocode/ZeroCodeServiceImplTest.java | 28 + .../operation/ZeroCodeManagerTest.java | 15 + web-ide-api/pom.xml | 16 + .../inspur/edp/web/ide/api/PluginConfig.java | 6 + .../inspur/edp/web/ide/api/WebIDEService.java | 10 + web-ide-webapi/pom.xml | 36 + .../ide/config/webapi/common/FileUtil.java | 33 + .../webapi/config/WebIdeConfiguration.java | 17 + .../control/WebIDEServiceController.java | 21 + .../webapi/entity/PanelDescription.java | 24 + .../ide/config/webapi/entity/PanelStyle.java | 10 + .../config/webapi/entity/PluginConfig.java | 20 + .../config/webapi/service/WebIDEService.java | 127 + .../main/resources/META-INF/spring.factories | 2 + web-npmpackage-api/pom.xml | 29 + .../entity/NpmInstallPackageParameter.java | 44 + .../api/entity/NpmInstallParameter.java | 184 + .../entity/NpmPackageCheckUpdateOptions.java | 47 + .../api/entity/NpmPackageConstants.java | 43 + .../api/entity/NpmPackageResponse.java | 68 + .../api/entity/NpmPackageResponseLevel.java | 16 + .../NpmPackageJsonDependencyInfo.java | 29 + .../packagejson/NpmPackageJsonInfo.java | 133 + .../api/entity/settings/NpmRepository.java | 131 + .../api/entity/settings/NpmSettingConfig.java | 35 + .../api/entity/settings/NpmSettingMode.java | 22 + .../api/entity/settings/NpmSettings.java | 57 + .../api/entity/settings/NpmUpdatePolicy.java | 24 + .../NpmPackageInstallWebService.java | 45 + .../NpmPackagePublishWebService.java | 8 + .../api/webservice/NpmPackageWebService.java | 38 + web-npmpackage-core/pom.xml | 32 + .../NpmCacheCleanCommandExecutor.java | 62 + .../core/config/NpmPackageConfiguration.java | 23 + .../NpmPackageInstallConfiguration.java | 20 + .../npminstall/NodeModulesPathGenerator.java | 71 + .../npminstall/NpmInstallCommandExecutor.java | 77 + .../NpmInstallCommandParameterGenerator.java | 87 + .../NpmInstallLockFilePathGenerator.java | 14 + .../core/npminstall/NpmInstallManager.java | 279 + .../NpmInstallParameterValidator.java | 58 + .../npminstall/NpmInstallingParameter.java | 28 + .../npminstall/NpmInstallingTagManager.java | 46 + .../npminstall/NpmRepositoryConnection.java | 24 + .../npminstall/PackageJsonCopyManager.java | 50 + .../npminstall/PackageJsonPathGenerator.java | 37 + .../global/GlobalNpmDeployPathGenerator.java | 42 + .../GlobalNpmInstallCommandExecutor.java | 101 + ...alNpmInstallCommandParameterGenerator.java | 77 + .../GlobalPackageJsonPathGenerator.java | 45 + .../global/NpmInstallGlobalManager.java | 186 + .../npmlogin/NpmLoginCommandExecutor.java | 192 + .../NpmLoginCommandParameterGenerator.java | 17 + .../npmlogout/NpmLogoutCommandExecutor.java | 133 + .../NpmLogoutCommandParameterGenerator.java | 16 + .../core/npmpackagecheck/NpmPackageCheck.java | 111 + .../core/npmsetting/NpmSettingConstant.java | 17 + .../core/npmsetting/NpmSettingConvertor.java | 42 + .../npmsetting/NpmSettingEncryptService.java | 72 + .../npmsetting/NpmSettingInitialization.java | 47 + .../core/npmsetting/NpmSettingManager.java | 68 + .../npmsetting/NpmSettingPathManager.java | 42 + .../core/npmsetting/NpmSettingReader.java | 41 + .../core/npmsetting/NpmSettingWriter.java | 34 + .../core/packagejsonfile/package.json | 216 + .../service/NpmPackageInstallService.java | 26 + .../core/service/NpmPackageService.java | 59 + .../webservice/NpmPacakgeWebServiceImpl.java | 90 + .../NpmPackageInstallWebServiceImpl.java | 81 + .../main/resources/META-INF/spring.factories | 2 + ...mInstallCommandParameterGeneratorTest.java | 52 + .../npmpackagecheck/NpmPackageCheckTest.java | 19 + web-npmpackage-patch/pom.xml | 25 + .../web/npmpackagepatch/FileOperation.java | 175 + .../MyPropertyNamingStrategy.java | 27 + .../NpmPackagePatchService.java | 130 + .../PackageJsonFileManager.java | 93 + .../web/npmpackagepatch/PatchConstants.java | 6 + .../inspur/edp/web/npmpackagepatch/README.md | 2 + .../web/npmpackagepatch/RescureReadFiles.java | 28 + .../npmpackagepatch/SerializePackageJson.java | 184 + .../PackageJsonDependencyInfo.java | 27 + .../packagejson/PackageJsonInfo.java | 107 + .../packagejson/SerializedPackageJson.java | 85 + web-pageflow-metadata/pom.xml | 40 + .../pageflow/metadata/entity/AdaptedPage.java | 27 + .../entity/AdaptedPageFlowMetadataEntity.java | 35 + .../AdaptedPageFlowMetadataEntityService.java | 131 + .../metadata/entity/AdaptedRoute.java | 20 + .../web/pageflow/metadata/entity/Page.java | 31 + .../entity/PageFlowMetadataEntity.java | 105 + .../entity/PageFlowMetadataEntityManager.java | 66 + .../pageflow/metadata/entity/PagePublish.java | 22 + .../web/pageflow/metadata/entity/Project.java | 10 + .../web/pageflow/metadata/entity/Route.java | 60 + .../PageFlowMetadataEventListener.java | 84 + .../PageFlowMetadataEntityManager.java | 34 + .../PageFlowMetadataEntitySerializer.java | 43 + .../PageFlowMetadataTransferSerializer.java | 45 + .../PageFlowMetadataUpdateService.java | 398 + .../metadata/service/RouteMetataService.java | 83 + web-sourcecode-metadata/pom.xml | 40 + .../entity/RelativePathEnumEntity.java | 21 + .../metadata/entity/SourceCodeItemEntity.java | 72 + .../entity/SourceCodeMetadataEntity.java | 64 + .../SourceCodeMetadataEventListener.java | 49 + .../manager/SourceCodeMetadataManager.java | 34 + .../SourceCodeMetadataEntitySerializer.java | 28 + .../SourceCodeMetadataTransferSerializer.java | 29 + .../utility/FileOperationExtensions.java | 48 + .../metadata/utility/FileUtility.java | 24 + .../utility/SourceCodeMetadataUtility.java | 79 + web-statemachine/pom.xml | 33 + .../manager/StateMachineMetadataManager.java | 16 + .../metadata/StateMachineMetadataContent.java | 74 + .../serializer/StateMachineSerializer.java | 32 + .../StateMachineTransferSerializer.java | 27 + web-tsfile-api/pom.xml | 27 + .../edp/web/tsfile/api/entity/FileObject.java | 9 + .../web/tsfile/api/service/TsFileService.java | 64 + .../api/webservice/TsFileWebService.java | 30 + web-tsfile-core/pom.xml | 41 + .../web/tsfile/core/TsFileWebServiceImpl.java | 43 + .../core/config/TsFileConfiguration.java | 27 + .../core/service/TsFileService4WebApi.java | 58 + .../core/service/TsFileServiceImpl.java | 103 + .../edp/web/tsfile/core/util/NameUtil.java | 26 + .../main/resources/META-INF/spring.factories | 2 + xpath0.1.bat | 122 + 734 files changed, 75742 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .mvn/settings.xml create mode 100644 .mvn/wrapper/MavenWrapperDownloader.java create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100644 jitengine-web-api/pom.xml create mode 100644 jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/JitEngineService.java create mode 100644 jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewParameter.java create mode 100644 jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewResponse.java create mode 100644 jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/webservice/JitEngineWebService.java create mode 100644 jitengine-web-core/pom.xml create mode 100644 jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/config/JitEngineWebConfiguration.java create mode 100644 jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/JitEngineServiceImpl.java create mode 100644 jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobilEApprovePreviewImpl.java create mode 100644 jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobileApproveDocker.java create mode 100644 jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/webservice/JitEngineWebSericeImpl.java create mode 100644 jitengine-web-core/src/main/resources/META-INF/spring.factories create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 runtime-api/pom.xml create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/DeployTargetEnum.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildParameter.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildRefMetadata.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildResponse.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitMetadataTypeEnum.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitRuntimeConstant.java create mode 100644 runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/service/JitBuildService.java create mode 100644 runtime-core/pom.xml create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/builddeploy/BuildDeployManager.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametergenerator/JitBuildParameterGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametervalidator/JitBuildParameterValidator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/config/JitBuildConfiguration.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/constant/FormJsonFileSuffixConstant.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/AbstractFormJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/CommandJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/EapiJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormJsonFileManager.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameter.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameterManager.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRouteJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRuntimeMetadataEntity.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FrmJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorFactory.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorInterface.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/ResourceJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/StateMachineJsonFileGenerator.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteEntity.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRoutePageEntity.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteProjectEntity.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI18nResourceList.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI8nResource.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/service/JitBuildServiceImp.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/sourcecodemetadata/SourceCodeMetadataManager.java create mode 100644 runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/utility/JitBuildUtility.java create mode 100644 runtime-core/src/main/resources/META-INF/spring.factories create mode 100644 runtime-scriptcache-api/pom.xml create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormProjectCache.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCache.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCacheContent.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/PublishScriptRequest.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheCheckVersionRequest.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheResponse.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/service/ScriptCacheService.java create mode 100644 runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/webservice/ScriptCacheWebService.java create mode 100644 runtime-scriptcache-api/src/main/resources/log4j2.properties create mode 100644 runtime-scriptcache/libs/bef-engine-core-0.1.12.jar create mode 100644 runtime-scriptcache/libs/bef-engine-core.jar create mode 100644 runtime-scriptcache/libs/bff-engine-core-0.1.4.jar create mode 100644 runtime-scriptcache/libs/bff-engine-core.jar create mode 100644 runtime-scriptcache/libs/cdp-sgf-api.jar create mode 100644 runtime-scriptcache/libs/lcm-metadata-api.jar create mode 100644 runtime-scriptcache/libs/task-api-0.3.11.jar create mode 100644 runtime-scriptcache/libs/web-jitengine-frontendproject-api.jar create mode 100644 runtime-scriptcache/libs/web-jitengine-frontendproject.jar create mode 100644 runtime-scriptcache/pom.xml create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/config/ScriptCacheConfiguration.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/constants/ScriptCacheDBTableConstant.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormProjectCacheConverter.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheContentConverter.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheConverter.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormProjectCacheEntity.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheContentEntity.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheEntity.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormProjectCacheManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheContentManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepository.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheContentRepository.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheRepository.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerFileOperation.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerPathGenerator.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerProjectVersion.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerScriptVersion.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileContent.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileOperation.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcService.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcServiceImpl.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/CustomizationCacheServiceInstanceManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/ScriptCacheVersionManager.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpl.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncrypt.java create mode 100644 runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/webservice/ScriptCacheWebServiceImpl.java create mode 100644 runtime-scriptcache/src/main/resources/META-INF/spring.factories create mode 100644 runtime-scriptcache/src/main/resources/log4j2.properties create mode 100644 runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepositoryTest.java create mode 100644 runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpTest.java create mode 100644 runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncryptTest.java create mode 100644 toout.bat create mode 100644 web-appconfig-api/pom.xml create mode 100644 web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/entity/GspAppConfig.java create mode 100644 web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/webservice/AppConfigWebService.java create mode 100644 web-appconfig-core/pom.xml create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFileManager.java create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFilePathGenerator.java create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/config/AppConfigConfiguration.java create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/constants/GspAppConfigConstants.java create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/service/GspAppConfigService.java create mode 100644 web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/webservice/AppConfigWebServiceImpl.java create mode 100644 web-appconfig-core/src/main/resources/META-INF/spring.factories create mode 100644 web-approval-format-api/pom.xml create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormUpdateRequestBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormat.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateRequestBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateResponseBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatDimensionUpdateRequestBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatEnum.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatForestByDimension.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatQueryResponseBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatTreeNode.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatUpdateRequestBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalViewObjectUpdateRequestBody.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApproveFormatPreviewParameter.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpMetadataSimpleContent.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpProviderResult.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/ComplexField.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Entity.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Field.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/FormSchema.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/SimpleField.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/CheckBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/DateBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/EnumField.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/FieldEditor.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/LanguageTextBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/MultiTextBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/NumericBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/TextBox.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/BooleanType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DateType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DynamicObjectType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EntityType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumItem.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/FieldType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/HierarchyType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/NumericType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/ObjectType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/StringType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/TextType.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/rpcservice/IApprovalFormatRpcService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormMetadataService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormatService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/BusinessEntityService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/DimensionService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/IRuntimeMetadataService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormMetadataWebService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormatWebService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/BusinessEntityWebService.java create mode 100644 web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/DimensionWebService.java create mode 100644 web-approval-format-core/pom.xml create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/config/ApprovalFormatConfiguration.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/converter/ApprovalFormatConverter.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/entity/ApprovalFormatDO.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/manager/ApprovalFormatManager.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/repository/ApprovalFormatRepository.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/rpcservice/ApprovalFormatRpcServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormMetadataServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormatServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/BusinessEntityServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/DimensionServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/RuntimeMetadataServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormSchemaUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatPermission.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatTreeUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApproveFormatPreviewUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/FieldUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/HelpProviderUtil.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/TypeBuildingContext.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormMetadataWebServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormatWebServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/BusinessEntityWebServiceImpl.java create mode 100644 web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/DimensionWebServiceImpl.java create mode 100644 web-approval-format-core/src/main/resources/META-INF/spring.factories create mode 100644 web-approval-format-rpc/pom.xml create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcDeployApprovalFormatConfiguration.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcValidationApproveConfiguration.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/WebApprovalFormatRpcConfiguration.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/ApprovalFormatRpcServiceImpl.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/IApprovalFormatRpcService.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormat.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormatImpl.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/RtcValidationApproveWebService.java create mode 100644 web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/impl/RtcValidationApproveWebServiceImpl.java create mode 100644 web-approval-format-rpc/src/main/resources/META-INF/spring.factories create mode 100644 web-common/pom.xml create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/GSPException.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/GspProjectUtil.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/JITEngineConstants.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/constant/FrontendProjectConstant.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/constant/LanguageConstant.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/constant/MetadataConstant.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/core/EnumValueParsable.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptConstant.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/entity/NodeJsCommandEnum.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessage.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/entity/TerminalType.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/environment/EnvironmentException.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironment.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironmentEnum.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckResult.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentChecker.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/io/FileUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/io/NodeJsCommandResult.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/io/NodejsFunctionUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/logger/WebLogger.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/metadata/MetadataUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/serialize/MyPropertyNamingStrategy.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/Base64Utility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteInterceptor.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteResult.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/CommonUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/DesigntimeLoggerUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/EqualsUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/ListUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerLevelEnum.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/OperatingSystemUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/RandomUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/RuntimeLoggerUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/StringUtility.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/TupleFour.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/TupleTwo.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/OSHelperTest.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckerTest.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/io/FileUtilityTest.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/logger/WebLoggerTest.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/utility/CommandLineUtilityTest.java create mode 100644 web-common/src/test/java/com/inspur/edp/web/common/utility/OperatingSystemUtilityTest.java create mode 100644 web-designschema-api/pom.xml create mode 100644 web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/entity/DesignSchemaCreateEntity.java create mode 100644 web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/webservice/DesignSchemaWebService.java create mode 100644 web-designschema/libs/caf-cef-schema.jar create mode 100644 web-designschema/libs/com.inspur.edp.cef.designtime.api.jar create mode 100644 web-designschema/libs/com.inspur.edp.das.commonmodel.jar create mode 100644 web-designschema/libs/com.inspur.edp.formserver.viewmodel.jar create mode 100644 web-designschema/libs/com.inspur.edp.udt.designtime.api.jar create mode 100644 web-designschema/pom.xml create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/config/DesignSchemaConfiguration.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/ComplexField.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/DynamicField.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Entity.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Field.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Schema.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/SimpleField.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Variable.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/CheckBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DataSource.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DateBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DefaultEditor.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/EnumField.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/FieldEditor.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LanguageTextBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LookupEdit.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/MultiTextBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/NumericBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/RadioGroup.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/SwitchField.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/TextBox.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BigNumericType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BooleanType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateTimeType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DynamicObjectType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EntityType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumItem.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/FieldType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/HierarchyType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/NumericType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/ObjectType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/StringType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/TextType.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/EntityBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldTypeBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/SchemaBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/TypeBuildingContext.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtExtBuildingContext.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtFieldTreeNode.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableTypeBuilder.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/BaseDesignSchemaChangeHandler.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListener.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/FormMetadataUpdate.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/LookupConfig.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/NocodeDesignSchemaChangeListener.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/Synchronizer.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtension.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionDeserializer.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionSerializer.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/utils/StringUtils.java create mode 100644 web-designschema/src/main/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImpl.java create mode 100644 web-designschema/src/main/resources/META-INF/spring.factories create mode 100644 web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListenerTest.java create mode 100644 web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/help.json create mode 100644 web-designschema/src/main/test/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImplTest.java create mode 100644 web-form-jitengine/pom.xml create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/JITEngineManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/NpmInstallBeforeGenerate.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/ProjectCompileContext.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/babelgrnerate/GenerateForBabel.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/constant/JitConstant.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormMetaFileNameGenerator.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormModuleOperation.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/DesignExpressionValue.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldExpression.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldJsonEntity.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGenerator.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormJsonEntity.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifest.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonEntity.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonItemEntity.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/FieldInfo.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleExpressionStatement.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionFieldItem.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionItem.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressions.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntities.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntityType.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/DefaultFunctionExpressionParser.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/EntityExpressionParser.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/ExpressionParserManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/FieldsExpressionParser.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/ExpressionUtility.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/FieldByIDAndVMIDResult.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/TableFieldsInfo.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GenerateResourceManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI18nResourceList.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI8nResource.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/I18nResourceLanguage.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandServiceAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandsAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/EapiAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/FormAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/StateMachineAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/TsBuildConfigJsonGenerator.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/form/FormComponentParser.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/BaseMetaDataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandExtendProperty.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandServiceManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandsMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/ComponentMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/EapiMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/FormMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/StateMachineMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/app/AppMetadataManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/AppConfig.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/form/AnalysisExternalComponentResult.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataparser/commandservice/CommandServiceAnalysis.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormManager.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormRef.java create mode 100644 web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/utility/PathUtility.java create mode 100644 web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGeneratorTest.java create mode 100644 web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/SystemVariableTest.java create mode 100644 web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/bxd003.frm.json create mode 100644 web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/expensemrgtxflcjt.frm.json create mode 100644 web-form-jitengine/src/test/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImplTest.java create mode 100644 web-form-metadata-api/pom.xml create mode 100644 web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataCommonService.java create mode 100644 web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataWebService.java create mode 100644 web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/FormSuInfoEntity.java create mode 100644 web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/ReplicateFormRequestBody.java create mode 100644 web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/SuInfoWithBizobjIdEntity.java create mode 100644 web-form-metadata/pom.xml create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/constant/ReplicationConstant.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/entity/FormRelateViewModelEntity.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/FormMetadataSaveEventListener.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/WebCommandMetadataDelete.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/I18nResourceItemManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/II18nResource.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/BaseComponent.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentContext.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentUtility.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyContext.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyFactory.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceUtility.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/IComponent.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/II18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/AbstractI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ButtonI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CalendarI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CheckGroupI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboListI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboLookupI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DataGridI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DateBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DatePickerI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DefaultComponentI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/EnumFieldI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FieldSetI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FileUploadPreviewI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FooterI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/GridFieldI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HeaderI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HelpProviderI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HtmlTemplateI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/InputGroupI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LanguageTextBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListFilterI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListNavI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListViewII18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LookupI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/MultiTextBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NavTabI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberRangeI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberSpinnerI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumericBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/OrganizationSelectorI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/PersonnelSelectorI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QueryFrameworkI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QuerySchemeI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RadioGroupI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RichTextBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ScrollSpyI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/SectionI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagsI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TextBoxI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimePickerI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimeSpinnerI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ToolBarItemI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ViewChangeI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/WizardI18nResourceStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/AbstractComponentIdStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdFactory.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdType.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/DefaultIdStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/HtmlTemplateIdStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/IComponentIdStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/AbstractComponentNameStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/CaptionStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameFactory.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameType.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/DefaultNameStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/IComponentNameStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/LabelStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/PresetQuerySolutionNameStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/QueryNameStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TextStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TitleStrategy.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/ComponentType.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/I18nResourceConstant.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/initialization/FormMetadataInitialization.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListener.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/ModuleWithMetadataType.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/manager/FormMetadataManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContent.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContentService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDOM.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDomService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormOptions.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/i18nsetting/I18nSetting.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/languagepackage/LanguagePackage.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/Module.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/ModuleService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataReplicator.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataSmManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataVoManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataCloneManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContext.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContextService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/ProjectInformationManager.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializer.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataJsonSerializer.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataTransferSerializer.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataCommonServiceImpl.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataRTService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetataService.java create mode 100644 web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/FormMetadataWebServiceImpl.java create mode 100644 web-form-metadata/src/main/resources/META-INF/spring.factories create mode 100644 web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nServiceTest.java create mode 100644 web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/HtmlTemplateTest.java create mode 100644 web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/form.json create mode 100644 web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListenerTest.java create mode 100644 web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializerTest.java create mode 100644 web-form-process-api/pom.xml create mode 100644 web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java create mode 100644 web-form-process/pom.xml create mode 100644 web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java create mode 100644 web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java create mode 100644 web-frontendproject-api/pom.xml create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormItem.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormList.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/FrontendProjectGenerateParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/RestMessage.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataItem.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataList.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormDynamicParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebService.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebService.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebService.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormFormatParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormRefMetadataParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameter.java create mode 100644 web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeService.java create mode 100644 web-frontendproject/pom.xml create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectCompiler.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectExtractor.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectUtility.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/NpmPackageCheckUpdate.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/build/FrontendProjectBuild.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteResult.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteType.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ExcludePathEntity.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/AbstractCompileChangeDetectStepExecuteService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectExecuteServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectType.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/stepexecute/FileChangeStepExecuteImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/context/ChangeDetectContext.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/AbstractGenerateChangeDetectStepExecuteService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectExecuteServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectStepType.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/FileChangeStepExecuteImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/AbstractChangeDetectStepExecuteService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteResult.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FormMetadataDebugUriConfiguration.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FrontendProjectConfiguration.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/ZeroCodeConfiguration.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/customservice/SourceServicePathGenerator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/AbstractFormMetadataDebugUri.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriService.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithMobile.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithPC.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/FrontendProjectDeploy.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/SingleDynamicFormDeploy.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicMetadataResolver.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicParameterValidator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicSourceCodeGenerate.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicTagGetter.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/metadata/FormMetadataManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/pageflow/PageFlowMetadataManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/resolver/FormMetadataResolver.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeConstants.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterInitialization.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterValidator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImpl.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/CommandMetadataOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/EapiMetadataOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormExpressionOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormMetadataContentOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/MetaDataOperationManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/PageFlowMetadataOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/StateMachineMetadataOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/services/ServicePathGenerator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/AbstractSourceCodeOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/ISourceCodeOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeMobileOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePCOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePathGenerator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/AbstractWebDevJsonOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/IWevDevJsonOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonManager.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonPathGenerator.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevMobileJsonOperation.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJson.java create mode 100644 web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJsonOperation.java create mode 100644 web-frontendproject/src/main/resources/META-INF/spring.factories create mode 100644 web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImplTest.java create mode 100644 web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImplTest.java create mode 100644 web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManagerTest.java create mode 100644 web-ide-api/pom.xml create mode 100644 web-ide-api/src/main/java/com/inspur/edp/web/ide/api/PluginConfig.java create mode 100644 web-ide-api/src/main/java/com/inspur/edp/web/ide/api/WebIDEService.java create mode 100644 web-ide-webapi/pom.xml create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/common/FileUtil.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/config/WebIdeConfiguration.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/control/WebIDEServiceController.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelDescription.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelStyle.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PluginConfig.java create mode 100644 web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/service/WebIDEService.java create mode 100644 web-ide-webapi/src/main/resources/META-INF/spring.factories create mode 100644 web-npmpackage-api/pom.xml create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java create mode 100644 web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java create mode 100644 web-npmpackage-core/pom.xml create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallService.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageService.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImpl.java create mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java create mode 100644 web-npmpackage-core/src/main/resources/META-INF/spring.factories create mode 100644 web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java create mode 100644 web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java create mode 100644 web-npmpackage-patch/pom.xml create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java create mode 100644 web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java create mode 100644 web-pageflow-metadata/pom.xml create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java create mode 100644 web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetataService.java create mode 100644 web-sourcecode-metadata/pom.xml create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileUtility.java create mode 100644 web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java create mode 100644 web-statemachine/pom.xml create mode 100644 web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java create mode 100644 web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java create mode 100644 web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java create mode 100644 web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java create mode 100644 web-tsfile-api/pom.xml create mode 100644 web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java create mode 100644 web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java create mode 100644 web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java create mode 100644 web-tsfile-core/pom.xml create mode 100644 web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java create mode 100644 web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java create mode 100644 web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java create mode 100644 web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java create mode 100644 web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java create mode 100644 web-tsfile-core/src/main/resources/META-INF/spring.factories create mode 100644 xpath0.1.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..19fd071d --- /dev/null +++ b/.gitignore @@ -0,0 +1,758 @@ +.scratch/ +.mvn/repository + +# Created by https://www.gitignore.io/api/vim,node,java,linux,macos,emacs,nanoc,eclipse,windows,java-web,visualstudio,jetbrains+iml,visualstudiocode,maven,gradle + +### Eclipse ### + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +### Eclipse Patch ### +# Eclipse Core +.project + +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +### Java ### +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +### Java-Web ### +## ignoring target file +target/ + +### JetBrains+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +### JetBrains+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +### Linux ### + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Maven ### +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +### Nanoc ### +# For projects using Nanoc (http://nanoc.ws/) + +# Default location for output (needs to match output_dir's value found in nanoc.yaml) +output/ + +# Temporary file directory +tmp/nanoc/ + +# Crash Log +crash.log + +### Node ### +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +# !.vscode/settings.json +# !.vscode/tasks.json +# !.vscode/launch.json +# !.vscode/extensions.json + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### Gradle ### +.gradle +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp_proj +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + + +# End of https://www.gitignore.io/api/vim,node,java,linux,macos,emacs,nanoc,eclipse,windows,java-web,visualstudio,jetbrains+iml,visualstudiocode,maven,gradle + +!charts/*/charts/*.tgz + +# flatten plugin xml +**/.flattened-pom.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..0d525977 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,88 @@ +stages: + - build + - test + - package + - deploy + +variables: + # Maven + MAVEN_OPTS: -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true + # MAVEN_CONFIG: --batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true -s .mvn/settings.xml + MAVEN_CONFIG: --batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -s .mvn/settings.xml + MAVEN_USER_HOME: .mvn/ + +before_script: + - echo _auth=$(echo -n $ARTIFACTS_REPO_USERNAME:$ARTIFACTS_REPO_PASSWORD | base64) >> .npmrc + + + +Build with Maven: + stage: build + tags: + - alicloud + except: + variables: + - $CI_COMMIT_MESSAGE =~ /^Helm debug:\ .*/ + cache: + paths: + - .mvn/wrapper/maven-wrapper.jar + - .mvn/wrapper/dists/ + - .mvn/repository/ + image: openjdk:8-stretch + script: + - chmod a+x ./mvnw + - ./mvnw -DskipTests=true clean install +# artifacts: +# paths: +# - caf-boot-parent/target/app.jar +# expire_in: 10d + + + +Run Java unit tests: + stage: test + tags: + - alicloud + except: + variables: + - $CI_COMMIT_MESSAGE =~ /^Helm debug:\ .*/ + cache: + paths: + - .mvn/wrapper/maven-wrapper.jar + - .mvn/wrapper/dists/ + - .mvn/repository/ + services: + - name: redis:latest + alias: redis + - name: postgres:10 + alias: postgres + image: openjdk:8-stretch + script: + - chmod a+x ./mvnw + - ./mvnw -U clean clover:setup test clover:aggregate clover:clover + - ./mvnw -Dmaven.clover.singleCloverDatabase=true clover:log + coverage: '/^ {8}Total\: (\d+%|\d+\.\d+%)/' + artifacts: + paths: + - target/site/clover + expire_in: 10d + dependencies: [] + + +Package: + stage: package + tags: + - alicloud + only: + - master + - tags + cache: + paths: + - .mvn/wrapper/maven-wrapper.jar + - .mvn/wrapper/dists/ + - .mvn/repository/ + image: openjdk:8-stretch + script: + - chmod a+x ./mvnw + - ./mvnw -DskipTests=true clean deploy + diff --git a/.mvn/settings.xml b/.mvn/settings.xml new file mode 100644 index 00000000..c1a2a190 --- /dev/null +++ b/.mvn/settings.xml @@ -0,0 +1,113 @@ + + .mvn/repository + + + caf-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + caf-snapshots-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + caf-releases-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + gsp-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + gsp-snapshots-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + gsp-releases-repo + ${env.ARTIFACTS_REPO_USERNAME} + ${env.ARTIFACTS_REPO_PASSWORD} + + + + + gsp-repo + gsp-rep + gsp-repo + https://repos.iec.io/repository/maven-gsp/ + + + gsp-releases-repo + gsp-rep + gsp-releases-repo + https://repos.iec.io/repository/maven-gsp-releases/ + + + gsp-snapshots-repo + gsp-rep + gsp-snapshots + https://repos.iec.io/repository/maven-gsp-snapshots/ + + + + + caf-repo + caf-rep + https://repos.iec.io/repository/maven-caf/ + + + caf-releases-repo + caf-rep + caf-releases-repo + https://repos.iec.io/repository/maven-caf-releases/ + + + caf-snapshots-repo + caf-rep + caf-snapshots-repo + https://repos.iec.io/repository/maven-caf-snapshots/ + + + + + repos.iec.io-caf + + + caf-rep + https://repos.iec.io/repository/maven-caf/ + + true + + + true + always + + + + + + repos.iec.io-gsp + + + gsp-rep + https://repos.iec.io/repository/maven-gsp/ + + true + + + true + always + + + + + + + + repos.iec.io-caf + repos.iec.io-gsp + + diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..66cd9905 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,111 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + // "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + "https://repo1.maven.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..43d9d397 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +# distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip +distributionUrl=http://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip \ No newline at end of file diff --git a/jitengine-web-api/pom.xml b/jitengine-web-api/pom.xml new file mode 100644 index 00000000..52a51ca1 --- /dev/null +++ b/jitengine-web-api/pom.xml @@ -0,0 +1,20 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-web-api + + + io.iec.edp + caf-boot-starter-rest-server + + + + diff --git a/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/JitEngineService.java b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/JitEngineService.java new file mode 100644 index 00000000..2e8566ca --- /dev/null +++ b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/JitEngineService.java @@ -0,0 +1,9 @@ +package com.inspur.edp.web.jitengine.web.api.service; + +public interface JitEngineService { + /** + * 删除移动审批设计时文件 + * * @param formId 移动审批表单id + */ + void deleteMobileApproveDevSource(String formId) throws Exception; +} diff --git a/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewParameter.java b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewParameter.java new file mode 100644 index 00000000..1aa373d8 --- /dev/null +++ b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewParameter.java @@ -0,0 +1,65 @@ +package com.inspur.edp.web.jitengine.web.api.service; + +/** + * description: + * + * @author Noah Guo + * @date 2020/05/16 + */ +public class MobileApproveReviewParameter { + private String id; + + private String formCode; + + /** + * 维度1 + */ + private String dim1; + + /** + * 维度2 + */ + private String dim2; + + private String formId; + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public String getDim1() { + return dim1; + } + + public void setDim1(String dim1) { + this.dim1 = dim1; + } + + public String getDim2() { + return dim2; + } + + public void setDim2(String dim2) { + this.dim2 = dim2; + } + + public String getFormCode() { + return formCode; + } + + public void setFormCode(String formCode) { + this.formCode = formCode; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewResponse.java b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewResponse.java new file mode 100644 index 00000000..7e0b9350 --- /dev/null +++ b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/service/MobileApproveReviewResponse.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.jitengine.web.api.service; + +/** + * description: + * + * @author Noah Guo + * @date 2020/05/18 + */ +public class MobileApproveReviewResponse { + private String path; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/webservice/JitEngineWebService.java b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/webservice/JitEngineWebService.java new file mode 100644 index 00000000..251df21e --- /dev/null +++ b/jitengine-web-api/src/main/java/com/inspur/edp/web/jitengine/web/api/webservice/JitEngineWebService.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.jitengine.web.api.webservice; + +import com.inspur.edp.web.jitengine.web.api.service.MobileApproveReviewParameter; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.io.IOException; + +@Path("/jitengine") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface JitEngineWebService { + + @POST + @Path("/") + Object createNewTemplate(@RequestBody Object data) throws IOException; + + @GET + @Path("/{id}") + Object getMetaDataById(@PathParam("id") String id); + + @POST + @Path("/preview") + Object preview(@RequestBody MobileApproveReviewParameter data) throws Exception; + +} diff --git a/jitengine-web-core/pom.xml b/jitengine-web-core/pom.xml new file mode 100644 index 00000000..2c2c459f --- /dev/null +++ b/jitengine-web-core/pom.xml @@ -0,0 +1,54 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-web-core + + + + com.inspur.edp + web-jitengine-runtimebuild-api + + + com.inspur.edp + web-jitengine-runtimebuild-core + + + io.iec.edp + caf-boot-starter-rest-client + + + com.inspur.edp + web-jitengine-web-api + + + com.inspur.edp + runtime-customize-api + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + metadata-rtcustomization-api + + + com.inspur.edp + metadata-rtcustomization-core + + + io.iec.edp + caf-business-object-api + + + + + diff --git a/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/config/JitEngineWebConfiguration.java b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/config/JitEngineWebConfiguration.java new file mode 100644 index 00000000..f071bc98 --- /dev/null +++ b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/config/JitEngineWebConfiguration.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.jitengine.web.core.config; + +import io.iec.edp.caf.rest.RESTEndpoint; +import com.inspur.edp.web.jitengine.web.api.service.JitEngineService; +import com.inspur.edp.web.jitengine.web.api.webservice.JitEngineWebService; +import com.inspur.edp.web.jitengine.web.core.service.JitEngineServiceImpl; +import com.inspur.edp.web.jitengine.web.core.webservice.JitEngineWebSericeImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JitEngineWebConfiguration { + + @Bean + public JitEngineService jitEngineService(){ + return new JitEngineServiceImpl(); + } + + @Bean + public JitEngineWebService jitEngineWebService(JitEngineService jitEngineService){ + return new JitEngineWebSericeImpl(); + } + + @Bean + public RESTEndpoint JitEngineWebServiceEndpoint(JitEngineWebService jitEngineWebService){ + return new RESTEndpoint("/gsp/jit/v1.0", jitEngineWebService); + } +} diff --git a/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/JitEngineServiceImpl.java b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/JitEngineServiceImpl.java new file mode 100644 index 00000000..75dd8dd8 --- /dev/null +++ b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/JitEngineServiceImpl.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.jitengine.web.core.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitengine.web.api.service.JitEngineService; + +public class JitEngineServiceImpl implements JitEngineService { + + @Override + public void deleteMobileApproveDevSource(String formId) throws Exception { + if (StringUtility.isNullOrEmpty(formId)) { + throw new Exception("delete mobileapprove dev source failed,the formId is null"); + } + + GspMetadata gspMetadata = MobilEApprovePreviewImpl.getGspMetadataWithFormId(formId); + String formCode = gspMetadata.getHeader().getCode(); + String mobileApproveAppPath = MobilEApprovePreviewImpl.generateMobileApproveDevBasePath(formCode,false); + try { + FileUtility.deleteFolder(mobileApproveAppPath); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobilEApprovePreviewImpl.java b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobilEApprovePreviewImpl.java new file mode 100644 index 00000000..8604b796 --- /dev/null +++ b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobilEApprovePreviewImpl.java @@ -0,0 +1,114 @@ +package com.inspur.edp.web.jitengine.web.core.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.jitengine.web.api.service.MobileApproveReviewParameter; +import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo; +import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * description: + * + * @author Noah Guo + * @date 2020/05/17 + */ +public class MobilEApprovePreviewImpl { + private static final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + private static final DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class); + + /** + * 根据预览参数获取元数据信息 + * + * @param reviewParameter + * @return + */ + public static GspMetadata getGspMetaDataWithPreviewParameter(MobileApproveReviewParameter reviewParameter) throws Exception { + return getGspMetadataWithFormId(reviewParameter.getFormId()); + } + + /** + * 根据formId获取元数据 + * + * @param formId + * @return + * @throws Exception + */ + + public static GspMetadata getGspMetadataWithFormId(String formId) throws Exception { + GspMetadata gspMetadata = customizationService.getMetadata(formId); + if (gspMetadata == null) { + throw new Exception("根据formId 获取元数据为空"); + } + return gspMetadata; + } + + + /** + * 保存表单元数据 + * + * @param basePath + * @param fileName + */ + public static void saveMetaDataContent(String basePath, String fileName, String content) { + + FileUtility.writeFile(basePath, fileName, content); + } + + public static String generateWebDevPath(String formCode,boolean isUpdradeTool) { + String projectRuntimeAppBasePath = generateMobileApproveDevBasePath(formCode,isUpdradeTool); + String projectRuntimeAppWebdevPath = projectRuntimeAppBasePath + FileUtility.DIRECTORY_SEPARATOR_CHAR + "webdev"; + return projectRuntimeAppWebdevPath; + } + + /** + * 获取移动审批对应表单路径 + * + * @param formCode + * @return + */ + public static String generateMobileApproveDevBasePath(String formCode,boolean isUpdradeTool) { + String currentWorkSpace = FileUtility.getCurrentWorkPath(isUpdradeTool); + String projectRuntimeAppPath = currentWorkSpace + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "runtime" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "projects" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "mobileapproval" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + formCode; + return projectRuntimeAppPath; + } + + + public static String generatePublishPath(String formCode, GspMetadata gspMetadata,boolean isUpdradeTool) { + String serviceUnitPath = getServiceUnit(gspMetadata); + String currentWorkSpace = FileUtility.getCurrentWorkPath(isUpdradeTool); + + String projectRuntimeAppPath = currentWorkSpace + FileUtility.DIRECTORY_SEPARATOR_CHAR + + ("web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "apps" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + serviceUnitPath + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "mobileapproval" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + formCode + FileUtility.DIRECTORY_SEPARATOR_CHAR).toLowerCase(); + return projectRuntimeAppPath; + } + + public static String generatePublishFormPathUrl(String formCode, GspMetadata gspMetadata) { + String serviceUnitPath = getServiceUnit(gspMetadata); + + String projectRuntimeAppPath = "/apps/" + serviceUnitPath + "/mobileapproval/" + formCode; + return projectRuntimeAppPath.toLowerCase(); + } + + /** + * 获取元数据所在su + * + * @param gspMetadata + * @return + */ + public static String getServiceUnit(GspMetadata gspMetadata) { + DevBasicBoInfo devBasicBoInfo = devBasicInfoService.getDevBasicBoInfo(gspMetadata.getHeader().getBizobjectID()); + String serviceUnitPath = devBasicBoInfo.getAppCode().toLowerCase() + "/" + devBasicBoInfo.getSuCode().toLowerCase(); + return serviceUnitPath; + } +} diff --git a/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobileApproveDocker.java b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobileApproveDocker.java new file mode 100644 index 00000000..86b85cdc --- /dev/null +++ b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/service/MobileApproveDocker.java @@ -0,0 +1,39 @@ +package com.inspur.edp.web.jitengine.web.core.service; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.PublishScriptRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerPathGenerator; +import com.inspur.edp.web.jitruntimebuild.scriptcache.service.ScriptCacheServiceImpl; + + +public class MobileApproveDocker { + + public void afterPreview(String formCode, String publishPath, String metadataId) { + //去部署路径取js内容,存入数据库 + //projectName="mobileapproval" + try { + ScriptCacheServiceImpl scriptCacheServiceImpl = new ScriptCacheServiceImpl(); + PublishScriptRequest request = new PublishScriptRequest(); + request.setFormCode(formCode); + request.setProjectName("bo-mobileapprovalpresetproject"); + request.setMetaDataId(metadataId); + //部署路径 + request.setAbsoluteBaseDirectory(publishPath); + // 设置脚本文件相对于运行环境的相对路径 + String strLocalServerPath = LocalServerPathGenerator.getNewInstance(false).getLocalServerWebPath(); + String strRelativePath = FileUtility.getRelativePath(strLocalServerPath, publishPath, true); + request.setProjectRelativePath(strRelativePath); + + request.setScriptName(formCode + ".js"); + + scriptCacheServiceImpl.publishScriptWithDirectory(request); + LoggerUtility.log("execute mobile approval script cache completely!!!", LoggerLevelEnum.Info); + } catch (Exception e) { + e.printStackTrace(); + } + } + + +} diff --git a/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/webservice/JitEngineWebSericeImpl.java b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/webservice/JitEngineWebSericeImpl.java new file mode 100644 index 00000000..5d0227fa --- /dev/null +++ b/jitengine-web-core/src/main/java/com/inspur/edp/web/jitengine/web/core/webservice/JitEngineWebSericeImpl.java @@ -0,0 +1,88 @@ +package com.inspur.edp.web.jitengine.web.core.webservice; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitengine.ProjectCompileContext; +import com.inspur.edp.web.jitengine.web.api.service.MobileApproveReviewParameter; +import com.inspur.edp.web.jitengine.web.api.service.MobileApproveReviewResponse; +import com.inspur.edp.web.jitengine.web.api.webservice.JitEngineWebService; +import com.inspur.edp.web.jitengine.web.core.service.MobilEApprovePreviewImpl; +import com.inspur.edp.web.jitengine.web.core.service.MobileApproveDocker; + +import java.io.IOException; + +public class JitEngineWebSericeImpl implements JitEngineWebService { + + @Override + public Object createNewTemplate(Object data) throws IOException { + return null; + } + + @Override + public Object getMetaDataById(String id) { + return null; + } + + @Override + public Object preview(MobileApproveReviewParameter data) throws Exception { + // 将参数转换成预览实体类型 + if (data == null) { + return null; + } + + // 根据维度信息读取表单元数据信息 + GspMetadata gspMetadata = MobilEApprovePreviewImpl.getGspMetaDataWithPreviewParameter(data); + //FormMetaDataContent + String serializedMetaDataContent = SerializeUtility.getInstance().serialize(gspMetadata.getContent()); + FormMetadataContent formMetadataContent = SerializeUtility.getInstance().deserialize(serializedMetaDataContent, FormMetadataContent.class); + + String metaDataContent = formMetadataContent.getContents().toString(); + // 保存表单json文件 + //根据id读取对应的表单json文件 + // 获取su的路径参数 + String formCode = gspMetadata.getHeader().getCode(); + String webDevPath = MobilEApprovePreviewImpl.generateWebDevPath(formCode, false); + // 全部转换成小写 + String publishPath = MobilEApprovePreviewImpl.generatePublishPath(formCode, gspMetadata, false); + //保存表单元数据至json文件 + MobilEApprovePreviewImpl.saveMetaDataContent(webDevPath, formCode + ".frm.json", metaDataContent); + + + String mobileApproveFormCode = formCode; + String serviceUnitPath = MobilEApprovePreviewImpl.getServiceUnit(gspMetadata); + + // 构造webdev文件路径 + // 设置为移动审批 + ProjectCompileContext compileContext = new ProjectCompileContext( + formCode, + "", + "pc", "angular", + webDevPath, + publishPath, + "", + serviceUnitPath, ExecuteEnvironment.Runtime + ); + // 设置移动审批表单code + compileContext.setMobileApproveFormCode(formCode); + compileContext.setIsMobileApprove(true); + + JITEngineManager.compileProject(compileContext); + + // 调用jit进行脚本文件生成 + // js存入数据库 + MobileApproveDocker mobileApproveDocker = new MobileApproveDocker(); + mobileApproveDocker.afterPreview(formCode, publishPath, data.getFormId()); + + + // 返回文件路径 + String publishFormUrl = MobilEApprovePreviewImpl.generatePublishFormPathUrl(formCode, gspMetadata); + MobileApproveReviewResponse reviewResponse = new MobileApproveReviewResponse(); + // 返回路径转换成小写 + String reviewPath = publishFormUrl + "/" + (formCode + ".js").toLowerCase(); + reviewResponse.setPath(reviewPath); + return reviewResponse; + } +} diff --git a/jitengine-web-core/src/main/resources/META-INF/spring.factories b/jitengine-web-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..67056e71 --- /dev/null +++ b/jitengine-web-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.jitengine.web.core.config.JitEngineWebConfiguration diff --git a/mvnw b/mvnw new file mode 100644 index 00000000..5551fde8 --- /dev/null +++ b/mvnw @@ -0,0 +1,286 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..e5cfb0ae --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,161 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" +FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..d9965318 --- /dev/null +++ b/pom.xml @@ -0,0 +1,508 @@ + + + 4.0.0 + + web-common + web-form-metadata-api + web-form-metadata + web-sourcecode-metadata + web-pageflow-metadata + web-appconfig-api + web-appconfig-core + web-frontendproject + web-frontendproject-api + web-form-jitengine + web-designschema + web-designschema-api + web-statemachine + web-tsfile-api + web-tsfile-core + web-ide-api + web-ide-webapi + runtime-api + runtime-core + runtime-scriptcache + runtime-scriptcache-api + jitengine-web-api + jitengine-web-core + web-approval-format-api + web-approval-format-core + web-npmpackage-core + web-npmpackage-api + web-npmpackage-patch + + + + io.iec.edp + caf-boot-parent + 0.3.4 + + + web + + com.inspur.edp + pom + ${custom.version} + + + 0.1.9-SNAPSHOT + 1.8 + 1.8 + 1.8 + + + + + + org.codehaus.mojo + flatten-maven-plugin + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + + + + com.inspur.edp + web-jitengine-web-api + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-web-core + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-runtimebuild-api + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-runtimebuild-core + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + ${custom.version} + compile + + + com.inspur.edp + web-appconfig-api + ${custom.version} + compile + + + com.inspur.edp + web-appconfig-core + ${custom.version} + compile + + + com.inspur.edp + web-approval-format-api + ${custom.version} + compile + + + com.inspur.edp + web-approval-format-core + ${custom.version} + compile + + + com.inspur.edp + web-approval-format-rpc + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-common + ${custom.version} + compile + + + com.inspur.edp + web-designschema + ${custom.version} + compile + + + com.inspur.edp + web-designschema-api + ${custom.version} + compile + + + com.inspur.edp + web-jitengine + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-formmetadata + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-formmetadata-api + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-frontendproject + ${custom.version} + compile + + + com.inspur.edp + web-jitengine-frontendproject-api + ${custom.version} + compile + + + com.inspur.edp + web-ide-api + ${custom.version} + compile + + + com.inspur.edp + ide-config-webapi + ${custom.version} + compile + + + com.inspur.edp + web-npmpackage-core + ${custom.version} + compile + + + com.inspur.edp + web-npmpackage-api + ${custom.version} + compile + + + com.inspur.edp + web-pageflow-metadata + ${custom.version} + compile + + + com.inspur.edp + web-sourcecode-metadata + ${custom.version} + compile + + + com.inspur.edp + web-statemachine-metadata + ${custom.version} + compile + + + com.inspur.edp + web-tsfile-api + ${custom.version} + compile + + + com.inspur.edp + web-tsfile-core + ${custom.version} + compile + + + org.junit.jupiter + junit-jupiter-api + 5.5.2 + compile + + + commons-io + commons-io + 2.8.0 + + + com.inspur.edp + lcm-metadata-api + 0.1.35-SNAPSHOT + + + jakarta.ws.rs + jakarta.ws.rs-api + 2.1.5 + + + com.fasterxml.jackson.core + jackson-databind + 2.10.0 + compile + + + com.inspur.edp + i18n-resource-api + 0.1.4 + + + com.inspur.edp + formserver-viewmodel + 0.2.15 + + + com.inspur.edp + lcm-metadata-spi + 0.1.37 + compile + + + io.iec.edp + caf-i18n-framework-api + 0.2.8 + + + org.springframework.boot + spring-boot-starter-test + test + 2.1.6.RELEASE + + + io.iec.edp + caf-boot-starter-rest-server + 0.3.5 + + + com.inspur.edp + lcm-logging-service + 0.1.4 + + + javax.ws.rs + javax.ws.rs-api + 2.1.1 + + + io.iec.edp + caf-boot-commons-environment + 0.3.7-SNAPSHOT + compile + + + com.inspur.edp + lcm-debugger-api + 0.1.0 + + + com.inspur.edp + ide-setting-api + 0.1.2 + + + com.inspur.edp + lcm-metadata-common + 0.1.23 + compile + + + com.inspur.edp + cdp-sgf-api + 0.1.13 + + + com.inspur.edp + cef-designtime-api + 0.2.14 + + + com.inspur.edp + lcm-metadata-manager + 0.1.22 + compile + + + org.apache.commons + commons-lang3 + 3.10 + + + com.inspur.edp + metadata-rtcustomization-api + 0.1.17 + compile + + + com.inspur.edp + metadata-rtcustomization-server-api + 0.1.17 + compile + + + com.inspur.edp + web-component-metadata + 0.1.0 + compile + + + com.inspur.edp + web-command-coponent-metadata + 0.1.0-SNAPSHOT + + + com.inspur.edp + bef-api + 0.2.2 + + + com.inspur.edp + udt-designtime-api + 0.1.7 + + + com.inspur.edp + bef-bizentity + 0.1.1 + compile + + + com.inspur.edp + cef-entity + 0.2.3 + compile + + + com.inspur.edp + web-help-api + 0.1.11 + compile + + + com.inspur.edp + metadata-rtcustomization-core + 0.1.17 + + + com.inspur.edp + runtime-customize-api + 0.1.0 + + + com.inspur.edp + lcm-metadata-rtservice + 0.1.23 + + + com.inspur.edp + lcm-metadata-core + 0.1.23 + + + com.inspur.edp + metadata-businesstype-api + 0.1.0-SNAPSHOT + + + io.iec.edp + caf-business-object-api + 0.1.3 + + + com.inspur.edp + bcc-billcategory-api + 0.1.0 + + + com.inspur.edp + bcc-billcategory-entity + 0.1.0 + + + com.inspur.edp + lcm-rtcustomization-cache-api + 0.1.1 + compile + + + io.iec.edp + caf-boot-tenancy-api + 0.3.4 + compile + + + io.iec.edp + caf-boot-tenancy-core + 0.3.4 + compile + + + + com.inspur.edp + bef-engine-core + 0.1.13 + compile + + + io.iec.edp + caf-framework-licservice-api + 0.1.1 + compile + + + com.inspur.edp + lcm-metadata-spi + 0.1.37 + + + + + + + + gsp-snapshots-repo + https://repos.iec.io/repository/maven-gsp-snapshots/ + + + gsp-releases-repo + https://repos.iec.io/repository/maven-gsp-releases/ + + + + diff --git a/runtime-api/pom.xml b/runtime-api/pom.xml new file mode 100644 index 00000000..99d055dc --- /dev/null +++ b/runtime-api/pom.xml @@ -0,0 +1,15 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-runtimebuild-api + + + diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/DeployTargetEnum.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/DeployTargetEnum.java new file mode 100644 index 00000000..f9e06e74 --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/DeployTargetEnum.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +/** + * 部署目标选项枚举 + * @author noah + */ +public enum DeployTargetEnum { + /** + * 单个表单脚本部署 + */ + Form, + /** + * 整个工程部署 + */ + Project +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildParameter.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildParameter.java new file mode 100644 index 00000000..ea1f8058 --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildParameter.java @@ -0,0 +1,332 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * description:运行时定制编译参数 + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class JitBuildParameter { + /** + * 编译的工程目录 绝对路径 运行时定制根目录 + */ + private String buildProjectPath; + + /** + * 编译依赖的node_modules路径 绝对路径 + */ + private String buildNodeModulePath; + + /** + * 编译的表单路径。 依据表单所在的维度信息构造唯一的路径信息 + */ + private String buildFormPath; + + public String getExtraFormPathStr() { + return extraFormPathStr; + } + + public void setExtraFormPathStr(String extraFormPathStr) { + this.extraFormPathStr = extraFormPathStr; + } + + /** + * 表单路径额外参数 只有在buildFormPath为空时读取该参数 + */ + private String[] extraFormPath; + + + /** + * 维度信息的字符串表述形式 + */ + private String extraFormPathStr; + + /** + * 表单JSON文件存放路径 + */ + private String buildWebDevPath; + + /** + * webdev 文件目录名称 默认为webdev + * 该参数默认不需要任何更改,仅当需要调整存放目录时进行调整 + */ + private String webDevPathName = "webdev"; + + /** + * node_modules 路径名称 + * 该参数默认不需要任何更改,仅当node_modules文件夹名称发生变化时进行调整。 + */ + private String node_ModulesName = "node_modules"; + + /** + * 生成表单ts源代码文件目录 + */ + private String buildAppPath; + + /** + * app 路径 + */ + private String appPathName = "app"; + + /** + * 表单文件保存后缀 + */ + private String formFileSuffix = ".json"; + + private String formId; + + /** + * 是否移动app + */ + private boolean isMobileApp = false; + + public boolean isMobileApp() { + return isMobileApp; + } + + public void setMobileApp(boolean mobileApp) { + isMobileApp = mobileApp; + } + + private boolean isBabelCompile = false; + + public boolean isBabelCompile() { + return isBabelCompile; + } + + public void setBabelCompile(boolean babelCompile) { + isBabelCompile = babelCompile; + } + + // 是否移动审批 + private boolean isMobileApprove = false; + + + // 是否在tool中运行 + private boolean isInUpgradeTool = false; + + public boolean isInUpgradeTool() { + return isInUpgradeTool; + } + + public void setInUpgradeTool(boolean inUpgradeTool) { + isInUpgradeTool = inUpgradeTool; + } + + /** + * 表单code + */ + private String formCode; + + /** + * 表单名称 + */ + private String formName; + + /** + * su路径。apps/scm/sd + */ + private String serviceUnitPath; + + private String boCode; + + private String boName; + + /** + * 部署目标选项枚举 默认为部署单个表单 + */ + private DeployTargetEnum deployTargetEnum = DeployTargetEnum.Form; + + /** + * 部署目标选项 + * + * @return + */ + public DeployTargetEnum getDeployTargetEnum() { + return deployTargetEnum; + } + + /** + * 设置部署目标选项 + * + * @param deployTargetEnum + */ + public void setDeployTargetEnum(DeployTargetEnum deployTargetEnum) { + this.deployTargetEnum = deployTargetEnum; + } + + + public String getBoCode() { + return boCode; + } + + public void setBoCode(String boCode) { + this.boCode = boCode; + } + + public String getBoName() { + return boName; + } + + public void setBoName(String boName) { + this.boName = boName; + } + + public boolean isMobileApprove() { + return isMobileApprove; + } + + public void setMobileApprove(boolean mobileApprove) { + isMobileApprove = mobileApprove; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + /** + * 运行时表单编译依赖元数据 + */ + private List buildRefMetadataList; + + public String getBuildProjectPath() { + return buildProjectPath; + } + + public void setBuildProjectPath(String buildProjectPath) { + this.buildProjectPath = buildProjectPath; + } + + public String getBuildNodeModulePath() { + return buildNodeModulePath; + } + + public void setBuildNodeModulePath(String buildNodeModulePath) { + this.buildNodeModulePath = buildNodeModulePath; + } + + public String getBuildFormPath() { + return buildFormPath; + } + + public void setBuildFormPath(String buildFormPath) { + this.buildFormPath = buildFormPath; + } + + public String[] getExtraFormPath() { + return extraFormPath; + } + + public void setExtraFormPath(String[] extraFormPath) { + this.extraFormPath = extraFormPath; + } + + public String getBuildWebDevPath() { + return buildWebDevPath; + } + + public void setBuildWebDevPath(String buildWebDevPath) { + this.buildWebDevPath = buildWebDevPath; + } + + public String getWebDevPathName() { + return webDevPathName; + } + + public void setWebDevPathName(String webDevPathName) { + this.webDevPathName = webDevPathName; + } + + public String getNode_ModulesName() { + return node_ModulesName; + } + + public void setNode_ModulesName(String node_ModulesName) { + this.node_ModulesName = node_ModulesName; + } + + public String getBuildAppPath() { + return buildAppPath; + } + + public void setBuildAppPath(String buildAppPath) { + this.buildAppPath = buildAppPath; + } + + public String getAppPathName() { + return appPathName; + } + + public String getBabelRunTimeAppPathName() { + return "appForBabel"; + } + + public void setAppPathName(String appPathName) { + this.appPathName = appPathName; + } + + public String getFormFileSuffix() { + return formFileSuffix; + } + + public void setFormFileSuffix(String formFileSuffix) { + this.formFileSuffix = formFileSuffix; + } + + public String getFormCode() { + return formCode; + } + + public void setFormCode(String formCode) { + this.formCode = formCode; + } + + public String getFormName() { + return formName; + } + + public void setFormName(String formName) { + this.formName = formName; + } + + public String getServiceUnitPath() { + return serviceUnitPath; + } + + public void setServiceUnitPath(String serviceUnitPath) { + this.serviceUnitPath = serviceUnitPath; + } + + public List getBuildRefMetadataList() { + return buildRefMetadataList; + } + + public void setBuildRefMetadataList(List buildRefMetadataList) { + this.buildRefMetadataList = buildRefMetadataList; + } + + /** + * 额外的参数选项 为了避免每次参数的增加都需要进行多方修正 + * 因此增加该参数 + */ + private Map extraOptions; + + public Map getExtraOptions() { + if (extraOptions == null) { + extraOptions = new HashMap<>(); + } + return extraOptions; + } + + public void setExtraOptions(Map extraOptions) { + this.extraOptions = extraOptions; + } +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildRefMetadata.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildRefMetadata.java new file mode 100644 index 00000000..ca7b71a0 --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildRefMetadata.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class JitBuildRefMetadata { + /** + * 元数据内容 + */ + private String content; + + /** + * 元数据类型 + */ + private JitMetadataTypeEnum metadataType; + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public JitMetadataTypeEnum getMetadataType() { + return metadataType; + } + + public void setMetadataType(JitMetadataTypeEnum metadataType) { + this.metadataType = metadataType; + } + + /** + * 元数据名称 + */ + private String metaDataName; + + public String getMetaDataName() { + return metaDataName; + } + + public void setMetaDataName(String metaDataName) { + this.metaDataName = metaDataName; + } +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildResponse.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildResponse.java new file mode 100644 index 00000000..8c13cddd --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitBuildResponse.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +import java.util.HashMap; +import java.util.Map; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class JitBuildResponse { + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + private boolean success = true; + + /** + * 额外的参数 + */ + private MapextraMessages; + + public Map getExtraMessages() { + if(extraMessages==null){ + extraMessages=new HashMap<>(); + } + return extraMessages; + } + + public void setExtraMessages(Map extraMessages) { + this.extraMessages = extraMessages; + } +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitMetadataTypeEnum.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitMetadataTypeEnum.java new file mode 100644 index 00000000..4431fc7d --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitMetadataTypeEnum.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +/** + * 运行时依赖元数据类型 + */ +public enum JitMetadataTypeEnum { + /** + * 表单元数据 + */ + Frm, + /** + * eapi 元数据 + */ + Eapi, + /** + * 资源元数据 + */ + Resource, + /** + * 状态机元数据 + */ + StateMachine, + /** + * 命令元数据 + */ + Command, + /** + * 页面流 + */ + Route +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitRuntimeConstant.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitRuntimeConstant.java new file mode 100644 index 00000000..a619da8a --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/entity/JitRuntimeConstant.java @@ -0,0 +1,8 @@ +package com.inspur.edp.web.jitruntimebuild.api.entity; + +/** + * jit运行时定制常量参数 + */ +public class JitRuntimeConstant { + +} diff --git a/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/service/JitBuildService.java b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/service/JitBuildService.java new file mode 100644 index 00000000..b15f5d6b --- /dev/null +++ b/runtime-api/src/main/java/com/inspur/edp/web/jitruntimebuild/api/service/JitBuildService.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.jitruntimebuild.api.service; + +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildResponse; + +/** + * jit 编译service + */ +public interface JitBuildService { + /** + * jit 编译入口 + * @param buildParameter + * @return + */ + JitBuildResponse jitBuild(JitBuildParameter buildParameter); + +} diff --git a/runtime-core/pom.xml b/runtime-core/pom.xml new file mode 100644 index 00000000..cbbfe27a --- /dev/null +++ b/runtime-core/pom.xml @@ -0,0 +1,60 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-runtimebuild-core + + + + com.inspur.edp + web-jitengine-runtimebuild-api + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache + + + com.inspur.edp + web-jitengine + + + io.iec.edp + caf-boot-tenancy-api + + + io.iec.edp + caf-boot-tenancy-core + + + org.springframework.boot + spring-boot-starter-test + + + commons-io + commons-io + + + org.junit.jupiter + junit-jupiter-api + + + com.inspur.edp + web-sourcecode-metadata + + + diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/builddeploy/BuildDeployManager.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/builddeploy/BuildDeployManager.java new file mode 100644 index 00000000..14bfb5e2 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/builddeploy/BuildDeployManager.java @@ -0,0 +1,148 @@ +package com.inspur.edp.web.jitruntimebuild.core.builddeploy; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.jitruntimebuild.api.entity.DeployTargetEnum; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.core.utility.JitBuildUtility; +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.PublishScriptRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerPathGenerator; +import com.inspur.edp.web.jitruntimebuild.scriptcache.service.ScriptCacheServiceImpl; +import io.iec.edp.caf.tenancy.core.context.MultiTenantContextHolder; + +/** + * @author noah + */ +public class BuildDeployManager { + private BuildDeployManager() { + } + + /** + * 表单参数部署 + * + * @param buildParameter + */ + public static void deployForm(JitBuildParameter buildParameter) { + LoggerUtility.log("begin deploy form, the formCode is " + buildParameter.getFormCode(), LoggerLevelEnum.Info); + String strDeployPath = FileUtility.getCurrentWorkPath(buildParameter.isInUpgradeTool()) + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getServiceUnitPath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + + FormJsonFileSuffixConstant.DeployWebPathName + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode() + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getFormName() + JitBuildUtility.getExtraPath(buildParameter.getExtraFormPath())).toLowerCase(); + if (buildParameter.isMobileApp()) { + strDeployPath = FileUtility.getCurrentWorkPath(buildParameter.isInUpgradeTool()) + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getServiceUnitPath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "mob" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode() + JitBuildUtility.getExtraPath(buildParameter.getExtraFormPath())).toLowerCase(); + } + + if (buildParameter.isBabelCompile()) { + + strDeployPath = FileUtility.getCurrentWorkPath(buildParameter.isInUpgradeTool()) + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getServiceUnitPath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode() + "forbabelruntime" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getFormName() + + JitBuildUtility.getExtraPath(buildParameter.getExtraFormPath())).toLowerCase(); + } + + String strBaseSourcePath = buildParameter.getBuildAppPath() + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + FormJsonFileSuffixConstant.DistRollupPathName + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode()).toLowerCase(); + + if (buildParameter.getDeployTargetEnum() == DeployTargetEnum.Form) { + String sourcePath = strBaseSourcePath + FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getFormName(); + // 如果是移动或babel编译 那么拷贝整个工程到模板目录 + if (buildParameter.isMobileApp() || buildParameter.isBabelCompile()) { + sourcePath = strBaseSourcePath; + } + FileUtility.copyFolder(sourcePath, strDeployPath, true); + + LoggerUtility.log("deploy form,the source path is " + sourcePath + " , target path is " + strDeployPath, LoggerLevelEnum.Info); + + // 部署version.json 文件 + String strSourceVersionPath = strBaseSourcePath + FileUtility.DIRECTORY_SEPARATOR_CHAR + "version.json"; + String strTargetVersionPath = strDeployPath + FileUtility.DIRECTORY_SEPARATOR_CHAR + "version.json"; + if (FileUtility.exists(strSourceVersionPath)) { + FileUtility.copyFile(strSourceVersionPath, strTargetVersionPath, true); + LoggerUtility.log("deploy version file success,the source file path is " + strSourceVersionPath + ",the target file path is " + strTargetVersionPath, LoggerLevelEnum.Info); + } + + LoggerUtility.log("deploy form success, the formCode is " + buildParameter.getFormCode(), LoggerLevelEnum.Info); + + + // 郭志奇 获取对应的元数据id + String currentServiceUnit = null; + // 如果是在tool中运行 + if (buildParameter.isInUpgradeTool()) { + currentServiceUnit = MultiTenantContextHolder.get().getServiceUnit(); + MultiTenantContextHolder.get().setServiceUnit(null); + } + + publishScript(buildParameter, strDeployPath); + + // 如果是在tool中运行 + if (buildParameter.isInUpgradeTool()) { + MultiTenantContextHolder.get().setServiceUnit(currentServiceUnit); + } + } else if (buildParameter.getDeployTargetEnum() == DeployTargetEnum.Project) { + LoggerUtility.log("deploy project,the source project path is " + strBaseSourcePath, LoggerLevelEnum.Info); + + FileUtility.copyFolder(strBaseSourcePath, strDeployPath, true); + + publishScript(buildParameter, strDeployPath); + + LoggerUtility.log("deploy project success,the deploy path is " + strDeployPath, LoggerLevelEnum.Info); + } + } + + /** + * 执行脚本发布 + * + * @param buildParameter + * @param strDeployPath + */ + private static void publishScript(JitBuildParameter buildParameter, String strDeployPath) { + LoggerUtility.log("execute form script cache ", LoggerLevelEnum.Info); + try { + ScriptCacheServiceImpl scriptCacheServiceImpl = new ScriptCacheServiceImpl(); + PublishScriptRequest request = getPublishScriptRequest(buildParameter, strDeployPath); + + scriptCacheServiceImpl.publishScriptWithDirectory(request); + LoggerUtility.log("execute form script cache completely!!!", LoggerLevelEnum.Info); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 构造对应的请求入参 + * + * @param buildParameter + * @param strDeployPath + * @return + */ + private static PublishScriptRequest getPublishScriptRequest(JitBuildParameter buildParameter, String strDeployPath) { + PublishScriptRequest request = new PublishScriptRequest(); + request.setAbsoluteBaseDirectory(strDeployPath); + request.setMetaDataId(buildParameter.getFormId()); + request.setProjectName(buildParameter.getBoCode().toLowerCase()); + request.setScriptName(buildParameter.getFormCode()); + // 设置当前表单code + request.setFormCode(buildParameter.getFormCode()); + + // 设置脚本文件相对于运行环境得相对路径 + String strLocalServerPath = LocalServerPathGenerator.getNewInstance(buildParameter.isInUpgradeTool()).getLocalServerWebPath(); + String strRelativePath = FileUtility.getRelativePath(strLocalServerPath, strDeployPath, true); + request.setProjectRelativePath(strRelativePath); + return request; + } + + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametergenerator/JitBuildParameterGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametergenerator/JitBuildParameterGenerator.java new file mode 100644 index 00000000..622b0e2c --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametergenerator/JitBuildParameterGenerator.java @@ -0,0 +1,108 @@ +package com.inspur.edp.web.jitruntimebuild.core.buildparametergenerator; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; +import com.inspur.edp.web.jitruntimebuild.core.utility.JitBuildUtility; + +import java.util.ArrayList; + +/** + * jit 编译参数构造 + */ +public class JitBuildParameterGenerator { + + /** + * 构造jit编译参数。 根据其中的参数值,来进行补充 + * + * @param buildParameter 编译参数 + * @return + */ + public static void generate(JitBuildParameter buildParameter) { + + String currentWorkPath = FileUtility.getCurrentWorkPath(buildParameter.isInUpgradeTool()); + + if (buildParameter.isInUpgradeTool()) { + System.out.println("web: current work path is " + currentWorkPath); + } + + // 如果未设定编译路径 那么设定当前程序运行环境所在根目录 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildProjectPath())) { + // 工当前运行环境目录下增加runtimeprojects 文件目录 + String strCurrentWorkPath = currentWorkPath + (FileUtility.DIRECTORY_SEPARATOR_CHAR + FormJsonFileSuffixConstant.defaultProjectPathName).toLowerCase(); + buildParameter.setBuildProjectPath(strCurrentWorkPath); + } + + // 如果node_modules 文件路径为空 移动到projects文件目录下 不再放置于rtc文件目录下 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildNodeModulePath())) { + + // 工当前运行环境目录下增加runtime/projects 文件目录 不再放置于rtc目录下 + String strCurrentWorkPath = currentWorkPath + (FileUtility.DIRECTORY_SEPARATOR_CHAR + FormJsonFileSuffixConstant.defaultProjectPathNameWithoutRtc).toLowerCase(); + String node_modulesPath = strCurrentWorkPath + FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getNode_ModulesName(); + buildParameter.setBuildNodeModulePath(node_modulesPath); + } + + // 如果boCode为空 那么采用formCode + if (StringUtility.isNullOrEmpty(buildParameter.getBoCode())) { + buildParameter.setBoCode(buildParameter.getFormCode()); + } + String extraPath = JitBuildUtility.getExtraPath(buildParameter.getExtraFormPath()); + // 设置维度路径信息 + buildParameter.setExtraFormPathStr(extraPath); + // 如果构造表单路径为空 那么从参数中读取 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildFormPath())) { + + String defaultBuildFormPath = buildParameter.getBuildProjectPath() + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode() + FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getFormCode()).toLowerCase(); + if (buildParameter.isMobileApp()) { + defaultBuildFormPath = buildParameter.getBuildProjectPath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + "mobile" + (FileUtility.DIRECTORY_SEPARATOR_CHAR + + buildParameter.getBoCode() + FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getFormCode()).toLowerCase(); + } + + String buildFormPath = defaultBuildFormPath + extraPath.toLowerCase(); + buildParameter.setBuildFormPath(buildFormPath); + } + + // 如果未设定webdev目录 那么构造对应的目录 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildWebDevPath())) { + String buildWebDevPath = buildParameter.getBuildFormPath() + (FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getWebDevPathName()).toLowerCase(); + buildParameter.setBuildWebDevPath(buildWebDevPath); + } + + // 如果未设置formName,那么以formCode为准 + if (StringUtility.isNullOrEmpty(buildParameter.getFormName())) { + buildParameter.setFormName(buildParameter.getFormCode().toLowerCase()); + } + + // 如果编译app路径为空 那么构造 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildAppPath())) { + String buildAppPath = buildParameter.getBuildFormPath() + (FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getAppPathName()).toLowerCase(); + // 如果采用babel 编译 + if (buildParameter.isBabelCompile()) { + buildAppPath = buildParameter.getBuildFormPath() + (FileUtility.DIRECTORY_SEPARATOR_CHAR + buildParameter.getBabelRunTimeAppPathName()).toLowerCase(); + } + buildParameter.setBuildAppPath(buildAppPath); + } + + if (buildParameter.getBuildRefMetadataList() == null) { + buildParameter.setBuildRefMetadataList(new ArrayList<>()); + } + + // 如果su路径不为空 + if (!StringUtility.isNullOrEmpty(buildParameter.getServiceUnitPath())) { + String serviceUnitPath = buildParameter.getServiceUnitPath(); + if (!serviceUnitPath.startsWith(FormJsonFileSuffixConstant.defaultSUBasePath)) { + // 在serviceUnit 路径前面追加apps + serviceUnitPath = FormJsonFileSuffixConstant.defaultSUBasePath + FileUtility.DIRECTORY_SEPARATOR_CHAR + serviceUnitPath; + buildParameter.setServiceUnitPath(serviceUnitPath.toLowerCase()); + } + } + + // 转换成为小写形式 + buildParameter.setFormName(buildParameter.getFormName().toLowerCase()); + buildParameter.setFormCode(buildParameter.getFormCode().toLowerCase()); + buildParameter.setBoCode(buildParameter.getBoCode().toLowerCase()); + + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametervalidator/JitBuildParameterValidator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametervalidator/JitBuildParameterValidator.java new file mode 100644 index 00000000..412876f7 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/buildparametervalidator/JitBuildParameterValidator.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.jitruntimebuild.core.buildparametervalidator; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildResponse; + +/** + * jit 编译参数校验 + */ +public class JitBuildParameterValidator { + /** + * 编译参数验证 + * + * @param buildParameter 编译参数 + */ + public static JitBuildResponse validate(JitBuildParameter buildParameter) { + JitBuildResponse buildResponse = new JitBuildResponse(); + // 编译参数不允许为空 + if (buildParameter == null) { + buildResponse.setSuccess(false); + buildResponse.setErrorMessage("build parameter can not be null"); + return buildResponse; + } + boolean isMobileApprove = buildParameter.isMobileApprove(); + + // 针对具体类型进行不同参数的验证 + if (!isMobileApprove) { + buildResponse = specificValidate(buildParameter); + } else { + buildResponse = mobileApprovalValidate(buildParameter); + } + return buildResponse; + + } + + /** + * 运行时定制传递参数验证 + * + * @param buildParameter + * @return + */ + private static JitBuildResponse specificValidate(JitBuildParameter buildParameter) { + JitBuildResponse buildResponse = new JitBuildResponse(); + if (StringUtility.isNullOrEmpty(buildParameter.getFormCode())) { + buildResponse.setSuccess(false); + buildResponse.setErrorMessage("jit build,formCode can not be null"); + return buildResponse; + } + + if ((buildParameter.getBuildRefMetadataList() == null || buildParameter.getBuildRefMetadataList().size() == 0)) { + buildResponse.setSuccess(false); + buildResponse.setErrorMessage("jit build,form metadata can not be null"); + return buildResponse; + } + return buildResponse; + } + + /** + * 移动审批参数校验 + * + * @param buildParameter 构建参数验证 + * @return + */ + private static JitBuildResponse mobileApprovalValidate(JitBuildParameter buildParameter) { + JitBuildResponse buildResponse = new JitBuildResponse(); + // 移动审批中webdev path 是必须存在 + if (StringUtility.isNullOrEmpty(buildParameter.getBuildWebDevPath())) { + buildResponse.setSuccess(false); + buildResponse.setErrorMessage("webdev path is necessary"); + return buildResponse; + } + return buildResponse; + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/config/JitBuildConfiguration.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/config/JitBuildConfiguration.java new file mode 100644 index 00000000..3ef0717f --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/config/JitBuildConfiguration.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.jitruntimebuild.core.config; + + +import com.inspur.edp.web.jitruntimebuild.api.service.JitBuildService; +import com.inspur.edp.web.jitruntimebuild.core.service.JitBuildServiceImp; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + + +@Configuration +public class JitBuildConfiguration { + + @Bean + public JitBuildService JitBuildService(){ + return new JitBuildServiceImp(); + } + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/constant/FormJsonFileSuffixConstant.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/constant/FormJsonFileSuffixConstant.java new file mode 100644 index 00000000..639bb183 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/constant/FormJsonFileSuffixConstant.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.jitruntimebuild.core.constant; + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class FormJsonFileSuffixConstant { + + /** + * 表单文件后缀 + */ + public static final String FrmJsonFile = ".json"; + + /** + * 命令json文件后缀 .command.json + */ + public static final String CommandJsonFile = ".command.json"; + + /** + * eapi json文件后缀.eapi.json + */ + public static final String EapiJsonFile = ".eapi.json"; + + /** + * 资源文件后缀 .resource.json + */ + public static final String ResourceJsonFile = ".resource.json"; + + /** + * 状态机文件后缀 .sm.json + */ + public static final String StateMachineJsonFile = ".sm.json"; + + /** + * 表单文件后缀 .frm + */ + public static final String FrmSuffix = ".frm"; + + /** + * 默认的运行时工程路径名称 转换成小写形式 + */ + public static final String defaultProjectPathName = ("web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + "runtime" + FileUtility.DIRECTORY_SEPARATOR_CHAR + "projects" + FileUtility.DIRECTORY_SEPARATOR_CHAR + "rtc").toLowerCase(); + + /** + * 默认的运行时工程路径名称 转换成小写形式 + */ + public static final String defaultProjectPathNameWithoutRtc = ("web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + "runtime" + FileUtility.DIRECTORY_SEPARATOR_CHAR + "projects").toLowerCase(); + + /** + * su运行的根目录 apps + */ + public static final String defaultSUBasePath = "apps"; + + /** + * 生成脚本文件目录名称 dist-rollup + */ + public static final String DistRollupPathName = "dist-rollup"; + + /** + * 部署目录中web + */ + public static final String DeployWebPathName = "web"; + + /** + * 维度信息为空时,设置的默认维度信息 + */ + public static final String DefaultWeiDuName = "public"; +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/AbstractFormJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/AbstractFormJsonFileGenerator.java new file mode 100644 index 00000000..7c954404 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/AbstractFormJsonFileGenerator.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public abstract class AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + private String executeEnvironment; + private boolean isUpdradeTool=false; + + protected AbstractFormJsonFileGenerator(String executeEnvironment, boolean isUpdradeTool) { + this.executeEnvironment = executeEnvironment; + this.isUpdradeTool=isUpdradeTool; + } + + public boolean isUpdradeTool() { + return isUpdradeTool; + } + + + + public String getExecuteEnvironment() { + return this.executeEnvironment; + } + + public void setExecuteEnvironment(String value) { + this.executeEnvironment = value; + } + + + /** + * 生成文件全称 + * + * @param fileNameWithoutExtension + * @param fileSuffix + * @return + */ + protected String generateFileName(String fileNameWithoutExtension, String fileSuffix) { + return fileNameWithoutExtension + fileSuffix; + } + + /** + * 文件写入 + * + * @param basePath + * @param fileName + * @param content + */ + protected void writeFile(String basePath, String fileName, String content) { + FileUtility.writeFile(basePath, fileName, content); + } + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/CommandJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/CommandJsonFileGenerator.java new file mode 100644 index 00000000..a887eb8e --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/CommandJsonFileGenerator.java @@ -0,0 +1,57 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inspur.edp.web.common.utility.StringUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +class CommandJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + public CommandJsonFileGenerator(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + + /** + * 命令文件生成 + * + * @param basePath + * @param formName + * @param content + */ + @Override + public void generate(String basePath, String formName, String content) { + if (StringUtility.isNullOrEmpty(content)) { + return; + } + + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree(content).get("serviceList"); + if (jsonNode != null) { + jsonNode.forEach(node -> { + try { + String tsFileCode = node.at("/Content/Code").textValue() + ".ts"; + + JsonNode sourceCodeNode = mapper.readTree(node.get("ExtendProperty").textValue()).get("sourceCode"); + if (sourceCodeNode != null) { + String tsFileContent = sourceCodeNode.textValue(); + this.writeFile(basePath, tsFileCode.toLowerCase(), tsFileContent); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + }); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/EapiJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/EapiJsonFileGenerator.java new file mode 100644 index 00000000..d955a202 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/EapiJsonFileGenerator.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class EapiJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + public EapiJsonFileGenerator(String executeEnvironment,boolean isUpdradeTool) { + super(executeEnvironment,isUpdradeTool); + } + + @Override + public void generate(String basePath, String formName, String content) { + if (StringUtility.isNullOrEmpty(content)) { + return; + } + + //eapi 内容需要转换为数组形式 当前传递过来的是单个对象 组装成数组形式 + content="["+content+"]"; + + String eapiJsonFileName = this.generateFileName(formName, FormJsonFileSuffixConstant.FrmSuffix + FormJsonFileSuffixConstant.EapiJsonFile); + this.writeFile(basePath, eapiJsonFileName, content); + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormJsonFileManager.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormJsonFileManager.java new file mode 100644 index 00000000..24aa0179 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormJsonFileManager.java @@ -0,0 +1,55 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class FormJsonFileManager { + + /** + * 根据参数构造具体的表单json文件 + * + * @param buildParameter + */ + public static void generateSpecificJsonFile(JitBuildParameter buildParameter, String executeEnvironment) { + String webDevPath = buildParameter.getBuildWebDevPath(); + if (buildParameter.getBuildRefMetadataList() != null && buildParameter.getBuildRefMetadataList().size() > 0) { + buildParameter.getBuildRefMetadataList().forEach(jitBuildRefMetadata -> { + if (!StringUtility.isNullOrEmpty(jitBuildRefMetadata.getContent())) { + JitMetadataTypeEnum metadataTypeEnum = jitBuildRefMetadata.getMetadataType(); + String strBasePath = webDevPath; + // 针对命令构件 主表单需要放置于对应的moduleCode目录下 + if (metadataTypeEnum == JitMetadataTypeEnum.Command) { + AtomicReference formModuleCode = FormModuleWithBuildParameterManager.getFormModuleCodeAtomicReference(buildParameter); + if (formModuleCode != null && formModuleCode.get() != null) { + strBasePath = webDevPath + "/services/" + formModuleCode.get().toLowerCase() + "/services/"; + } else { + LoggerUtility.log("can not get form module content,please check!", LoggerLevelEnum.Error); + return; + } + } + JsonFileGeneratorInterface jsonFileGenerator = JsonFileGeneratorFactory.create(jitBuildRefMetadata.getMetadataType(), executeEnvironment, buildParameter.isInUpgradeTool()); + // 针对移动状态机的定义,如果传递的元数据包含的自定义的名称 那么使用自定义的名称 否则使用表单code + jsonFileGenerator.generate(strBasePath, buildParameter.getFormCode().toLowerCase(), jitBuildRefMetadata.getContent()); + + } + }); + } + + // 生成页面流文件 + FormRouteJsonFileGenerator routeJsonFileGenerator = new FormRouteJsonFileGenerator(executeEnvironment, buildParameter.isInUpgradeTool()); + routeJsonFileGenerator.generate(webDevPath, buildParameter.getBoCode().toLowerCase(), buildParameter.getFormCode(), null, buildParameter); + } + + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameter.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameter.java new file mode 100644 index 00000000..55ac550a --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameter.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * description: + * + * @author Noah Guo + * @date 2020/07/29 + */ +public class FormModuleWithBuildParameter { + + /** + * 根据编译参数获取对应的表单 moduleCode + * @param buildParameter + * @return + */ + public static AtomicReference getFormModuleCodeAtomicReference(JitBuildParameter buildParameter) { + AtomicReference formModuleCode = new AtomicReference<>(); + buildParameter.getBuildRefMetadataList().forEach((item) -> { + if (item.getMetadataType() == JitMetadataTypeEnum.Frm) { + FormRuntimeMetadataEntity formRuntimeMetadataEntity = SerializeUtility.getInstance().deserialize(item.getContent(), FormRuntimeMetadataEntity.class); + if (formRuntimeMetadataEntity != null) { + FormDOM visualDom = SerializeUtility.getInstance().deserialize(formRuntimeMetadataEntity.getContents().toString(), FormDOM.class); + if (visualDom != null) { + formModuleCode.set(visualDom.getModule().getCode()); + } + } + } + }); + return formModuleCode; + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameterManager.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameterManager.java new file mode 100644 index 00000000..9bed1438 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormModuleWithBuildParameterManager.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * description: + * + * @author Noah Guo + * @date 2020/07/29 + */ +public class FormModuleWithBuildParameterManager { + + /** + * 根据编译参数获取对应的表单 moduleCode + * @param buildParameter + * @return + */ + public static AtomicReference getFormModuleCodeAtomicReference(JitBuildParameter buildParameter) { + AtomicReference formModuleCode = new AtomicReference<>(); + buildParameter.getBuildRefMetadataList().forEach((item) -> { + if (item.getMetadataType() == JitMetadataTypeEnum.Frm) { + FormRuntimeMetadataEntity formRuntimeMetadataEntity = SerializeUtility.getInstance().deserialize(item.getContent(), FormRuntimeMetadataEntity.class); + if (formRuntimeMetadataEntity != null) { + FormDOM visualDom = SerializeUtility.getInstance().deserialize(formRuntimeMetadataEntity.getContents().toString(), FormDOM.class); + if (visualDom != null) { + formModuleCode.set(visualDom.getModule().getCode()); + } + } + } + }); + return formModuleCode; + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRouteJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRouteJsonFileGenerator.java new file mode 100644 index 00000000..4da775dd --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRouteJsonFileGenerator.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute.FormRouteEntity; +import com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute.FormRoutePageEntity; +import com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute.FormRouteProjectEntity; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class FormRouteJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + public FormRouteJsonFileGenerator(String executeEnvironment,boolean isUpdradeTool) { + super(executeEnvironment,isUpdradeTool); + } + + @Override + public void generate(String basePath, String formName, String content) { + + } + + public void generate(String basePath, String projectName, String formName, String content, JitBuildParameter buildParameter) { + String routeJsonFileName = this.generateFileName(projectName, JITEngineConstants.ProjectRouteFileExtension); + FormRouteEntity formRouteEntity = this.generateRouteContent(formName, projectName, buildParameter); + this.writeFile(basePath, routeJsonFileName, SerializeUtility.getInstance().serialize(formRouteEntity)); + } + + /** + * 根据表单code构造页面流 + * + * @param formCode + * @return + */ + private FormRouteEntity generateRouteContent(String formCode, String projectName, JitBuildParameter buildParameter) { + AtomicReference formModuleCode = FormModuleWithBuildParameterManager.getFormModuleCodeAtomicReference(buildParameter); + + FormRouteEntity formRouteEntity = new FormRouteEntity(); + formRouteEntity.setId(UUID.randomUUID().toString()); + + // 设置路由entry + formRouteEntity.setEntry(projectName); + // 设置页面流 project + FormRouteProjectEntity formRouteProjectEntity = new FormRouteProjectEntity(); + formRouteProjectEntity.setName(projectName); + formRouteEntity.setProject(formRouteProjectEntity); + + FormRoutePageEntity[] pages = new FormRoutePageEntity[1]; + FormRoutePageEntity formRoutePageEntity = new FormRoutePageEntity(); + formRoutePageEntity.setId(UUID.randomUUID().toString()); + if (formModuleCode != null) { + formRoutePageEntity.setCode(formModuleCode.get()); + } else { + formRoutePageEntity.setCode(formCode); + } + formRoutePageEntity.setRouteUri(buildParameter.getFormName()); + + formRoutePageEntity.setName(formCode); + formRoutePageEntity.setFileName(formCode + ".frm"); + formRoutePageEntity.setRouteUri(buildParameter.getFormName()); + pages[0] = formRoutePageEntity; + formRouteEntity.setPages(pages); + return formRouteEntity; + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRuntimeMetadataEntity.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRuntimeMetadataEntity.java new file mode 100644 index 00000000..5e2fe2f4 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FormRuntimeMetadataEntity.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * 运行时表单元数据 + */ +public class FormRuntimeMetadataEntity { + private String Id; + + public String getId() { + return Id; + } + + public void setId(String id) { + Id = id; + } + + public String getCode() { + return Code; + } + + public void setCode(String code) { + Code = code; + } + + public String getName() { + return Name; + } + + public void setName(String name) { + Name = name; + } + + public JsonNode getContents() { + return Contents; + } + + public void setContents(JsonNode contents) { + Contents = contents; + } + + private String Code; + private String Name; + private JsonNode Contents; +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FrmJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FrmJsonFileGenerator.java new file mode 100644 index 00000000..392148e8 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/FrmJsonFileGenerator.java @@ -0,0 +1,290 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.i18n.resource.api.metadata.ResourceMetadata; +import com.inspur.edp.lcm.metadata.api.entity.*; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +import com.inspur.edp.web.jitengine.expressions.*; +import com.inspur.edp.web.jitengine.expressions.utility.ExpressionUtility; +import com.inspur.edp.web.jitengine.metadataanalysis.CommandsAnalysis; +import com.inspur.edp.web.jitengine.metadataanalysis.EapiAnalysis; +import com.inspur.edp.web.jitengine.metadataanalysis.FormAnalysis; +import com.inspur.edp.web.jitengine.metadataanalysis.StateMachineAnalysis; +import com.inspur.edp.web.jitengine.metadatamodel.app.form.AnalysisExternalComponentResult; +import com.inspur.edp.web.jitengine.metadataparser.commandservice.CommandServiceAnalysis; + +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class FrmJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + public FrmJsonFileGenerator(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + @Override + public void generate(String basePath, String formName, String content) { + String frmJsonFileName = this.generateFileName(formName, FormJsonFileSuffixConstant.FrmSuffix + FormJsonFileSuffixConstant.FrmJsonFile); + FormRuntimeMetadataEntity formRuntimeMetadataEntity = SerializeUtility.getInstance().deserialize(content, FormRuntimeMetadataEntity.class); + if (formRuntimeMetadataEntity != null) { + this.writeFile(basePath, frmJsonFileName, formRuntimeMetadataEntity.getContents().toString()); + } else { + LoggerUtility.log("build parameter has none form metadata content, the formCode is " + formName, LoggerLevelEnum.Warning); + } + + // 生成command json文件 + this.generateCommandJson(formRuntimeMetadataEntity.getContents().toString(), basePath, formName); + + // 生成对应的资源文件 + // this.generateResourceJson(formRuntimeMetadataEntity.getContents(), basePath, formName, ""); + + + FormDOM visualDom = SerializeUtility.getInstance().deserialize(formRuntimeMetadataEntity.getContents().toString(), FormDOM.class); + + ExpressionManifest expressionManifest = new ExpressionManifest(); + // 设置表达式 manifest.json 文件的code及其对应的文件名 + expressionManifest.setFormModuleCode(visualDom.getModule().getCode()); + expressionManifest.setManifestJsonPath(ExpressionUtility.getExpressionManifestJsonPath(formRuntimeMetadataEntity.getCode())); + + ///获取表单对应的表达式 + ModuleFormExpressions moduleFormExpressions = ExpressionFormGenerator.generate(visualDom, "", null); + // 仅仅在包含表达式时才进行添加 + if (moduleFormExpressions != null && moduleFormExpressions.getExpressions() != null && moduleFormExpressions.getExpressions().size() > 0) { + expressionManifest.getExpressions().add(moduleFormExpressions); + } + + HashMap projectWebCmd = new HashMap<>(); + this.executeExternalComponent(visualDom, basePath, basePath + "/services", basePath, basePath, projectWebCmd, expressionManifest); + + // 写入表单表达式json文件 + ExpressionManifestManager.writeExpressionJson(expressionManifest, basePath, false); + } + + + /** + * 生成command json文件 + * + * @param content + * @param basePath + */ + private void generateCommandJson(String content, String basePath, String fileName) { + if (StringUtility.isNullOrEmpty(content)) { + return; + } + LoggerUtility.log("generate command json file", LoggerLevelEnum.Info); + // 反序列化表单元数据 + FormDOM json = SerializeUtility.getInstance().deserialize(content, FormDOM.class); + CommandsAnalysis commandsAnalysis = new CommandsAnalysis(this.getExecuteEnvironment(), this.isUpdradeTool()); + HashMap projectCmpList = new HashMap<>(); + try { + fileName = fileName + ".frm"; + commandsAnalysis.resolveCommand(json, fileName, basePath, projectCmpList, null, fileName); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 生成对应的资源文件 + * + * @param content + * @param basePath + * @param fileName + */ + private void generateResourceJson(String content, String basePath, String fileName, String keyPrefix) { + GspMetadata gspMetadata = SerializeUtility.getInstance().deserialize(content, FormDOM.class); + List refList = gspMetadata.getRefs(); + if (refList != null && refList.size() > 0) { + List resourceList = new ArrayList<>(); + refList.forEach(MetadataReference -> { + if (MetadataReference.getDependentMetadata().getType().equals("ResourceMetadata")) { + GspMetadata refMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(MetadataReference.getDependentMetadata().getId(), this.getExecuteEnvironment(), this.isUpdradeTool()); + ResourceMetadata resourceMetadata = (refMetadata == null || refMetadata.getContent() == null) ? null : ((ResourceMetadata) refMetadata.getContent()); + I18nResource item = ConvertToI18nResource(resourceMetadata, resourceMetadata.getOriginalLanguage()); + resourceList.add(item); + } + }); + + if (resourceList.size() > 0) { + resourceList.forEach(item -> { + I18nResourceItemCollection resourceItemCollection = item.getStringResources(); + if (resourceItemCollection == null || resourceItemCollection.size() <= 0) { + return; + } + + // 根据资源项构建生成结构 + StringBuilder resouceItemsStringBuilder = new StringBuilder(); + resouceItemsStringBuilder.append("{"); + for (int i = 0; i < resourceItemCollection.size(); i++) { + I18nResourceItem resourceItem = resourceItemCollection.get(i); + StringBuilder resouceItemStringBuilder = new StringBuilder(); + String id = resourceItem.getKey(); + + String updatedId = id.substring(id.lastIndexOf(".") + 1);// 解析ID + String value = resourceItem.getValue(); + String comment = resourceItem.getComment(); + resouceItemStringBuilder.append("\"").append(updatedId).append("\": {"); + resouceItemStringBuilder.append(" \"name\": " + "\"").append(value).append("\","); + resouceItemStringBuilder.append(" \"comment\": " + "\"").append(comment).append("\""); + resouceItemStringBuilder.append("}"); + + + if (i != resourceItemCollection.size() - 1) { + resouceItemStringBuilder.append(","); + } + + resouceItemsStringBuilder.append(resouceItemStringBuilder); + } + resouceItemsStringBuilder.append("}"); + + // 将生成的结构持久化到磁盘 + FileUtility.writeFile(basePath, gspMetadata.getHeader().getFileName().toLowerCase() + ".resource.json", resouceItemsStringBuilder.toString()); + + }); + } + + + } + } + + + private I18nResource ConvertToI18nResource(ResourceMetadata metadata, String language) { + if (metadata == null) { + return null; + } + I18nResource i18nResource = new I18nResource(); + i18nResource.setLanguage((language == null) ? "en" : language); + i18nResource.setStringResources(new I18nResourceItemCollection()); + + if (metadata.getStringResources() != null && metadata.getStringResources().size() != 0) { + metadata.getStringResources().forEach(stringResource -> { + I18nResourceItem item = new I18nResourceItem(); + item.setKey(stringResource.getId()); + item.setValue(stringResource.getValue()); + item.setValue(stringResource.getComment()); + + i18nResource.getStringResources().add(item); + }); + + } + + return i18nResource; + } + + /** + * 处理扩展组件 + */ + private void executeExternalComponent(FormDOM json, String targetStorageBasePath, String formServicePath, String projectPath, + String webdevpath, HashMap projectCmpList, ExpressionManifest expressionManifest) { + + if (json != null && json.getModule() != null && json.getModule().getExternalComponents() != null && json.getModule().getExternalComponents().size() > 0) { + for (HashMap item : json.getModule().getExternalComponents()) { + + FormAnalysis formAnalysis = new FormAnalysis(this.getExecuteEnvironment(), this.isUpdradeTool()); + + AnalysisExternalComponentResult externalVisualDom; + try { + externalVisualDom = formAnalysis.analysisExternalComponent(targetStorageBasePath, json.getModule().getCode().toLowerCase(), item, webdevpath); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + // 如果获取不到对应的表单元数据。针对的是弹窗Url 情况 + if (externalVisualDom != null && externalVisualDom.getJson() != null) { + + String strContainerId = getExternalContainerId(item); + if (externalVisualDom.isUseIsolateJs()) { + return; + } + + ///获取表单对应的表达式 + ModuleFormExpressions moduleFormExpressions = ExpressionFormGenerator.generate(externalVisualDom.getJson(), strContainerId, item); + // 仅仅在包含表达式时才进行添加 + if (moduleFormExpressions != null && moduleFormExpressions.getExpressions() != null && moduleFormExpressions.getExpressions().size() > 0) { + expressionManifest.getExpressions().add(moduleFormExpressions); + } + + String externalFormBasePath = FileUtility.combine(targetStorageBasePath, json.getModule().getCode().toLowerCase(), externalVisualDom.getExternalComponentPath()); + /// 表单service文件路径 + String externalFormServicePath = FileUtility.combine(formServicePath, json.getModule().getCode().toLowerCase(), "externalcomponents", externalVisualDom.getExternalComponentPath()); + String metaFileName = externalVisualDom.getJson().getModule().getCode() + ".frm"; + GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(externalVisualDom.getExternalComponentUri(), this.getExecuteEnvironment(), this.isUpdradeTool()); + + String[] params = {externalVisualDom.getExternalComponentPath(), externalVisualDom.getJson().getModule().getCode()}; + + try { + resolveFormMetadataWithVisualDom(formMetadata, externalVisualDom.getJson(), + externalFormBasePath, externalVisualDom.getRelativePath(), externalFormServicePath, projectPath, + projectCmpList, webdevpath, expressionManifest); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + } + + private String getExternalContainerId(HashMap item) { + String externalComponentId = (String) item.get("id"); + String externalComponentType = (String) item.get("type"); + String containerId = (String) item.get("containerId"); + String strContainerId; + if (externalComponentType.equals("ModalContainer")) { + strContainerId = !StringUtility.isNullOrEmpty(containerId) ? containerId : externalComponentId; + } else { + strContainerId = externalComponentId; + } + + return strContainerId; + } + + + private void resolveFormMetadataWithVisualDom(GspMetadata formMetadata, FormDOM formDom, + String targetStorageBasePath, String relativePath, String formServiceBasePath, + String projectPath, HashMap projectCmpList, + String webDevPath, ExpressionManifest expressionManifest) throws Exception { + String formMetadataName = formMetadata.getHeader().getFileName(); +// 临时注释,方便调试 + // Step 2: Resolve StateMachine, and Save StateMachine + StateMachineAnalysis.resolveStateMachine(formDom, formMetadataName, targetStorageBasePath, webDevPath, projectPath, this.getExecuteEnvironment(), this.isUpdradeTool()); +// +// // Step 3: Resolve Command + CommandsAnalysis commandsAnalysis = new CommandsAnalysis(this.getExecuteEnvironment(), this.isUpdradeTool()); + commandsAnalysis.resolveCommand(formDom, formMetadataName, targetStorageBasePath, projectCmpList, webDevPath, null); +// +// // Step 4: Resolve eapi + EapiAnalysis eapiAnalysis = new EapiAnalysis(this.getExecuteEnvironment(), this.isUpdradeTool()); + eapiAnalysis.resolveEapi(formDom, formMetadataName, targetStorageBasePath, projectPath, webDevPath); +// +// // Step 5: Resolve command service + CommandServiceAnalysis.resolveCommandService(formDom, relativePath, formServiceBasePath, webDevPath, this.getExecuteEnvironment(), this.isUpdradeTool()); + + // 构造对应的国际化资源项 + //GenerateResourceManager.generateI18nResource(formMetadata, i18nResourceList, i18nResourceKeyPrefix,"en"); + + // 递归解析 如果存在子组件 那么需要递归执行子组件 + executeExternalComponent(formDom, + targetStorageBasePath, formServiceBasePath, projectPath, + webDevPath, projectCmpList, expressionManifest); + } + + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorFactory.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorFactory.java new file mode 100644 index 00000000..81cc5dc0 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorFactory.java @@ -0,0 +1,40 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + + +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class JsonFileGeneratorFactory { + public static JsonFileGeneratorInterface create(JitMetadataTypeEnum metadataType, String executeEnvironment,boolean isUpdradeTool) { + JsonFileGeneratorInterface jsonFileGenerator = null; + switch (metadataType) { + case Frm: + jsonFileGenerator = new FrmJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + case Eapi: + jsonFileGenerator = new EapiJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + case Command: + jsonFileGenerator = new CommandJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + case Resource: + jsonFileGenerator = new ResourceJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + case StateMachine: + jsonFileGenerator = new StateMachineJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + case Route: + jsonFileGenerator = new FormRouteJsonFileGenerator(executeEnvironment,isUpdradeTool); + break; + default: + System.out.println("unknown meta data type " + metadataType); + break; + } + return jsonFileGenerator; + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorInterface.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorInterface.java new file mode 100644 index 00000000..dd3ec246 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/JsonFileGeneratorInterface.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +public interface JsonFileGeneratorInterface { + /** + * json文件生成接口方法 + * @param basePath + * @param formName + * @param content + */ + void generate(String basePath, String formName, String content) ; +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/ResourceJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/ResourceJsonFileGenerator.java new file mode 100644 index 00000000..ab0f1663 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/ResourceJsonFileGenerator.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class ResourceJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + public ResourceJsonFileGenerator(String executeEnvironment,boolean isUpdradeTool) { + super(executeEnvironment,isUpdradeTool); + } + + @Override + public void generate(String basePath, String formName, String content) { + String resourceFileName = this.generateFileName(formName, FormJsonFileSuffixConstant.FrmSuffix + FormJsonFileSuffixConstant.ResourceJsonFile); + this.writeFile(basePath, resourceFileName, content); + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/StateMachineJsonFileGenerator.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/StateMachineJsonFileGenerator.java new file mode 100644 index 00000000..f5e5f750 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/StateMachineJsonFileGenerator.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator; + +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; + +/** + * description: + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class StateMachineJsonFileGenerator extends AbstractFormJsonFileGenerator implements JsonFileGeneratorInterface { + + public StateMachineJsonFileGenerator(String executeEnvironment,boolean isUpdradeTool) { + super(executeEnvironment,isUpdradeTool); + } + + + @Override + public void generate(String basePath, String formName, String content) { + String smJsonFileName = this.generateFileName(formName, FormJsonFileSuffixConstant.FrmSuffix + FormJsonFileSuffixConstant.StateMachineJsonFile); + this.writeFile(basePath, smJsonFileName, content); + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteEntity.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteEntity.java new file mode 100644 index 00000000..502a707b --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteEntity.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + + +@Data +public class FormRouteEntity { + @JsonProperty("id") + private String id; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getEntry() { + return entry; + } + + public void setEntry(String entry) { + this.entry = entry; + } + + public FormRoutePageEntity[] getPages() { + return pages; + } + + public void setPages(FormRoutePageEntity[] pages) { + this.pages = pages; + } + + public FormRouteProjectEntity getProject() { + return project; + } + + public void setProject(FormRouteProjectEntity project) { + this.project = project; + } + + @JsonProperty("entry") + private String entry; + + @JsonProperty("pages") + private FormRoutePageEntity[] pages; + + @JsonProperty("project") + private FormRouteProjectEntity project; +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRoutePageEntity.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRoutePageEntity.java new file mode 100644 index 00000000..b1bee8bc --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRoutePageEntity.java @@ -0,0 +1,96 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class FormRoutePageEntity { + @JsonProperty("id") + private String id; + + @JsonProperty("code") + private String code; + + @JsonProperty("name") + private String name; + + @JsonProperty("fileName") + private String fileName; + + @JsonProperty("relativePath") + private String relativePath; + + @JsonProperty("formUri") + private String formUri; + + @JsonProperty("routeUri") + private String routeUri; + + @JsonProperty("routeParams") + private String routeParams; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getRelativePath() { + return relativePath; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + + public String getFormUri() { + return formUri; + } + + public void setFormUri(String formUri) { + this.formUri = formUri; + } + + public String getRouteUri() { + return routeUri; + } + + public void setRouteUri(String routeUri) { + this.routeUri = routeUri; + } + + public String getRouteParams() { + return routeParams; + } + + public void setRouteParams(String routeParams) { + this.routeParams = routeParams; + } + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteProjectEntity.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteProjectEntity.java new file mode 100644 index 00000000..b4c0c68b --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/formjsonfilegenerator/formroute/FormRouteProjectEntity.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.formroute; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class FormRouteProjectEntity { + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @JsonProperty("name") + private String name; + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI18nResourceList.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI18nResourceList.java new file mode 100644 index 00000000..737b3d4a --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI18nResourceList.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.jitruntimebuild.core.i18n; + +import com.inspur.edp.web.jitengine.i18nresource.GeneratedI8nResource; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2020/06/03 + */ +public class GeneratedI18nResourceList { + + /// + /// 生成的资源项列表集合 + /// + public List ResourceList = new ArrayList<>(); + + + + /// + /// 增加资源项 + /// + /// + /// + public void Add(String key, String value) + { + GeneratedI8nResource generatedI8nResource=new GeneratedI8nResource(); + generatedI8nResource.setKey(key); + generatedI8nResource.setValue(value); + this.ResourceList.add(generatedI8nResource); + } +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI8nResource.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI8nResource.java new file mode 100644 index 00000000..18ee0b32 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/i18n/GeneratedI8nResource.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.jitruntimebuild.core.i18n; + +/** + * description: + * + * @author Noah Guo + * @date 2020/06/03 + */ +public class GeneratedI8nResource { + /// + /// 生成资源项key + /// + private String key; + + /// + /// 生成资源项value + /// + private String value; + + public String getKey() { + return this.key; + } + + public void setKey(String value) { + this.key = value; + } + + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/service/JitBuildServiceImp.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/service/JitBuildServiceImp.java new file mode 100644 index 00000000..f02f5b56 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/service/JitBuildServiceImp.java @@ -0,0 +1,145 @@ +package com.inspur.edp.web.jitruntimebuild.core.service; + +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitengine.ProjectCompileContext; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildResponse; +import com.inspur.edp.web.jitruntimebuild.api.service.JitBuildService; +import com.inspur.edp.web.jitruntimebuild.core.builddeploy.BuildDeployManager; +import com.inspur.edp.web.jitruntimebuild.core.buildparametergenerator.JitBuildParameterGenerator; +import com.inspur.edp.web.jitruntimebuild.core.buildparametervalidator.JitBuildParameterValidator; +import com.inspur.edp.web.jitruntimebuild.core.formjsonfilegenerator.FormJsonFileManager; +import com.inspur.edp.web.jitruntimebuild.core.sourcecodemetadata.SourceCodeMetadataManager; + +import java.util.HashMap; +import java.util.Map; + + +/** + * description:运行时表单执行入口 + * 该方法被其他引用 方法名不能更改 + * + * @author Noah Guo + * @date 2020/04/29 + */ +public class JitBuildServiceImp implements JitBuildService { + + /** + * jit 运行时编译 + * + * @param buildParameter + * @return + */ + @Override + public JitBuildResponse jitBuild(JitBuildParameter buildParameter) { + + LoggerUtility.log("begin execute runtime build", LoggerLevelEnum.Info); + // 执行入参验证 + JitBuildResponse buildResponse = JitBuildParameterValidator.validate(buildParameter); + if (!buildResponse.isSuccess()) { + LoggerUtility.log(buildResponse.getErrorMessage(), LoggerLevelEnum.Error); + return buildResponse; + } + + // 对编译参数进行调整 设置默认值 + if (!buildParameter.isMobileApprove()) { + JitBuildParameterGenerator.generate(buildParameter); + LoggerUtility.log("build parameter executed completely", LoggerLevelEnum.Info); + } + // 设定当前运行环境为runtime + String executeEnvironment = ExecuteEnvironment.Runtime; + // 首先删除service文件夹 避免service文件变更导致的编译失败 + String sourceServicePath = buildParameter.getBuildWebDevPath() + "/services/"; + try { + FileUtility.deleteFolder(sourceServicePath); + LoggerUtility.log("delete service path ,the service path is " + sourceServicePath, LoggerLevelEnum.Info); + } catch (Exception ignored) { + + } + + // 生成具体的json文件 + LoggerUtility.log("begin generate form json file, the formCode is " + buildParameter.getFormCode(), LoggerLevelEnum.Info); + FormJsonFileManager.generateSpecificJsonFile(buildParameter, executeEnvironment); + LoggerUtility.log("generate form json file completely, the formCode is " + buildParameter.getFormCode(), LoggerLevelEnum.Info); + + // 执行 脚本文件生成 + LoggerUtility.log("begine generate source code", LoggerLevelEnum.Info); + ProjectCompileContext projectCompileContext = new ProjectCompileContext( + buildParameter.getBoCode(), + buildParameter.getBuildNodeModulePath(), + "pc", "angular", + buildParameter.getBuildWebDevPath(), + buildParameter.getBuildAppPath(), null, + buildParameter.getServiceUnitPath(), ExecuteEnvironment.Runtime); + if (buildParameter.isMobileApp()) { + projectCompileContext.setFormType("mobile"); + projectCompileContext.setFrameworkType("vue"); + } + // 设置运行时定制维度信息 + projectCompileContext.extraFormPath = buildParameter.getExtraFormPathStr(); + projectCompileContext.setGenerateViewModel(!buildParameter.isBabelCompile()); + // 运行时定制设置生成前删除代码目录 + projectCompileContext.setDeleteSourceCodeBeforeGenerate(true); + JITEngineManager.compileProject(projectCompileContext); + + LoggerUtility.log("begin compile project, the formCode is " + buildParameter.getFormCode(), LoggerLevelEnum.Info); + + + // 拷贝service文件到具体的文件夹路径 + String targetServiceProductPath = buildParameter.getBuildAppPath() + "/projects" + "/" + buildParameter.getBoCode().toLowerCase() + "/src/app"; + if (buildParameter.isMobileApp()) { + targetServiceProductPath = buildParameter.getBuildAppPath() + "/src/apps"; + } + FileUtility.copyFolder(sourceServicePath, targetServiceProductPath); + + + ///解析自定义web构件 + SourceCodeMetadataManager.analysisSourceCodeMetadata(buildParameter); + + // 脚本编译 + // 临时注释编译 + String buildErrorMessage = null; + + try { + buildErrorMessage = JITEngineManager.buildFrontendProjectWithRuntime(buildParameter.getBuildAppPath(), buildParameter.isInUpgradeTool(),buildParameter); + } catch (RuntimeException ex) { + // 捕获编译异常 应该指定特定的异常 方便进行异常信息提示 + buildErrorMessage = ex.getMessage(); + WebLogger.Instance.error(ex.getMessage() + ex.getStackTrace()); + } + + + // 执行工程部署 且执行文件脚本发布 + if (StringUtility.isNullOrEmpty(buildErrorMessage) || StringUtility.isBlank(buildErrorMessage.trim())) { + BuildDeployManager.deployForm(buildParameter); + } else { + LoggerUtility.log("build failed,can not execute script deploy", LoggerLevelEnum.Error); + buildResponse = new JitBuildResponse(); + buildResponse.setSuccess(false); + buildResponse.setErrorMessage(buildErrorMessage); + return buildResponse; + } + + if (buildParameter.isBabelCompile()) { + // 如果是babel编译 那么返回对应的url参数 + String babelUrl = FileUtility.getPlatformIndependentPath("/" + buildParameter.getServiceUnitPath() + "/" + "web" + "/" + buildParameter.getBoCode() + "forbabelruntime" + "/" + + buildParameter.getFormName() + + com.inspur.edp.web.jitruntimebuild.core.utility.JitBuildUtility.getExtraPath(buildParameter.getExtraFormPath()) + "/index.html#/" + buildParameter.getFormName()); + System.out.println(babelUrl); + Map mapResult = new HashMap<>(); + mapResult.put("babelUrl", babelUrl); + } + + // 构造成功的返回值 + buildResponse = new JitBuildResponse(); + + return buildResponse; + } + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/sourcecodemetadata/SourceCodeMetadataManager.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/sourcecodemetadata/SourceCodeMetadataManager.java new file mode 100644 index 00000000..b20b2aa9 --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/sourcecodemetadata/SourceCodeMetadataManager.java @@ -0,0 +1,116 @@ +package com.inspur.edp.web.jitruntimebuild.core.sourcecodemetadata; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.Base64Utility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitengine.sourcecode.SourceCodeInFormManager; +import com.inspur.edp.web.jitengine.sourcecode.SourceCodeInFormRef; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildRefMetadata; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeItemEntity; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; + +import java.io.UnsupportedEncodingException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * description: 运行时定制自定义web构件 + * + * @author Noah Guo + * @date 2020/06/16 + */ +public class SourceCodeMetadataManager { + + + /** + * 解析自定义web构件元数据 + * + * @param jitBuildParameter + */ + public static void analysisSourceCodeMetadata(JitBuildParameter jitBuildParameter) { + + List sourceCodeInFormRefList = SourceCodeMetadataManager.getSourceCodeRefInForm(jitBuildParameter); + + List sourceCodeMetadataEntityList = SourceCodeInFormManager.getSourceCodeMetadataEntities(sourceCodeInFormRefList, jitBuildParameter.isInUpgradeTool()); + + // 解压缩内容到指定的文件路径 + unZipSourceMetadataEntity(sourceCodeMetadataEntityList, jitBuildParameter); + } + + /** + * 解析自定义web构件元数据信息 + * + * @param sourceCodeMetadataEntityList + */ + private static void unZipSourceMetadataEntity(List sourceCodeMetadataEntityList, JitBuildParameter buildParameter) { + if (sourceCodeMetadataEntityList != null && sourceCodeMetadataEntityList.size() > 0) { + String projectAppPath = buildParameter.getBuildAppPath(); + + sourceCodeMetadataEntityList.forEach((sourceCodeMetadataEntityItem) -> { + List items = sourceCodeMetadataEntityItem.getItems(); + if (items != null && items.size() > 0) { + + items.forEach(item -> { + + try { + String strFileContent = Base64Utility.decode(item.getSourceFileContent()); + // 如果文件内容为空 也进行文件内容的生成操作 + String strWriteFilePath = getWriteFilePath(item, buildParameter); + System.out.println("待写入的目标文件路径为" + strWriteFilePath); + FileUtility.writeFile(strWriteFilePath, strFileContent); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + }); + } + }); + } + } + + private static String getWriteFilePath(SourceCodeItemEntity sourceCodeItemEntity, JitBuildParameter buildParameter) { + + Path writeFilePath = Paths.get(buildParameter.getBuildAppPath(), generateSourcePath(sourceCodeItemEntity, buildParameter)); + String strWritePath = writeFilePath.toString(); + + System.out.println("target file path is " + strWritePath); + return strWritePath; + } + + private static String generateSourcePath(SourceCodeItemEntity sourceCodeItemEntity, JitBuildParameter buildParameter) { + String strGeneratedSourcePath = StringUtility.isNullOrEmpty(sourceCodeItemEntity.getTargetPath()) ? sourceCodeItemEntity.getSourcePath() : sourceCodeItemEntity.getTargetPath(); + String strSourcePath = strGeneratedSourcePath; + strSourcePath = strSourcePath.replace("{{projectname}}", buildParameter.getBoCode()); + return strSourcePath.toLowerCase(); + } + + + /** + * 从表单元数据中读取自定义web构件引用 + * + * @param buildParameter + * @return + */ + public static List getSourceCodeRefInForm(JitBuildParameter buildParameter) { + + List formRefList = new ArrayList<>(); + + List refMetadataList = buildParameter.getBuildRefMetadataList(); + if (refMetadataList != null && refMetadataList.size() > 0) { + refMetadataList.forEach((metadata) -> { + JitMetadataTypeEnum metadataTypeEnum = metadata.getMetadataType(); + if (metadataTypeEnum == JitMetadataTypeEnum.Frm) { + String strFormMetadataContent = metadata.getContent(); + SourceCodeInFormManager.getSourceCodeWithFormMetadataContent(formRefList, strFormMetadataContent); + } + }); + } + return formRefList; + } + + +} diff --git a/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/utility/JitBuildUtility.java b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/utility/JitBuildUtility.java new file mode 100644 index 00000000..a8f5532f --- /dev/null +++ b/runtime-core/src/main/java/com/inspur/edp/web/jitruntimebuild/core/utility/JitBuildUtility.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.jitruntimebuild.core.utility; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.core.constant.FormJsonFileSuffixConstant; + +public class JitBuildUtility { + /** + * 根据维度获取对应路径 + * @param extraData + * @return + */ + public static String getExtraPath(String[] extraData) { + StringBuilder strWeiDuInfo = new StringBuilder(); + for (String extraDataItem : extraData) { + if (StringUtility.isNullOrEmpty(extraDataItem)) { + strWeiDuInfo.append(FileUtility.DIRECTORY_SEPARATOR_CHAR).append(FormJsonFileSuffixConstant.DefaultWeiDuName); + } else { + strWeiDuInfo.append(FileUtility.DIRECTORY_SEPARATOR_CHAR).append(extraDataItem); + } + } + return strWeiDuInfo.toString(); + + } +} diff --git a/runtime-core/src/main/resources/META-INF/spring.factories b/runtime-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..befe61b7 --- /dev/null +++ b/runtime-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.jitruntimebuild.core.config.JitBuildConfiguration diff --git a/runtime-scriptcache-api/pom.xml b/runtime-scriptcache-api/pom.xml new file mode 100644 index 00000000..532483d5 --- /dev/null +++ b/runtime-scriptcache-api/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + + + web + com.inspur.edp + ${custom.version} + + + jar + + web-jitengine-runtimebuild-scriptcache-api + + + + + com.jayway.jsonpath + json-path + + + io.iec.edp + caf-boot-starter-rest-server + + + com.inspur.edp + web-jitengine-common + + + + + diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormProjectCache.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormProjectCache.java new file mode 100644 index 00000000..51d6d8b2 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormProjectCache.java @@ -0,0 +1,148 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.Date; + +/** + * description: 表单工程缓存 + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class FormProjectCache { + + /** + * 主键字段 + */ + private String id; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 工程编码 + */ + private String projectCode; + + /** + * 工程相对路径 + */ + private String projectRelativePath; + + /** + * 工程对应版本 + */ + private String version; + + public String getId() { + if (StringUtility.isNullOrEmpty(id)) { + id = StringUtility.convertNullToEmptyString(id); + } + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getProjectName() { + if (StringUtility.isNullOrEmpty(projectName)) { + projectName = StringUtility.convertNullToEmptyString(projectName); + } + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectCode() { + if (StringUtility.isNullOrEmpty(projectCode)) { + projectCode = StringUtility.convertNullToEmptyString(projectCode); + } + return projectCode; + } + + public void setProjectCode(String projectCode) { + this.projectCode = projectCode; + } + + public String getProjectRelativePath() { + if (StringUtility.isNullOrEmpty(projectRelativePath)) { + projectRelativePath = StringUtility.convertNullToEmptyString(projectRelativePath); + } + return projectRelativePath; + } + + public void setProjectRelativePath(String projectRelativePath) { + this.projectRelativePath = projectRelativePath; + } + + public String getVersion() { + if (StringUtility.isNullOrEmpty(version)) { + version = StringUtility.convertNullToEmptyString(version); + } + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getLastModifier() { + return lastModifier; + } + + public void setLastModifier(String lastModifier) { + this.lastModifier = lastModifier; + } + + public Date getLastModifyTime() { + return lastModifyTime; + } + + public void setLastModifyTime(Date lastModifyTime) { + this.lastModifyTime = lastModifyTime; + } + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 创建人 + */ + private String creator; + + /** + * 最后修改人 + */ + private String lastModifier; + + /** + * 最后修改时间 + */ + private Date lastModifyTime; + + +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCache.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCache.java new file mode 100644 index 00000000..e67315b6 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCache.java @@ -0,0 +1,199 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.Date; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class FormScriptCache { + /** + * 主键 + */ + private String id; + + /** + * 表单元数据id + */ + private String formMetadataId; + + /** + * 对应工程缓存id + */ + private String projectVersionId; + + /** + * 脚本文件版本 + */ + private String version; + + /** + * 脚本文件名称 + */ + private String scriptName; + + /** + * 脚本文件编码 + */ + private String scriptCode; + + /** + * 脚本文件相对路径 + */ + private String scriptRelativePath; + + /** + * 脚本文件内容关联id + */ + private String scriptContentId; + + /** + * 脚本文件内容 + */ + private String scriptContent; + + private Date createDate; + + private String creator; + + private Date lastModifyTime; + + private String lastModifier; + + public String getId() { + if (StringUtility.isNullOrEmpty(id)) { + id = StringUtility.convertNullToEmptyString(id); + } + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFormMetadataId() { + if (StringUtility.isNullOrEmpty(formMetadataId)) { + formMetadataId = StringUtility.convertNullToEmptyString(formMetadataId); + } + return formMetadataId; + } + + public void setFormMetadataId(String formMetadataId) { + this.formMetadataId = formMetadataId; + } + + public String getProjectVersionId() { + if (StringUtility.isNullOrEmpty(projectVersionId)) { + projectVersionId = StringUtility.convertNullToEmptyString(projectVersionId); + } + return projectVersionId; + } + + public void setProjectVersionId(String projectVersionId) { + this.projectVersionId = projectVersionId; + } + + public String getVersion() { + if (StringUtility.isNullOrEmpty(version)) { + version = StringUtility.convertNullToEmptyString(version); + } + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getScriptName() { + if (StringUtility.isNullOrEmpty(scriptName)) { + scriptName = StringUtility.convertNullToEmptyString(scriptName); + } + return scriptName; + } + + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + + public String getScriptCode() { + if (StringUtility.isNullOrEmpty(scriptCode)) { + scriptCode = StringUtility.convertNullToEmptyString(scriptCode); + } + return scriptCode; + } + + public void setScriptCode(String scriptCode) { + this.scriptCode = scriptCode; + } + + public String getScriptRelativePath() { + if (StringUtility.isNullOrEmpty(scriptRelativePath)) { + scriptRelativePath = StringUtility.convertNullToEmptyString(scriptRelativePath); + } + return scriptRelativePath; + } + + public void setScriptRelativePath(String scriptRelativePath) { + this.scriptRelativePath = scriptRelativePath; + } + + public String getScriptContentId() { + if (StringUtility.isNullOrEmpty(scriptContentId)) { + scriptContentId = StringUtility.convertNullToEmptyString(scriptContentId); + } + return scriptContentId; + } + + public void setScriptContentId(String scriptContentId) { + this.scriptContentId = scriptContentId; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + // 如果未设置最后修改时间 那么设置该时间为当前时间 + public Date getLastModifyTime() { + if (lastModifyTime == null) { + lastModifyTime = new Date(); + } + return lastModifyTime; + } + + public void setLastModifyTime(Date lastModifyTime) { + this.lastModifyTime = lastModifyTime; + } + + public String getLastModifier() { + return lastModifier; + } + + public void setLastModifier(String lastModifier) { + this.lastModifier = lastModifier; + } + + public String getScriptContent() { + return scriptContent; + } + + public void setScriptContent(String scriptContent) { + this.scriptContent = scriptContent; + } +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCacheContent.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCacheContent.java new file mode 100644 index 00000000..653f912c --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/FormScriptCacheContent.java @@ -0,0 +1,88 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.Date; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class FormScriptCacheContent { + /** + * 主键id + */ + private String id; + + /** + * 文件内容 + */ + private String content; + + /** + * 创建时间 + */ + private Date createDate; + + private String creator; + + private String lastModifier; + + private Date lastModifyTime; + + public String getId() { + if (StringUtility.isNullOrEmpty(id)) { + id = StringUtility.convertNullToEmptyString(id); + } + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContent() { + if (StringUtility.isNullOrEmpty(content)) { + content = StringUtility.convertNullToEmptyString(content); + } + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getLastModifier() { + return lastModifier; + } + + public void setLastModifier(String lastModifier) { + this.lastModifier = lastModifier; + } + + public Date getLastModifyTime() { + return lastModifyTime; + } + + public void setLastModifyTime(Date lastModifyTime) { + this.lastModifyTime = lastModifyTime; + } +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/PublishScriptRequest.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/PublishScriptRequest.java new file mode 100644 index 00000000..c60a47ba --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/PublishScriptRequest.java @@ -0,0 +1,100 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/29 + */ +public class PublishScriptRequest { + // 表单元数据id + private String metaDataId; + + // 所属工程名称 + private String projectName; + + // 部署脚本相对路径 + private String projectRelativePath; + + // 脚本文件名称 + private String scriptName; + + //关联表单code + private String formCode; + + /** + * 是否更新元数据版本 + */ + private boolean updateMetadataVersion = true; + + private String absoluteBaseDirectory; + + /** + * 是否零代码表单 默认为false + */ + private boolean isZeroCodeMobileForm = false; + + public String getMetaDataId() { + return metaDataId; + } + + public void setMetaDataId(String metaDataId) { + this.metaDataId = metaDataId; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectRelativePath() { + return projectRelativePath; + } + + public void setProjectRelativePath(String projectRelativePath) { + this.projectRelativePath = projectRelativePath; + } + + public String getScriptName() { + return scriptName; + } + + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + + public String getAbsoluteBaseDirectory() { + return absoluteBaseDirectory; + } + + public void setAbsoluteBaseDirectory(String absoluteBaseDirectory) { + this.absoluteBaseDirectory = absoluteBaseDirectory; + } + + public String getFormCode() { + return formCode; + } + + public void setFormCode(String formCode) { + this.formCode = formCode; + } + + public boolean isUpdateMetadataVersion() { + return updateMetadataVersion; + } + + public void setUpdateMetadataVersion(boolean updateMetadataVersion) { + this.updateMetadataVersion = updateMetadataVersion; + } + + public boolean isZeroCodeMobileForm() { + return isZeroCodeMobileForm; + } + + public void setZeroCodeMobileForm(boolean zeroCodeMobileForm) { + isZeroCodeMobileForm = zeroCodeMobileForm; + } +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheCheckVersionRequest.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheCheckVersionRequest.java new file mode 100644 index 00000000..af5961e6 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheCheckVersionRequest.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + +/** + * description:脚本缓存 + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class ScriptCacheCheckVersionRequest { + /** + * 关联表单元数据id + */ + private String formMetadataId; + /** + * 工程名称 + */ + private String projectName; + /** + * 工程相对路径 + */ + private String projectRelativePath; + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectRelativePath() { + return projectRelativePath; + } + + public void setProjectRelativePath(String projectRelativePath) { + this.projectRelativePath = projectRelativePath; + } + + public String getFormMetadataId() { + return formMetadataId; + } + + public void setFormMetadataId(String formMetadataId) { + this.formMetadataId = formMetadataId; + } +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheResponse.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheResponse.java new file mode 100644 index 00000000..a5293e09 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/entity/ScriptCacheResponse.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class ScriptCacheResponse { + public ScriptCacheResponse() { + this.success = true; + this.errorMessage = null; + } + + public static ScriptCacheResponse getInstance() { + return new ScriptCacheResponse(); + } + + // 是否成功标识 + private boolean success = true; + //异常西悉尼 + private String errorMessage; + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + /** + * 设置错误信息 会同步将是否成功标识设置为false + * + * @param errorMessage + */ + public void setErrorMessage(String errorMessage) { + this.success = false; + this.errorMessage = errorMessage; + } +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/service/ScriptCacheService.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/service/ScriptCacheService.java new file mode 100644 index 00000000..0406a848 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/service/ScriptCacheService.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.service; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.PublishScriptRequest; + +/** + * description:脚本缓存服务 + * + * @author Noah Guo + * @date 2020/09/28 + */ +public interface ScriptCacheService { + + /** + * 发布文件目录下的所有脚本文件 并更新对应的版本 + * @param request 请求参数 + */ + void publishScriptWithSingleFileName(PublishScriptRequest request,String relativeFolder,String fileName); + + /** + * 发布文件目录下的所有脚本文件 并更新对应的版本 + * @param request 请求参数 + */ + void publishScriptWithDirectory(PublishScriptRequest request); + void checkScriptVersion(); +} diff --git a/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/webservice/ScriptCacheWebService.java b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/webservice/ScriptCacheWebService.java new file mode 100644 index 00000000..31229a73 --- /dev/null +++ b/runtime-scriptcache-api/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/api/webservice/ScriptCacheWebService.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.api.webservice; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheCheckVersionRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/23 + */ +@Path("/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface ScriptCacheWebService { + + /** + * 工程版本监测 + * + * @param request 请求参数 + * @return + */ + @POST + @Path("/checkversion") + ScriptCacheResponse checkVersion(@RequestBody ScriptCacheCheckVersionRequest request); + + @GET + @Path("/resttest") + ScriptCacheResponse resttest(); +} diff --git a/runtime-scriptcache-api/src/main/resources/log4j2.properties b/runtime-scriptcache-api/src/main/resources/log4j2.properties new file mode 100644 index 00000000..328db356 --- /dev/null +++ b/runtime-scriptcache-api/src/main/resources/log4j2.properties @@ -0,0 +1,7 @@ + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n +rootLogger.level = INFO +rootLogger.appenderRef.out.ref = out diff --git a/runtime-scriptcache/libs/bef-engine-core-0.1.12.jar b/runtime-scriptcache/libs/bef-engine-core-0.1.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..b9ed7c9fd5cb0b5745507634c10b4cb4c0138c21 GIT binary patch literal 80073 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
H2 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ℑF&cA?6hftiIW&C8~lsQnS2`ID)#=2ob zKWhg8V}rxnQPoJ7E3a`Upu~b%P8~+UnEwrhrb=D4Kc#~}ukr>?6y8QcR`kQB@9jJr=z0Ggho)NgNAHCPgT74weH-5G7WvNu zM@j_%>vq(fCYUlIW$YAP3~P6sqZ@9PMO9ARCJbm31JEYG{X&Z7>3Ip(baMkf-w=<+ z;16LPfg&_*=J4Q6Zw;{7F0cmBfItxlfpc_Wr{mI2&1iGc0tW*gECTb|QJ^TiLl|A8 zi-w+Dky66`1i*!^21wJi8RGEcCa}Zgw2IQRR)_rqZuZGSd+EKrVzB!=j4#nXi{1nnyFI*CN^N9*8bq~#t zL%u;t$$;L!-3l{J)X4l8v)}roSb6yDQhNISprC|;Aa)J&V`EuQiSqFNCUk@f(3l1>^s)UNmFj6%N;LFfh(4JMJ~eaw6M8P4p*ydn zb0_4Y&-XXrKfA3nPoYq%4BcRX_pL*M|3aRr@dEHo9Rjfx{FHz|QX|3);J5z)|Fm^+ literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/bef-engine-core.jar b/runtime-scriptcache/libs/bef-engine-core.jar new file mode 100644 index 0000000000000000000000000000000000000000..a7f93345dc699772b06b37114ce3dd13860750a0 GIT binary patch literal 86961 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
w(zWESD2i72Wbu{h=Gq@dWRpcs(B(p?rLIDTur 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 literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/cdp-sgf-api.jar b/runtime-scriptcache/libs/cdp-sgf-api.jar new file mode 100644 index 0000000000000000000000000000000000000000..b16f77f06f1c0d8c5db62d2e93a2049626369dd9 GIT binary patch literal 33265 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 DhRbbj literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/lcm-metadata-api.jar b/runtime-scriptcache/libs/lcm-metadata-api.jar new file mode 100644 index 0000000000000000000000000000000000000000..0581143447cfe4937e206c2938317ecff6c32d22 GIT binary patch literal 127802 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 On+qFQKfzB4gnt3r7wz}} literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/task-api-0.3.11.jar b/runtime-scriptcache/libs/task-api-0.3.11.jar new file mode 100644 index 0000000000000000000000000000000000000000..30572addaa44da10029bb506fc617b386f7f8b6a GIT binary patch literal 76098 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 O^d8KGEET|{j`Tm}z?x_P literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/web-jitengine-frontendproject-api.jar b/runtime-scriptcache/libs/web-jitengine-frontendproject-api.jar new file mode 100644 index 0000000000000000000000000000000000000000..1a1960bf13dd2ce499bed8ae6da7788839545c18 GIT binary patch literal 10469 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 tzwtTaaS1~aGQ#DIi_5ov$K_OwE||=20Q; + + + 4.0.0 + + web + com.inspur.edp + ${custom.version} + + jar + web-jitengine-runtimebuild-scriptcache + + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + + + com.inspur.edp + web-jitengine-common + + + org.junit.jupiter + junit-jupiter-api + + + io.iec.edp + caf-boot-starter-data-orm + + + io.iec.edp + caf-boot-starter-rest-server + + + com.inspur.edp + lcm-rtcustomization-cache-api + + + com.inspur.edp + web-jitengine-formmetadata + + + com.inspur.edp + bef-engine-core + 0.1.12 + system + ${project.basedir}/libs/bef-engine-core-0.1.12.jar + + + com.inspur.edp + bff-engine-core + 0.1.12 + system + ${project.basedir}/libs/bff-engine-core.jar + + + io.iec.edp + caf-database-object-api + 0.2.3 + + + io.iec.edp + caf-rpc-client + + + + + + diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/config/ScriptCacheConfiguration.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/config/ScriptCacheConfiguration.java new file mode 100644 index 00000000..18f22b58 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/config/ScriptCacheConfiguration.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.config; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormProjectCacheManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormScriptCacheContentManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormScriptCacheManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormProjectCacheRepository; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormScriptCacheContentRepository; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormScriptCacheRepository; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc.LocalServerVersionRpcService; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc.LocalServerVersionRpcServiceImpl; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.ScriptCacheVersionManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.service.ScriptCacheServiceImpl; +import com.inspur.edp.web.jitruntimebuild.scriptcache.webservice.ScriptCacheWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@Configuration +@EnableJpaRepositories("com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository") +@EntityScan({"com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity"}) +public class ScriptCacheConfiguration { + @Bean + public FormProjectCacheManager formProjectCacheManager(FormProjectCacheRepository repository) { + return new FormProjectCacheManager(repository); + } + + @Bean + public FormScriptCacheContentManager formScriptCacheContentManager(FormScriptCacheContentRepository repository) { + return new FormScriptCacheContentManager(repository); + } + + @Bean + public FormScriptCacheManager formScriptCacheManager(FormScriptCacheRepository repository) { + return new FormScriptCacheManager(repository); + } + + @Bean + public ScriptCacheVersionManager scriptCacheVersionManager() { + return new ScriptCacheVersionManager(); + } + + @Bean + public ScriptCacheServiceImpl scriptCacheServiceImp() { + return new ScriptCacheServiceImpl(); + } + + @Bean + public ScriptCacheWebServiceImpl scriptCacheWebServiceImp() { + return new ScriptCacheWebServiceImpl(); + } + + + @Bean + public RESTEndpoint ScriptCacheWebServiceEndpoint(ScriptCacheWebServiceImpl webservice){ + return new RESTEndpoint("/runtime/jit/v1.0/scriptcache", webservice); + } + + @Bean() + public LocalServerVersionRpcService localServerVersionRpcService() { + return new LocalServerVersionRpcServiceImpl(); + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/constants/ScriptCacheDBTableConstant.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/constants/ScriptCacheDBTableConstant.java new file mode 100644 index 00000000..9b34833a --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/constants/ScriptCacheDBTableConstant.java @@ -0,0 +1,49 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.constants; + +/** + * description:脚本缓存关联数据库表常量 + * + * @author Noah Guo + * @date 2020/09/23 + */ +public class ScriptCacheDBTableConstant { + + /** + * 工程缓存关联数据库表名 + */ + private String projectCacheTableName="formprojectcache"; + + /** + * 表单脚本关联数据库表名 + */ + private String formscriptcacheTableName="formscriptcache"; + + /** + * 表单脚本内容关联数据库表名 + */ + private String formscriptcachecontentTableName="formscriptcachecontent"; + + public String getProjectCacheTableName() { + return projectCacheTableName; + } + + public void setProjectCacheTableName(String projectCacheTableName) { + this.projectCacheTableName = projectCacheTableName; + } + + public String getFormscriptcacheTableName() { + return formscriptcacheTableName; + } + + public void setFormscriptcacheTableName(String formscriptcacheTableName) { + this.formscriptcacheTableName = formscriptcacheTableName; + } + + public String getFormscriptcachecontentTableName() { + return formscriptcachecontentTableName; + } + + public void setFormscriptcachecontentTableName(String formscriptcachecontentTableName) { + this.formscriptcachecontentTableName = formscriptcachecontentTableName; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormProjectCacheConverter.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormProjectCacheConverter.java new file mode 100644 index 00000000..a70ea897 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormProjectCacheConverter.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter; + +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormProjectCacheEntity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/29 + */ +public class FormProjectCacheConverter { + /** + * 实体与domain的转换 将projectCache转换成对应的projectCacheEntity domain实体 + * + * @param projectCache + * @return + */ + public static FormProjectCacheEntity convert(FormProjectCache projectCache) { + FormProjectCacheEntity projectCacheEntity = new FormProjectCacheEntity(); + if (projectCache == null) { + return projectCacheEntity; + } + projectCacheEntity.setId(projectCache.getId()); + projectCacheEntity.setCreateDate(projectCache.getCreateDate()); + projectCacheEntity.setCreator(projectCache.getCreator()); + projectCacheEntity.setLastModifier(projectCache.getLastModifier()); + if (projectCache.getLastModifyTime() == null) { + projectCacheEntity.setLastModifyTime(CommonUtility.getCurrentDate()); + } else { + projectCacheEntity.setLastModifyTime(projectCache.getLastModifyTime()); + } + + projectCacheEntity.setProjectCode(projectCache.getProjectCode()); + projectCacheEntity.setProjectName(projectCache.getProjectName()); + projectCacheEntity.setProjectRelativePath(projectCache.getProjectRelativePath()); + projectCacheEntity.setVersion(projectCache.getVersion()); + return projectCacheEntity; + + } + + /** + * 将domain实体转换成对应的entity + * + * @param projectCacheEntity + * @return + */ + public static FormProjectCache convertReverse(FormProjectCacheEntity projectCacheEntity) { + + FormProjectCache projectCache = new FormProjectCache(); + if (projectCacheEntity == null) { + return projectCache; + } + projectCache.setId(projectCacheEntity.getId()); + projectCache.setCreateDate(projectCacheEntity.getCreateDate()); + projectCache.setCreator(projectCacheEntity.getCreator()); + projectCache.setLastModifier(projectCacheEntity.getLastModifier()); + projectCache.setLastModifyTime(CommonUtility.getCurrentDate()); + projectCache.setProjectCode(projectCacheEntity.getProjectCode()); + projectCache.setProjectName(projectCacheEntity.getProjectName()); + projectCache.setProjectRelativePath(projectCacheEntity.getProjectRelativePath()); + projectCache.setVersion(projectCacheEntity.getVersion()); + return projectCache; + } + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheContentConverter.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheContentConverter.java new file mode 100644 index 00000000..ea3951b4 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheContentConverter.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter; + +import com.inspur.edp.web.common.encrypt.EncryptUtility; +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheContentEntity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/29 + */ +public class FormScriptCacheContentConverter { + + /** + * @param scriptCacheContent + * @return + */ + public static FormScriptCacheContentEntity convert(FormScriptCacheContent scriptCacheContent) { + + FormScriptCacheContentEntity cacheContentEntity = new FormScriptCacheContentEntity(); + if (scriptCacheContent == null) { + return cacheContentEntity; + } + String encodeContent = scriptCacheContent.getContent(); + // 如果内容进行了base64编码 那么进行base64解码之后返回 + // 保存的脚本内容永远进行base64编码 + encodeContent = EncryptUtility.getInstance().Base64Encode(encodeContent); + + cacheContentEntity.setContent(encodeContent); + cacheContentEntity.setCreateDate(scriptCacheContent.getCreateDate()); + cacheContentEntity.setCreator(scriptCacheContent.getCreator()); + cacheContentEntity.setId(scriptCacheContent.getId()); + cacheContentEntity.setLastModifier(scriptCacheContent.getLastModifier()); + if (scriptCacheContent.getLastModifyTime() == null) { + cacheContentEntity.setLastModifyTime(CommonUtility.getCurrentDate()); + } else { + cacheContentEntity.setLastModifyTime(scriptCacheContent.getLastModifyTime()); + } + + return cacheContentEntity; + } + + public static FormScriptCacheContent convertReverse(FormScriptCacheContentEntity contentEntity) { + + FormScriptCacheContent cacheContent = new FormScriptCacheContent(); + if (contentEntity == null) { + return cacheContent; + } + + String decodeContent = contentEntity.getContent(); + // 获取到的脚本永远进行解码操作 + if(EncryptUtility.getInstance().isBase64(decodeContent)){ + decodeContent=EncryptUtility.getInstance().Base64Decode(decodeContent); + } + cacheContent.setContent(decodeContent); + cacheContent.setId(contentEntity.getId()); + cacheContent.setCreateDate(contentEntity.getCreateDate()); + cacheContent.setCreator(contentEntity.getCreator()); + cacheContent.setLastModifier(contentEntity.getLastModifier()); + cacheContent.setLastModifyTime(contentEntity.getLastModifyTime()); + return cacheContent; + } + + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheConverter.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheConverter.java new file mode 100644 index 00000000..5ddb894e --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/converter/FormScriptCacheConverter.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter; + +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheEntity; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/29 + */ +public class FormScriptCacheConverter { + public static FormScriptCacheEntity convert(FormScriptCache scriptCache) { + + FormScriptCacheEntity cacheEntity = new FormScriptCacheEntity(); + if (scriptCache == null) { + return cacheEntity; + } + cacheEntity.setCreateDate(scriptCache.getCreateDate()); + cacheEntity.setCreator(scriptCache.getCreator()); + cacheEntity.setFormMetadataId(scriptCache.getFormMetadataId()); + cacheEntity.setId(scriptCache.getId()); + cacheEntity.setLastModifier(scriptCache.getLastModifier()); + if (scriptCache.getLastModifyTime() == null) { + cacheEntity.setLastModifyTime(CommonUtility.getCurrentDate()); + } else { + cacheEntity.setLastModifyTime(scriptCache.getLastModifyTime()); + } + + cacheEntity.setProjectVersionId(scriptCache.getProjectVersionId()); + cacheEntity.setScriptCode(scriptCache.getScriptCode()); + cacheEntity.setScriptContentId(scriptCache.getScriptContentId()); + cacheEntity.setScriptName(scriptCache.getScriptName()); + cacheEntity.setScriptRelativePath(scriptCache.getScriptRelativePath()); + cacheEntity.setVersion(scriptCache.getVersion()); + return cacheEntity; + } + + public static FormScriptCache convertReverse(FormScriptCacheEntity scriptCacheEntity) { + + FormScriptCache scriptCache = new FormScriptCache(); + if (scriptCacheEntity == null) { + return scriptCache; + } + scriptCache.setScriptContent(scriptCacheEntity.getScriptContentId()); + scriptCache.setScriptContentId(scriptCacheEntity.getScriptContentId()); + scriptCache.setScriptRelativePath(scriptCacheEntity.getScriptRelativePath()); + scriptCache.setScriptCode(scriptCacheEntity.getScriptCode()); + scriptCache.setScriptName(scriptCacheEntity.getScriptName()); + scriptCache.setVersion(scriptCacheEntity.getVersion()); + scriptCache.setProjectVersionId(scriptCacheEntity.getProjectVersionId()); + scriptCache.setId(scriptCacheEntity.getId()); + scriptCache.setFormMetadataId(scriptCacheEntity.getFormMetadataId()); + scriptCache.setCreateDate(scriptCacheEntity.getCreateDate()); + scriptCache.setCreator(scriptCacheEntity.getCreator()); + scriptCache.setLastModifier(scriptCacheEntity.getLastModifier()); + scriptCache.setLastModifyTime(scriptCacheEntity.getLastModifyTime()); + return scriptCache; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormProjectCacheEntity.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormProjectCacheEntity.java new file mode 100644 index 00000000..afabf2ed --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormProjectCacheEntity.java @@ -0,0 +1,134 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Data +@Entity +@Table(name="formprojectcache") +public class FormProjectCacheEntity { + /** + * 主键字段 + */ + @Id + private String id; + + /** + * 工程名称 + */ + private String projectName; + + /** + * 工程编码 + */ + private String projectCode; + + /** + * 工程相对路径 + */ + private String projectRelativePath; + + /** + * 工程对应版本 + */ + private String version; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectCode() { + return projectCode; + } + + public void setProjectCode(String projectCode) { + this.projectCode = projectCode; + } + + public String getProjectRelativePath() { + return projectRelativePath; + } + + public void setProjectRelativePath(String projectRelativePath) { + this.projectRelativePath = projectRelativePath; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getLastModifier() { + return lastModifier; + } + + public void setLastModifier(String lastModifier) { + this.lastModifier = lastModifier; + } + + public Date getLastModifyTime() { + return lastModifyTime; + } + + public void setLastModifyTime(Date lastModifyTime) { + this.lastModifyTime = lastModifyTime; + } + + /** + * 创建时间 + */ + private Date createDate; + + /** + * 创建人 + */ + private String creator; + + /** + * 最后修改人 + */ + private String lastModifier; + + /** + * 最后修改时间 + */ + private Date lastModifyTime; + + +} + diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheContentEntity.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheContentEntity.java new file mode 100644 index 00000000..71c4e3e8 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheContentEntity.java @@ -0,0 +1,83 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Data +@Entity +@Table(name = "formscriptcachecontent") +public class FormScriptCacheContentEntity { + /** + * 主键id + */ + @Id + private String id; + + /** + * 文件内容 + */ + private String content; + + /** + * 创建时间 + */ + private Date createDate; + + private String creator; + + private String lastModifier; + + private Date lastModifyTime; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getLastModifier() { + return lastModifier; + } + + public void setLastModifier(String lastModifier) { + this.lastModifier = lastModifier; + } + + public Date getLastModifyTime() { + return lastModifyTime; + } + + public void setLastModifyTime(Date lastModifyTime) { + this.lastModifyTime = lastModifyTime; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheEntity.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheEntity.java new file mode 100644 index 00000000..162d17db --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/entity/FormScriptCacheEntity.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; + +@Data +@Entity +@Table(name="formscriptcache") +public class FormScriptCacheEntity { + + @Id + private String id; + + /** + * 表单元数据id + */ + private String formMetadataId; + + /** + * 对应工程缓存id + */ + private String projectVersionId; + + /** + * 脚本文件版本 + */ + private String version; + + /** + * 脚本文件名称 + */ + private String scriptName; + + /** + * 脚本文件编码 + */ + private String scriptCode; + + /** + * 脚本文件相对路径 + */ + private String scriptRelativePath; + + /** + * 脚本文件内容关联id + */ + private String scriptContentId; + + private Date createDate; + + private String creator; + + private Date lastModifyTime; + + private String lastModifier; + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormProjectCacheManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormProjectCacheManager.java new file mode 100644 index 00000000..786c4b2d --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormProjectCacheManager.java @@ -0,0 +1,81 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormProjectCacheConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormProjectCacheEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormProjectCacheRepository; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/24 + */ +public class FormProjectCacheManager { + private final FormProjectCacheRepository repository; + + public FormProjectCacheManager(FormProjectCacheRepository repository) { + + this.repository = repository; + } + + /** + * 保存工程交换缓存 + * + * @param formProjectCacheEntity + */ + public void save(FormProjectCacheEntity formProjectCacheEntity) { + + this.repository.save(formProjectCacheEntity); + } + + /** + * 更新工程交换缓存 + * + * @param formProjectCacheEntity + */ + public void update(FormProjectCacheEntity formProjectCacheEntity) { + + this.repository.updateFormProjectCacheVersion(formProjectCacheEntity.getId(), formProjectCacheEntity.getVersion(), formProjectCacheEntity.getLastModifier(), formProjectCacheEntity.getLastModifyTime()); + } + + /** + * 根据工程名称及工程部署相对路径获取对应得工程缓存信息 + * + * @param projectName + * @param strProjectRelativePath + * @return + */ + public FormProjectCache getByProjectNameAndProjectRelativePath(String projectName, String strProjectRelativePath) { + List formProjectCacheEntities = this.repository.getByProjectNameAndProjectRelativePath(projectName); + if (formProjectCacheEntities == null || formProjectCacheEntities.size() == 0) { + return null; + } + + AtomicReference findProjectCacheEntity = new AtomicReference<>(); + formProjectCacheEntities.forEach((item) -> { + if (item.getProjectRelativePath().equals(strProjectRelativePath)) { + findProjectCacheEntity.set(item); + } + }); + if (findProjectCacheEntity != null && findProjectCacheEntity.get() != null) { + return FormProjectCacheConverter.convertReverse(findProjectCacheEntity.get()); + } + return null; + } + + /** + * 根据id获取projectVersion + * + * @param formProjectId + * @return + */ + public FormProjectCache getById(String formProjectId) { + Optional formProjectCacheEntity = this.repository.findFormProjectCacheById(formProjectId); + return formProjectCacheEntity.map(FormProjectCacheConverter::convertReverse).orElse(null); + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheContentManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheContentManager.java new file mode 100644 index 00000000..d98da83d --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheContentManager.java @@ -0,0 +1,55 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormScriptCacheContentConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheContentEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormScriptCacheContentRepository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/24 + */ +public class FormScriptCacheContentManager { + private final FormScriptCacheContentRepository repository; + + public FormScriptCacheContentManager(FormScriptCacheContentRepository repository) { + this.repository = repository; + } + + /** + * 保存表单脚本文件缓存内容 + * + * @param contentEntity + */ + public void save(FormScriptCacheContentEntity contentEntity) { + this.repository.save(contentEntity); + } + + /** + * 保存表单脚本文件缓存内容 + * + * @param contentEntity + */ + @Transactional + public void update(FormScriptCacheContentEntity contentEntity) { + this.repository.updateFormScriptCacheContentVersion(contentEntity.getId(), contentEntity.getContent(), contentEntity.getLastModifier(), contentEntity.getLastModifyTime()); + } + + /** + * 根据contentId获取对应的内容 + * + * @param scriptContentId + * @return + */ + public FormScriptCacheContent findById(String scriptContentId) { + Optional scriptCacheContentEntity = this.repository.findById(scriptContentId); + return scriptCacheContentEntity.map(FormScriptCacheContentConverter::convertReverse).orElse(null); + + } + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheManager.java new file mode 100644 index 00000000..87658f62 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/manager/FormScriptCacheManager.java @@ -0,0 +1,123 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormScriptCacheConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository.FormScriptCacheRepository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/24 + */ +public class FormScriptCacheManager { + private final FormScriptCacheRepository repository; + + public FormScriptCacheManager(FormScriptCacheRepository repository) { + this.repository = repository; + } + + /** + * 保存表单脚本缓存 + * + * @param formScriptCacheEntity + */ + public void save(FormScriptCacheEntity formScriptCacheEntity) { + this.repository.save(formScriptCacheEntity); + } + + /** + * 保存表单脚本缓存 + * + * @param formScriptCacheEntity + */ + @Transactional + public void update(FormScriptCacheEntity formScriptCacheEntity) { + this.repository.updateFormScriptCacheVersion(formScriptCacheEntity.getId(), formScriptCacheEntity.getVersion(), formScriptCacheEntity.getLastModifier(), formScriptCacheEntity.getFormMetadataId(), formScriptCacheEntity.getScriptCode(), formScriptCacheEntity.getLastModifyTime()); + } + + + /** + * 根据多个条件参数获取对应的脚本文件缓存信息 + * + * @param projectVersionId + * @param scriptName + * @param scriptRelativePath + * @return + */ + public FormScriptCache getFormScriptCacheByMulCondition(String projectVersionId, String scriptCode, String scriptName, String scriptRelativePath) { + + scriptRelativePath = FileUtility.getPlatformIndependentPath(scriptRelativePath); + + Optional formScriptCacheEntity; + if (StringUtility.isNullOrEmpty(scriptRelativePath)) { + if (StringUtility.isNullOrEmpty(scriptCode)) { + formScriptCacheEntity = this.repository.getFormScriptCacheByMulCondition(projectVersionId, scriptName); + } else { + formScriptCacheEntity = this.repository.getFormScriptCacheByMulConditionAndScriptCode(projectVersionId, scriptName, scriptCode); + } + + } else { + if (StringUtility.isNullOrEmpty(scriptCode)) { + formScriptCacheEntity = this.repository.getFormScriptCacheByMulCondition(projectVersionId, scriptName, scriptRelativePath); + } else { + formScriptCacheEntity = this.repository.getFormScriptCacheByMulConditionAndScriptCode(projectVersionId, scriptName, scriptRelativePath, scriptCode); + } + } + + if (formScriptCacheEntity == null || !formScriptCacheEntity.isPresent()) { + return null; + } + + return FormScriptCacheConverter.convertReverse(formScriptCacheEntity.get()); + } + + /** + * 根据表单元数据id获取对应的脚本缓存列表 + * + * @param formMetadataId + * @return + */ + public List getFormScriptCacheByMetadataId(String formMetadataId) { + List formScriptCacheEntityList = this.repository.getFormScriptCacheByMetadataId(formMetadataId); + if (formScriptCacheEntityList == null) { + return null; + } + List formScriptCacheList = new ArrayList<>(); + // 创建并行流 进行数据转换 + formScriptCacheEntityList.parallelStream().forEach((cacheEntityItem) -> { + FormScriptCache formScriptCache = FormScriptCacheConverter.convertReverse(cacheEntityItem); + if (formScriptCache != null) { + formScriptCacheList.add(formScriptCache); + } + }); + return formScriptCacheList; + } + + /** + * 根据工程脚本缓存获取对应的脚本缓存列表 + * + * @param projectVersionId + * @return + */ + public List getFormScriptCacheByProjectVersionId(String projectVersionId) { + List formScriptCacheEntityList = this.repository.getFormScriptCacheByProjectVersionId(projectVersionId); + if (formScriptCacheEntityList == null) { + return null; + } + List formScriptCacheList = new ArrayList<>(); + formScriptCacheEntityList.forEach((cacheEntityItem) -> { + FormScriptCache formScriptCache = FormScriptCacheConverter.convertReverse(cacheEntityItem); + formScriptCacheList.add(formScriptCache); + }); + return formScriptCacheList; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepository.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepository.java new file mode 100644 index 00000000..baf8c286 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepository.java @@ -0,0 +1,65 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormProjectCacheEntity; +import io.iec.edp.caf.data.orm.DataRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/24 + */ +public interface FormProjectCacheRepository extends DataRepository { + + @Query(value = "SELECT a FROM FormProjectCacheEntity a WHERE id= :id") + Optional findFormProjectCacheById(@Param("id") String id); + + + /** + * 保存缓存实体 + * + * @param entity + * @return + */ + @Override + FormProjectCacheEntity save(FormProjectCacheEntity entity); + + + /** + * 更新工程版本缓存 + * + * @param id + * @param version + * @param lastModifier + * @param lastModifyTime + */ + @Modifying + @Query(value = "UPDATE FormProjectCacheEntity SET version = :version , lastmodifier= :lastModifier, lastmodifytime=:lastModifyTime WHERE id=:id") + void updateFormProjectCacheVersion(@Param("id") String id,@Param("version") String version,@Param("lastModifier") String lastModifier,@Param("lastModifyTime") Date lastModifyTime); + + + /** + * 根据id删除对应的数据 + * + * @param id + */ + @Modifying + @Query(value = "DELETE FROM FormProjectCacheEntity WHERE id = :id") + void deleteFormProjectCacheById(@Param("id") String id); + + /** + * 根据工程名称及工程相对路径获取对应得工程缓存信息 + * @param projectName + * @return + */ + @Query(value = "SELECT a FROM FormProjectCacheEntity a WHERE projectname= :projectName ") + List getByProjectNameAndProjectRelativePath(@Param("projectName") String projectName); + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheContentRepository.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheContentRepository.java new file mode 100644 index 00000000..cc8072c6 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheContentRepository.java @@ -0,0 +1,54 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheContentEntity; +import io.iec.edp.caf.data.orm.DataRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.Optional; + +/** + * description: + * + * @author Noah Guo + * @date 2020/10/01 + */ +public interface FormScriptCacheContentRepository extends DataRepository { + + @Query(value = "SELECT a FROM FormScriptCacheContentEntity a WHERE id= :id") + Optional findFormScriptCacheContentById(@Param("id") String id); + + + /** + * 保存脚本内容缓存 + * + * @param entity + * @return + */ + @Override + FormScriptCacheContentEntity save(FormScriptCacheContentEntity entity); + + + /** + * 根据id删除对应的数据 + * + * @param id + */ + @Modifying + @Query(value = "DELETE FROM FormScriptCacheContentEntity WHERE id = :id") + void deleteFormScriptCacheContentById(@Param("id") String id); + + /** + * 更新工程版本缓存 + * + * @param id + * @param lastModifier + * @param lastModifyTime + */ + @Modifying + @Query(value = "UPDATE FormScriptCacheContentEntity SET content=:content, lastmodifier= :lastModifier, lastmodifytime=:lastModifyTime where id= :id") + void updateFormScriptCacheContentVersion(@Param("id") String id, @Param("content") String content,@Param("lastModifier") String lastModifier, @Param("lastModifyTime") Date lastModifyTime); + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheRepository.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheRepository.java new file mode 100644 index 00000000..26d07c56 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormScriptCacheRepository.java @@ -0,0 +1,112 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheEntity; +import io.iec.edp.caf.data.orm.DataRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +/** + * description: + * + * @author Noah Guo + * @date 2020/10/01 + */ +public interface FormScriptCacheRepository extends DataRepository { + + /** + * 保存脚本内容缓存 + * + * @param entity + * @return + */ + @Override + FormScriptCacheEntity save(FormScriptCacheEntity entity); + + + /** + * 根据id删除对应的数据 + * + * @param id + */ + @Modifying + @Query(value = "DELETE FROM FormScriptCacheEntity WHERE id = :id") + void deleteFormScriptCacheById(@Param("id") String id); + + /** + * 更新工程版本缓存 + * + * @param id + * @param version + * @param lastModifier + * @param lastModifyTime + */ + @Modifying + @Query(value = "UPDATE FormScriptCacheEntity SET version = :version , lastModifier= :lastModifier, lastModifyTime=:lastModifyTime,formMetadataId=:formMetadataId,scriptCode=:scriptCode WHERE id=:id") + void updateFormScriptCacheVersion(@Param("id") String id, @Param("version") String version, @Param("lastModifier") String lastModifier, @Param("formMetadataId") String formMetadataId, @Param("scriptCode") String scriptCode, @Param("lastModifyTime") Date lastModifyTime); + + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE id= :id") + Optional findFormScriptCacheById(@Param("id") String id); + + /** + * 根据元数据id、工程versionid、脚本名称、脚本相对路径 + * + * @param projectVersionId + * @param scriptName + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE projectversionid= :projectVersionId and scriptname= :scriptName ") + Optional getFormScriptCacheByMulCondition(@Param("projectVersionId") String projectVersionId, @Param("scriptName") String scriptName); + + /** + * 根据元数据id、工程versionid、脚本名称、脚本相对路径 + * + * @param projectVersionId + * @param scriptName + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE projectversionid= :projectVersionId and scriptname= :scriptName and scriptcode= :scriptcode") + Optional getFormScriptCacheByMulConditionAndScriptCode(@Param("projectVersionId") String projectVersionId, @Param("scriptName") String scriptName,@Param("scriptcode")String scriptCode); + + /** + * 根据元数据id、工程versionid、脚本名称、脚本相对路径 + * + * @param projectVersionId + * @param scriptName + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE projectversionid= :projectVersionId and scriptname= :scriptName and scriptrelativepath= :scriptrelativepath") + Optional getFormScriptCacheByMulCondition(@Param("projectVersionId") String projectVersionId, @Param("scriptName") String scriptName,@Param("scriptrelativepath") String scriptRelativePath); + + /** + * 根据元数据id、工程versionid、脚本名称、脚本相对路径 + * + * @param projectVersionId + * @param scriptName + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE projectversionid= :projectVersionId and scriptname= :scriptName and scriptrelativepath= :scriptrelativepath and scriptcode= :scriptcode") + Optional getFormScriptCacheByMulConditionAndScriptCode(@Param("projectVersionId") String projectVersionId, @Param("scriptName") String scriptName,@Param("scriptrelativepath") String scriptRelativePath,@Param("scriptcode") String scriptCode); + + /** + * 根据表单元数据id获取对应的脚本缓存列表 + * + * @param formMetadataId + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE formmetadataid= :formmetadataid ") + List getFormScriptCacheByMetadataId(@Param("formmetadataid") String formMetadataId); + + /** + * 根据工程脚本缓存d获取对应的脚本缓存列表 + * + * @param projectVersionId + * @return + */ + @Query(value = "SELECT a FROM FormScriptCacheEntity a WHERE projectversionid= :projectVersionId ") + List getFormScriptCacheByProjectVersionId(@Param("projectVersionId") String projectVersionId); +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerFileOperation.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerFileOperation.java new file mode 100644 index 00000000..ea1ef6a2 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerFileOperation.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2020/10/03 + */ +public class LocalServerFileOperation { + + /** + * 保存文件内容至指定的文件位置 + * @param scriptFileName + * @param strRelativePath + * @param fileContent + */ + public static void saveFile(String scriptFileName, String strRelativePath, String fileContent) { + String localServerPath = LocalServerPathGenerator.getNewInstance(false).getLocalServerWebPath(); + String scriptFilePath = FileUtility.combine(localServerPath, strRelativePath); + FileUtility.writeFile(scriptFilePath, scriptFileName, fileContent); + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerPathGenerator.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerPathGenerator.java new file mode 100644 index 00000000..5e4cf663 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerPathGenerator.java @@ -0,0 +1,100 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class LocalServerPathGenerator { + + private String _localServerPath; + // 是否运行在元数据部署工具 + private boolean isUpgradeTool = false; + + + private LocalServerPathGenerator() { + } + + /** + * 通过具体实例方式进行方法读取 + * + * @param isUpgradeTool + * @return + */ + public static LocalServerPathGenerator getNewInstance(boolean isUpgradeTool) { + + LocalServerPathGenerator _instance = new LocalServerPathGenerator(); + _instance.isUpgradeTool = isUpgradeTool; + return _instance; + } + + /** + * 获取当前服务器路径 + * + * @return + */ + public String getLocalServerPath() { + // 重复调用得参数 增加缓存定义 避免每次都需要重新获取 + // 获取该参数值得成本相对较高 + if (StringUtility.isNullOrEmpty(_localServerPath)) { + _localServerPath = FileUtility.getPlatformIndependentPath(FileUtility.getCurrentWorkPath(isUpgradeTool)); + } + + return _localServerPath; + } + + /** + * 当前服务器缓存脚本文件路径 不包含文件名称 + * + * @return 缓存文件路径 + */ + + public String getLocalServerFilePath() { + String currentServerPath = getLocalServerPath(); + String localServerFilePath = FileUtility.combine(currentServerPath, "web", "runtime", "web"); + localServerFilePath = FileUtility.getPlatformIndependentPath(localServerFilePath); + return localServerFilePath; + } + + + /** + * 当前服务器缓存脚本文件路径 不包含文件名称 + * + * @return 缓存文件路径 + */ + + public String getLocalServerWebPath() { + String currentServerPath = getLocalServerPath(); + String localServerFilePath = FileUtility.combine(currentServerPath, "web"); + localServerFilePath = FileUtility.getPlatformIndependentPath(localServerFilePath); + return localServerFilePath; + } + + /** + * 当前服务器缓存脚本文件路径 包含文件名称 + * + * @return 缓存文件路径 + */ + + public String getLocalServerFilePathAndName() { + String currentServerPath = getLocalServerPath(); + String versionFileName = getLocalServerFileName(); + String localServerFilePath = FileUtility.combine(currentServerPath, "web", "runtime", "web", versionFileName); + localServerFilePath = FileUtility.getPlatformIndependentPath(localServerFilePath); + return localServerFilePath; + } + + + /** + * 获取放置于服务器环境目录下得脚本缓存文件名称 + * + * @return + */ + public String getLocalServerFileName() { + return "scriptcache.json"; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerProjectVersion.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerProjectVersion.java new file mode 100644 index 00000000..3b39d3dc --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerProjectVersion.java @@ -0,0 +1,73 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class LocalServerProjectVersion { + private LocalServerProjectVersion() { + this.scriptVersionList = new ArrayList<>(); + } + + public static LocalServerProjectVersion getInstance() { + return new LocalServerProjectVersion(); + } + + + /** + * 工程名称 + */ + private String projectName; + + /** + * 工程部署相对路径 + */ + private String projectRelativePath; + + /** + * 当前server 当前工程对应版本 + */ + private String version; + + /** + * 工程关联的脚本文件缓存信息列表 + */ + private List scriptVersionList; + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getProjectRelativePath() { + return projectRelativePath; + } + + public void setProjectRelativePath(String projectRelativePath) { + this.projectRelativePath = projectRelativePath; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List getScriptVersionList() { + return scriptVersionList; + } + + public void setScriptVersionList(List scriptVersionList) { + this.scriptVersionList = scriptVersionList; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerScriptVersion.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerScriptVersion.java new file mode 100644 index 00000000..0794240c --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerScriptVersion.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +/** + * description: + * + * @author Noah Guo + * @date 2020/10/03 + */ +public class LocalServerScriptVersion { + private String formMetadataId; + private String scriptName; + private String scriptPath; + private String version; + + + public String getFormMetadataId() { + return formMetadataId; + } + + public void setFormMetadataId(String formMetadataId) { + this.formMetadataId = formMetadataId; + } + + public String getScriptName() { + return scriptName; + } + + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + + public String getScriptPath() { + return scriptPath; + } + + public void setScriptPath(String scriptPath) { + this.scriptPath = scriptPath; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileContent.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileContent.java new file mode 100644 index 00000000..b7d37d73 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileContent.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class LocalServerVersionFileContent { + /** + * 工程版本内容列表 + */ + private List versionList; + + /** + * 服务器server 路径 + */ + private String serverPath; + + public List getVersionList() { + if (this.versionList == null) { + this.versionList = new ArrayList<>(); + } + return versionList; + } + + public void setVersionList(List versionList) { + this.versionList = versionList; + } + + public String getServerPath() { + return serverPath; + } + + public void setServerPath(String serverPath) { + + this.serverPath = serverPath; + } + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileOperation.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileOperation.java new file mode 100644 index 00000000..c17bb53e --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionFileOperation.java @@ -0,0 +1,163 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.EqualsUtility; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * description: server缓存脚本文件操作 + * + * @author Noah Guo + * @date 2020/09/25 + */ +class LocalServerVersionFileOperation { + + /** + * 定义私有构造函数 + */ + private LocalServerVersionFileOperation() { + // 执行本地文件缓存初始化 + this.getLocalServerVersionList(); + } + + private final LocalServerPathGenerator localServerPathGeneratorInstance = LocalServerPathGenerator.getNewInstance(false); + + /** + * 定义本地脚本缓存 + */ + private static LocalServerVersionFileContent localServerVersionContent = new LocalServerVersionFileContent(); + + private static LocalServerVersionFileOperation instance; + + /** + * 获取文件操作实例 保持该实例唯一。避免由于多个实例,对同一个文件进行不同操作,导致文件被锁的问题 + * * @return + */ + public static LocalServerVersionFileOperation getSingleInstance() { + if (null == instance) { + synchronized (LocalServerVersionFileOperation.class) { + instance = new LocalServerVersionFileOperation(); + } + } + return instance; + } + + /** + * 初始化本地脚本缓存文件列表 + */ + private void getLocalServerVersionList() { + + String strLocalServerPath = localServerPathGeneratorInstance.getLocalServerPath(); + String localServerVersionFilePathAndName = localServerPathGeneratorInstance.getLocalServerFilePathAndName(); + + // 如果文件不存在 那么创建一个默认的空文件 + if (!FileUtility.exists(localServerVersionFilePathAndName)) { + this.reInitServerVersionContent(strLocalServerPath); + return; + } + // 如果文件存在 + String versionFileContent = FileUtility.readAsString(localServerVersionFilePathAndName); + localServerVersionContent = SerializeUtility.getInstance().deserialize(versionFileContent, LocalServerVersionFileContent.class); + // 如果不是当前的服务器 那么删除该文件 重新创建文件 + if (!EqualsUtility.getInstance().equalsWithOS(localServerVersionContent.getServerPath(), strLocalServerPath)) { + this.reInitServerVersionContent(strLocalServerPath); + } + } + + /** + * 重新初始化服务器脚本版本 + * + * @param strLocalServerPath + */ + private void reInitServerVersionContent(String strLocalServerPath) { + localServerVersionContent.setVersionList(new ArrayList<>()); + // 设置当前的服务器路径 + localServerVersionContent.setServerPath(strLocalServerPath); + // 保存当前缓存文件 + saveFile(); + } + + + /** + * 保存缓存工程脚本至本地文件 + * + * @param version + */ + public void saveProjectVersion(LocalServerProjectVersion version) { + if (version == null) { + return; + } + + LocalServerProjectVersion currentLocalProjectVersion = findProjectVersionByProjectNameAndProjectRelativePath(version.getProjectName(), version.getProjectRelativePath()); + if (currentLocalProjectVersion == null) { + localServerVersionContent.getVersionList().add(version); + } else { + currentLocalProjectVersion.setVersion(version.getVersion()); + } + saveFile(); + } + + + /** + * 根据工程名称及工程相对路径获取本地文件缓存信息 + * + * @param projectName + * @param projectRelativePath + * @return + */ + public LocalServerProjectVersion findProjectVersionByProjectNameAndProjectRelativePath(String projectName, String projectRelativePath) { + List versionList = localServerVersionContent.getVersionList().stream().filter((item) -> EqualsUtility.getInstance().equalsWithOS(item.getProjectName(), projectName) + && EqualsUtility.getInstance().equalsWithOS(item.getProjectRelativePath(), projectRelativePath)).collect(Collectors.toList()); + if (versionList != null && versionList.size() > 0) { + return versionList.get(0); + } + return null; + } + + /** + * 根据工程名称和工程部署相对路径获取对应版本 + * + * @param projectName 工程名称 + * @param strProjectRelativePath 工程相对路径 + * @return + */ + public String getVersion(String projectName, String strProjectRelativePath) { + LocalServerProjectVersion projectVersion = getProjectVersionInfo(projectName, strProjectRelativePath); + if (projectVersion != null) { + return projectVersion.getVersion(); + } + + return null; + } + + /** + * 根据工程名称及工程相对路径获取工程缓存信息 + * + * @param projectName + * @param strProjectPath + * @return + */ + public LocalServerProjectVersion getProjectVersionInfo(String projectName, String strProjectPath) { + Optional localServerProjectVersionOptional = localServerVersionContent.getVersionList().stream() + .filter((serverVersion) -> EqualsUtility.getInstance().equalsWithOS(serverVersion.getProjectName(), projectName) && + EqualsUtility.getInstance().equalsWithOS(serverVersion.getProjectRelativePath(), strProjectPath)).findFirst(); + return localServerProjectVersionOptional.orElse(null); + } + + /** + * 保存本地服务器缓存文件 + */ + public void saveFile() { + synchronized (LocalServerVersionFileOperation.class) { + String localServerVersionFilePath = localServerPathGeneratorInstance.getLocalServerFilePath(); + String localServerVersionFileName = localServerPathGeneratorInstance.getLocalServerFileName(); + String serializedVersionList = SerializeUtility.getInstance().serialize(localServerVersionContent); + FileUtility.writeFile(localServerVersionFilePath, localServerVersionFileName, serializedVersionList); + } + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionManager.java new file mode 100644 index 00000000..ab25dc99 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/LocalServerVersionManager.java @@ -0,0 +1,320 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.bef.engine.core.BefEngineInfoCache; +import com.inspur.edp.bff.engine.core.cache.BffEngineCacheService; +import com.inspur.edp.das.commonmodel.IGspCommonObject; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.EqualsUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc.LocalServerVersionRpcService; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.CustomizationCacheServiceInstanceManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.ScriptCacheVersionManager; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.databaseobject.api.service.IDatabaseObjectRtService; +import io.iec.edp.caf.rpc.client.RpcClassHolder; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * description:服务器脚本版本manager + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class LocalServerVersionManager { + private static LocalServerVersionManager instance; + + + private LocalServerVersionRpcService localServerVersionRpcService; + + private final ScriptCacheVersionManager scriptCacheVersionManagerInstance = new ScriptCacheVersionManager(); + + private LocalServerVersionManager() { + if (localServerVersionRpcService == null) { + RpcClassHolder rpcClassHolder = SpringBeanUtils.getBean(RpcClassHolder.class); + this.localServerVersionRpcService = rpcClassHolder.getRpcClass("bcc", LocalServerVersionRpcService.class); + } + } + + /** + * 获取唯一的实力 + * + * @return + */ + public static LocalServerVersionManager getSingleInstance() { + if (instance == null) { + synchronized (LocalServerVersionManager.class) { + instance = new LocalServerVersionManager(); + } + } + return instance; + } + + /** + * 获取工程对应的版本 + * + * @param projectName 工程名称 + * @param strProjectRelativePath 工程相对路径 + * @return + */ + public String getProjectVersion(String projectName, String strProjectRelativePath) { + // 获取当前工程对应的版本 + String strCurrentVersion = LocalServerVersionFileOperation.getSingleInstance().getVersion(projectName, strProjectRelativePath); + return strCurrentVersion; + } + + /** + * 本地脚本文件与数据库脚本文件进行比较 + * + * @param formMetadataId + */ + public ScriptCacheResponse checkVersionWithFormMetadataId(String formMetadataId) { + ScriptCacheResponse cacheResponse = ScriptCacheResponse.getInstance(); + + if (StringUtility.isNullOrEmpty(formMetadataId)) { + cacheResponse.setSuccess(false); + cacheResponse.setErrorMessage("表单元数据id为空"); + return cacheResponse; + } + // 获取数据库中存储的脚本文件信息 + List formScriptCacheList = this.localServerVersionRpcService.getFormScriptCacheByMetadataId(formMetadataId); + if (formScriptCacheList == null || formScriptCacheList.size() == 0) { + cacheResponse.setSuccess(false); + String errorMessage = "根据元数据id获取文件列表为空,对应元数据id:" + formMetadataId; + System.out.println(errorMessage); + errorMessage = "打开当前维度失败,请在【业务配置中心】,检查此维度是否进行了保存预览操作。相关元数据id:" + formMetadataId; + cacheResponse.setErrorMessage(errorMessage); + return cacheResponse; + } + + FormProjectCache formProjectCache = this.localServerVersionRpcService.getFormProjectCacheById(formScriptCacheList.get(0).getProjectVersionId()); + if (formProjectCache == null) { + cacheResponse.setSuccess(false); + cacheResponse.setErrorMessage("元数据对应的工程缓存信息为空,元数据id为" + formMetadataId); + return cacheResponse; + } + + cacheResponse = checkProjectVersion(formScriptCacheList, formProjectCache); + + return cacheResponse; + } + + private ScriptCacheResponse checkProjectVersion(List formScriptCacheList, FormProjectCache formProjectCache) { + ScriptCacheResponse cacheResponse = ScriptCacheResponse.getInstance(); + + String formProjectVersion = formProjectCache.getVersion(); + + //获取本地的工程缓存信息 + //根据工程名和工程路径获取工程的版本信息 + LocalServerProjectVersion localServerProjectVersion = LocalServerVersionFileOperation.getSingleInstance().getProjectVersionInfo(formProjectCache.getProjectName(), formProjectCache.getProjectRelativePath()); + + boolean needReSaveFile = false; + // 注意 本地工程版本可能会为空 因为在初始化时 该参数即为空 + if (localServerProjectVersion == null) { + localServerProjectVersion = LocalServerProjectVersion.getInstance(); + localServerProjectVersion.setProjectName(formProjectCache.getProjectName()); + localServerProjectVersion.setProjectRelativePath(formProjectCache.getProjectRelativePath()); + // 设定版本为新的随机数值 + localServerProjectVersion.setVersion(this.scriptCacheVersionManagerInstance.generageRandomVersion()); + needReSaveFile = true; + } + // 获取当前工程本地存储的工程版本 + String currentLocalServerProjectVersion = localServerProjectVersion.getVersion(); + boolean needUpdateMetadataVersion = true; + // 比较工程版本 + if (!EqualsUtility.getInstance().equalsWithCaseSensitive(formProjectVersion, currentLocalServerProjectVersion, false)) { + // 如果工程版本发生变化 那么更新工程版本 + localServerProjectVersion.setVersion(formProjectCache.getVersion()); + needReSaveFile = true; + // 如果工程版本不同 那么进行脚本文件的检测 + // 否则认为没有发生任何变化 + AtomicBoolean existsInLocal = new AtomicBoolean(false); + + // 已执行更新的元数据id列表 + List updatedMetadataList = new ArrayList<>(); + // 针对从数据库表获取到的表单脚本文件 + for (FormScriptCache t : formScriptCacheList) { + existsInLocal.set(false); + + // 针对本地存储的脚本版本列表 + for (LocalServerScriptVersion m : localServerProjectVersion.getScriptVersionList()) { + // 如果存在对应的项 那么比较版本 + if (EqualsUtility.getInstance().equalsWithoutOS(t.getScriptName(), m.getScriptName()) && + EqualsUtility.getInstance().equalsWithoutOS(t.getScriptRelativePath(), m.getScriptPath())) { + existsInLocal.set(true); + // 表示版本发生了变化 那么需要重新获取最新脚本文件 + if (!EqualsUtility.getInstance().equalsWithoutOS(t.getVersion(), m.getVersion())) { + needReSaveFile = true; + m.setVersion(t.getVersion()); + // 获取最新的脚本文件内容 并保存至本地server + // 获取数据库存储的问价内容脚本 + FormScriptCacheContent formScriptCacheContent = this.localServerVersionRpcService.getFormScriptCacheContentById(t.getScriptContentId()); + if (formScriptCacheContent != null) { + // 构造脚本文件路径 + saveScriptFileWithContent(formProjectCache, t, formScriptCacheContent, currentLocalServerProjectVersion, needUpdateMetadataVersion, updatedMetadataList); + if (needUpdateMetadataVersion) { + needUpdateMetadataVersion = false; + } + + } else { + LoggerUtility.log("数据库存储的脚本文件内容为空,contentId:" + t.getScriptContentId(), LoggerLevelEnum.Warning); + } + } + break; + } + } + + + // 如果是新增的脚本文件 + if (!existsInLocal.get()) { + LocalServerScriptVersion localServerScriptVersion = new LocalServerScriptVersion(); + localServerScriptVersion.setVersion(t.getVersion()); + localServerScriptVersion.setFormMetadataId(t.getFormMetadataId()); + localServerScriptVersion.setScriptName(t.getScriptName()); + localServerScriptVersion.setScriptPath(t.getScriptRelativePath()); + localServerProjectVersion.getScriptVersionList().add(localServerScriptVersion); + needReSaveFile = true; + + // 如果为新增的脚本文件配置 那么保存至本地脚本文件中 + FormScriptCacheContent formScriptCacheContent = this.localServerVersionRpcService.getFormScriptCacheContentById(t.getScriptContentId()); + if (formScriptCacheContent != null) { + // 构造脚本文件路径 + saveScriptFileWithContent(formProjectCache, t, formScriptCacheContent, currentLocalServerProjectVersion, needUpdateMetadataVersion, updatedMetadataList); + if (needUpdateMetadataVersion) { + needUpdateMetadataVersion = false; + } + } + + } + } + } else { + LoggerUtility.log("checkProjectVersion equalsWithCaseSensitive:false formProjectVersion:" + formProjectVersion + " currentLocalServerProjectVersion:" + currentLocalServerProjectVersion, LoggerLevelEnum.Info); + } + // 同步更新本地文件版本 如果需要同步回写脚本文件数据 那么重新保存至本地文件 + if (needReSaveFile) { + LocalServerVersionFileOperation.getSingleInstance().saveProjectVersion(localServerProjectVersion); + } + + return cacheResponse; + } + + /** + * 更新元数据版本 + * + * @param metadataId + * @param version + */ + private void updateMetadataVersion(String metadataId, String version) { + LoggerUtility.log("开始执行元数据版本更新检测", LoggerLevelEnum.Info); + try { + CustomizationCacheServiceInstanceManager.getCustomizationCacheInstance().checkGlobalVersion(metadataId, version); + LoggerUtility.log("元数据版本更新检测完成,id:" + metadataId + ",version:" + version, LoggerLevelEnum.Info); + // + LoggerUtility.log("清理DBO及BE缓存,表单元数据id为:" + metadataId, LoggerLevelEnum.Info); + clearDBOAndBECache(metadataId); + } catch (Exception e) { + LoggerUtility.log("元数据版本更新检测失败,id:" + metadataId + " version:" + version, LoggerLevelEnum.Info); + throw e; + } + } + + private void clearDBOAndBECache(String metaDataId) { + GspMetadata formMetadata = MetadataUtility.getInstance().getCustomizationService().getMetadata(metaDataId); + if (formMetadata != null) { + FormMetadataContent formMetadataContent = (FormMetadataContent) formMetadata.getContent(); + JsonNode content = formMetadataContent.getContents(); + String voId = content.at("/module/schemas/0/id").textValue(); + if (!StringUtility.isNullOrEmpty(voId)) { + GspMetadata vo = MetadataUtility.getInstance().getCustomizationService().getMetadata(voId); + //vo缓存清理 + BffEngineCacheService.remove(voId); + LoggerUtility.log("清理VO元数据,元数据id为:" + voId, LoggerLevelEnum.Info); + if (vo != null) { + String beId = ((GspViewModel) vo.getContent()).getMapping().getTargetMetadataId(); + if (!StringUtility.isNullOrEmpty(beId)) { + GspMetadata beMetadata = MetadataUtility.getInstance().getCustomizationService().getMetadata(beId); + // 如果获取到BE元数据 + if (beMetadata != null) { + IDatabaseObjectRtService databaseObjectRtService = SpringBeanUtils.getBean(IDatabaseObjectRtService.class); + List allObjectList = ((GspBusinessEntity) beMetadata.getContent()).getAllObjectList(); + allObjectList.forEach(obj -> { + LoggerUtility.log("清理DBO,对应id为:" + obj.getRefObjectName(), LoggerLevelEnum.Info); + databaseObjectRtService.clearDatabaseObjectContentById(obj.getRefObjectName()); + }); + } + //清理be元数据 + LoggerUtility.log("清理be元数据,元数据id为:" + beId, LoggerLevelEnum.Info); + BefEngineInfoCache.removeBefEngineInfo(beId); + } + } + } + } + + //databaseObjectRtService.clearDatabaseObjectContentById(dboid); + } + + + /** + * 保存脚本文件至本地文件路径 + * + * @param formProjectCache + * @param t + * @param formScriptCacheContent + */ + private void saveScriptFileWithContent(FormProjectCache formProjectCache, FormScriptCache t, FormScriptCacheContent formScriptCacheContent, String currentLocalServerProjectVersion, boolean needUpdateMedataVersion, List updatedMetadataList) { + + //if (needUpdateMedataVersion) { + // 如果该元数据未进行更新 那么执行更新 否则不进行更新,主要针对一个元数据id对应多个文件的情况 + // 避免元数据id的重复更新产生的性能问题 + if (!updatedMetadataList.contains(t.getFormMetadataId())) { + // 执行元数据id更新 + updateMetadataVersion(t.getFormMetadataId(), currentLocalServerProjectVersion); + // 将更新的元数据id保存至更新列表中 + updatedMetadataList.add(t.getFormMetadataId()); + } + //} + + String strProjectRelativePath = formProjectCache.getProjectRelativePath(); + String strScriptRelativePath = t.getScriptRelativePath(); + String strRelativePath = FileUtility.combine(strProjectRelativePath, strScriptRelativePath); + LocalServerFileOperation.saveFile(t.getScriptName(), strRelativePath, formScriptCacheContent.getContent()); + } + + + /** + * 检测工程下所有表单的依赖 + * + * @param projectName + * @param strProjectRelativePath + * @return + */ + public ScriptCacheResponse checkVersionWithProjectNameAndRelativePath(String projectName, String strProjectRelativePath) { + + ScriptCacheResponse scriptCacheResponse = ScriptCacheResponse.getInstance(); + + strProjectRelativePath = FileUtility.getPlatformIndependentPath(strProjectRelativePath); + FormProjectCache formProjectCache = this.localServerVersionRpcService.getByProjectNameAndProjectRelativePath(projectName, strProjectRelativePath); + if (formProjectCache == null) { + LoggerUtility.log("未找到工程对应的脚本缓存信息,工程名称:" + projectName, LoggerLevelEnum.Warning); + return scriptCacheResponse; + } + List formScriptCacheList = this.localServerVersionRpcService.getFormScriptCacheByProjectVersionId(formProjectCache.getId()); + scriptCacheResponse = checkProjectVersion(formScriptCacheList, formProjectCache); + return scriptCacheResponse; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcService.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcService.java new file mode 100644 index 00000000..da9930fe --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcService.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import io.iec.edp.caf.rpc.api.annotation.GspServiceBundle; +import io.iec.edp.caf.rpc.api.annotation.RpcParam; + +import java.util.List; + +@GspServiceBundle(applicationName = "runtime",serviceUnitName = "bcc",serviceName = "local_server_version_rpc_service") +public interface LocalServerVersionRpcService { + + /** + * 获取文件列表 + * + * @param formMetadataId rpc参数 表单元数据id + * @return + */ + List getFormScriptCacheByMetadataId(@RpcParam(paramName = "formMetadataId") String formMetadataId); + + /** + * 根据缓存工程id获取对应的工程版本信息 + * @param projectVersionId + * @return + */ + FormProjectCache getFormProjectCacheById(@RpcParam(paramName = "projectVersionId") String projectVersionId); + + /** + * 根据脚本缓存id获取对应的脚本缓存内容 + * @param contentId + * @return + */ + FormScriptCacheContent getFormScriptCacheContentById(@RpcParam(paramName = "contentId") String contentId); + + /** + * 根据工程名以及对应的工程路径获取工程版本缓存信息 + * @param projectName + * @param strProjectRelativePath + * @return + */ + FormProjectCache getByProjectNameAndProjectRelativePath(@RpcParam(paramName = "projectName") String projectName, @RpcParam(paramName = "strProjectRelativePath") String strProjectRelativePath); + + /** + * 根据工程版本id信息获取对应的脚本缓存列表 + * @param formProjectVersionId + * @return + */ + List getFormScriptCacheByProjectVersionId(@RpcParam(paramName = "formProjectVersionId") String formProjectVersionId); +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcServiceImpl.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcServiceImpl.java new file mode 100644 index 00000000..e30a6a05 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/localserver/rpc/LocalServerVersionRpcServiceImpl.java @@ -0,0 +1,75 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc; + +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.ScriptCacheVersionManager; + +import java.util.List; + +public class LocalServerVersionRpcServiceImpl implements LocalServerVersionRpcService { + + private final ScriptCacheVersionManager scriptCacheVersionManagerInstance = new ScriptCacheVersionManager(); + + public LocalServerVersionRpcServiceImpl() { + + } + + + /** + * 获取文件列表 + * + * @param formMetadataId rpc参数 表单元数据id + * @return + */ + @Override + public List getFormScriptCacheByMetadataId(String formMetadataId) { + return this.scriptCacheVersionManagerInstance.getFormScriptCacheByMetadataId(formMetadataId); + } + + /** + * 根据缓存工程id获取对应的工程版本信息 + * + * @param projectVersionId + * @return + */ + @Override + public FormProjectCache getFormProjectCacheById(String projectVersionId) { + return this.scriptCacheVersionManagerInstance.getFormProjectCacheById(projectVersionId); + } + + /** + * 根据脚本缓存id获取对应的脚本缓存内容 + * + * @param contentId + * @return + */ + @Override + public FormScriptCacheContent getFormScriptCacheContentById(String contentId) { + return this.scriptCacheVersionManagerInstance.getFormScriptCacheContentById(contentId); + } + + /** + * 根据工程名以及对应的工程路径获取工程版本缓存信息 + * + * @param projectName + * @param strProjectRelativePath + * @return + */ + @Override + public FormProjectCache getByProjectNameAndProjectRelativePath(String projectName, String strProjectRelativePath) { + return this.scriptCacheVersionManagerInstance.getByProjectNameAndProjectRelativePath(projectName, strProjectRelativePath); + } + + /** + * 根据工程版本id信息获取对应的脚本缓存列表 + * + * @param formProjectVersionId@return + */ + @Override + public List getFormScriptCacheByProjectVersionId(String formProjectVersionId) { + return this.scriptCacheVersionManagerInstance.getFormScriptCacheByProjectVersionId(formProjectVersionId); + } + + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/CustomizationCacheServiceInstanceManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/CustomizationCacheServiceInstanceManager.java new file mode 100644 index 00000000..c6884a94 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/CustomizationCacheServiceInstanceManager.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.manager; + +import com.inspur.edp.lcm.rtcustomization.cache.api.service.ICustomizationCacheService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * description: + * + * @author Noah Guo + * @date 2020/11/24 + */ +public class CustomizationCacheServiceInstanceManager { + + private CustomizationCacheServiceInstanceManager() { + + } + + private static final class CustomizationCacheServiceHolder { + static final ICustomizationCacheService customizationCacheService = SpringBeanUtils.getBean(ICustomizationCacheService.class); + } + + public static ICustomizationCacheService getCustomizationCacheInstance() { + return CustomizationCacheServiceHolder.customizationCacheService; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/ScriptCacheVersionManager.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/ScriptCacheVersionManager.java new file mode 100644 index 00000000..9d26a2ea --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/manager/ScriptCacheVersionManager.java @@ -0,0 +1,226 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.manager; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormProjectCacheConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormScriptCacheContentConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.converter.FormScriptCacheConverter; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormProjectCacheEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheContentEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.entity.FormScriptCacheEntity; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormProjectCacheManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormScriptCacheContentManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.domain.manager.FormScriptCacheManager; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class ScriptCacheVersionManager { + + private final FormProjectCacheManager formProjectCacheManager; + private final FormScriptCacheManager formScriptCacheManager; + private final FormScriptCacheContentManager formScriptCacheContentManager; + + public ScriptCacheVersionManager() { + this.formProjectCacheManager = SpringBeanUtils.getBean(FormProjectCacheManager.class); + this.formScriptCacheContentManager = SpringBeanUtils.getBean(FormScriptCacheContentManager.class); + this.formScriptCacheManager = SpringBeanUtils.getBean(FormScriptCacheManager.class); + } + + /** + * 元数据版本检测 + * + * @param metadataId + * @param version + * @return + */ + public boolean checkMetadataVersion(String metadataId, String version) { + return true; + } + + /** + * 生成随机数版本号 + * + * @return + */ + public String generageRandomVersion() { + return CommonUtility.generateRandomId(); + } + + + /** + * 保存工程脚本缓存 + * + * @param formProjectCache 工程脚本缓存 + */ + public void saveFormProjectCache(FormProjectCache formProjectCache) { + + if (StringUtility.isNullOrEmpty(formProjectCache.getId())) { + formProjectCache.setId(CommonUtility.generateRandomId()); + } + FormProjectCacheEntity projectCacheEntity = FormProjectCacheConverter.convert(formProjectCache); + this.formProjectCacheManager.save(projectCacheEntity); + } + + /** + * 更新工程脚本缓存 + * + * @param formProjectCache 工程脚本缓存 + */ + public void updateFormProjectCache(FormProjectCache formProjectCache) { + + if (StringUtility.isNullOrEmpty(formProjectCache.getId())) { + formProjectCache.setId(CommonUtility.generateRandomId()); + } + FormProjectCacheEntity projectCacheEntity = FormProjectCacheConverter.convert(formProjectCache); + this.formProjectCacheManager.save(projectCacheEntity); + } + + /** + * 保存表单脚本缓存 + * + * @param formScriptCache 表单脚本缓存 + */ + public void saveFormScriptCache(FormScriptCache formScriptCache) { + + if (StringUtility.isNullOrEmpty(formScriptCache.getId())) { + formScriptCache.setId(CommonUtility.generateRandomId()); + } + FormScriptCacheEntity scriptCacheEntity = FormScriptCacheConverter.convert(formScriptCache); + this.formScriptCacheManager.save(scriptCacheEntity); + } + + /** + * 保存表单脚本缓存 + * + * @param formScriptCache 表单脚本缓存 + */ + public void updateFormScriptCache(FormScriptCache formScriptCache) { + + if (StringUtility.isNullOrEmpty(formScriptCache.getId())) { + formScriptCache.setId(CommonUtility.generateRandomId()); + } + FormScriptCacheEntity scriptCacheEntity = FormScriptCacheConverter.convert(formScriptCache); + this.formScriptCacheManager.update(scriptCacheEntity); + } + + + /** + * 保存表单脚本缓存内容 + * + * @param formScriptCacheContent 表单脚本缓存内容 + */ + public void saveFormScriptCacheContent(FormScriptCacheContent formScriptCacheContent) { + if (StringUtility.isNullOrEmpty(formScriptCacheContent.getId())) { + formScriptCacheContent.setId(CommonUtility.generateRandomId()); + } + FormScriptCacheContentEntity contentEntity = FormScriptCacheContentConverter.convert(formScriptCacheContent); + this.formScriptCacheContentManager.save(contentEntity); + + } + + /** + * 保存表单脚本缓存内容 + * + * @param formScriptCacheContent 表单脚本缓存内容 + */ + public void updateFormScriptCacheContent(FormScriptCacheContent formScriptCacheContent) { + if (StringUtility.isNullOrEmpty(formScriptCacheContent.getId())) { + formScriptCacheContent.setId(CommonUtility.generateRandomId()); + } + FormScriptCacheContentEntity contentEntity = FormScriptCacheContentConverter.convert(formScriptCacheContent); + this.formScriptCacheContentManager.update(contentEntity); + + } + + /** + * 根据工程名称及对应得部署相对路径获取对应得工程缓存信息 + * + * @param projectName + * @param strProjectRelativePath + * @return + */ + public FormProjectCache getByProjectNameAndProjectRelativePath(String projectName, String strProjectRelativePath) { + // 调整路径分隔符为一致形式 + strProjectRelativePath = FileUtility.getPlatformIndependentPath(strProjectRelativePath); + return this.formProjectCacheManager.getByProjectNameAndProjectRelativePath(projectName, strProjectRelativePath); + } + + /** + * 根据元数据id、工程版本id、脚本文件名称、脚本相对路径获取对应的脚本缓存信息 + * + * @param projectVersionId + * @param scriptName + * @param strScriptRelativePath + * @return + */ + public FormScriptCache getFormScriptCacheByMulCondition(String projectVersionId, String scriptName, String strScriptRelativePath) { + // 脚本相对文件路径 + strScriptRelativePath = FileUtility.getPlatformIndependentPath(strScriptRelativePath); + return this.formScriptCacheManager.getFormScriptCacheByMulCondition(projectVersionId,null, scriptName, strScriptRelativePath); + } + + /** + * 根据元数据id、工程版本id、脚本文件名称、脚本相对路径获取对应的脚本缓存信息 + * + * @param projectVersionId + * @param scriptName + * @param strScriptRelativePath + * @return + */ + public FormScriptCache getFormScriptCacheByMulCondition(String projectVersionId, String scriptCode, String scriptName, String strScriptRelativePath) { + // 脚本相对文件路径 + strScriptRelativePath = FileUtility.getPlatformIndependentPath(strScriptRelativePath); + return this.formScriptCacheManager.getFormScriptCacheByMulCondition(projectVersionId, scriptCode, scriptName, strScriptRelativePath); + } + + /** + * 根据内容项id获取对应的内容 + * + * @param contentId + * @return + */ + public FormScriptCacheContent getFormScriptCacheContentById(String contentId) { + return this.formScriptCacheContentManager.findById(contentId); + } + + /** + * 根据元数据id获取对应的脚本缓存列表 + * + * @param formMetadataId + * @return + */ + public List getFormScriptCacheByMetadataId(String formMetadataId) { + return this.formScriptCacheManager.getFormScriptCacheByMetadataId(formMetadataId); + } + + /** + * 根据工程缓存id获取对应的工程缓存信息 + * + * @param formProjectCacheId + * @return + */ + public FormProjectCache getFormProjectCacheById(String formProjectCacheId) { + return this.formProjectCacheManager.getById(formProjectCacheId); + } + + /** + * 根据工程脚本缓存id获取对应的脚本缓存信息 + * + * @param formProjecVersionId + * @return + */ + public List getFormScriptCacheByProjectVersionId(String formProjecVersionId) { + return this.formScriptCacheManager.getFormScriptCacheByProjectVersionId(formProjecVersionId); + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpl.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpl.java new file mode 100644 index 00000000..c589e304 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpl.java @@ -0,0 +1,320 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.service; + +import com.inspur.edp.lcm.rtcustomization.cache.api.entity.CustomizationGlobalVersion; +import com.inspur.edp.lcm.rtcustomization.cache.api.entity.CustomizationType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.*; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormProjectCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCache; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.FormScriptCacheContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.PublishScriptRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.service.ScriptCacheService; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.CustomizationCacheServiceInstanceManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.manager.ScriptCacheVersionManager; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.io.File; +import java.util.ArrayList; + +/** + * description: 脚本缓存service + * + * @author Noah Guo + * @date 2020/09/28 + */ +public class ScriptCacheServiceImpl implements ScriptCacheService { + + private final ScriptCacheVersionManager scriptCacheVersionManager; + + public ScriptCacheServiceImpl() { + this.scriptCacheVersionManager = SpringBeanUtils.getBean(ScriptCacheVersionManager.class); + } + + /** + * 发布文件目录下的脚本文件 如果发生变化 则更新对应的版本 + * + * @param request 脚本缓存发布入参 + */ + @Override + public void publishScriptWithSingleFileName(PublishScriptRequest request, String relativeFolder, String fileName) { + String strProjectName = request.getProjectName(); + String strProjectCode = request.getProjectName(); + String strProjectRelativePath = request.getProjectRelativePath(); + // 初始化工程脚本缓存信息 + FormProjectCache formProjectCache = this.scriptCacheVersionManager.getByProjectNameAndProjectRelativePath(strProjectName, strProjectRelativePath); + if (formProjectCache == null) { + // 如果获取工程缓存信息为空 + formProjectCache = this.createFormProjectCache(strProjectName, strProjectCode, strProjectRelativePath); + + // 将当前工程缓存信息保存至数据库表 + this.scriptCacheVersionManager.saveFormProjectCache(formProjectCache); + } + if (StringUtility.isNullOrEmpty(relativeFolder)) { + relativeFolder = ""; + } + + // 获取文件目录下的所有文件列表 + String strFolder = request.getAbsoluteBaseDirectory(); + + if (!StringUtility.isNullOrEmpty(relativeFolder)) { + strFolder = FileUtility.combine(request.getAbsoluteBaseDirectory(), relativeFolder); + } + + ArrayList fileList = new ArrayList<>(); + if (StringUtility.isNullOrEmpty(fileName)) { + fileList = FileUtility.getFiles(strFolder, true); + } else { + String filePath = FileUtility.combine(strFolder, fileName); + //fileList = FileUtility.getFiles(filePath, true); + fileList.add(new File(filePath)); + } + + + System.out.println("absoluteBaseDirectory:" + request.getAbsoluteBaseDirectory() + " 获取文件列表个数为:" + fileList.size()); + + // 如果存在文件列表 + if (fileList != null && fileList.size() > 0) { + FormProjectCache finalFormProjectCache = formProjectCache; + fileList.forEach(t -> { + // 脚本发布 + if (t != null) { + pubishScript(t, request.getMetaDataId(), finalFormProjectCache, request); + } + }); + + } + + // 保存元数据版本 + saveMetadataVersion(request, formProjectCache); + } + + /** + * 发布文件目录下的所有脚本文件 并更新对应的版本 + * + * @param request 请求参数 + */ + @Override + public void publishScriptWithDirectory(PublishScriptRequest request) { + publishScriptWithSingleFileName(request, null, null); + } + + /** + * 保存元数据版本 + * + * @param request + * @param formProjectCache + */ + private void saveMetadataVersion(PublishScriptRequest request, FormProjectCache formProjectCache) { + if (!request.isUpdateMetadataVersion()) { + return; + } + LoggerUtility.log("开始执行元数据版本更新", LoggerLevelEnum.Info); + try { + CustomizationGlobalVersion globalVersionInstance = new CustomizationGlobalVersion(); + globalVersionInstance.setCustomizationType(CustomizationType.Metadata); + globalVersionInstance.setId(request.getMetaDataId()); + globalVersionInstance.setObjectId(request.getMetaDataId()); + globalVersionInstance.setVersion(formProjectCache.getVersion()); + CustomizationCacheServiceInstanceManager.getCustomizationCacheInstance().saveGlobalVersion(globalVersionInstance); + LoggerUtility.log("元数据版本更新完成,id:" + request.getMetaDataId() + ",version:" + formProjectCache.getVersion(), LoggerLevelEnum.Info); + } catch (Exception e) { + LoggerUtility.log("元数据版本更新失败,id:" + request.getMetaDataId() + " version:" + formProjectCache.getVersion(), LoggerLevelEnum.Info); + throw e; + } + + + } + + + /** + * 发布指定路径下的脚本文件 + * + * @param scriptFilePath + * @param metaDataId + * @param formProjectCache + */ + public void publishScriptWithFilePath(String scriptFilePath, String metaDataId, FormProjectCache formProjectCache, PublishScriptRequest request) { + File file = new File(scriptFilePath); + pubishScript(file, metaDataId, formProjectCache, request); + } + + /** + * 发布脚本 依据 + * + * @param file + * @param metaDataId + * @param formProjectCache + */ + public void pubishScript(File file, String metaDataId, FormProjectCache formProjectCache, PublishScriptRequest request) { + if (!file.exists()) { + LoggerUtility.log("the file is not exists, file path is:" + file.getPath(), LoggerLevelEnum.Warning); + return; + } + + // 获取当前脚本的相对路径 + // 此相对路径是相对于工程路径而言 + String strDeployFileDirectory = file.getParent(); + String strDeployBaseDirectory = request.getAbsoluteBaseDirectory(); + String relativePath = FileUtility.getRelativePath(strDeployBaseDirectory, strDeployFileDirectory, true); + + if (StringUtility.isNullOrEmpty(relativePath)) { + relativePath = ""; + } + + // 获取当前文件内容 + String fileContent = FileUtility.readAsString(file.getPath()); + + // 定义脚本文件内容id + String formScriptContentId = null; + String formScriptVersion = null; + + FormScriptCache formScriptCache; + // 移动零代码特殊处理 + if (!request.isZeroCodeMobileForm()) { + formScriptCache = this.scriptCacheVersionManager.getFormScriptCacheByMulCondition(formProjectCache.getId(), file.getName(), relativePath); + } else { + formScriptCache = this.scriptCacheVersionManager.getFormScriptCacheByMulCondition(formProjectCache.getId(), request.getFormCode(), file.getName(), relativePath); + } + + // 是否新建脚本缓存 + boolean isNewScriptCache = formScriptCache == null; + + + // 构造对应的表单缓存脚本文件内容 + FormScriptCacheContent scriptCacheContent = this.createFormScriptCacheContent(fileContent, formScriptVersion, formScriptContentId); + if (isNewScriptCache) { + formScriptContentId = CommonUtility.generateRandomId(); + formScriptVersion = this.scriptCacheVersionManager.generageRandomVersion(); + formScriptCache = this.createFormScriptCache(file.getName(), request.getFormCode(), relativePath, metaDataId, formProjectCache, formScriptContentId, formScriptVersion); + + scriptCacheContent.setId(formScriptContentId); + + // 保存表单脚本缓存 + this.scriptCacheVersionManager.saveFormScriptCache(formScriptCache); + this.scriptCacheVersionManager.saveFormScriptCacheContent(scriptCacheContent); + + formProjectCache.setVersion(this.scriptCacheVersionManager.generageRandomVersion()); + formProjectCache.setLastModifyTime(CommonUtility.getCurrentDate()); + this.scriptCacheVersionManager.updateFormProjectCache(formProjectCache); + } else { + formScriptContentId = formScriptCache.getScriptContentId(); + formScriptVersion = formScriptCache.getVersion(); + + // 从数据库表读取脚本文件内容项 + FormScriptCacheContent formScriptCacheContent = this.scriptCacheVersionManager.getFormScriptCacheContentById(formScriptContentId); + if (formScriptCacheContent == null) { + formScriptVersion = this.scriptCacheVersionManager.generageRandomVersion(); + scriptCacheContent.setId(formScriptContentId); + + formScriptCache.setVersion(formScriptVersion); + formScriptCache.setLastModifyTime(CommonUtility.getCurrentDate()); + formScriptCache.setFormMetadataId(metaDataId); + formScriptCache.setScriptCode(request.getFormCode()); + this.scriptCacheVersionManager.updateFormScriptCache(formScriptCache); + this.scriptCacheVersionManager.saveFormScriptCacheContent(scriptCacheContent); + + formProjectCache.setVersion(this.scriptCacheVersionManager.generageRandomVersion()); + formProjectCache.setLastModifyTime(CommonUtility.getCurrentDate()); + this.scriptCacheVersionManager.updateFormProjectCache(formProjectCache); + } else { + boolean hasSameContent = EqualsUtility.getInstance().equalsWithoutOS(fileContent, formScriptCacheContent.getContent()); + if (!hasSameContent) { + formScriptVersion = this.scriptCacheVersionManager.generageRandomVersion(); + scriptCacheContent.setId(formScriptCacheContent.getId()); + scriptCacheContent.setLastModifyTime(CommonUtility.getCurrentDate()); + scriptCacheContent.setContent(fileContent); + + formScriptCache.setLastModifyTime(CommonUtility.getCurrentDate()); + formScriptCache.setFormMetadataId(metaDataId); + formScriptCache.setVersion(formScriptVersion); + formScriptCache.setScriptCode(request.getFormCode()); + this.scriptCacheVersionManager.updateFormScriptCache(formScriptCache); + // 保存表单脚本缓存内容 + this.scriptCacheVersionManager.updateFormScriptCacheContent(scriptCacheContent); + + formProjectCache.setVersion(this.scriptCacheVersionManager.generageRandomVersion()); + formProjectCache.setLastModifyTime(CommonUtility.getCurrentDate()); + this.scriptCacheVersionManager.updateFormProjectCache(formProjectCache); + } + } + } + + + } + + + @Override + public void checkScriptVersion() { + + } + + /** + * 初始化一个表单工程版本信息 + * + * @param projectName 工程名称 + * @param projectCode 工程code + * @param projectRelativePath 工程相对路径 + * @return + */ + private FormProjectCache createFormProjectCache(String projectName, String projectCode, String projectRelativePath) { + FormProjectCache formProjectCache = new FormProjectCache(); + formProjectCache.setId(CommonUtility.generateRandomId()); + formProjectCache.setProjectName(projectName); + formProjectCache.setProjectCode(projectCode); + formProjectCache.setProjectRelativePath(projectRelativePath); + formProjectCache.setVersion(this.scriptCacheVersionManager.generageRandomVersion()); + formProjectCache.setCreateDate(CommonUtility.getCurrentDate()); + formProjectCache.setLastModifyTime(CommonUtility.getCurrentDate()); + return formProjectCache; + } + + /** + * 创建对应的表单脚本文件缓存内容 + * + * @param fileContent + * @return + */ + private FormScriptCacheContent createFormScriptCacheContent(String fileContent, String formScriptVersion, String formScriptContentId) { + FormScriptCacheContent formScriptCacheContent = new FormScriptCacheContent(); + formScriptCacheContent.setId(formScriptContentId); + formScriptCacheContent.setContent(fileContent); + formScriptCacheContent.setLastModifyTime(CommonUtility.getCurrentDate()); + formScriptCacheContent.setCreateDate(CommonUtility.getCurrentDate()); + return formScriptCacheContent; + } + + + /** + * 构造对应的表单脚本文件缓存 + * + * @param scriptFileName + * @param scriptCode + * @param scriptRelativePath + * @param metaDataId + * @param formProjectCache* + * @return + */ + private FormScriptCache createFormScriptCache(String scriptFileName, String scriptCode, String scriptRelativePath, + String metaDataId, FormProjectCache formProjectCache, String formScriptCacheContentId, String formScriptVersion) { + FormScriptCache formScriptCache = new FormScriptCache(); + formScriptCache.setId(CommonUtility.generateRandomId()); + formScriptCache.setFormMetadataId(metaDataId); + + formScriptCache.setProjectVersionId(formProjectCache.getId()); + + formScriptCache.setVersion(formScriptVersion); + // 设置脚本文件名称 + formScriptCache.setScriptName(scriptFileName); + // 可以为不包含文件后缀的文件名称 + formScriptCache.setScriptCode(scriptCode); + // 设置脚本的相对路径 相对于apps而言 + formScriptCache.setScriptRelativePath(scriptRelativePath); + + // 设置对应的脚本文件内容 + formScriptCache.setScriptContentId(formScriptCacheContentId); + formScriptCache.setLastModifyTime(CommonUtility.getCurrentDate()); + formScriptCache.setCreateDate(CommonUtility.getCurrentDate()); + + return formScriptCache; + } +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncrypt.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncrypt.java new file mode 100644 index 00000000..d02c1c01 --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncrypt.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.utility; + +import com.inspur.edp.web.common.encrypt.EncryptConstant; +import com.inspur.edp.web.common.encrypt.EncryptUtility; + +/** + * description: 表单脚本文件内容加密 + * + * @author Noah Guo + * @date 2020/10/01 + */ +public class ScriptCacheContentEncrypt { + /** + * 文件内容加密 + * @param fileContent 文件内容 + * @return + */ + public static String encode(String fileContent) { + return EncryptUtility.getInstance().DESencode(fileContent, EncryptConstant.EncryptKey); + } + + /** + * 文件内容解密 + * @param decodeContent + * @return + */ + public static String decode(String decodeContent) { + return EncryptUtility.getInstance().DESdecode(decodeContent, EncryptConstant.EncryptKey); + } + + +} diff --git a/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/webservice/ScriptCacheWebServiceImpl.java b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/webservice/ScriptCacheWebServiceImpl.java new file mode 100644 index 00000000..6987941d --- /dev/null +++ b/runtime-scriptcache/src/main/java/com/inspur/edp/web/jitruntimebuild/scriptcache/webservice/ScriptCacheWebServiceImpl.java @@ -0,0 +1,80 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.webservice; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheCheckVersionRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.webservice.ScriptCacheWebService; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerVersionManager; + +/** + * description: 脚本缓存web调用入口 + * + * @author Noah Guo + * @date 2020/09/24 + */ +public class ScriptCacheWebServiceImpl implements ScriptCacheWebService { + /** + * 脚本缓存 版本检测 + * + * @param request 请求参数 + * @return + */ + @Override + public ScriptCacheResponse checkVersion(ScriptCacheCheckVersionRequest request) { + ScriptCacheResponse scriptCacheResponse = ScriptCacheResponse.getInstance(); + + // 进行入参检测 + if (request == null) { + scriptCacheResponse.setSuccess(false); + scriptCacheResponse.setErrorMessage("script version check,the parameter request is null"); + return scriptCacheResponse; + } + + // 如果参数中表单元数据id不为空 那么使用元数据id进行版本检测 + if (!StringUtility.isNullOrEmpty(request.getFormMetadataId())) { + // 进行本地版本与数据库版本比较 + scriptCacheResponse = LocalServerVersionManager.getSingleInstance().checkVersionWithFormMetadataId(request.getFormMetadataId()); + } else { + scriptCacheResponse = this.checkVersionWithProjectInfo(request); + } + + //获取当前工程对应的版本 + //ScriptCacheVersionManager.checkMetadataVersion() + //进行元数据的版本检测 + // 检查ts文件 不需要进行版本检测 + // 如果需要更新 获取工程下哪些脚本需要更新 + + // + return scriptCacheResponse; + } + + + /** + * 依据工程信息进行脚本文件版本检测 + * + * @param request + * @return + */ + private ScriptCacheResponse checkVersionWithProjectInfo(ScriptCacheCheckVersionRequest request) { + ScriptCacheResponse scriptCacheResponse = ScriptCacheResponse.getInstance(); + + if (StringUtility.isNullOrEmpty(request.getProjectName())) { + scriptCacheResponse.setSuccess(false); + scriptCacheResponse.setErrorMessage("脚本检测,工程名称不能为空"); + return scriptCacheResponse; + } + if (StringUtility.isNullOrEmpty(request.getProjectRelativePath())) { + scriptCacheResponse.setSuccess(false); + scriptCacheResponse.setErrorMessage("脚本检测,工程路径不能为空"); + return scriptCacheResponse; + } + scriptCacheResponse = LocalServerVersionManager.getSingleInstance().checkVersionWithProjectNameAndRelativePath(request.getProjectName(), request.getProjectRelativePath()); + return scriptCacheResponse; + } + + @Override + public ScriptCacheResponse resttest() { + return null; + } + +} diff --git a/runtime-scriptcache/src/main/resources/META-INF/spring.factories b/runtime-scriptcache/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..29e6cb9e --- /dev/null +++ b/runtime-scriptcache/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.jitruntimebuild.scriptcache.config.ScriptCacheConfiguration diff --git a/runtime-scriptcache/src/main/resources/log4j2.properties b/runtime-scriptcache/src/main/resources/log4j2.properties new file mode 100644 index 00000000..328db356 --- /dev/null +++ b/runtime-scriptcache/src/main/resources/log4j2.properties @@ -0,0 +1,7 @@ + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n +rootLogger.level = INFO +rootLogger.appenderRef.out.ref = out diff --git a/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepositoryTest.java b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepositoryTest.java new file mode 100644 index 00000000..be839ba7 --- /dev/null +++ b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/domain/repository/FormProjectCacheRepositoryTest.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.domain.repository; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class FormProjectCacheRepositoryTest { + + @Test + public void testR(){ + + } + + +} \ No newline at end of file diff --git a/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpTest.java b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpTest.java new file mode 100644 index 00000000..0014127a --- /dev/null +++ b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/service/ScriptCacheServiceImpTest.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.service; + +import org.junit.Assert; + +import java.nio.file.Paths; + +class ScriptCacheServiceImpTest { + + + // @org.junit.jupiter.api.Test + void publishScriptWithDirectory() { + + String strScriptBaseDir = "C:\\env\\igix_2011_x86_64_build20200918_rc2\\web\\apps\\scm\\sd\\web\\bo-salesorderfrontguojihua"; + String strRelativeScriptBaseDir = "apps\\scm\\sd\\web\\bo-salesorderfrontguojihua"; + } + + + // @org.junit.jupiter.api.Test + void testRelativePath() { + String strLocalServerPath = "C:\\env\\igix_2011_x86_64_build20200918_rc2\\web"; + String strDeployPath = "C:\\env\\igix_2011_x86_64_build20200918_rc2\\web\\apps\\scm\\sd\\web\\bo-salesorderfrontcombolist"; + String strRelativePath = Paths.get(strLocalServerPath).relativize(Paths.get(strDeployPath)).toString(); + + + String strDeplayFilePath = "C:\\env\\igix_2011_x86_64_build20200918_rc2\\web\\apps\\scm\\sd\\web\\bo-salesorderfronttestruntime\\version.json"; + String strParentDirectory = Paths.get(strDeplayFilePath).getParent().toString(); + + + Assert.assertNotNull(strRelativePath); + } + +} diff --git a/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncryptTest.java b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncryptTest.java new file mode 100644 index 00000000..be2c2247 --- /dev/null +++ b/runtime-scriptcache/src/test/java/com/inspur/edp/web/jitruntimebuild/scriptcache/utility/ScriptCacheContentEncryptTest.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.jitruntimebuild.scriptcache.utility; + +import com.inspur.edp.web.common.encrypt.EncryptUtility; +import com.inspur.edp.web.common.io.FileUtility; +import org.junit.Assert; +import org.junit.jupiter.api.Test; + +class ScriptCacheContentEncryptTest { + + @Test + void encode() { + } + + + @Test + void getPascal() { + + } + + + // @Test + void decode() { + String fileContent = FileUtility.readAsString("C:\\Users\\guozhiqi\\Documents\\Tencent Files\\474351703\\FileRecv\\runtime.txt"); + + String result = EncryptUtility.getInstance().Base64Decode(fileContent); + + Assert.assertTrue(true); + } +} diff --git a/toout.bat b/toout.bat new file mode 100644 index 00000000..f620c72a --- /dev/null +++ b/toout.bat @@ -0,0 +1,62 @@ +@echo off + +for /f "tokens=*" %%i in ('CALL .\xpath0.1.bat pom.xml "/project/properties/custom.version"') do set version=%%i +ECHO version=%version% + +DEL /S/Q .\out + +MKDIR .\out\server\platform\dev\main\libs +MKDIR .\out\server\platform\common\libs +MKDIR .\out\server\platform\runtime\bcc\libs + + +COPY .\web-appconfig-core\target\web-appconfig-core-%version%.jar .\out\server\platform\common\libs\web-appconfig-core.jar +COPY .\web-appconfig-manager\target\web-appconfig-manager-%version%.jar .\out\server\platform\dev\main\libs\web-appconfig-manager.jar +COPY .\web-appconfig-webapi\target\web-appconfig-webapi-%version%.jar .\out\server\platform\dev\main\libs\web-appconfig-webapi.jar +COPY .\web-common\target\web-common-%version%.jar .\out\server\platform\common\libs\web-common.jar + +COPY .\runtime-api\target\web-jitengine-runtimebuild-api-%version%.jar .\out\server\platform\common\libs\web-jitengine-runtimebuild-api.jar +COPY .\runtime-core\target\web-jitengine-runtimebuild-core-%version%.jar .\out\server\platform\common\libs\web-jitengine-runtimebuild-core.jar + +COPY .\runtime-scriptcache\target\web-jitengine-runtimebuild-scriptcache-%version%.jar .\out\server\platform\common\libs\web-jitengine-runtimebuild-scriptcache.jar +COPY .\runtime-scriptcache-api\target\web-jitengine-runtimebuild-scriptcache-api-%version%.jar .\out\server\platform\common\libs\web-jitengine-runtimebuild-scriptcache-api.jar + +COPY .\web-appconfig-core\target\web-appconfig-core-%version%.jar .\out\server\platform\common\libs\web-appconfig-core.jar +COPY .\web-appconfig-api\target\web-appconfig-api-%version%.jar .\out\server\platform\common\libs\web-appconfig-api.jar + +COPY .\web-common\target\web-jitengine-common-%version%.jar .\out\server\platform\common\libs\web-jitengine-common.jar + + +COPY .\web-form-jitengine\target\web-jitengine-%version%.jar .\out\server\platform\common\libs\web-jitengine.jar + +COPY .\web-form-metadata\target\web-jitengine-formmetadata-%version%.jar .\out\server\platform\common\libs\web-jitengine-formmetadata.jar +COPY .\web-form-metadata-api\target\web-jitengine-formmetadata-api-%version%.jar .\out\server\platform\common\libs\web-jitengine-formmetadata-api.jar + +COPY .\web-frontendproject\target\web-jitengine-frontendproject-%version%.jar .\out\server\platform\common\libs\web-jitengine-frontendproject.jar +COPY .\web-frontendproject-api\target\web-jitengine-frontendproject-api-%version%.jar .\out\server\platform\common\libs\web-jitengine-frontendproject-api.jar + +COPY .\web-designschema\target\web-designschema-%version%.jar .\out\server\platform\common\libs\web-designschema.jar +COPY .\web-designschema-api\target\web-designschema-api-%version%.jar .\out\server\platform\common\libs\web-designschema-api.jar + + +COPY .\web-pageflow-metadata\target\web-pageflow-metadata-%version%.jar .\out\server\platform\common\libs\web-pageflow-metadata.jar +COPY .\web-statemachine\target\web-statemachine-metadata-%version%.jar .\out\server\platform\common\libs\web-statemachine-metadata.jar + +COPY .\web-sourcecode-metadata\target\web-sourcecode-metadata-%version%.jar .\out\server\platform\common\libs\web-sourcecode-metadata.jar + +COPY .\web-tsfile-api\target\web-tsfile-api-%version%.jar .\out\server\platform\common\libs\web-tsfile-api.jar +COPY .\web-tsfile-core\target\web-tsfile-core-%version%.jar .\out\server\platform\common\libs\web-tsfile-core.jar + +COPY .\jitengine-web-api\target\web-jitengine-web-api-%version%.jar .\out\server\platform\common\libs\web-jitengine-web-api.jar +COPY .\jitengine-web-core\target\web-jitengine-web-core-%version%.jar .\out\server\platform\common\libs\web-jitengine-web-core.jar + +COPY .\web-approval-format-api\target\web-approval-format-api-%version%.jar .\out\server\platform\runtime\bcc\libs\web-approval-format-api.jar +COPY .\web-approval-format-core\target\web-approval-format-core-%version%.jar .\out\server\platform\runtime\bcc\libs\web-approval-format-core.jar +COPY .\web-approval-format-rpc\target\web-approval-format-rpc-%version%.jar .\out\server\platform\common\libs\web-approval-format-rpc.jar + +COPY .\web-npmpackage-api\target\web-npmpackage-api-%version%.jar .\out\server\platform\common\libs\web-npmpackage-api.jar +COPY .\web-npmpackage-core\target\web-npmpackage-core-%version%.jar .\out\server\platform\common\libs\web-npmpackage-core.jar +::pause +::pause + + diff --git a/web-appconfig-api/pom.xml b/web-appconfig-api/pom.xml new file mode 100644 index 00000000..75fc31c7 --- /dev/null +++ b/web-appconfig-api/pom.xml @@ -0,0 +1,20 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-appconfig-api + + + + com.inspur.edp + web-jitengine-common + + + diff --git a/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/entity/GspAppConfig.java b/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/entity/GspAppConfig.java new file mode 100644 index 00000000..978077ac --- /dev/null +++ b/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/entity/GspAppConfig.java @@ -0,0 +1,109 @@ +package com.inspur.edp.web.appconfig.api.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.inspur.edp.web.common.serialize.SerializeUtility; + +/** + * 前端工程应用配置实体 + */ +public class GspAppConfig { + + /** + * PC页面流元数据ID + */ + @JsonProperty("pageFlowMetadataID") + private String pageFlowMetadataID; + /** + * PC页面流元数据文件名 + */ + @JsonProperty("pageFlowMetadataFileName") + private String pageFlowMetadataFileName; + /** + * PC页面流元数据ID + * 全路径,包含projects信息 + */ + @JsonProperty("pageFlowMetadataPath") + private String pageFlowMetadataPath; + + /** + * 移动页面流元数据ID + */ + @JsonProperty("mobilePageFlowMetadataID") + private String mobilePageFlowMetadataID; + + /** + * 移动页面流元数据文件名 + */ + @JsonProperty("mobilePageFlowMetadataFileName") + private String mobilePageFlowMetadataFileName; + /** + * 移动页面流元数据ID + * 全路径,包含projects信息 + */ + @JsonProperty("mobilePageFlowMetadataPath") + private String mobilePageFlowMetadataPath; + + public String getPageFlowMetadataID() { + return pageFlowMetadataID; + } + + public void setPageFlowMetadataID(String pageFlowMetadataID) { + this.pageFlowMetadataID = pageFlowMetadataID; + } + + public String getPageFlowMetadataFileName() { + return pageFlowMetadataFileName; + } + + public void setPageFlowMetadataFileName(String pageFlowMetadataFileName) { + this.pageFlowMetadataFileName = pageFlowMetadataFileName; + } + + public String getPageFlowMetadataPath() { + return pageFlowMetadataPath; + } + + public void setPageFlowMetadataPath(String pageFlowMetadataPath) { + this.pageFlowMetadataPath = pageFlowMetadataPath; + } + + public String getMobilePageFlowMetadataID() { + return mobilePageFlowMetadataID; + } + + public void setMobilePageFlowMetadataID(String mobilePageFlowMetadataID) { + this.mobilePageFlowMetadataID = mobilePageFlowMetadataID; + } + + public String getMobilePageFlowMetadataFileName() { + return mobilePageFlowMetadataFileName; + } + + public void setMobilePageFlowMetadataFileName(String mobilePageFlowMetadataFileName) { + this.mobilePageFlowMetadataFileName = mobilePageFlowMetadataFileName; + } + + public String getMobilePageFlowMetadataPath() { + return mobilePageFlowMetadataPath; + } + + public void setMobilePageFlowMetadataPath(String mobilePageFlowMetadataPath) { + this.mobilePageFlowMetadataPath = mobilePageFlowMetadataPath; + } + + /** + * 将当前实体进行JSON序列化 + */ + public final String toJson() { + return SerializeUtility.getInstance().serialize(this, false); + } + + /** + * 获取对应实例 + * + * @return + */ + public static GspAppConfig getNewInstance() { + return new GspAppConfig(); + } +} diff --git a/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/webservice/AppConfigWebService.java b/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/webservice/AppConfigWebService.java new file mode 100644 index 00000000..f3305f63 --- /dev/null +++ b/web-appconfig-api/src/main/java/com/inspur/edp/web/appconfig/api/webservice/AppConfigWebService.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.appconfig.api.webservice; + + +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * 应用配置文件(app.config.json)服务接口 + * @author noah + */ +@Path("/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface AppConfigWebService { + /** + * 获取应用配置文件内容 + * + * @param projectPath 工程路径 + * @return + */ + @Path("") + @GET + GspAppConfig getGspAppConfigContent(@QueryParam("projectPath") String projectPath); + + + /** + * 保存应用配置文件内容 + * @param appConfigEntity 应用程序配置实体 + * @param projectPath 工程路径 + */ + @Path("") + @POST + void saveGspAppConfigContent(GspAppConfig appConfigEntity, @QueryParam("projectPath") String projectPath); +} diff --git a/web-appconfig-core/pom.xml b/web-appconfig-core/pom.xml new file mode 100644 index 00000000..07329a26 --- /dev/null +++ b/web-appconfig-core/pom.xml @@ -0,0 +1,32 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-appconfig-core + + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-appconfig-api + + + com.inspur.edp + lcm-metadata-spi + + + io.iec.edp + caf-boot-starter-rest-server + + + diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFileManager.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFileManager.java new file mode 100644 index 00000000..bb65fb47 --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFileManager.java @@ -0,0 +1,60 @@ +package com.inspur.edp.web.appconfig.core.appconfig; + +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +/** + * description: + * + * @author Noah Guo + * @date 2021/03/15 + */ +public class AppConfigFileManager { + + /** + * 创建app.config.json 空结构文件 + * + * @param appConfigFileFolderPath app.config.json文件路径 + * @return + */ + public static GspAppConfig createEmptyAppConfigFile(String appConfigFileFolderPath) { + GspAppConfig emptyAppConfig = GspAppConfig.getNewInstance(); + String appConfigFilePath = AppConfigFilePathGenerator.generateAppConfigFilePath(appConfigFileFolderPath); + saveAppConfig(appConfigFilePath, emptyAppConfig); + return emptyAppConfig; + } + + /** + * 读取配置文件内容 + * + * @param appConfigFilePath 文件路径 将路径调整成为路径无关参数 + * @return + */ + public static GspAppConfig getAppConfigWithPath(String appConfigFilePath) { + if (StringUtility.isNullOrEmpty(appConfigFilePath)) { + return null; + } + appConfigFilePath = FileUtility.getPlatformIndependentPath(appConfigFilePath); + if (!FileUtility.exists(appConfigFilePath)) { + return null; + } + String fileStr = FileUtility.readAsString(appConfigFilePath); + + // 将获取的文件内容反序列化成JSON对象 + return SerializeUtility.getInstance().deserialize(fileStr, GspAppConfig.class); + } + + /** + * 依据app.config.json 文件路径及具体内容保存 + * + * @param appConfigFilePath app.config.json 文件路径 + * @param appConfig + */ + public static void saveAppConfig(String appConfigFilePath, GspAppConfig appConfig) { + FileUtility.writeFile(appConfigFilePath, appConfig.toJson()); + } + + +} diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFilePathGenerator.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFilePathGenerator.java new file mode 100644 index 00000000..a7f9a74c --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/appconfig/AppConfigFilePathGenerator.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.appconfig.core.appconfig; + +import com.inspur.edp.web.appconfig.core.constants.GspAppConfigConstants; +import com.inspur.edp.web.common.io.FileUtility; + +/** + * @Title: AppConfigFilePathGenerator + * @Description: com.inspur.edp.web.appconfig.core.appconfig app.config.json 文件路径构造 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/5 9:55 + */ +public class AppConfigFilePathGenerator { + + /** + * 依据app.config.json 所在文件夹构造完整的app.config.json 文件路径 + * @param appConfigFolderPath + * @return + */ + public static String generateAppConfigFilePath(String appConfigFolderPath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(appConfigFolderPath, GspAppConfigConstants.APP_CONFIG_NAME)); + } + +} diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/config/AppConfigConfiguration.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/config/AppConfigConfiguration.java new file mode 100644 index 00000000..e168f07e --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/config/AppConfigConfiguration.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.appconfig.core.config; + +import com.inspur.edp.web.appconfig.core.webservice.AppConfigWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/16 + */ +@Configuration +public class AppConfigConfiguration { + @Bean + public RESTEndpoint appConfigWebServiceEndpoint() { + return new RESTEndpoint("/dev/main/v1.0/app-config", new AppConfigWebServiceImpl()); + } +} diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/constants/GspAppConfigConstants.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/constants/GspAppConfigConstants.java new file mode 100644 index 00000000..f9575a40 --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/constants/GspAppConfigConstants.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.appconfig.core.constants; + +/** + app config 使用常量 + * @author guozhiqi + */ +public final class GspAppConfigConstants +{ + /** + 应用配置文件名称app.config.json + */ + public static final String APP_CONFIG_NAME = "app.config.json"; + + /** + 内部使用路径分隔符 + */ + public static final String INTERNAL_PATH_SEPARATOR = "/"; + +} diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/service/GspAppConfigService.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/service/GspAppConfigService.java new file mode 100644 index 00000000..65f24a6d --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/service/GspAppConfigService.java @@ -0,0 +1,204 @@ +package com.inspur.edp.web.appconfig.core.service; + +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.core.appconfig.AppConfigFileManager; +import com.inspur.edp.web.appconfig.core.appconfig.AppConfigFilePathGenerator; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.exception.CAFRuntimeException; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * app.config文件对外服务 + * + * @author noah + */ +public class GspAppConfigService { + private static final GspAppConfigService current = new GspAppConfigService(); + + + private GspAppConfigService() { + } + + public static GspAppConfigService getCurrent() { + return current; + } + + + + + + /** + * 基于相对路径(不包含开发路径),获取app.config文件内容 + * @param relativeProjectPath + * @return + */ + public final GspAppConfig getGspAppConfigInfo(String relativeProjectPath) { + if (StringUtility.isNullOrEmpty(relativeProjectPath)) { + return null; + } + String appConfigFolderPath = combinePathWithDevRootPath(relativeProjectPath); + String appConfigFilePath = AppConfigFilePathGenerator.generateAppConfigFilePath(appConfigFolderPath); + return AppConfigFileManager.getAppConfigWithPath(appConfigFilePath); + } + + /** + * 获取或新建app.config.json 文件及其内容 + * + * @param projectPath 工程路径 + * @return 应用实体 + */ + public GspAppConfig getOrCreateAppConfig(String projectPath) { + GspAppConfig gspAppConfig = getGspAppConfigInfo(projectPath); + if (gspAppConfig == null) { + gspAppConfig = createEmptyAppConfigFile(projectPath); + } + return gspAppConfig; + } + /** + * 创建app.config.json 空文件 + * 如果app.config.json 文件不存在 那么创建对应的文件 + * + * @param appConfigFileFolderPath 工程路径 scm/sd/..../bo- + */ + private GspAppConfig createEmptyAppConfigFile(String appConfigFileFolderPath) { + return AppConfigFileManager.createEmptyAppConfigFile(appConfigFileFolderPath); + } + + /** + * 获取开发元数据绝对路径 将当前路径和devRootPath合并 + * @param path + * @return + */ + private String combinePathWithDevRootPath(String path) { + //开发根路径 + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + return FileUtility.getPlatformIndependentPath(FileUtility.combine(devRootPath, path)); + } + + /** + * 根据元数据信息,更新工程下的app.config.json文件中内容 + */ + public final void updateAppConfigFileWhenPageFlowFileCreated(String pageFlowMetadataID, String pageFlowMetadataFileName, String pageFlowMetadataFullPath) { + TerminalType terminalType = TerminalType.PC; + if (pageFlowMetadataFileName.endsWith("mpf")) { + terminalType = TerminalType.MOBILE; + } + updateAppConfigFile(terminalType, pageFlowMetadataID, pageFlowMetadataFileName, pageFlowMetadataFullPath); + } + + /** + * 根据元数据信息,更新工程下的app.config.json文件中内容 + */ + public final void updateAppConfigFile(TerminalType terminalType, String pageFlowMetadataID, String pageFlowMetadataFileName, String pageFlowMetadataFullPath) { + String appConfigPath = getAppConfigPath(pageFlowMetadataFullPath); + String appConfigContent = FileUtility.readAsString(appConfigPath); + GspAppConfig appConfig = SerializeUtility.getInstance().deserialize(appConfigContent, GspAppConfig.class); + switch (terminalType) { + case PC: + appConfig.setPageFlowMetadataID(pageFlowMetadataID); + appConfig.setPageFlowMetadataFileName(pageFlowMetadataFileName); + appConfig.setPageFlowMetadataPath(pageFlowMetadataFullPath); + break; + case MOBILE: + appConfig.setMobilePageFlowMetadataID(pageFlowMetadataID); + appConfig.setMobilePageFlowMetadataFileName(pageFlowMetadataFileName); + appConfig.setMobilePageFlowMetadataPath(pageFlowMetadataFullPath); + break; + default: + throw new CAFRuntimeException("", "Web_UpdateAppConfigFile", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType, null); + } + + modifyPageFlowMetadataPath(appConfig, pageFlowMetadataFullPath); + AppConfigFileManager.saveAppConfig(appConfigPath, appConfig); + } + + + /** + * 保存app.config.json文件内容 + * + * @param projectPath app.config.json所在工程路径 + * @param appConfigEntity 待保存appConfig Entity + */ + public final void saveAppConfigFile(String projectPath, GspAppConfig appConfigEntity) { + // 获取app.config.json文件路径 + String appConfigPath = getAppConfigPath(projectPath); + // 调整页面流中路径为基于工程相对路径 + modifyPageFlowMetadataPath(appConfigEntity, projectPath); + + AppConfigFileManager.saveAppConfig(appConfigPath, appConfigEntity); + } + + /** + * 调整页面流路径为基于工程名称相对路径 + * + * @param appConfigEntity config 应用实体 + * @param projectPath 工程路径 + */ + private void modifyPageFlowMetadataPath(GspAppConfig appConfigEntity, String projectPath) { + if (appConfigEntity == null) { + return; + } + String projectName = GspProjectUtil.getProjectName(projectPath); + // 如果pc页面流路径不为空 + if (!StringUtility.isNullOrEmpty(appConfigEntity.getPageFlowMetadataPath())) { + String relativePageFlowMetadataPath = getRelativePageflowMetadataPath(appConfigEntity.getPageFlowMetadataPath(), projectName); + appConfigEntity.setPageFlowMetadataPath(relativePageFlowMetadataPath); + } + // 如果pc页面流路径不为空 + if (!StringUtility.isNullOrEmpty(appConfigEntity.getMobilePageFlowMetadataPath())) { + String relativeMobilePageFlowMetadataPath = getRelativePageflowMetadataPath(appConfigEntity.getMobilePageFlowMetadataPath(), projectName); + appConfigEntity.setMobilePageFlowMetadataPath(relativeMobilePageFlowMetadataPath); + } + } + + /** + * 获取页面流相对于工程的相对路径 + * + * @param pageFlowMetadataPath + * @param projectName + * @return + */ + private String getRelativePageflowMetadataPath(String pageFlowMetadataPath, String projectName) { + String independentPageFlowMetadataPath = FileUtility.getPlatformIndependentPath(pageFlowMetadataPath); + // 表示当前页面流中包含工程名称 + if (independentPageFlowMetadataPath.contains(projectName)) { + independentPageFlowMetadataPath = independentPageFlowMetadataPath.substring(independentPageFlowMetadataPath.indexOf(projectName) + projectName.length()); + if (independentPageFlowMetadataPath.startsWith("/")) { + independentPageFlowMetadataPath = independentPageFlowMetadataPath.substring(1); + } + } + return independentPageFlowMetadataPath; + } + + private String getAppConfigPath(String metadataFullPath) { + // 基于当前元数据获取工程路径信息 + String projectPath = getMetadataProjectPath(metadataFullPath); + // 获取app.config.json文件内容 + return AppConfigFilePathGenerator.generateAppConfigFilePath(projectPath); + } + + /** + * 获取当前元数据所在工程路径 + */ + private String getMetadataProjectPath(String metadataFullPath) { + MetadataProjectService bean = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProject = bean.getMetadataProjInfo(metadataFullPath); + + return getAbsPath(metadataProject.getProjectPath()); + } + + private String getAbsPath(String relPath) { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + if (relPath.contains(devRootPath)) { + return relPath; + } + return java.nio.file.Paths.get(devRootPath).resolve(relPath).toString(); + } +} diff --git a/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/webservice/AppConfigWebServiceImpl.java b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/webservice/AppConfigWebServiceImpl.java new file mode 100644 index 00000000..eb0ed01c --- /dev/null +++ b/web-appconfig-core/src/main/java/com/inspur/edp/web/appconfig/core/webservice/AppConfigWebServiceImpl.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.appconfig.core.webservice; + +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.api.webservice.AppConfigWebService; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/14 + */ +public class AppConfigWebServiceImpl implements AppConfigWebService { + /** + * 获取应用配置文件内容 + * + * @param projectPath 工程路径 + * @return + */ + @Override + public GspAppConfig getGspAppConfigContent(String projectPath) { + + return GspAppConfigService.getCurrent().getGspAppConfigInfo(projectPath); + } + + /** + * 保存应用配置文件内容 + */ + @Override + public void saveGspAppConfigContent(GspAppConfig appConfigEntity, String projectPath) { + GspAppConfigService.getCurrent().saveAppConfigFile(projectPath, appConfigEntity); + } +} diff --git a/web-appconfig-core/src/main/resources/META-INF/spring.factories b/web-appconfig-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..de3d648d --- /dev/null +++ b/web-appconfig-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.appconfig.core.config.AppConfigConfiguration diff --git a/web-approval-format-api/pom.xml b/web-approval-format-api/pom.xml new file mode 100644 index 00000000..8ab32745 --- /dev/null +++ b/web-approval-format-api/pom.xml @@ -0,0 +1,44 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-approval-format-api + + + + javax.ws.rs + javax.ws.rs-api + + + com.inspur.edp + bef-bizentity + + + com.inspur.edp + web-help-api + + + com.inspur.edp + web-jitengine-formmetadata + + + io.iec.edp + caf-rpc-api + + + com.inspur.edp + formserver-viewmodel + + + com.inspur.edp + bcc-billcategory-entity + + + diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormUpdateRequestBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormUpdateRequestBody.java new file mode 100644 index 00000000..3ae3ebe4 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormUpdateRequestBody.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 审批单据更新请求体 + * @author Xu‘fa Wang + * @date 2020/5/18 20:53 + */ +@Data +public class ApprovalFormUpdateRequestBody { + /** + * 审批单据id + */ + @NotNull( + message = "审批单据的元数据id不能为空" + ) + private String formMetadataId; + + /** + * 审批单据内容 + */ + @NotNull + private FormMetadataContent formMetadataContent; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormat.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormat.java new file mode 100644 index 00000000..9140da6a --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormat.java @@ -0,0 +1,66 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * 审批格式实体 + * @author Xu‘fa Wang + * @date 2020/5/15 9:51 + */ +@Data +public class ApprovalFormat { + /** + * id + */ + private String id; + + /** + * 编号 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 模板属性名 + */ + private String attributeName; + + /** + * 第一维度 + */ + private String firstDimension; + + /** + * 第二维度 + */ + private String secondDimension; + + /** + * 单据种类id + */ + private String billCategoryId; + + /** + * 审批格式关联业务实体id + */ + private String bizEntityId; + + /** + * 审批格式关联viewObject id + */ + private String viewObjectId; + + /** + * 审批格式关联审批单据id + */ + private String approvalFormId; + + /** + * 审批单据的发布地址 + */ + private String approvalFormPublishUri; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateRequestBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateRequestBody.java new file mode 100644 index 00000000..5268dc7b --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateRequestBody.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * 审批格式创建请求实体类 + * @author Xu‘fa Wang + * @date 2020/5/19 19:38 + */ +@Data +public class ApprovalFormatCreateRequestBody { + /** + * 单据种类id + */ + private String billCategoryId; + /** + * 业务对象id + */ + private String bizObjectId; + /** + * 命名空间 + */ + private String nameSpace; + /** + * 业务实体id + */ + private String beId; + /** + * 基础视图对象id + */ + private String basicVoId; + /** + * 视图id + */ + private String voId; + /** + * 基础表单id + */ + private String basicFormId; + /** + * 表单id + */ + private String formId; + /** + * 表单编号 + */ + private String code; + /** + * 表单名称 + */ + private String name; + /** + * 第一维度 + */ + private String dim1; + /** + * 第二维度 + */ + private String dim2; + /** + * 视图对象内容 + */ + private String voContent; + /** + * 表单内容 + */ + private String formContent; + /** + * 表单url + */ + private String formUrl; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateResponseBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateResponseBody.java new file mode 100644 index 00000000..1bb1724b --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatCreateResponseBody.java @@ -0,0 +1,65 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * 审批格式创建返回实体类 + * @author Xu‘fa Wang + * @date 2020/5/22 15:07 + */ +@Data +public class ApprovalFormatCreateResponseBody { + /** + * id + */ + private String id; + + /** + * 编号 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 模板属性名 + */ + private String attributeName; + + /** + * 第一维度 + */ + private String firstDimension; + + /** + * 第二维度 + */ + private String secondDimension; + + /** + * 单据种类id + */ + private String billCategoryId; + + /** + * 审批格式关联业务实体id + */ + private String bizEntityId; + + /** + * 审批格式关联viewObject id + */ + private String viewObjectId; + + /** + * 审批格式关联审批单据id + */ + private String approvalFormId; + /** + * 审批单据的发布地址 + */ + private String approvalFormPublishUri; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatDimensionUpdateRequestBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatDimensionUpdateRequestBody.java new file mode 100644 index 00000000..cc9eb5fd --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatDimensionUpdateRequestBody.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 审批格式更新请求体 + * @author Xu‘fa Wang + * @date 2020/5/18 20:53 + */ +@Data +public class ApprovalFormatDimensionUpdateRequestBody { + /** + * 审批单据id + */ + @NotNull( + message = "审批格式的id不能为空" + ) + private String id; + + /** + * 第一维度 + */ + private String firstDimension; + + /** + * 第二维度 + */ + private String secondDimension; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatEnum.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatEnum.java new file mode 100644 index 00000000..aedabe58 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatEnum.java @@ -0,0 +1,59 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +/** + * 审批格式枚举 + * @author Xu‘fa Wang + * @date 2020/5/16 14:37 + */ +public class ApprovalFormatEnum { + public enum TEMPLATE_ATTRIBUTES { + SYS, NEW + } + + public enum LEVEL { + ONE, TWO, THREE + } + + public enum FIELD_TYPES{ + SIMPLE("SimpleField"), COMPLEX("ComplexField"); + private final String text; + FIELD_TYPES(String text){ + this.text = text; + } + public String text(){ + return this.text; + } + } + + public enum SIMPLE_FIELD_TYPES{ + BOOLEAN("BooleanType"), + DATETYPE("DateType"), + DATE("Date"), + DATETIME("DateTime"), + ENUM("EnumType"), + NUMBER("NumericType"), + INTEGER("Integer"), + DECIMAL("Decimal"), + STRING("StringType"), + TEXT("TextType"); + + private final String text; + SIMPLE_FIELD_TYPES(String text){ + this.text = text; + } + public String text(){ + return this.text; + } + } + + public enum COMPLEX_FIELD_TYPES{ + ENTITY("EntityType"), OBJECT("ObjectType"), HIERARCHY("HierarchyType"); + private final String text; + COMPLEX_FIELD_TYPES(String text){ + this.text = text; + } + public String text(){ + return this.text; + } + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatForestByDimension.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatForestByDimension.java new file mode 100644 index 00000000..3a54226b --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatForestByDimension.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; + +import java.util.List; + +/** + * 基于维度的审批格式树集合 + * @author Xu‘fa Wang + * @date 2020/5/16 9:28 + */ +@Data +public class ApprovalFormatForestByDimension { + /** + * 树形审批格式集合--审批格式森林 + */ + private List approvalFormatForest; + + /** + * 单据种类维度 + */ + private BillCategoryDimension billCategoryDimension; + + public ApprovalFormatForestByDimension() { + + } + + public ApprovalFormatForestByDimension(List approvalFormatForest, BillCategoryDimension billCategoryDimension) { + this.approvalFormatForest = approvalFormatForest; + this.billCategoryDimension = billCategoryDimension; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatQueryResponseBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatQueryResponseBody.java new file mode 100644 index 00000000..5dfd7e17 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatQueryResponseBody.java @@ -0,0 +1,76 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * 审批格式创建返回实体类 + * @author Xu‘fa Wang + * @date 2020/5/22 15:07 + */ +@Data +public class ApprovalFormatQueryResponseBody { + /** + * id + */ + private String id; + + /** + * 编号 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 模板属性名 + */ + private String attributeName; + + /** + * 第一维度 + */ + private String firstDimension; + + /** + * 第一维度名称 + */ + private String firstDimensionName; + + /** + * 第二维度 + */ + private String secondDimension; + + /** + * 第二维度名称 + */ + private String secondDimensionName; + + /** + * 单据种类id + */ + private String billCategoryId; + + /** + * 审批格式关联业务实体id + */ + private String bizEntityId; + + /** + * 审批格式关联viewObject id + */ + private String viewObjectId; + + /** + * 审批格式关联审批单据id + */ + private String approvalFormId; + + /** + * 审批单据的发布地址 + */ + private String approvalFormPublishUri; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatTreeNode.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatTreeNode.java new file mode 100644 index 00000000..d27b3e95 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatTreeNode.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +import java.util.List; + +/** + * 树形结构的审批格式集合 + * @author Xu‘fa Wang + * @date 2020/5/16 9:37 + */ +@Data +public class ApprovalFormatTreeNode { + private ApprovalFormat data; + private Boolean expanded; + private List children; + + public ApprovalFormatTreeNode(ApprovalFormat data) { + this.data = data; + this.expanded = true; + } + + public ApprovalFormatTreeNode(ApprovalFormat data, List children) { + this.data = data; + this.children = children; + this.expanded = true; + } + + @Override + public String toString() { + return "ApprovalFormatTreeNode{" + + "data=" + data + + ", children=" + children + + '}'; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatUpdateRequestBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatUpdateRequestBody.java new file mode 100644 index 00000000..e12516e4 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalFormatUpdateRequestBody.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 审批格式更新请求体 + * @author Xu‘fa Wang + * @date 2020/5/18 20:53 + */ +@Data +public class ApprovalFormatUpdateRequestBody { + /** + * 审批单据id + */ + @NotNull( + message = "审批格式的id不能为空" + ) + private String approvalFormatId; + + /** + * 审批格式 + */ + @NotNull + private ApprovalFormat approvalFormatInstance; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalViewObjectUpdateRequestBody.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalViewObjectUpdateRequestBody.java new file mode 100644 index 00000000..455d61e9 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApprovalViewObjectUpdateRequestBody.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import com.inspur.edp.formserver.viewmodel.GspViewModel; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 审批视图对象更新请求体 + * @author Xu‘fa Wang + * @date 2020/5/18 20:53 + */ +@Data +public class ApprovalViewObjectUpdateRequestBody { + /** + * 审批单据id + */ + @NotNull( + message = "审批单据的元数据id不能为空" + ) + private String viewModelId; + + /** + * 审批单据内容 + */ + @NotNull + private GspViewModel viewModelContent; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApproveFormatPreviewParameter.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApproveFormatPreviewParameter.java new file mode 100644 index 00000000..d27e9b7c --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/ApproveFormatPreviewParameter.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * description: + * + * @author Noah Guo + * @date 2020/05/16 + */ +@Data +public class ApproveFormatPreviewParameter { + + private String id; + + private String formCode; + + /** + * 维度1 + */ + private String dim1; + + /** + * 维度2 + */ + private String dim2; + + private String formId; + +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpMetadataSimpleContent.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpMetadataSimpleContent.java new file mode 100644 index 00000000..7221808a --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpMetadataSimpleContent.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import lombok.Data; + +/** + * 帮助元数据精简内容体 + * @author Xu‘fa Wang + * @date 2020/5/18 10:59 + */ +@Data +public class HelpMetadataSimpleContent { + public static final String TREE_TYPE = "TreeList"; + public static final String PATH_CODE = "pathcode"; + private String version; + private String id; + private String code; + private String name; + private String title; + private String idField; + private String idFieldName; + private String textField; + private String textFieldName; + private String valueField; + private String valueFieldName; + private String displayType; + private String description; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpProviderResult.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpProviderResult.java new file mode 100644 index 00000000..d6d6464e --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/HelpProviderResult.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.approvalformat.api.entity; + +import com.inspur.edp.web.help.api.LookupResult; +import lombok.Data; + +/** + * 帮助返回实体类 + * @author Xu‘fa Wang + * @date 2020/5/18 10:58 + */ +@Data +public class HelpProviderResult { + private HelpMetadataSimpleContent helpMetadataSimpleContent; + LookupResult lookupResult; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/ComplexField.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/ComplexField.java new file mode 100644 index 00000000..aa4f9650 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/ComplexField.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:33 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ComplexField extends Field { + public ComplexField() { + super(ComplexField.class.getSimpleName()); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Entity.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Entity.java new file mode 100644 index 00000000..b6f26071 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Entity.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema; + +import com.inspur.edp.web.approvalformat.api.entity.schema.type.EntityType; +import lombok.Data; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:12 + */ +@Data +public class Entity { + private String id; + private String code; + private String name; + private String label; + private EntityType type; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Field.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Field.java new file mode 100644 index 00000000..37f61a17 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/Field.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema; + +import com.inspur.edp.web.approvalformat.api.entity.schema.type.FieldType; +import lombok.Data; + +/** + * 字段实体类 + * @author Xu‘fa Wang + * @date 2020/6/8 16:13 + */ +@Data +public class Field { + private String $type; + private String id; + private String originalId; + private String code; + private String name; + private String label; + private String bindingField; + private FieldType type; + private String path; + private String bindingPath; + + public Field() { + } + + public Field(String $type) { + this.$type = $type; + } + + public String get$type(){ + return this.$type; + } + + public void set$type(String $type) { + this.$type = $type; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/FormSchema.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/FormSchema.java new file mode 100644 index 00000000..4109fb17 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/FormSchema.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema; + +import lombok.Data; + +import java.util.List; + +/** + * 表单Schema实体类 + * @author Xu‘fa Wang + * @date 2020/6/8 16:11 + */ +@Data +public class FormSchema { + private String id; + private String code; + private String name; + private String sourceUri; + private String sourceType; + private List entities; + private List variables; + private String eapiId; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/SimpleField.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/SimpleField.java new file mode 100644 index 00000000..d588ae65 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/SimpleField.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema; + +import com.inspur.edp.web.approvalformat.api.entity.schema.editor.FieldEditor; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:31 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class SimpleField extends Field { + private String defaultValue; + private Boolean require; + private Boolean readonly; + private FieldEditor editor; + private Boolean multiLanguage = false; + + public SimpleField() { + super(SimpleField.class.getSimpleName()); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/CheckBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/CheckBox.java new file mode 100644 index 00000000..a2d72624 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/CheckBox.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:35 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class CheckBox extends FieldEditor { + public CheckBox() { + super(CheckBox.class.getSimpleName()); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/DateBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/DateBox.java new file mode 100644 index 00000000..ee56d5cd --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/DateBox.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:36 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DateBox extends FieldEditor { + private String format; + + public DateBox(String format) { + super(DateBox.class.getSimpleName()); + this.format = format; + } + +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/EnumField.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/EnumField.java new file mode 100644 index 00000000..14d7d81f --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/EnumField.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:36 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class EnumField extends FieldEditor { + public EnumField() { + super(EnumField.class.getSimpleName()); + } +} + diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/FieldEditor.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/FieldEditor.java new file mode 100644 index 00000000..f65e9c08 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/FieldEditor.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +/** + * 字段编辑器 + * @author Xu‘fa Wang + * @date 2020/6/8 16:34 + */ +public class FieldEditor { + private String $type; + + public FieldEditor() { + } + + public FieldEditor(String $type) { + this.$type = $type; + } + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/LanguageTextBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/LanguageTextBox.java new file mode 100644 index 00000000..04cbbac8 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/LanguageTextBox.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:37 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class LanguageTextBox extends FieldEditor { + public LanguageTextBox() { + super(LanguageTextBox.class.getSimpleName()); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/MultiTextBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/MultiTextBox.java new file mode 100644 index 00000000..7e9aead4 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/MultiTextBox.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:37 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class MultiTextBox extends FieldEditor { + public MultiTextBox() { + super(MultiTextBox.class.getSimpleName()); + } +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/NumericBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/NumericBox.java new file mode 100644 index 00000000..3174c878 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/NumericBox.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:38 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class NumericBox extends FieldEditor { + public NumericBox() { + super(NumericBox.class.getSimpleName()); + } +} + diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/TextBox.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/TextBox.java new file mode 100644 index 00000000..443746c0 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/editor/TextBox.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.editor; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:38 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TextBox extends FieldEditor { + public TextBox() { + super(TextBox.class.getSimpleName()); + } +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/BooleanType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/BooleanType.java new file mode 100644 index 00000000..b7773745 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/BooleanType.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:41 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class BooleanType extends FieldType { + public BooleanType() { + super(BooleanType.class.getSimpleName(),"Boolean", "布尔"); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DateType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DateType.java new file mode 100644 index 00000000..c51302f4 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DateType.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:42 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DateType extends FieldType { + public DateType() { + super(DateType.class.getSimpleName(), "Date","日期/时间"); + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DynamicObjectType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DynamicObjectType.java new file mode 100644 index 00000000..539d9613 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/DynamicObjectType.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:42 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class DynamicObjectType extends FieldType { + public DynamicObjectType() { + super(DynamicObjectType.class.getSimpleName(),"DynamicEntity",""); + } +} + diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EntityType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EntityType.java new file mode 100644 index 00000000..27be278f --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EntityType.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import com.inspur.edp.web.approvalformat.api.entity.schema.Entity; +import com.inspur.edp.web.approvalformat.api.entity.schema.Field; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 实体类型 + * @author Xu‘fa Wang + * @date 2020/6/8 16:13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class EntityType extends FieldType { + public EntityType(String name, String displayName, String primary, List fields, List entities) { + super(EntityType.class.getSimpleName(),name,displayName); + this.primary = primary; + this.fields = fields; + this.entities = entities; + } + private String primary; + private List fields; + private List entities; +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumItem.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumItem.java new file mode 100644 index 00000000..bd900b99 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumItem.java @@ -0,0 +1,18 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:42 + */ +@Data +public class EnumItem { + private String value; + private String name; + + public EnumItem(String value, String name) { + this.value = value; + this.name = name; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumType.java new file mode 100644 index 00000000..f2dbe91d --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/EnumType.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 17:00 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class EnumType extends FieldType { + private FieldType valueType; + private List enumValues; + + public EnumType(FieldType valueType, List enumValues) { + super(EnumType.class.getSimpleName(),"Enum","枚举"); + this.valueType = valueType; + this.enumValues = enumValues; + } +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/FieldType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/FieldType.java new file mode 100644 index 00000000..aea532ad --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/FieldType.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; + +/** + * 字段类型 + * @author Xu‘fa Wang + * @date 2020/6/8 16:17 + */ +@Data +public class FieldType { + private String $type; + private String name; + private String displayName; + + public FieldType() { + } + + public FieldType(String $type, String name, String displayName) { + this.$type = $type; + this.name = name; + this.displayName = displayName; + } + + public String get$type(){ + return this.$type; + } + + public void set$type(String $type) { + this.$type = $type; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/HierarchyType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/HierarchyType.java new file mode 100644 index 00000000..b8756936 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/HierarchyType.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import com.inspur.edp.web.approvalformat.api.entity.schema.Field; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:43 + */ + +@EqualsAndHashCode(callSuper = true) +public class HierarchyType extends ObjectType { + public HierarchyType(String name, String displayName, List fields) { + super(HierarchyType.class.getSimpleName(), name, displayName, fields); + } +} + diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/NumericType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/NumericType.java new file mode 100644 index 00000000..dbf0804f --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/NumericType.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:44 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class NumericType extends FieldType { + private Integer length; + private Integer precision; + + public NumericType(Integer length, Integer precision) { + super(NumericType.class.getSimpleName(),"Number","数字"); + this.length = length; + this.precision = precision; + } +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/ObjectType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/ObjectType.java new file mode 100644 index 00000000..86b8857d --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/ObjectType.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import com.inspur.edp.web.approvalformat.api.entity.schema.Field; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:44 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class ObjectType extends FieldType { + private List fields; + + public ObjectType(String name, String displayName, List fields) { + super(ObjectType.class.getSimpleName(), name, displayName); + this.fields = fields; + } + + public ObjectType(String $type, String name, String displayName, List fields){ + super($type, name, displayName); + this.fields = fields; + } +} \ No newline at end of file diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/StringType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/StringType.java new file mode 100644 index 00000000..2b85c507 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/StringType.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:45 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class StringType extends FieldType { + private Integer length; + + public StringType(Integer length) { + super(StringType.class.getSimpleName(),"String","字符串"); + this.length = length; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/TextType.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/TextType.java new file mode 100644 index 00000000..3b1a77ff --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/entity/schema/type/TextType.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.approvalformat.api.entity.schema.type; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:45 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TextType extends FieldType { + private Integer length; + + public TextType(Integer length) { + super(TextType.class.getSimpleName(),"Text","文本"); + this.length = length; + } +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/rpcservice/IApprovalFormatRpcService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/rpcservice/IApprovalFormatRpcService.java new file mode 100644 index 00000000..cfa71e8e --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/rpcservice/IApprovalFormatRpcService.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.approvalformat.api.rpcservice; + +import com.inspur.edp.cef.entity.entity.IEntityData; +import io.iec.edp.caf.rpc.api.annotation.GspServiceBundle; +import io.iec.edp.caf.rpc.api.annotation.RpcParam; +import io.iec.edp.caf.rpc.api.annotation.RpcServiceMethod; + +import java.util.List; + +/** + * 审批格式rpc服务 + * @author Xu‘fa Wang + * @date 2020/5/20 12:39 + */ +@GspServiceBundle(applicationName = "runtime",serviceUnitName = "bcc", serviceName = "approval_format") +public interface IApprovalFormatRpcService { + /** + * 基于业务实体id获取实体数据 + * @param dataId 数据id + * @param bizEntityId 业务实体id + * @return 实体数据 + */ + @RpcServiceMethod(serviceId = "com.inspur.edp.web.approvalformat.api.rpcservice.IApprovalFormatRpcService.getEntityDataByBizEntityId") + IEntityData getEntityDataByBizEntityId(@RpcParam(paramName = "dataId") String dataId, + @RpcParam(paramName = "bizEntityId") String bizEntityId); + + /** + * 基于业务实体id(含维度)获取数据 + * @param bizEntityId 业务实体id + * @return 实体数据集合 + */ + @RpcServiceMethod(serviceId = "com.inspur.edp.web.approvalformat.api.rpcservice.IApprovalFormatRpcService.queryEntityData") + List queryEntityData(@RpcParam(paramName = "bizEntityId") String bizEntityId); + + /*** + * 获取业务实体关联审批格式中审批单据uri + * @param businessEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批单据uri + */ + @RpcServiceMethod(serviceId = "com.inspur.edp.web.approvalformat.api.rpcservice.IApprovalFormatRpcService.getApprovalFormUriByBizEntityId") + String getApprovalFormUriByBizEntityId(@RpcParam(paramName = "businessEntityId") String businessEntityId, + @RpcParam(paramName = "firstDimension") String firstDimension, + @RpcParam(paramName = "secondDimension") String secondDimension); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormMetadataService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormMetadataService.java new file mode 100644 index 00000000..e212c099 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormMetadataService.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.approvalformat.api.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatCreateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalViewObjectUpdateRequestBody; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +/** + * 审批表单元数据服务 + * @author Xu‘fa Wang + * @date 2020/5/14 18:17 + */ +public interface ApprovalFormMetadataService { + /** + * 创建审批单据 + * @param approvalFormatCreateRequestBody 审批单据创建请求体 + */ + void createApprovalForm(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody); + + /** + * 创建审批单据视图对象 + * @param approvalFormatCreateRequestBody 审批单据创建请求体 + */ + void createApprovalFormViewObject(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody); + + /** + * 更新审批表单元数据(仅更新元数据内容) + * @param approvalFormUpdateRequestBody 待更新审批单据元数据id + */ + void updateApprovalFormMetadata(ApprovalFormUpdateRequestBody approvalFormUpdateRequestBody); + + /** + * 更新审批视图模型元数据(仅更新元数据内容) + * @param approvalViewObjectUpdateRequestBody 审批视图模型更新请求体 + */ + void updateApprovalViewModelMetadata(ApprovalViewObjectUpdateRequestBody approvalViewObjectUpdateRequestBody); + + /** + * 基于id获取审批表单元数据内容 + * @param approvalFormMetadataId 审批单据id + * @return 审批单据元数据内容 + */ + FormMetadataContent getApprovalFormMetadataContent(String approvalFormMetadataId); + + /** + * 基于voContent创建表单Schema + * @param voContent 视图对象内容 + * @return schema json串 + */ + String createSchemaFromVo(JsonNode voContent); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormatService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormatService.java new file mode 100644 index 00000000..937de23f --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/ApprovalFormatService.java @@ -0,0 +1,185 @@ +package com.inspur.edp.web.approvalformat.api.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.web.approvalformat.api.entity.*; + +import java.util.List; +import java.util.Map; + +/** + * 审批格式服务 + * @author Xu‘fa Wang + * @date 2020/5/14 19:53 + */ +public interface ApprovalFormatService { + /** + * 获取含维度信息的审批单据树集合 + * @param billCategoryId 单据种类id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @return ApprovalFormatForestByDimension 基于维度的审批格式树集合 + */ + ApprovalFormatForestByDimension getApprovalFormatByDimension(String billCategoryId, String billCategoryExtendCode); + + /** + * 基于业务实体id获取实体数据 + * @param dataId 数据id + * @param bizEntityId 业务实体id + * @return 实体数据 + */ + Map getEntityDataByBizEntityId(String dataId, String bizEntityId); + + /** + * 基于业务实体配置id获取实体数据 + * @param dataId 数据id + * @param bizEntityConfigId 业务实体配置id + * @return 实体数据 + */ + @Deprecated + IEntityData getEntityDataByBizEntityConfigId(String dataId, String bizEntityConfigId); + + /** + * 基于业务实体id(含维度)获取数据 + * @param bizEntityId 业务实体id + * @return 实体数据集合 + */ + List queryEntityData(String bizEntityId); + + + List queryEntityDataWithCondition(JsonNode queryStringMap); + + /** + * 创建审批格式实例 + * @param approvalFormatCreateRequestBody 审批格式创建请求体 + * @return ApprovalFormatCreateResponseBody 审批格式创建返回体实例 + */ + ApprovalFormatCreateResponseBody createApprovalFormat(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody); + + /** + * 创建审批格式 + * @param approvalFormatCreateRequestBody 审批格式创建请求体 + * @return ApprovalFormat 审批格式实例 + */ + ApprovalFormat createApprovalFormatRelation(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody); + + /** + * 删除审批格式实例(仅删除审批格式) + * @param approvalFormatId 审批格式id + */ + void deleteApprovalFormat(String approvalFormatId); + + /** + * 删除审批格式实例 + * @param billCategoryId 审批格式关联单据种类id + * @param metadataId 审批格式关联元数据id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + */ + @Deprecated + void deleteApprovalFormatAndRelation(String billCategoryId, String metadataId, String firstDimension, String secondDimension); + + /** + * 删除审批格式实例及关联数据 + * @param id 审批格式id + */ + void deleteApprovalFormatAndRelationById(String id); + + /** + * 更新审批格式实例 + * @param approvalFormatUpdateRequestBody 审批格式更新请求体 + * @return 更新后ApprovalFormat实例 + */ + ApprovalFormat updateApprovalFormat(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody); + + ApprovalFormat updateApprovalFormatFormUrl(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody); + /** + * 更新审批格式维度 + * @param approvalFormatDimensionUpdateRequestBody 审批格式维度更新请求体 + * @return 更新后ApprovalFormat实例 + */ + ApprovalFormat updateApprovalFormatDimension(ApprovalFormatDimensionUpdateRequestBody approvalFormatDimensionUpdateRequestBody); + + /** + * 基于ID查询审批格式 + * @param approvalFormatId 审批格式id + * @return 审批格式实例 + */ + ApprovalFormat getApprovalFormatEntityById(String approvalFormatId); + + /** + * 基于单据种类id获取审批格式 + * @param billCategoryId 单据种类id + * @return 审批格式实例集合 + */ + List getApprovalFormatCollection(String billCategoryId); + + /** + * 基于单据种类id获取审批格式并按照维度排序 + * @param billCategoryId 单据种类Id + * @return 审批格式实例集合 + */ + @Deprecated + List getApprovalFormatCollectionOrderByDimension(String billCategoryId); + + /** + * 基于单据种类id获取已排序(基于维度)审批格式集合 + * @param billCategoryId 单据种类Id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @return 审批格式实例集合 + */ + List getApprovalFormatCollectionOrderByDimension(String billCategoryId, String billCategoryExtendCode); + + /** + * 基于ID复制审批格式 + * @param approvalFormatId 审批格式id + */ + void replicateApprovalFormat(String approvalFormatId); + + /** + * 基于业务实体ID获取审批格式实例 + * @param businessEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批格式实例 + */ + ApprovalFormat getApprovalFormatByBizEntityIdWithDimension(String businessEntityId, String firstDimension, String secondDimension); + + /** + * 基于单据种类ID获取审批格式实例 + * @param billCategoryId 单据种类Id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批格式实例 + */ + ApprovalFormat getApprovalFormatByBillCategoryIdWithDimension(String billCategoryId, String firstDimension, String secondDimension); + + /*** + * 获取业务实体关联审批格式中审批单据uri + * @param businessEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批单据uri + */ + String getApprovalFormUri(String businessEntityId, String firstDimension, String secondDimension); + + /*** + * 获取单据种类关联审批格式的审批单据uri + * @param billCategoryId 单据种类id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批单据uri + */ + String getApprovalFormUriByBillCategoryId( String billCategoryId, String firstDimension, String secondDimension); + + /*** + * 获取帮助数据 + * @param billCategoryId 单据种类id + * @param dimensionId 维度id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @param billCategoryDimensionItemId 单据种类维度项id + * @return 帮助结果 + */ + HelpProviderResult getHelpProviderData(String billCategoryId, String billCategoryExtendCode, String dimensionId, String billCategoryDimensionItemId); + + +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/BusinessEntityService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/BusinessEntityService.java new file mode 100644 index 00000000..e5424408 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/BusinessEntityService.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.approvalformat.api.service; + +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * 业务实体服务 + * @author Xu‘fa Wang + * @date 2020/5/14 18:07 + */ +public interface BusinessEntityService { + /** + * 基于业务实体Id获取业务实体实例 + * @param bizEntityId 业务实体id + * @return 业务实体实例 + */ + GspBusinessEntity getBusinessEntity(String bizEntityId); + + /** + * 基于业务实体Id获取业务实体元数据 + * @param bizEntityId 业务实体id + * @return 业务实体实例 + */ + GspMetadata getBusinessEntityMetadata(String bizEntityId); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/DimensionService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/DimensionService.java new file mode 100644 index 00000000..041b05d3 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/DimensionService.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.approvalformat.api.service; + +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; + +import java.util.List; + +/** + * 维度服务接口 + * @author Xu‘fa Wang + * @date 2020/5/13 19:59 + */ +public interface DimensionService { + /** + * 基于单据种类Id和单据种类扩展码获取维度 + * @param billCategoryId 单据种类Id + * @param billCategoryExtendCode 单据种类扩展码 + * @return 单据种类维度实例 + */ + BillCategoryDimension getDimension(String billCategoryId, String billCategoryExtendCode); + + /** + * 基于单据种类Id获取维度集合 + * @param billCategoryId 单据种类Id + * @return 单据种类维度实例集合 + */ + List getDimensionCollection(String billCategoryId); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/IRuntimeMetadataService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/IRuntimeMetadataService.java new file mode 100644 index 00000000..24692986 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/service/IRuntimeMetadataService.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.approvalformat.api.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * 元数据运行时服务 + * @author Xu‘fa Wang + * @date 2020/5/18 14:28 + */ +public interface IRuntimeMetadataService { + /** + * 基于维度获取元数据 + * @param metadataId 元数据id + * @param metadataCertificateId 元数据证书id + * @param firstDimension 第一维度名称 + * @param secondDimension 第二维度名称 + * @return 获取的元数据实例 + */ + GspMetadata getMetadataByIdWithDimension(String metadataId, + String metadataCertificateId, + String firstDimension, + String secondDimension); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormMetadataWebService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormMetadataWebService.java new file mode 100644 index 00000000..df691039 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormMetadataWebService.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.approvalformat.api.webservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalViewObjectUpdateRequestBody; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; + +/** + * 审批单据元数据web服务 + * @author Xu‘fa Wang + * @date 2020/5/17 17:54 + */ +@Path("/metadata") +public interface ApprovalFormMetadataWebService { + + /** + * 更新审批表单元数据(仅更新元数据内容) + * @param approvalFormUpdateRequestBody 审批单据更新请求体 + */ + @PUT + @Path("/") + void updateApprovalFormMetadata(@RequestBody ApprovalFormUpdateRequestBody approvalFormUpdateRequestBody); + + /** + * 更新审批视图模型元数据(仅更新元数据内容) + * @param approvalViewObjectUpdateRequestBody 审批视图模型更新请求体 + */ + @PUT + @Path("/viewmodel/") + void updateApprovalViewModelMetadata(@RequestBody ApprovalViewObjectUpdateRequestBody approvalViewObjectUpdateRequestBody); + + /** + * 基于id获取审批表单元数据内容 + * @param approvalFormMetadataId 审批单据id + * @return 审批单据元数据内容 + */ + @GET + @Path("/{formMetadataId}") + FormMetadataContent getApprovalFormMetadataContent(@PathParam("formMetadataId") String approvalFormMetadataId); + + /** + * 基于voContent创建表单Schema + * @param voContent 视图对象内容 + * @return schema json串 + */ + @POST + @Path("/schema") + String createSchemaFromVo(@RequestBody JsonNode voContent); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormatWebService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormatWebService.java new file mode 100644 index 00000000..49501767 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/ApprovalFormatWebService.java @@ -0,0 +1,238 @@ +package com.inspur.edp.web.approvalformat.api.webservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.web.approvalformat.api.entity.*; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; +import java.util.Map; + +/** + * 审批格式 web 服务 + * @author Xu‘fa Wang + * @date 2020/5/15 10:06 + */ +@Path("/format") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface ApprovalFormatWebService { + /** + * 获取含维度信息的审批单据树集合 + * @param billCategoryId 单据种类Id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @return ApprovalFormatForestByDimension 基于维度的审批格式树集合 + */ + @GET + @Path("/dimension/{billCategoryId}/{billCategoryExtendCode}") + @Deprecated + ApprovalFormatForestByDimension getApprovalFormatByDimension(@PathParam("billCategoryId") String billCategoryId, @PathParam("billCategoryExtendCode") String billCategoryExtendCode); + + /** + * 基于业务实体id获取实体数据 + * @param dataId 数据id + * @param bizEntityId 业务实体id + * @return 实体数据 + */ + @GET + @Path("/entity/data/{dataId}/{bizEntityId}") + Map getEntityDataByBizEntityId(@PathParam("dataId") String dataId, + @PathParam("bizEntityId") String bizEntityId); + + /** + * 基于业务实体id获取实体数据 + * @param dataId 数据id + * @param bizEntityConfigId 业务实体配置id + * @return 实体数据 + */ + @GET + @Path("/entity/data/configid/{dataId}/{bizEntityConfigId}") + @Deprecated + IEntityData getEntityDataByBizEntityConfigId(@PathParam("dataId") String dataId, + @PathParam("bizEntityConfigId") String bizEntityConfigId); + + /** + * 基于业务实体id(含维度)获取数据 + * @param bizEntityId 业务实体id + * @return 实体数据集合 + */ + @GET + @Path("/entity/data/query/{bizEntityId}") + List queryEntityData(@PathParam("bizEntityId") String bizEntityId); + + /** + * 基于业务实体id(含维度)和条件获取数据 + * @param condition + * @return + */ + @POST + @Path("/entity/data/query") + List queryEntityDataWithCondition(@RequestBody JsonNode condition); + /** + * 创建审批格式实例 + * @param approvalFormatCreateRequestBody 审批格式创建请求体 + * @return ApprovalFormatCreateResponseBody 审批格式创建返回体实例 + */ + @POST + @Path("/") + ApprovalFormatCreateResponseBody createApprovalFormat(@RequestBody ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody); + + /** + * 删除审批格式实例(仅删除审批格式) + * @param approvalFormatId 审批格式id + */ + @DELETE + @Path("/{id}") + @Deprecated + void deleteApprovalFormat(@PathParam("id") String approvalFormatId); + + /** + * 删除审批格式实例 + * @param billCategoryId 审批格式关联单据种类id + * @param metadataId 审批格式关联元数据id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + */ + @DELETE + @Path("/{billCategoryId}/{metadataId}/{firstDimension}/{secondDimension}") + @Deprecated + void deleteApprovalFormatAndRelation(@PathParam("billCategoryId") String billCategoryId, + @PathParam("metadataId") String metadataId, + @PathParam("firstDimension") String firstDimension, + @PathParam("secondDimension") String secondDimension); + + /** + * 删除审批格式实例及关联数据 + * @param id 审批格式id + */ + @DELETE + @Path("/relation/{id}") + void deleteApprovalFormatAndRelationById(@PathParam("id") String id); + + /** + * 更新审批格式的formUrl + * @param approvalFormatUpdateRequestBody 审批格式更新请求体 + * @return 更新后ApprovalFormat实例 + */ + @PUT + @Path("/formUrl") + ApprovalFormat updateApprovalFormatFormUrl(@RequestBody ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody); + + /** + * 更新审批格式实例 + * @param approvalFormatUpdateRequestBody 审批格式更新请求体 + * @return 更新后ApprovalFormat实例 + */ + @PUT + @Path("/") + ApprovalFormat updateApprovalFormat(@RequestBody ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody); + + /** + * 更新审批格式维度 + * @param approvalFormatDimensionUpdateRequestBody 审批格式更新请求体 + * @return 更新后ApprovalFormat实例 + */ + @PUT + @Path("/dimension") + ApprovalFormat updateApprovalFormatDimension(@RequestBody ApprovalFormatDimensionUpdateRequestBody approvalFormatDimensionUpdateRequestBody); + + /** + * 基于ID查询审批格式 + * @param approvalFormatId 审批格式id + * @return 审批格式实例 + */ + @GET + @Path("/{id}") + ApprovalFormat getApprovalFormatEntityById(@PathParam("id") String approvalFormatId); + + /** + * 基于单据种类id获取审批格式 + * @param billCategoryId 单据种类Id + * @return 审批格式实例集合 + */ + @GET + @Path("/list/{billCategoryId}") + List getApprovalFormatCollection(@PathParam("billCategoryId") String billCategoryId); + + /** + * 基于单据种类id获取已排序(基于维度)审批格式集合 + * @param billCategoryId 单据种类Id + * @return 审批格式实例集合 + */ + @GET + @Path("/order/list/{billCategoryId}") + @Deprecated + List getApprovalFormatCollectionOrderByDimension(@PathParam("billCategoryId") String billCategoryId); + + /** + * 基于单据种类id获取已排序(基于维度)审批格式集合 + * @param billCategoryId 单据种类Id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @return 审批格式实例集合 + */ + @GET + @Path("/order/list/{billCategoryId}/{billCategoryExtendCode}") + List getApprovalFormatCollectionOrderByDimension(@PathParam("billCategoryId") String billCategoryId, @PathParam("billCategoryExtendCode") String billCategoryExtendCode); + + /** + * 基于ID复制审批格式 + * @param approvalFormatId 审批格式id + */ + @PUT + @Path("/replicate/{id}") + void replicateApprovalFormat(@PathParam("id") String approvalFormatId); + + /** + * 基于业务实体ID和审批格式维度获取审批格式实例 + * @param businessEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批格式实例 + */ + @GET + @Path("/business/entity/{bizEntityId}/{firstDimension}/{secondDimension}") + @Deprecated + ApprovalFormat getApprovalFormatByBizEntityIdWithDimension(@PathParam("bizEntityId") String businessEntityId, + @PathParam("firstDimension") String firstDimension, + @PathParam("secondDimension") String secondDimension); + + /*** + * 获取业务实体关联审批格式中审批单据uri + * @param businessEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批单据uri + */ + @GET + @Path("/form/url/{bizEntityId}/{firstDimension}/{secondDimension}") + String getApprovalFormUri(@PathParam("bizEntityId") String businessEntityId, @PathParam("firstDimension") String firstDimension, @PathParam("secondDimension") String secondDimension); + + /*** + * 获取单据种类关联审批格式的审批单据uri + * @param billCategoryId 单据种类id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批单据uri + */ + @GET + @Path("/billcategory/form/uri/{billCategoryId}/{firstDimension}/{secondDimension}") + String getApprovalFormUriByBillCategoryId(@PathParam("billCategoryId") String billCategoryId, @PathParam("firstDimension") String firstDimension, @PathParam("secondDimension") String secondDimension); + + /*** + * 获取帮助数据 + * @param billCategoryId 单据种类id + * @param billCategoryExtendCode 单据种类可扩展编号 + * @param dimensionId 维度id + * @param billCategoryDimensionItemId 单据种类维度项id + * @return 帮助结果 + */ + @GET + @Path("/lookup/{billCategoryId}/{billCategoryExtendCode}/{dimensionId}/{billCategoryDimensionItemId}") + HelpProviderResult getHelpProviderData(@PathParam("billCategoryId") String billCategoryId, + @PathParam("billCategoryExtendCode") String billCategoryExtendCode, + @PathParam("dimensionId") String dimensionId, + @PathParam("billCategoryDimensionItemId") String billCategoryDimensionItemId); + +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/BusinessEntityWebService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/BusinessEntityWebService.java new file mode 100644 index 00000000..339ded10 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/BusinessEntityWebService.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.approvalformat.api.webservice; + +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * 业务实体 web 服务 + * @author Xu‘fa Wang + * @date 2020/5/14 17:40 + */ +@Path("/business/entity") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface BusinessEntityWebService { + /** + * 基于业务实体Id获取业务实体实例 + * @param bizEntityId 业务实体id + * @return 业务实体实例 + */ + @GET + @Path("/{bizEntityId}") + GspBusinessEntity getBusinessEntity(@PathParam("bizEntityId") String bizEntityId); + + /** + * 基于业务实体Id获取业务实体元数据 + * @param bizEntityId 业务实体id + * @return 业务实体实例 + */ + @GET + @Path("/metadata/{bizEntityId}") + GspMetadata getBusinessEntityMetadata(@PathParam("bizEntityId") String bizEntityId); +} diff --git a/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/DimensionWebService.java b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/DimensionWebService.java new file mode 100644 index 00000000..7a825cc0 --- /dev/null +++ b/web-approval-format-api/src/main/java/com/inspur/edp/web/approvalformat/api/webservice/DimensionWebService.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.approvalformat.api.webservice; + +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; + +/** + * 维度 web 服务 + * @author Xu‘fa Wang + * @date 2020/5/14 9:24 + */ +@Path("/dimension") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface DimensionWebService { + /** + * 基于单据种类Id和单据种类扩展码获取维度 + * @param billCategoryId 单据种类Id + * @param billCategoryExtendCode 单据种类扩展码 + * @return 单据种类维度实例 + */ + @GET + @Path("/{billCategoryId}/{billCategoryExtendCode}") + BillCategoryDimension getDimension(@PathParam("billCategoryId") String billCategoryId, @PathParam("billCategoryExtendCode") String billCategoryExtendCode); + + /** + * 基于单据种类Id获取维度集合 + * @param billCategoryId 单据种类Id + * @return 单据种类维度实例集合 + */ + @GET + @Path("/list/{billCategoryId}") + List getDimensionCollection(@PathParam("billCategoryId") String billCategoryId); +} diff --git a/web-approval-format-core/pom.xml b/web-approval-format-core/pom.xml new file mode 100644 index 00000000..7d2e1a73 --- /dev/null +++ b/web-approval-format-core/pom.xml @@ -0,0 +1,81 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-approval-format-core + + + com.inspur.edp + web-approval-format-api + + + com.inspur.edp + runtime-customize-api + + + com.inspur.edp + metadata-rtcustomization-api + + + com.inspur.edp + metadata-rtcustomization-core + + + com.inspur.edp + lcm-metadata-rtservice + + + com.inspur.edp + lcm-metadata-core + + + com.inspur.edp + lcm-metadata-common + + + com.inspur.edp + metadata-businesstype-api + + + com.inspur.edp + web-help-api + + + io.iec.edp + caf-business-object-api + + + com.inspur.edp + cef-entity + + + com.inspur.edp + bcc-billcategory-api + + + com.inspur.edp + bef-api + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + + + io.iec.edp + caf-framework-licservice-api + 0.1.1 + + + + diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/config/ApprovalFormatConfiguration.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/config/ApprovalFormatConfiguration.java new file mode 100644 index 00000000..31cb7a5e --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/config/ApprovalFormatConfiguration.java @@ -0,0 +1,127 @@ +package com.inspur.edp.web.approvalformat.core.config; + +import com.inspur.edp.web.approvalformat.api.rpcservice.IApprovalFormatRpcService; +import com.inspur.edp.web.approvalformat.api.service.*; +import com.inspur.edp.web.approvalformat.api.webservice.ApprovalFormMetadataWebService; +import com.inspur.edp.web.approvalformat.api.webservice.ApprovalFormatWebService; +import com.inspur.edp.web.approvalformat.api.webservice.BusinessEntityWebService; +import com.inspur.edp.web.approvalformat.api.webservice.DimensionWebService; +import com.inspur.edp.web.approvalformat.core.domain.manager.ApprovalFormatManager; +import com.inspur.edp.web.approvalformat.core.domain.repository.ApprovalFormatRepository; +import com.inspur.edp.web.approvalformat.core.rpcservice.ApprovalFormatRpcServiceImpl; +import com.inspur.edp.web.approvalformat.core.service.*; +import com.inspur.edp.web.approvalformat.core.webservice.ApprovalFormMetadataWebServiceImpl; +import com.inspur.edp.web.approvalformat.core.webservice.ApprovalFormatWebServiceImpl; +import com.inspur.edp.web.approvalformat.core.webservice.BusinessEntityWebServiceImpl; +import com.inspur.edp.web.approvalformat.core.webservice.DimensionWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +/** + * 审批格式配置 + * @author Xu‘fa Wang + * @date 2020/5/14 16:18 + */ +@Configuration(proxyBeanMethods = false) +@EnableJpaRepositories("com.inspur.edp.web.approvalformat.core.domain.repository") +@EntityScan({"com.inspur.edp.web.approvalformat.core.domain.entity"}) +public class ApprovalFormatConfiguration { + /** + * TODO: 迁移到constant中 + */ + private final String KEY_APPLICATION_NAME = "runtime"; + private final String SERVICE_UNIT_NAME = "bcc"; + private final String BASE_PATH_NAME = "approval"; + private final String VERSION = "v1.0"; + private final String SEPARATOR = "/"; + + /** + * 审批格式 Web Service 基础 Uri + * uri实例如下: + * "/runtime/bcc/v1.0" + */ + private final String APPROVAL_FORMAT_WEB_SERVICE_BASE_URI = SEPARATOR + + KEY_APPLICATION_NAME + SEPARATOR + + SERVICE_UNIT_NAME + SEPARATOR + + VERSION + SEPARATOR + + BASE_PATH_NAME; + + @Bean + public ApprovalFormatManager approvalFormatManager(ApprovalFormatRepository repository) { + return new ApprovalFormatManager(repository); + } + + @Bean + public IRuntimeMetadataService runtimeMetadataService() { + return new RuntimeMetadataServiceImpl(); + } + + @Bean + public DimensionService dimensionService() { + return new DimensionServiceImpl(); + } + + @Bean + public DimensionWebService dimensionWebService(DimensionService dimensionService) { + return new DimensionWebServiceImpl(dimensionService); + } + + @Bean + public BusinessEntityService businessEntityService() { + return new BusinessEntityServiceImpl(); + } + + @Bean + public BusinessEntityWebService businessEntityWebService(BusinessEntityService businessEntityService) { + return new BusinessEntityWebServiceImpl(businessEntityService); + } + + @Bean + public ApprovalFormMetadataService approvalFormMetadataService() { + return new ApprovalFormMetadataServiceImpl(); + } + + @Bean + public ApprovalFormMetadataWebService approvalFormMetadataWebService(ApprovalFormMetadataService approvalFormMetadataService) { + return new ApprovalFormMetadataWebServiceImpl(approvalFormMetadataService); + } + + @Bean + public ApprovalFormatService approvalFormatService(DimensionService dimensionService, ApprovalFormatManager approvalFormatManager) { + return new ApprovalFormatServiceImpl(dimensionService, approvalFormatManager); + } + + @Bean + public ApprovalFormatWebService approvalFormatWebService(ApprovalFormatService approvalFormatService) { + return new ApprovalFormatWebServiceImpl(approvalFormatService); + } + + /** + * 构造RESTEndpoint实例,用来组装WebService,以发布 Web API + * @param dimensionWebService 维度服务 + * @param approvalFormatWebService 审批格式服务 + * @return RESTEndpoint实例 + */ + @Bean + public RESTEndpoint dimensionWebServiceEndPoint(ApprovalFormatWebService approvalFormatWebService, + DimensionWebService dimensionWebService, + BusinessEntityWebService businessEntityWebService, + ApprovalFormMetadataWebService approvalFormMetadataWebService) { + return new RESTEndpoint(APPROVAL_FORMAT_WEB_SERVICE_BASE_URI, + approvalFormatWebService, + dimensionWebService, + businessEntityWebService, + approvalFormMetadataWebService); + } + /** + * RPC服务的bean + * @return IApprovalFormatRpcService 实例化对象 + */ + @Bean + public IApprovalFormatRpcService approvalFormatRpcService(ApprovalFormatService approvalFormatService) { + return new ApprovalFormatRpcServiceImpl(approvalFormatService); + } +} \ No newline at end of file diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/converter/ApprovalFormatConverter.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/converter/ApprovalFormatConverter.java new file mode 100644 index 00000000..e1dea3a7 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/converter/ApprovalFormatConverter.java @@ -0,0 +1,85 @@ +package com.inspur.edp.web.approvalformat.core.domain.converter; + +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormat; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatCreateResponseBody; +import com.inspur.edp.web.approvalformat.core.domain.entity.ApprovalFormatDO; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Xu‘fa Wang + * @date 2020/5/16 20:52 + */ +public class ApprovalFormatConverter { + /** + * VO转DO + * @param entity + * @return + */ + public static ApprovalFormatDO toDo(ApprovalFormat entity) { + ApprovalFormatDO approvalFormatDO = new ApprovalFormatDO(); + + approvalFormatDO.setId(entity.getId()); + approvalFormatDO.setDim1(entity.getFirstDimension()); + approvalFormatDO.setDim2(entity.getSecondDimension()); + approvalFormatDO.setBillCategoryId(entity.getBillCategoryId()); + approvalFormatDO.setBeId(entity.getBizEntityId()); + approvalFormatDO.setVoId(entity.getViewObjectId()); + approvalFormatDO.setFormId(entity.getApprovalFormId()); + approvalFormatDO.setFormUrl(entity.getApprovalFormPublishUri()); + + return approvalFormatDO; + } + + public static ApprovalFormat toVo(ApprovalFormatDO entity) { + ApprovalFormat approvalFormat = new ApprovalFormat(); + if(entity == null) { + return null; + } + + approvalFormat.setId(entity.getId()); + + // 统一不同类型数据库返回 ""和null不一致的问题 + approvalFormat.setFirstDimension(entity.getDim1() == null || entity.getDim1().isEmpty() ? "" : entity.getDim1()); + approvalFormat.setSecondDimension(entity.getDim2() == null || entity.getDim2().isEmpty() ? "" : entity.getDim2()); + + approvalFormat.setBillCategoryId(entity.getBillCategoryId()); + approvalFormat.setBizEntityId(entity.getBeId()); + approvalFormat.setViewObjectId(entity.getVoId()); + approvalFormat.setApprovalFormId(entity.getFormId()); + approvalFormat.setApprovalFormPublishUri(entity.getFormUrl()); + + return approvalFormat; + } + + public static List toVo(List entityList) { + List voList = new ArrayList<>(); + if(entityList == null || entityList.size() == 0) { + return voList; + } + + for (ApprovalFormatDO entity: entityList) { + voList.add(ApprovalFormatConverter.toVo(entity)); + } + + return voList; + } + + public static ApprovalFormatCreateResponseBody toCreateResponseBody(ApprovalFormat approvalFormat) { + ApprovalFormatCreateResponseBody approvalFormatCreateResponseBody = new ApprovalFormatCreateResponseBody(); + + approvalFormatCreateResponseBody.setId(approvalFormat.getId()); + approvalFormatCreateResponseBody.setCode(approvalFormat.getCode()); + approvalFormatCreateResponseBody.setName(approvalFormat.getName()); + approvalFormatCreateResponseBody.setFirstDimension(approvalFormat.getFirstDimension()); + approvalFormatCreateResponseBody.setSecondDimension(approvalFormat.getSecondDimension()); + approvalFormatCreateResponseBody.setBillCategoryId(approvalFormat.getBillCategoryId()); + approvalFormatCreateResponseBody.setBizEntityId(approvalFormat.getBizEntityId()); + approvalFormatCreateResponseBody.setViewObjectId(approvalFormat.getViewObjectId()); + approvalFormatCreateResponseBody.setApprovalFormId(approvalFormat.getApprovalFormId()); + approvalFormatCreateResponseBody.setApprovalFormPublishUri(approvalFormat.getApprovalFormPublishUri()); + + return approvalFormatCreateResponseBody; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/entity/ApprovalFormatDO.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/entity/ApprovalFormatDO.java new file mode 100644 index 00000000..08ef12ed --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/entity/ApprovalFormatDO.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.approvalformat.core.domain.entity; + +import lombok.Data; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * @author Xu‘fa Wang + * @date 2020/5/16 20:27 + */ +@Data +@Entity +@Table(name="gspapprovalformat") +public class ApprovalFormatDO { + @Id + private String id; + private String dim1; + private String dim2; + private String billCategoryId; + private String beId; + private String voId; + private String formId; + private String formUrl; +} \ No newline at end of file diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/manager/ApprovalFormatManager.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/manager/ApprovalFormatManager.java new file mode 100644 index 00000000..74e64b62 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/manager/ApprovalFormatManager.java @@ -0,0 +1,213 @@ +package com.inspur.edp.web.approvalformat.core.domain.manager; + +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormat; +import com.inspur.edp.web.approvalformat.core.domain.converter.ApprovalFormatConverter; +import com.inspur.edp.web.approvalformat.core.domain.entity.ApprovalFormatDO; +import com.inspur.edp.web.approvalformat.core.domain.repository.ApprovalFormatRepository; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +/** + * @author Xu‘fa Wang + * @date 2020/5/16 20:44 + */ +public class ApprovalFormatManager { + private final ApprovalFormatRepository repository; + public ApprovalFormatManager(ApprovalFormatRepository repository) { + this.repository = repository; + } + + /** + * 根据 bizEntity id 获取审批格式 + * @param bizEntityId 业务实体id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批格式集合 + */ + public List getApprovalFormatByBeIdWithFirstDimensionAndSecondDimension(String bizEntityId, String firstDimension, String secondDimension) { + List list = null; + + if(firstDimension == null || firstDimension.isEmpty()) { + if(secondDimension == null || secondDimension.isEmpty()) { + list = this.repository.findAllByBeIdAndDim1IsNullAndDim2IsNull(bizEntityId); + } else { + //throw new RuntimeException("第一维度为空时,第二维度必须为空。请联系开发人员处理"); + list = this.repository.findAllByBeIdAndDim1IsNullAndDim2IsNull(bizEntityId); + } + } else { + if(secondDimension == null || secondDimension.isEmpty()) { + list = this.repository.findAllByBeIdAndDim1AndDim2IsNull(bizEntityId, firstDimension); + } else { + list = this.repository.findAllByBeIdAndDim1AndDim2(bizEntityId, firstDimension, secondDimension); + //尝试查找firstDimension-public + if(list == null || list.size() <= 0) { + list = this.repository.findAllByBeIdAndDim1AndDim2IsNull(bizEntityId, firstDimension); + } + } + + // 如果根据第一维度或第二维度未获取到数据,则尝试基于beId取数 + if(list == null || list.size() <= 0) { + list = this.repository.findAllByBeIdAndDim1IsNullAndDim2IsNull(bizEntityId); + } + } + + return ApprovalFormatConverter.toVo(list); + } + + /** + * 根据 billCategory id 和维度获取审批格式 + * @param billCategoryId 单据种类id + * @param firstDimension 审批格式第一维度 + * @param secondDimension 审批格式第二维度 + * @return 审批格式集合 + */ + public List getApprovalFormatByBillCategoryIdWithFirstDimensionAndSecondDimension(String billCategoryId, String firstDimension, String secondDimension) { + List list = null; + + if(firstDimension == null || firstDimension.isEmpty()) { + if(secondDimension == null || secondDimension.isEmpty()) { + list = this.repository.findAllByBillCategoryIdAndDim1IsNullAndDim2IsNull(billCategoryId); + } else { + //throw new RuntimeException("第一维度为空时,第二维度必须为空。请联系开发人员处理"); + list = this.repository.findAllByBillCategoryIdAndDim1IsNullAndDim2IsNull(billCategoryId); + } + } else { + if(secondDimension == null || secondDimension.isEmpty()) { + list = this.repository.findAllByBillCategoryIdAndDim1AndDim2IsNull(billCategoryId, firstDimension); + } else { + list = this.repository.findAllByBillCategoryIdAndDim1AndDim2(billCategoryId, firstDimension, secondDimension); + //尝试查找firstDimension-public + if(list == null || list.size() <= 0) { + list = this.repository.findAllByBillCategoryIdAndDim1AndDim2IsNull(billCategoryId, firstDimension); + } + } + // 扩展找不到,返回基础 + if(list == null || list.size()<=0) { + list = this.repository.findAllByBillCategoryIdAndDim1IsNullAndDim2IsNull(billCategoryId); + } + } + + return ApprovalFormatConverter.toVo(list); + } + + /** + * 根据 billCategory id 获取审批格式 + * @param billCategoryId 单据种类id + * @return 审批格式集合 + */ + public List getApprovalFormatByBillCategoryId(String billCategoryId) { + List list = this.repository.findAllByBillCategoryId(billCategoryId); + return ApprovalFormatConverter.toVo(list); + } + + /** + * 根据 billCategory id 获取审批格式并根据维度排序 + * @param billCategoryId 单据种类id + * @return 审批格式集合 + */ + public List getApprovalFormatByBillCategoryIdAndOrderByDimension(String billCategoryId) { + // TODO: 使用 JPA 方式实现排序 + List list = this.repository.findAllByBillCategoryIdAndOrderByDimension(billCategoryId); + return ApprovalFormatConverter.toVo(list); + } + + /** + * 根据 formId id 获取审批格式 + * @param formId 表单id + * @return 审批格式集合 + */ + public List getApprovalFormatByFormId(String formId) { + if(formId == null || formId.isEmpty()) { + return null; + } + List list = this.repository.findAllByFormId(formId); + return ApprovalFormatConverter.toVo(list); + } + + /** + * 根据 id 获取审批格式 + * @param id 审批格式id + * @return 审批格式实例 + */ + public ApprovalFormat getApprovalFormatById(String id) { + Optional optional = this.repository.findById(id); + if(!optional.isPresent()) { + return null; + } + + ApprovalFormatDO entity = optional.get(); + return ApprovalFormatConverter.toVo(entity); + } + + /** + * 删除审批格式实例 + * @param id 审批格式id + */ + public void deleteApprovalFormatById(String id) { + if(id == null ) { + return; + } + + this.repository.deleteById(id); + } + + /** + * 添加审批格式实例 + * @param relation 审批格式DO + * @return ApprovalFormat 审批格式VO + */ + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) + public ApprovalFormat add(ApprovalFormatDO relation) { + ApprovalFormatDO entity = this.repository.save(relation); + return ApprovalFormatConverter.toVo(entity); + } + + /** + * 更新审批格式的formUrl + * @param relation 审批格式DO + * @return ApprovalFormat 审批格式VO + */ + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) + public ApprovalFormat updateFormUrl(ApprovalFormatDO relation) { + ApprovalFormatDO entity = this.repository.save(relation); + return ApprovalFormatConverter.toVo(entity); + } + /** + * 保存审批格式实例 + * @param relation 审批格式DO + * @return ApprovalFormat 审批格式VO + */ + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) + public ApprovalFormat save(ApprovalFormatDO relation) { + ApprovalFormatDO entity = this.repository.save(relation); + return ApprovalFormatConverter.toVo(entity); + } + + public boolean checkIfExistsById(String id) { + return this.repository.existsById(id); + } + + public boolean checkIfExistsByBillCategoryIdAndDimension(ApprovalFormatDO approvalFormatDO) { + ExampleMatcher matcher = ExampleMatcher.matching() + .withMatcher("billCategoryId", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.EXACT)) + .withMatcher("dim1", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.EXACT)) + .withMatcher("dim2", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.EXACT)) + .withIgnorePaths("id", "beId","voId", "formId", "formUrl"); + Example example = Example.of(approvalFormatDO, matcher); + return this.repository.exists(example); + } + + public boolean checkIfExistsByViewModelId(ApprovalFormatDO approvalFormatDO) { + ExampleMatcher matcher = ExampleMatcher.matching() + .withMatcher("voId", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.EXACT)) + .withIgnorePaths("id", "beId","dim1","dim2", "formId", "billCategoryId", "formUrl"); + Example example = Example.of(approvalFormatDO, matcher); + return this.repository.exists(example); + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/repository/ApprovalFormatRepository.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/repository/ApprovalFormatRepository.java new file mode 100644 index 00000000..34b51bce --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/domain/repository/ApprovalFormatRepository.java @@ -0,0 +1,92 @@ +package com.inspur.edp.web.approvalformat.core.domain.repository; + +import com.inspur.edp.web.approvalformat.core.domain.entity.ApprovalFormatDO; +import io.iec.edp.caf.data.orm.DataRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +/** + * 审批格式repo + * @author Xu‘fa Wang + * @date 2020/5/16 20:23 + */ +public interface ApprovalFormatRepository extends DataRepository { + /** + * 基于beId获取所有的审批格式记录 + * @param beId 业务实体id + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE beId = ?1 AND (dim1 = '' OR dim1 is null) AND (dim2 = '' OR dim2 is null)") + List findAllByBeIdAndDim1IsNullAndDim2IsNull(String beId); + + /** + * 基于beId获取所有的审批格式记录 + * @param beId 业务实体id + * @param dim1 审批格式第一维度 + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE beId = ?1 AND dim1 = ?2 AND (dim2 = '' OR dim2 is null)") + List findAllByBeIdAndDim1AndDim2IsNull(String beId, String dim1); + + /** + * 基于beId获取所有的审批格式记录 + * @param beId 业务实体id + * @param dim1 审批格式第一维度 + * @param dim2 审批格式第二维度 + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE beId = ?1 AND dim1 = ?2 AND dim2 = ?3") + List findAllByBeIdAndDim1AndDim2(String beId, String dim1, String dim2); + + /** + * 基于billCategoryId获取所有的审批格式记录 + * @param billCategoryId 单据种类id + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE billCategoryId = ?1") + List findAllByBillCategoryId(String billCategoryId); + + /** + * 基于billCategoryId获取所有的审批格式记录 + * @param billCategoryId 单据种类id + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE billCategoryId = ?1 ORDER BY dim1 ASC, dim2 ASC") + List findAllByBillCategoryIdAndOrderByDimension(String billCategoryId); + + /** + * 基于billCategoryId获取所有的审批格式记录 + * @param billCategoryId 单据种类id + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE billCategoryId = ?1 AND (dim1 = '' OR dim1 is null) AND (dim2 = '' OR dim2 is null)") + List findAllByBillCategoryIdAndDim1IsNullAndDim2IsNull(String billCategoryId); + + /** + * 基于BillCategoryId获取所有的审批格式记录 + * @param billCategoryId 单据种类id + * @param dim1 审批格式第一维度 + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE billCategoryId = ?1 AND dim1 = ?2 AND (dim2 = '' OR dim2 is null)") + List findAllByBillCategoryIdAndDim1AndDim2IsNull(String billCategoryId, String dim1); + + /** + * 基于billCategoryId获取所有的审批格式记录 + * @param billCategoryId 单据种类id + * @param dim1 审批格式第一维度 + * @param dim2 审批格式第二维度 + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE billCategoryId = ?1 AND dim1 = ?2 AND dim2 = ?3") + List findAllByBillCategoryIdAndDim1AndDim2(String billCategoryId, String dim1, String dim2); + + /** + * 基于formId获取所有的审批格式记录 + * @param formId 审批单据id + * @return 审批格式DO集合 + */ + @Query(nativeQuery = true, value = "SELECT * FROM gspapprovalformat WHERE formId = ?1") + List findAllByFormId(String formId); +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/rpcservice/ApprovalFormatRpcServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/rpcservice/ApprovalFormatRpcServiceImpl.java new file mode 100644 index 00000000..39232368 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/rpcservice/ApprovalFormatRpcServiceImpl.java @@ -0,0 +1,95 @@ +package com.inspur.edp.web.approvalformat.core.rpcservice; + +import com.inspur.edp.bef.api.lcp.ILcpFactory; +import com.inspur.edp.bef.api.lcp.IStandardLcp; +import com.inspur.edp.bef.api.services.IBefSessionManager; +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.cef.entity.condition.EntityFilter; +import com.inspur.edp.cef.entity.dependenceTemp.Pagination; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.approvalformat.api.rpcservice.IApprovalFormatRpcService; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormatService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.List; + +/** + * 审批格式RPC服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/20 12:43 + */ +public class ApprovalFormatRpcServiceImpl implements IApprovalFormatRpcService { + private ApprovalFormatService approvalFormatService = SpringBeanUtils.getBean(ApprovalFormatService.class); + private final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + public ApprovalFormatRpcServiceImpl(ApprovalFormatService approvalFormatService) { + if(approvalFormatService != null) { + this.approvalFormatService = approvalFormatService; + } + } + + @Override + public IEntityData getEntityDataByBizEntityId(String dataId, String bizEntityId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = null; + + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + + // 优先基于bizEntityConfigId创建lcp实例 + if(bizEntityMetadata != null) { + GspBusinessEntity businessEntity = (GspBusinessEntity)bizEntityMetadata.getContent(); + String bizEntityConfigId = businessEntity.getGeneratedConfigID(); + + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + } else { + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcpByBEId(bizEntityId); + } + + return lcp.retrieve(dataId).getData(); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + @Override + public List queryEntityData(String bizEntityId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = null; + + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + // 优先基于bizEntityConfigId创建lcp实例 + if(bizEntityMetadata != null) { + GspBusinessEntity businessEntity = (GspBusinessEntity)bizEntityMetadata.getContent(); + String bizEntityConfigId = businessEntity.getGeneratedConfigID(); + + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + } else { + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcpByBEId(bizEntityId); + } + return dividePage(lcp, 20, 1); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + private List dividePage(IStandardLcp lcp, int numberInPage, int pageIndex) { + Pagination pagination = new Pagination(); + pagination.setPageSize(numberInPage); + pagination.setPageIndex(pageIndex); + //pagination.setTotalCount(lcp.query().size()); + EntityFilter entityFilter = new EntityFilter(); + entityFilter.setIsUsePagination(true); + entityFilter.setPagination(pagination); + return lcp.query(entityFilter); + + } + + @Override + public String getApprovalFormUriByBizEntityId(String businessEntityId, String firstDimension, String secondDimension) { + return this.approvalFormatService.getApprovalFormUri(businessEntityId, firstDimension, secondDimension); + } +} + diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormMetadataServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormMetadataServiceImpl.java new file mode 100644 index 00000000..14831bec --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormMetadataServiceImpl.java @@ -0,0 +1,107 @@ +package com.inspur.edp.web.approvalformat.core.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.common.Utils; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatCreateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalViewObjectUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.schema.FormSchema; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormMetadataService; +import com.inspur.edp.web.approvalformat.core.util.ApprovalFormSchemaUtil; +import com.inspur.edp.web.approvalformat.core.util.ApprovalFormUtil; +import com.inspur.edp.web.approvalformat.core.util.ApprovalFormatPermission; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +/** + * 审批单据元数据服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/17 18:10 + */ +public class ApprovalFormMetadataServiceImpl implements ApprovalFormMetadataService { + private final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + @Override + public void updateApprovalFormMetadata(ApprovalFormUpdateRequestBody approvalFormUpdateRequestBody) { + new ApprovalFormatPermission().checkModulePermission(); + String approvalFormMetadataId = approvalFormUpdateRequestBody.getFormMetadataId(); + AbstractMetadataContent approvalFormMetadataContent = approvalFormUpdateRequestBody.getFormMetadataContent(); + + GspMetadata approvalFormMetadata = this.customizationService.getMetadata(approvalFormMetadataId); + if(approvalFormMetadata == null) { + return; + } + approvalFormMetadata.setContent(approvalFormMetadataContent); + + this.customizationService.save(approvalFormMetadata); + } + + @Override + public void updateApprovalViewModelMetadata(ApprovalViewObjectUpdateRequestBody approvalViewObjectUpdateRequestBody) { +// String viewModelId = approvalViewObjectUpdateRequestBody.getViewModelId(); + GspViewModel viewModelContent = approvalViewObjectUpdateRequestBody.getViewModelContent(); + + GspMetadata viewModelMetadata = this.customizationService.getMetadata(viewModelContent.getID()); + if(viewModelMetadata == null) { + return; + } + viewModelMetadata.setContent(viewModelContent); + + this.customizationService.save(viewModelMetadata); + } + + @Override + @Transactional(rollbackFor=Exception.class, propagation = Propagation.REQUIRED) + public void createApprovalForm(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody) { + if(StringUtility.isNullOrEmpty(approvalFormatCreateRequestBody.getBasicFormId())) { + ApprovalFormUtil.createRootApprovalForm(approvalFormatCreateRequestBody, "Form"); + } else { + //永远不会进else 20210825 + ApprovalFormUtil.createChildApprovalForm(approvalFormatCreateRequestBody, "Form"); + } + } + + @Override + @Transactional(rollbackFor=Exception.class, propagation = Propagation.REQUIRED) + public void createApprovalFormViewObject(ApprovalFormatCreateRequestBody request) { + if(StringUtility.isNullOrEmpty(request.getBasicVoId())) { + ApprovalFormUtil.createRootApprovalForm(request, "GSPViewModel"); + } else { + ApprovalFormUtil.createChildApprovalForm(request, "GSPViewModel"); + } + } + + @Override + public FormMetadataContent getApprovalFormMetadataContent(String approvalFormMetadataId) { + new ApprovalFormatPermission().checkModulePermission(); + GspMetadata approvalFormMetadata = this.customizationService.getMetadata(approvalFormMetadataId); + if(approvalFormMetadata == null) { + return null; + } + + return (FormMetadataContent)approvalFormMetadata.getContent(); + } + + @Override + @Transactional(rollbackFor=Exception.class, propagation = Propagation.REQUIRED) + public String createSchemaFromVo(JsonNode voContent) { + try { + ObjectMapper mapper = Utils.getMapper(); + String vmString = mapper.writeValueAsString(voContent); + GspViewModel vm = mapper.readValue(vmString, GspViewModel.class); + FormSchema schema = ApprovalFormSchemaUtil.constructSchema(vm); + return new ObjectMapper().writeValueAsString(schema); + } catch (JsonProcessingException e) { + throw new RuntimeException("Schema序列化失败,id=" + voContent.get("ID")); + } + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormatServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormatServiceImpl.java new file mode 100644 index 00000000..d51b32e8 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/ApprovalFormatServiceImpl.java @@ -0,0 +1,817 @@ +package com.inspur.edp.web.approvalformat.core.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; +import com.inspur.edp.bcc.billcategory.entity.dimension.inputtype.EnumInputInfo; +import com.inspur.edp.bcc.billcategory.entity.dimension.inputtype.EnumItem; +import com.inspur.edp.bcc.billcategory.entity.dimension.inputtype.InputType; +import com.inspur.edp.bcc.billcategory.entity.dimension.inputtype.SmartHelpInputInfo; +import com.inspur.edp.bcc.billcategory.entity.dimension.item.BillCatDimensionItem; +import com.inspur.edp.bef.api.lcp.ILcpFactory; +import com.inspur.edp.bef.api.lcp.IStandardLcp; +import com.inspur.edp.bef.api.services.IBefSessionManager; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.Metadata4Ref; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.common.Utils; +import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.metadata.rtcustomization.api.entity.DimensionExtendEntity; +import com.inspur.edp.web.approvalformat.api.entity.*; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormMetadataService; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormatService; +import com.inspur.edp.web.approvalformat.api.service.DimensionService; +import com.inspur.edp.web.approvalformat.core.domain.converter.ApprovalFormatConverter; +import com.inspur.edp.web.approvalformat.core.domain.entity.ApprovalFormatDO; +import com.inspur.edp.web.approvalformat.core.domain.manager.ApprovalFormatManager; +import com.inspur.edp.web.approvalformat.core.util.*; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.help.api.LookupDataService; +import com.inspur.edp.web.help.api.LookupQueryParam; +import com.inspur.edp.web.help.api.LookupResult; +import com.inspur.edp.web.help.metadata.HelpMetadataContent; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerVersionManager; +import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo; +import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.rpc.api.service.RpcClient; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import com.inspur.edp.sgf.api.service.EapiRuntimeDeployment; +import com.inspur.edp.web.approvalformat.core.util.ApprovalFormatPermission; + +import java.util.*; + +/** + * 维度服务 + * + * @author Xu‘fa Wang + * @date 2020/5/11 16:44 + */ +public class ApprovalFormatServiceImpl implements ApprovalFormatService { + private final static String FORM_TYPE = "form"; + + private final MdBizTypeMappingService mdBizTypeMappingService = SpringBeanUtils.getBean(MdBizTypeMappingService.class); + private final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + private final LookupDataService lookupDataService = SpringBeanUtils.getBean(LookupDataService.class); + private final DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class); + + private DimensionService dimensionService = SpringBeanUtils.getBean(DimensionService.class); + private final ApprovalFormMetadataService approvalFormMetadataService = SpringBeanUtils.getBean(ApprovalFormMetadataService.class); + private ApprovalFormatManager approvalFormatManager = SpringBeanUtils.getBean(ApprovalFormatManager.class); + private final EapiRuntimeDeployment eapiRuntimeDeployment = SpringBeanUtils.getBean(EapiRuntimeDeployment.class); + + public ApprovalFormatServiceImpl(DimensionService dimensionService, ApprovalFormatManager approvalFormatManager) { + if (dimensionService != null) { + this.dimensionService = dimensionService; + } + + if (approvalFormatManager != null) { + this.approvalFormatManager = approvalFormatManager; + } + } + + @Override + public ApprovalFormatForestByDimension getApprovalFormatByDimension(String billCategoryId, String billCategoryExtendCode) { + List refList = getApprovalFormatForest(billCategoryId); + BillCategoryDimension dList = this.dimensionService.getDimension(billCategoryId, billCategoryExtendCode); + return new ApprovalFormatForestByDimension(refList, dList); + } + + @Override + public Map getEntityDataByBizEntityId(String dataId, String bizEntityId) { + String targetServiceUnitCode = getServiceUnitCode(bizEntityId); + if (targetServiceUnitCode == null || targetServiceUnitCode.isEmpty()) { + throw new RuntimeException("当前BE对应su的编号为空。当前BE的id是:" + bizEntityId); + } + RpcClient client = SpringBeanUtils.getBean(RpcClient.class); + LinkedHashMap parameterHashMap = new LinkedHashMap<>(); + parameterHashMap.put("dataId", dataId); + parameterHashMap.put("bizEntityId", bizEntityId); + try { + return (Map) client.invoke(Object.class, + "com.inspur.edp.web.approvalformat.rpc.rpcservice.IApprovalFormatRpcService.getEntityDataByBizEntityId", + targetServiceUnitCode, + parameterHashMap, + null); + } catch (Exception e) { + throw new RuntimeException("调用RPC服务发生异常。当前BE的id是:" + bizEntityId+",获取到的su编号:"+targetServiceUnitCode, e); + } + } + + // TODO: 迁移到公共方法 + private String getServiceUnitCode(String metadataId) { + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(metadataId); + if (bizEntityMetadata == null) { + return null; + } + + DevBasicBoInfo devBasicBoInfo = this.devBasicInfoService.getDevBasicBoInfo(bizEntityMetadata.getHeader().getBizobjectID()); + return devBasicBoInfo.getSuCode(); + } + + /** + * 获取业务实体数据 + * + * @param dataId 数据id + * @param bizEntityConfigId 业务实体配置id + * @return 指定数据id的实体数据对象 + */ + @Override + public IEntityData getEntityDataByBizEntityConfigId(String dataId, String bizEntityConfigId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + return lcp.retrieve(dataId).getData(); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + @Override + public List queryEntityData(String bizEntityId) { + String targetServiceUnitCode = getServiceUnitCode(bizEntityId); + if (targetServiceUnitCode == null || targetServiceUnitCode.isEmpty()) { + throw new RuntimeException("当前BE对应su的编号为空。当前BE的id是:" + bizEntityId); + } + + LinkedHashMap parameterHashMap = new LinkedHashMap<>(); + parameterHashMap.put("bizEntityId", bizEntityId); + + RpcClient client = SpringBeanUtils.getBean(RpcClient.class); + try { + return (List) client.invoke(Object.class, + "com.inspur.edp.web.approvalformat.rpc.rpcservice.IApprovalFormatRpcService.queryEntityData", + targetServiceUnitCode, + parameterHashMap, + null); + } catch (Exception e) { + throw new RuntimeException("调用RPC服务发生异常。当前BE的id是:" + bizEntityId +",获取到的su编号:"+targetServiceUnitCode+ e.getMessage(), e); + } + } + + @Override + public List queryEntityDataWithCondition(JsonNode queryStringMap) { + String bizEntityId = queryStringMap.get("bizEntityId").asText(); + String targetServiceUnitCode = getServiceUnitCode(bizEntityId); + if (targetServiceUnitCode == null || targetServiceUnitCode.isEmpty()) { + throw new RuntimeException("当前BE对应su的编号为空。当前BE的id是:" + bizEntityId); + } + + LinkedHashMap parameterHashMap = new LinkedHashMap<>(); + parameterHashMap.put("queryStringMap", queryStringMap); + + RpcClient client = SpringBeanUtils.getBean(RpcClient.class); + try { + return (List) client.invoke(Object.class, + "com.inspur.edp.web.approvalformat.rpc.rpcservice.IApprovalFormatRpcService.queryEntityDataWithCondition", + targetServiceUnitCode, + parameterHashMap, + null); + } catch (Exception e) { + throw new RuntimeException("调用RPC服务发生异常。当前BE的id是:" + bizEntityId +",获取到的su编号:"+targetServiceUnitCode+ e.getMessage(), e); + } + } + + + @Override + public ApprovalFormatCreateResponseBody createApprovalFormat(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody) { + new ApprovalFormatPermission().checkModulePermission(); + // 完整性检测 + if (checkIfExistsByBillCategoryIdAndDimension(approvalFormatCreateRequestBody.getBillCategoryId(), + approvalFormatCreateRequestBody.getDim1(), + approvalFormatCreateRequestBody.getDim2())) { + throw new RuntimeException("不允许相同单据种类id下,存在两个维度定义相同的记录,请检查。"); + } + + + // TODO: 相同元数据namespace + code + type 重复检测 + String formatCode = approvalFormatCreateRequestBody.getCode(); + try { + ApprovalFormUtil.saveCheck(approvalFormatCreateRequestBody, "Form"); + } catch (Exception e) { + throw new RuntimeException("已存在格式编号为" + formatCode + "的审批格式,请更换格式编号后重试。"); + } + //todo 改为vo创建后,新增一个方法执行vo创建格式 + this.approvalFormMetadataService.createApprovalForm(approvalFormatCreateRequestBody); + if(!isCreatedByViewModel(approvalFormatCreateRequestBody)) { + this.approvalFormMetadataService.createApprovalFormViewObject(approvalFormatCreateRequestBody); + }else{ + //不允许使用审批格式的VO创建新的审批格式 + if(checkIfExistsByViewModelId(approvalFormatCreateRequestBody.getVoId())){ + throw new RuntimeException("当前视图对象已经创建过审批格式,不允许重复创建!"); + } + //根据VO创建eapi元数据 + ApprovalFormUtil.deployManualVOandEapi(approvalFormatCreateRequestBody,approvalFormatCreateRequestBody.getVoId(),""); + } + + ApprovalFormat approvalFormat = this.createApprovalFormatRelation(approvalFormatCreateRequestBody); + + return ApprovalFormatConverter.toCreateResponseBody(approvalFormat); + } + + @Override + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) + public ApprovalFormat createApprovalFormatRelation(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody) { + ApprovalFormatDO relation = new ApprovalFormatDO(); + + relation.setId(UUID.randomUUID().toString()); + relation.setBeId(approvalFormatCreateRequestBody.getBeId()); + relation.setDim1(approvalFormatCreateRequestBody.getDim1()); + relation.setDim2(approvalFormatCreateRequestBody.getDim2()); + relation.setFormId(approvalFormatCreateRequestBody.getFormId()); + relation.setVoId(approvalFormatCreateRequestBody.getVoId()); + relation.setFormUrl(approvalFormatCreateRequestBody.getFormUrl()); + relation.setBillCategoryId(approvalFormatCreateRequestBody.getBillCategoryId()); + + DevBasicBoInfo devBasicBoInfo = this.devBasicInfoService.getDevBasicBoInfo(approvalFormatCreateRequestBody.getBizObjectId()); + String formUrl = createApprovalFormUrl(devBasicBoInfo.getAppCode().toLowerCase(), devBasicBoInfo.getSuCode().toLowerCase(), approvalFormatCreateRequestBody.getCode().toLowerCase()); + relation.setFormUrl(formUrl); + + return this.approvalFormatManager.add(relation); + } + + @Override + public void deleteApprovalFormat(String approvalFormatId) { + // 基于id删除审批格式 + this.approvalFormatManager.deleteApprovalFormatById(approvalFormatId); + } + + @Override + public void deleteApprovalFormatAndRelation(String billCategoryId, String metadataId, String firstDimension, String secondDimension) { + ApprovalFormat approvalFormat = getApprovalFormatByApprovalFormId(metadataId); + if (approvalFormat == null) { + return; + } + + this.deleteApprovalFormatAndRelation(approvalFormat.getId(), billCategoryId, metadataId); + } + + @Override + @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED) + public void deleteApprovalFormatAndRelationById(String approvalFormatId) { + ApprovalFormat approvalFormat = this.approvalFormatManager.getApprovalFormatById(approvalFormatId); + if (approvalFormat == null) { + return; + } + String billCategoryId = approvalFormat.getBillCategoryId(); + String approvalFormId = approvalFormat.getApprovalFormId(); + String approvalViewObjectId = approvalFormat.getViewObjectId(); + String bizEntityId = approvalFormat.getBizEntityId(); + //删除顺序 产物 - Form - Eapi - VO - 表记录 + + // 删除审批格式相关产物 + // 删除预览审批格式之后产生的文件 + try { + this.deleteFilesGeneratedInPreviewApprovalFormat(approvalFormId); + } catch (Exception e) { + throw new RuntimeException("删除移动审批相关文件失败。详细信息如下:" + e.getMessage()); + } + + //根据表单元数据获取Eapi的ID + GspMetadata approvalFormMetaData = null; + approvalFormMetaData = this.customizationService.getMetadata(approvalFormId); + if(approvalFormMetaData==null){ + throw new RuntimeException("获取审批格式失败"); + } + // 删除审批单据 + this.customizationService.deleteGeneratedMetadata(approvalFormId); + this.mdBizTypeMappingService.delete(billCategoryId, approvalFormId); + ObjectNode voContent = ApprovalFormatUtil.getVoContent(approvalFormMetaData); + String eapiId = voContent.get("eapiId").textValue(); + if(!StringUtility.isNullOrEmpty(eapiId)) { + //取消部署Eapi元数据 + eapiRuntimeDeployment.removeDeploy(eapiId); + //删除Eapi元数据 + this.customizationService.deleteGeneratedMetadata(eapiId); + } + + //bizEntityId为空,代表是使用VO创建的审批格式 + if(!StringUtility.isNullOrEmpty(bizEntityId)) { + // 删除审批单据VO,VO存在则调用删除方法 + GspMetadata approvalViewObjectMetadata = this.customizationService.getMetadata(approvalViewObjectId); + if(approvalViewObjectMetadata!=null) { + this.customizationService.deleteGeneratedMetadata(approvalViewObjectId); + } + this.mdBizTypeMappingService.delete(billCategoryId, approvalViewObjectId); + } + // 删除审批格式 + this.approvalFormatManager.deleteApprovalFormatById(approvalFormatId); + } + + @Override + public ApprovalFormat updateApprovalFormat(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody) { + if (!approvalFormatUpdateRequestBody.getApprovalFormatId().equals(approvalFormatUpdateRequestBody.getApprovalFormatInstance().getId())) { + throw new RuntimeException("待更新审批格式id与待更新内容中id不一致,请检查。"); + } + + ApprovalFormat approvalFormatInstance = approvalFormatUpdateRequestBody.getApprovalFormatInstance(); + ApprovalFormat approvalFormatFromDatabase = this.approvalFormatManager.getApprovalFormatById(approvalFormatInstance.getId()); + if (approvalFormatFromDatabase == null) { + throw new RuntimeException("待更新审批格式不存在,不能调用更新接口。请联系开发人员处理"); + } + if (ApprovalFormatUtil.isEqual(approvalFormatInstance, approvalFormatFromDatabase)) { + return approvalFormatInstance; + } + + ApprovalFormatDO approvalFormatDO = ApprovalFormatConverter.toDo(approvalFormatInstance); + if (this.approvalFormatManager.checkIfExistsByBillCategoryIdAndDimension(approvalFormatDO)) { + throw new RuntimeException("不允许相同单据种类id下,存在两个维度定义相同的记录,请检查。"); + } + + return this.approvalFormatManager.save(approvalFormatDO); + } + + @Override + public ApprovalFormat updateApprovalFormatFormUrl(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody) { + if (!approvalFormatUpdateRequestBody.getApprovalFormatId().equals(approvalFormatUpdateRequestBody.getApprovalFormatInstance().getId())) { + throw new RuntimeException("待更新审批格式id与待更新内容中id不一致,请检查。"); + } + + ApprovalFormat approvalFormatInstance = approvalFormatUpdateRequestBody.getApprovalFormatInstance(); + ApprovalFormat approvalFormatFromDatabase = this.approvalFormatManager.getApprovalFormatById(approvalFormatInstance.getId()); + if (approvalFormatFromDatabase == null) { + throw new RuntimeException("待更新审批格式不存在,不能调用更新接口。请联系开发人员处理"); + } + // 检测到未修改,直接返回 + if(approvalFormatInstance.getApprovalFormPublishUri().equals(approvalFormatFromDatabase.getApprovalFormPublishUri())){ + return approvalFormatInstance; + } + approvalFormatFromDatabase.setApprovalFormPublishUri(approvalFormatInstance.getApprovalFormPublishUri()); + ApprovalFormatDO approvalFormatDO = ApprovalFormatConverter.toDo(approvalFormatFromDatabase); + return this.approvalFormatManager.save(approvalFormatDO); + } + + + @Override + public ApprovalFormat updateApprovalFormatDimension(ApprovalFormatDimensionUpdateRequestBody approvalFormatDimensionUpdateRequestBody) { + ApprovalFormat approvalFormatFromDatabase = this.approvalFormatManager.getApprovalFormatById(approvalFormatDimensionUpdateRequestBody.getId()); + if (approvalFormatFromDatabase == null) { + throw new RuntimeException("待更新审批格式不存在,不能调用更新接口。请联系开发人员处理"); + } + + // 检测到未修改,直接返回 + if (approvalFormatFromDatabase.getFirstDimension().equals(approvalFormatDimensionUpdateRequestBody.getFirstDimension()) + && approvalFormatFromDatabase.getSecondDimension().equals(approvalFormatDimensionUpdateRequestBody.getSecondDimension())) { + return approvalFormatFromDatabase; + } + approvalFormatFromDatabase.setFirstDimension(approvalFormatDimensionUpdateRequestBody.getFirstDimension()); + approvalFormatFromDatabase.setSecondDimension(approvalFormatDimensionUpdateRequestBody.getSecondDimension()); + + ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody = new ApprovalFormatUpdateRequestBody(); + approvalFormatUpdateRequestBody.setApprovalFormatId(approvalFormatDimensionUpdateRequestBody.getId()); + approvalFormatUpdateRequestBody.setApprovalFormatInstance(approvalFormatFromDatabase); + + return updateApprovalFormat(approvalFormatUpdateRequestBody); + } + + @Override + public ApprovalFormat getApprovalFormatEntityById(String approvalFormatId) { + return getApprovalFormatByApprovalFormId(approvalFormatId); + } + + @Override + public List getApprovalFormatCollection(String billCategoryId) { + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBillCategoryId(billCategoryId); + + updateApprovalFormatCodeAndName(approvalFormatCollection); + + return approvalFormatCollection; + } + + @Override + public List getApprovalFormatCollectionOrderByDimension(String billCategoryId) { + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBillCategoryIdAndOrderByDimension(billCategoryId); + + updateApprovalFormatCodeAndName(approvalFormatCollection); + + return approvalFormatCollection; + } + + @Override + public List getApprovalFormatCollectionOrderByDimension(String billCategoryId, String billCategoryExtendCode) { + return createApprovalFormatQueryResponseBody(billCategoryId, billCategoryExtendCode); + } + + @Override + public void replicateApprovalFormat(String approvalFormatId) { + System.out.println("replicateApprovalFormat"); + } + + @Override + public ApprovalFormat getApprovalFormatByBizEntityIdWithDimension(String businessEntityId, String firstDimension, String secondDimension) { + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBeIdWithFirstDimensionAndSecondDimension(businessEntityId, firstDimension, secondDimension); + if (approvalFormatCollection == null || approvalFormatCollection.size() <= 0) { + return null; + } + if (approvalFormatCollection.size() > 1) { + throw new RuntimeException("表中存在重复数据,请联系开发人员处理。"); + } + + return approvalFormatCollection.get(0); + } + + @Override + public ApprovalFormat getApprovalFormatByBillCategoryIdWithDimension(String billCategoryId, String firstDimension, String secondDimension) { + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBillCategoryIdWithFirstDimensionAndSecondDimension(billCategoryId, firstDimension, secondDimension); + if (approvalFormatCollection == null || approvalFormatCollection.size() <= 0) { + return null; + } + if (approvalFormatCollection.size() > 1) { + throw new RuntimeException("表中存在重复数据,请联系开发人员处理。"); + } + + return approvalFormatCollection.get(0); + } + + @Override + public String getApprovalFormUri(String businessEntityId, String firstDimension, String secondDimension) { + ApprovalFormat approvalFormat = getApprovalFormatByBizEntityIdWithDimension(businessEntityId, firstDimension, secondDimension); + if (approvalFormat == null) { + return null; + } else { + //从数据库取出移动审批js的content,放到publish目录 + if (!StringUtility.isNullOrEmpty(approvalFormat.getApprovalFormId())) { + ScriptCacheResponse scriptCacheResponse = LocalServerVersionManager.getSingleInstance().checkVersionWithFormMetadataId(approvalFormat.getApprovalFormId()); + } + } + return approvalFormat.getApprovalFormPublishUri(); + } + + @Override + public String getApprovalFormUriByBillCategoryId(String billCategory, String firstDimension, String secondDimension) { + //new ApprovalFormatPermission().checkModulePermission(); + ApprovalFormat approvalFormat = getApprovalFormatByBillCategoryIdWithDimension(billCategory, firstDimension, secondDimension); + if (approvalFormat == null) { + return null; + } + return approvalFormat.getApprovalFormPublishUri(); + } + + @Override + public HelpProviderResult getHelpProviderData(String billCategoryId, String billCategoryExtendCode, String dimensionId, String billCategoryDimensionItemId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + + try { + BillCategoryDimension billCategoryDimension = this.dimensionService.getDimension(billCategoryId, billCategoryExtendCode); + if (billCategoryDimension == null) { + return null; + } + + List billCategoryDimensionItemList = billCategoryDimension.getDimensionItems(); + if (billCategoryDimensionItemList == null || billCategoryDimensionItemList.size() <= 0) { + return null; + } + for (BillCatDimensionItem billCategoryDimensionItem : billCategoryDimensionItemList) { + if (billCategoryDimensionItem.getDimensionId().equals(dimensionId) && billCategoryDimensionItem.getId().equals(billCategoryDimensionItemId)) { + InputType inputType = billCategoryDimensionItem.getInputInfo().getInputType(); + if (inputType == InputType.SmartHelpInput) { + SmartHelpInputInfo smartHelpInputInfo = (SmartHelpInputInfo) billCategoryDimensionItem.getInputInfo(); + String helperId = smartHelpInputInfo.getHelperId(); + + HelpMetadataContent helpMetadataContent = (HelpMetadataContent) this.customizationService.getMetadata(helperId).getContent(); + HelpMetadataSimpleContent helpMetadataSimpleContent = HelpProviderUtil.convertToHelpMetadataSimpleContent(helpMetadataContent); + + HelpProviderResult helpProviderResult = new HelpProviderResult(); + helpProviderResult.setHelpMetadataSimpleContent(helpMetadataSimpleContent); + helpProviderResult.setLookupResult(this.lookupDataService.getData(helperId, new LookupQueryParam())); + + return helpProviderResult; + } + } + } + + return null; + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + private List getApprovalFormatForest(String billCategoryId) { + List treeList = new ArrayList<>(); + + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBillCategoryId(billCategoryId); + HashMap formIdApprovalFormatMap = new HashMap<>(16); + for (ApprovalFormat approvalFormat : approvalFormatCollection) { + String currentFormId = approvalFormat.getApprovalFormId(); + if (formIdApprovalFormatMap.containsKey(currentFormId)) { + throw new RuntimeException("审批格式和审批单据的一对一映射被破坏,请联系开发人员处理。审批单据id是:" + approvalFormat.getApprovalFormId()); + } + formIdApprovalFormatMap.put(currentFormId, approvalFormat); + } + + List matadataList = this.mdBizTypeMappingService.getMetadataListByBizTypeId(billCategoryId, Collections.singletonList(FORM_TYPE)); + if (matadataList == null || matadataList.size() <= 0) { + return treeList; + } + + List children; + MetadataHeader metadataHeader; + ApprovalFormat approvalFormat; + ApprovalFormatTreeNode treeNode; + for (Metadata4Ref approvalFormMetadataRef : matadataList) { + metadataHeader = approvalFormMetadataRef.getMetadata().getHeader(); + approvalFormat = formIdApprovalFormatMap.get(metadataHeader.getId()); + try { + children = this.customizationService.getMetadataInfoRecusively(metadataHeader.getId(), metadataHeader.getCertId()); + } catch (Exception e) { + throw new RuntimeException("getMetadataInfoRecusively Error."); + } + + if (children != null && children.size() > 0) { + + treeNode = ApprovalFormatTreeUtil.assembleTree(ApprovalFormatTreeUtil.convertToApprovalFormat(metadataHeader, approvalFormat, "", "", true), + ApprovalFormatTreeUtil.groupByDimensions(ApprovalFormatTreeUtil.convertToRtcTemplateList(children, formIdApprovalFormatMap))); + treeList.add(treeNode); + } else { + treeList.add(new ApprovalFormatTreeNode(ApprovalFormatTreeUtil.convertToApprovalFormat(metadataHeader, approvalFormat, "", "", true), new ArrayList<>())); + } + } + return treeList; + } + + private ApprovalFormat getApprovalFormatByApprovalFormId(String approvalFormId) { + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByFormId(approvalFormId); + if (approvalFormatCollection == null || approvalFormatCollection.size() <= 0) { + return null; + } + if (approvalFormatCollection.size() > 1) { + throw new RuntimeException("表中存在重复数据,请联系开发人员处理。"); + } + + return approvalFormatCollection.get(0); + } + + private boolean checkIfExistsByBillCategoryIdAndDimension(String billCategoryId, String firstDimension, String secondDimension) { + ApprovalFormat approvalFormatInstance = new ApprovalFormat(); + approvalFormatInstance.setBillCategoryId(billCategoryId); + approvalFormatInstance.setFirstDimension(firstDimension); + approvalFormatInstance.setSecondDimension(secondDimension); + + ApprovalFormatDO approvalFormatDO = ApprovalFormatConverter.toDo(approvalFormatInstance); + return this.approvalFormatManager.checkIfExistsByBillCategoryIdAndDimension(approvalFormatDO); + } + + /** + * VO创建审批格式专用 + * @param viewModelId 视图对象编号 + * @return + */ + private boolean checkIfExistsByViewModelId(String viewModelId) { + ApprovalFormat approvalFormatInstance = new ApprovalFormat(); + approvalFormatInstance.setViewObjectId(viewModelId); + ApprovalFormatDO approvalFormatDO = ApprovalFormatConverter.toDo(approvalFormatInstance); + return this.approvalFormatManager.checkIfExistsByViewModelId(approvalFormatDO); + } + + private String createApprovalFormUrl(String applicationCode, String serviceUnitCode, String approvalFormCode) { + String formUrl = "/" + "apps" + "/" + + applicationCode.toLowerCase() + "/" + + serviceUnitCode.toLowerCase() + "/" + + "mobileapproval" + "/" + + approvalFormCode.toLowerCase() + "/" + + approvalFormCode.toLowerCase() + ".js"; + + return formUrl; + } + + private void deleteApprovalFormatAndRelation(String approvalFormatId, String billCategoryId, String metadataId) { + if (metadataId == null || metadataId.isEmpty()) { + return; + } + + this.customizationService.deleteExtMetadata(metadataId, ""); + +// // 检查是否存在维度 +// boolean firstDimensionIsNullOrEmpty = firstDimension == null || firstDimension.isEmpty(); +// boolean secondDimensionIsNullOrEmpty = secondDimension == null || secondDimension.isEmpty(); +// if(firstDimensionIsNullOrEmpty && secondDimensionIsNullOrEmpty) { + this.mdBizTypeMappingService.delete(billCategoryId, metadataId); +// } + + if (approvalFormatId == null || approvalFormatId.isEmpty()) { + return; + } + this.approvalFormatManager.deleteApprovalFormatById(approvalFormatId); + } + + + /** + * 删除审批设计时文件 + * + * @param formId 审批表单id + * @throws Exception + */ + private void deleteFilesGeneratedInPreviewApprovalFormat(String formId) throws Exception { + if (formId == null || formId.isEmpty()) { + throw new Exception("删除移动审批相关文件失败,表单编号为空。"); + } + + GspMetadata gspMetadata = ApproveFormatPreviewUtil.getGspMetadataWithFormId(formId); + String formCode = gspMetadata.getHeader().getCode(); + String mobileApproveAppPath = ApproveFormatPreviewUtil.generateMobileApproveDevBasePath(formCode); + try { + FileUtility.deleteFolder(mobileApproveAppPath); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void updateApprovalFormatCodeAndName(List approvalFormatCollection) { + if (approvalFormatCollection == null || approvalFormatCollection.size() <= 0) { + return; + } + + for (ApprovalFormat approvalFormat : approvalFormatCollection) { + GspMetadata approvalForm = this.customizationService.getMetadata(approvalFormat.getApprovalFormId()); + if (approvalForm == null) { + throw new RuntimeException("获取元数据失败。待获取元数据ID是:" + approvalFormat.getApprovalFormId()); + } + MetadataHeader approvalFormMetadataHeader = approvalForm.getHeader(); + approvalFormat.setCode(approvalFormMetadataHeader.getCode()); + approvalFormat.setName(approvalFormMetadataHeader.getName()); + } + } + + private List createApprovalFormatQueryResponseBody(String billCategoryId, String billCategoryExtendCode) { + new ApprovalFormatPermission().checkModulePermission(); + List approvalFormatQueryResponseBodyList = new LinkedList<>(); + + List approvalFormatCollection = this.approvalFormatManager.getApprovalFormatByBillCategoryIdAndOrderByDimension(billCategoryId); + if (approvalFormatCollection == null || approvalFormatCollection.size() <= 0) { + return approvalFormatQueryResponseBodyList; + } + + BillCategoryDimension billCategoryDimension = this.dimensionService.getDimension(billCategoryId, billCategoryExtendCode); + List billCategoryDimensionCollection = null; + if (billCategoryDimension != null) { + billCategoryDimensionCollection = billCategoryDimension.getDimensionItems(); + } + Map> helpProviderCache = new HashMap<>(2); + + for (ApprovalFormat approvalFormat : approvalFormatCollection) { + ApprovalFormatQueryResponseBody approvalFormatQueryResponseBody = ApprovalFormatUtil.convertToApprovalFormatQueryResponseBody(approvalFormat); + GspMetadata approvalForm = this.customizationService.getMetadata(approvalFormatQueryResponseBody.getApprovalFormId()); + if (approvalForm == null) { + throw new RuntimeException("获取元数据失败。待获取元数据ID是:" + approvalFormatQueryResponseBody.getApprovalFormId()); + } + MetadataHeader approvalFormMetadataHeader = approvalForm.getHeader(); + approvalFormatQueryResponseBody.setCode(approvalFormMetadataHeader.getCode()); + approvalFormatQueryResponseBody.setName(approvalFormMetadataHeader.getName()); + + // 更新第一维度和第二维度(将code更新成name) + if (billCategoryDimensionCollection == null) { + approvalFormatQueryResponseBodyList.add(approvalFormatQueryResponseBody); + continue; + } + if (billCategoryDimensionCollection.size() > 0) { + for (BillCatDimensionItem billCatDimensionItem : billCategoryDimensionCollection) { + InputType inputType = billCatDimensionItem.getInputInfo().getInputType(); + if (inputType == InputType.SmartHelpInput) { + SmartHelpInputInfo smartHelpInputInfo = (SmartHelpInputInfo) billCatDimensionItem.getInputInfo(); + String helperId = smartHelpInputInfo.getHelperId(); + HelpMetadataContent helpMetadataContent = null; + LookupResult lookupResult = null; + List helpProvider = helpProviderCache.get(helperId); + if (helpProvider == null) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + helpMetadataContent = (HelpMetadataContent) this.customizationService.getMetadata(helperId).getContent(); + lookupResult = this.lookupDataService.getData(helperId, new LookupQueryParam()); + helpProvider = new ArrayList<>(); + helpProvider.add(0, helpMetadataContent); + helpProvider.add(1, lookupResult); + helpProviderCache.put(helperId, helpProvider); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } else { + helpMetadataContent = (HelpMetadataContent) helpProvider.get(0); + lookupResult = (LookupResult) helpProvider.get(1); + } + String textFieldCode = helpMetadataContent.getTextField(); + String idFieldCode = helpMetadataContent.getIdField(); + + Object itemCollectionObject = lookupResult.getItems(); + JsonNode itemCollectionJsonNode = getJsonNode(itemCollectionObject); + + for (JsonNode itemJsonNode : itemCollectionJsonNode) { + // treeList类型帮助 + // 遍历helpId + if ("TreeList".equals(lookupResult.getDisplayType())) { + do { + JsonNode dataJsonNode = itemJsonNode.get("data"); + while (dataJsonNode != null) { + tryToUpdateApprovalFormatQueryResponseBodyDimension(dataJsonNode, idFieldCode, textFieldCode, approvalFormatQueryResponseBody); + if (itemJsonNode.get("children") != null && itemJsonNode.get("children").isArray() && itemJsonNode.get("children").size() > 0) { + for (int i = 0; i < itemJsonNode.get("children").size(); i++) { + dataJsonNode = itemJsonNode.get("children").get(i).get("data"); + tryToUpdateApprovalFormatQueryResponseBodyDimension(dataJsonNode, idFieldCode, textFieldCode, approvalFormatQueryResponseBody); + + if (itemJsonNode.get("children").get(i).get("children") != null && itemJsonNode.get("children").get(i).get("children").isArray() && itemJsonNode.get("children").get(i).get("children").size() > 0) { + for (int j = 0; j < itemJsonNode.get("children").get(i).get("children").size(); j++) { + JsonNode childDataJsonNode = itemJsonNode.get("children").get(i).get("children").get(j).get("data"); + tryToUpdateApprovalFormatQueryResponseBodyDimension(childDataJsonNode, idFieldCode, textFieldCode, approvalFormatQueryResponseBody); + } + } + + } + if (itemJsonNode.elements().hasNext()) { + itemJsonNode = itemJsonNode.elements().next(); + dataJsonNode = itemJsonNode.get("data"); + } + } else { + dataJsonNode = null; + } + } + itemJsonNode = itemJsonNode.elements().next(); + } while (itemJsonNode.elements().hasNext()); + } + // list类型帮助 + if ("List".equals(lookupResult.getDisplayType())) { + tryToUpdateApprovalFormatQueryResponseBodyDimension(itemJsonNode, idFieldCode, textFieldCode, approvalFormatQueryResponseBody); + } + } + } else if (inputType == InputType.EnumInput) { + EnumInputInfo enumInputInfo = (EnumInputInfo) billCatDimensionItem.getInputInfo(); + for (EnumItem enumItem : enumInputInfo.getEnumItems()) { + if (enumItem.getKey().equals(approvalFormatQueryResponseBody.getFirstDimension())) { + approvalFormatQueryResponseBody.setFirstDimensionName(enumItem.getValue()); + } + if (enumItem.getKey().equals(approvalFormatQueryResponseBody.getSecondDimension())) { + approvalFormatQueryResponseBody.setSecondDimensionName(enumItem.getValue()); + } + } + } + } + } + + approvalFormatQueryResponseBodyList.add(approvalFormatQueryResponseBody); + } + + return approvalFormatQueryResponseBodyList; + } + + private void tryToUpdateApprovalFormatQueryResponseBodyDimension(JsonNode dataJsonNode, String idFieldCode, String textFieldCode, ApprovalFormatQueryResponseBody approvalFormatQueryResponseBody) { + if (dataJsonNode != null && dataJsonNode.get(idFieldCode) != null && dataJsonNode.get(textFieldCode) != null) { + if (dataJsonNode.get(idFieldCode).asText().equals(approvalFormatQueryResponseBody.getFirstDimension())) { + // JsonNode转换成String + approvalFormatQueryResponseBody.setFirstDimensionName(dataJsonNode.get(textFieldCode).asText()); + } + if (dataJsonNode.get(idFieldCode).asText().equals(approvalFormatQueryResponseBody.getSecondDimension())) { + approvalFormatQueryResponseBody.setSecondDimensionName(dataJsonNode.get(textFieldCode).asText()); + } + } + } + + private JsonNode getJsonNode(Object objectInstance) { + try { + ObjectMapper mapper = Utils.getMapper(); + String itemCollectionObjectStr = mapper.writeValueAsString(objectInstance); + + return mapper.readTree(itemCollectionObjectStr); + + } catch (JsonProcessingException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + private boolean isCreatedByViewModel(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody){ + if(approvalFormatCreateRequestBody==null){ + throw new RuntimeException("参数为空,请检查!"); + } + return StringUtility.isNullOrEmpty(approvalFormatCreateRequestBody.getBeId()); + + } + + private String checkVersionWithApprovalFormat(ApprovalFormat approvalFormat){ + if(!StringUtility.isNullOrEmpty(approvalFormat.getBizEntityId())) { + //String targetServiceUnitCode = getServiceUnitCode(approvalFormat.getBizEntityId()); + String targetServiceUnitCode = "bcc"; + if (targetServiceUnitCode == null || targetServiceUnitCode.isEmpty()) { + throw new RuntimeException("当前BE对应su的编号为空。当前BE的id是:" + approvalFormat.getBizEntityId()); + } + RpcClient client = SpringBeanUtils.getBean(RpcClient.class); + LinkedHashMap parameterHashMap = new LinkedHashMap<>(); + parameterHashMap.put("formMetadataId", approvalFormat.getApprovalFormId()); + try { + return (String)client.invoke(Object.class, + "com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.rpc.LocalServerVersionRpcService.checkVersionWithFormMetadataId", + targetServiceUnitCode, + parameterHashMap, + null); + } catch (Exception e) { + throw new RuntimeException("调用RPC服务发生异常。当前BE的id是:" + approvalFormat.getBizEntityId() + ",传递的su编号:" + targetServiceUnitCode, e); + } + } + return ""; + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/BusinessEntityServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/BusinessEntityServiceImpl.java new file mode 100644 index 00000000..48865394 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/BusinessEntityServiceImpl.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.approvalformat.core.service; + +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.approvalformat.api.service.BusinessEntityService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * 业务实体服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/16 19:15 + */ +public class BusinessEntityServiceImpl implements BusinessEntityService { + private final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + @Override + public GspBusinessEntity getBusinessEntity(String bizEntityId) { + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + if(bizEntityMetadata == null) { + throw new RuntimeException("The Metadata to search is null. The Searching Metadata ID is: " + bizEntityId); + } + + return (GspBusinessEntity)bizEntityMetadata.getContent(); + } + + @Override + public GspMetadata getBusinessEntityMetadata(String bizEntityId) { + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + if(bizEntityMetadata == null) { + throw new RuntimeException("The Metadata to search is null. The Searching Metadata ID is: " + bizEntityId); + } + + return bizEntityMetadata; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/DimensionServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/DimensionServiceImpl.java new file mode 100644 index 00000000..d72ccc42 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/DimensionServiceImpl.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.approvalformat.core.service; + +import com.inspur.edp.bcc.billcategory.api.BillCategoryService; +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; +import com.inspur.edp.web.approvalformat.api.service.DimensionService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +/** + * 维度服务 + * @author Xu‘fa Wang + * @date 2020/5/11 16:44 + */ +public class DimensionServiceImpl implements DimensionService { + @Autowired + private BillCategoryService billCategoryService; + + public DimensionServiceImpl() { + if(this.billCategoryService == null) { + billCategoryService = SpringBeanUtils.getBean(BillCategoryService.class); + } + } + + public DimensionServiceImpl(BillCategoryService billCategoryService) { + if(billCategoryService == null) { + this.billCategoryService = SpringBeanUtils.getBean(BillCategoryService.class); + } else { + this.billCategoryService = billCategoryService; + } + } + + @Override + public BillCategoryDimension getDimension(String billCategoryId, String billCategoryExtendCode) { + return this.billCategoryService.getDimension(billCategoryId, billCategoryExtendCode); + } + + @Override + public List getDimensionCollection(String billCategoryId) { + return this.billCategoryService.getDimensions(billCategoryId); + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/RuntimeMetadataServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/RuntimeMetadataServiceImpl.java new file mode 100644 index 00000000..012da836 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/service/RuntimeMetadataServiceImpl.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.approvalformat.core.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.approvalformat.api.service.IRuntimeMetadataService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * 元数据运行时服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/18 14:34 + */ +public class RuntimeMetadataServiceImpl implements IRuntimeMetadataService { + private final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + @Override + public GspMetadata getMetadataByIdWithDimension(String metadataId, + String metadataCertificateId, + String firstDimension, + String secondDimension){ + boolean isNullOrEmptyOfFirstDimension = firstDimension == null || firstDimension.isEmpty(); + boolean isNullOrEmptyOfSecondDimension = secondDimension == null || secondDimension.isEmpty(); + if(isNullOrEmptyOfFirstDimension && isNullOrEmptyOfSecondDimension) { + return this.customizationService.getMetadata(metadataId); + } else { + return this.customizationService.getMetadataWithDimensions(metadataId, metadataCertificateId, firstDimension, secondDimension); + } + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormSchemaUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormSchemaUtil.java new file mode 100644 index 00000000..b2f08698 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormSchemaUtil.java @@ -0,0 +1,89 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.cef.designtime.api.IGspCommonField; +import com.inspur.edp.cef.designtime.api.variable.CommonVariableCollection; +import com.inspur.edp.das.commonmodel.IGspCommonObject; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.formserver.viewmodel.GspViewObject; +import com.inspur.edp.web.approvalformat.api.entity.schema.Entity; +import com.inspur.edp.web.approvalformat.api.entity.schema.Field; +import com.inspur.edp.web.approvalformat.api.entity.schema.FormSchema; +import com.inspur.edp.web.approvalformat.api.entity.schema.type.EntityType; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 审批单据schema工具类 + * @author Xu‘fa Wang + * @date 2020/6/8 16:23 + */ +public class ApprovalFormSchemaUtil { + public ApprovalFormSchemaUtil() { + } + + /** + * 基于ViewModel构建表单Schema + * @param vm + * @return + */ + public static FormSchema constructSchema(GspViewModel vm){ + FormSchema schema = new FormSchema() { + { + this.setId(vm.getId()); + this.setCode(vm.getCode()); + this.setName(vm.getName()); + this.setSourceType("vo"); + this.setEntities(Collections.singletonList(constructEntity(vm.getMainObject()))); + this.setVariables(constructFields(vm.getVariables().getContainElements())); + //此时不需初始化eapiId + } + }; + return schema; + } + + private static List constructFields(CommonVariableCollection variables) { + List variableList = new ArrayList<>(); + if(variables == null || variables.size() <= 0) { + return variableList; + } + variables.forEach(field -> { + TypeBuildingContext context = TypeBuildingContext.createTypeBuildingContext(field, null); + Field variable = FieldUtil.constructField(context,null); + variableList.add(variable); + }); + return variableList; + } + + private static Entity constructEntity(GspViewObject mainObject) { + Entity entity = new Entity(){ + { + this.setId(mainObject.getId()); + this.setCode(mainObject.getCode()); + this.setName(mainObject.getName()); + this.setLabel(StringUtility.toCamelCase(mainObject.getCode()) + "s"); + this.setType(constructEntityType(mainObject)); + } + }; + return entity; + } + + private static EntityType constructEntityType(GspViewObject mainObject) { + if(mainObject.getIDElement() == null){ + throw new RuntimeException("标识为"+mainObject.getID()+"的视图对象"+mainObject.getName()+"的IDElement属性不允许为null。"); + } + List fields = new ArrayList<>(); + for(IGspCommonField element : mainObject.getContainElements()) { + fields.add(FieldUtil.createField(element, null)); + } + List entities = new ArrayList<>(); + for(IGspCommonObject childObject : mainObject.getContainChildObjects()){ + entities.add(constructEntity((GspViewObject) childObject)); + } + EntityType entityType = new EntityType(mainObject.getCode(),mainObject.getName(), + StringUtility.toCamelCase(mainObject.getIDElement().getLabelID()),fields, entities); + return entityType; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormUtil.java new file mode 100644 index 00000000..dc826c4c --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormUtil.java @@ -0,0 +1,394 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.cdp.common.utils.json.JsonUtil; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.entity.MetadataReference; +import com.inspur.edp.lcm.metadata.common.Utils; +import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatCreateRequestBody; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import com.inspur.edp.formserver.viewmodel.extendinfo.entity.GspVoExtendInfo; +import com.inspur.edp.formserver.viewmodel.extendinfo.api.GspVoExtendInfoService; +import com.inspur.edp.sgf.api.service.EapiMetadataRtService; +import com.inspur.edp.sgf.api.service.EapiRuntimeDeployment; +import com.inspur.edp.sgf.api.entity.SgMetadata; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 审批单据工具类 + * + * @author Xu‘fa Wang + * @date 2020/5/19 20:47 + */ +public class ApprovalFormUtil { + private static final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + private static final MdBizTypeMappingService mdBizTypeMappingService = SpringBeanUtils.getBean(MdBizTypeMappingService.class); + private static final ObjectMapper mapper = Utils.getMapper(); + private static final GspVoExtendInfoService gspVoExtendInfoService = SpringBeanUtils.getBean(GspVoExtendInfoService.class); + private static final EapiMetadataRtService eapiMetadataRtService = SpringBeanUtils.getBean(EapiMetadataRtService.class); + private static final EapiRuntimeDeployment eapiRuntimeDeployment = SpringBeanUtils.getBean(EapiRuntimeDeployment.class); + + + /** + * 创建根审批单据 + * + * @param request 审批格式创建请求体 + * @param metadataType 元数据类型 + */ + public static void createRootApprovalForm(ApprovalFormatCreateRequestBody request, String metadataType) { + //保存元数据到表:GspmdCustomContent + MetadataHeader header = createHeader(request, metadataType); + IMetadataContent content = createMetadataContent(request, metadataType); + GspMetadata metadata = new GspMetadata() { + { + this.setHeader(header); + this.setContent(content); + //临时添加,为了与运行时定制表单区分 + this.setExtendProperty("APPROVAL"); + } + }; + + customizationService.save(metadata); + // 保存关联关系到 gspmdbiztypemapping + createMatadataBizTypeMapping(request, metadataType); + //部署viewModel和Eapi + + if ("GSPViewModel".equals(metadataType)) { + //idp类型be暂不使用eapi取数 + if (!StringUtility.isNullOrEmpty(metadata.getHeader().getNameSpace())) { + //可能部署eapi失败的情况 + if (metadata.getHeader() != null && metadata.getHeader().getCode() != null && metadata.getHeader().getCode().contains("com.inspur.fastdweb")) { + return; + } + //部署viewModel + deployViewModel(request, metadata); + //创建运行时Eapi元数据,注意idp类型 + GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(metadata); + //自动保存 + //customizationService.save(RtEapiMetadata); + //部署Eapi元数据 + eapiRuntimeDeployment.deploy(RtEapiMetadata.getHeader().getId()); + //记录baseUri放置到表单元数据中 + SgMetadata sgMetadata = (SgMetadata) RtEapiMetadata.getContent(); + //"/api/scm/sd/v1.0/kuozhan_ebs" + String baseUri = sgMetadata.getRouter(); + + //更新Eapi元数据id到表单元数据中 + ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent()); + ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0"); + voContent.put("eapiId", RtEapiMetadata.getHeader().getId()); + voContent.put("getDataMethod", "byEapi"); + voContent.put("baseUri", baseUri); + //更新表单元数据 + GspMetadata formMetadata = customizationService.getMetadata(request.getFormId()); + GspMetadata newMetadata = (GspMetadata) formMetadata.clone(); + newMetadata.setContent(new FormMetadataContent() { + { + this.setId(request.getFormId()); + this.setContents(formModule); + } + }); + customizationService.save(newMetadata); + } + } + } + + /** + * 判断元数据对应的(namespace+code+type)是否重复 + * + * @param request 审批格式创建请求体 + * @param metadataType gsp元数据 + */ + public static void saveCheck(ApprovalFormatCreateRequestBody request, String metadataType) { + //保存元数据到表:GspmdCustomContent + MetadataHeader header = createHeader(request, metadataType); + IMetadataContent content = createMetadataContent(request, metadataType); + GspMetadata metadata = new GspMetadata() { + { + this.setHeader(header); + this.setContent(content); + //临时添加,为了与运行时定制表单区分 + this.setExtendProperty("APPROVAL"); + } + }; + //相同元数据namespace + code + type 重复检测,发生重复会抛出异常 + try { + customizationService.saveCheck(metadata); + } catch (Exception e) { + throw new RuntimeException("元数据namespace + code + type发生重复"); + } + } + + /** + * 部署VO,避免重复读取元数据 + * + * @param request ApprovalFormatCreateRequestBody + * @param ViewModelMetadata 视图对象元数据 + */ + public static void deployViewModel(ApprovalFormatCreateRequestBody request, GspMetadata ViewModelMetadata) { + GspViewModel vo = (GspViewModel) ViewModelMetadata.getContent(); + Date date = new Date(); + GspVoExtendInfo gspVoExtendInfo = new GspVoExtendInfo(ViewModelMetadata.getHeader().getId(), "", vo.getGeneratedConfigID(), null, date, null, date, request.getBeId()); + List gspVoExtendInfoList = new ArrayList<>(); + gspVoExtendInfoList.add(gspVoExtendInfo); + gspVoExtendInfoService.saveGspVoExtendInfos(gspVoExtendInfoList); + } + + /** + * 创建子审批单据 + * + * @param request 审批格式创建请求体 + * @param metadataType 元数据类型 + */ + public static void createChildApprovalForm(ApprovalFormatCreateRequestBody request, String metadataType) { + GspMetadata originalMetaData = null; + switch (metadataType) { + case "Form": + originalMetaData = getMetadata(request.getBasicFormId()); + break; + case "GSPViewModel": + originalMetaData = getMetadata(request.getBasicVoId()); + break; + default: + break; + } + + if (originalMetaData == null) { + return; + } + + //修改Header节点 + //只有Content节点没有Clone + GspMetadata newMetadata = (GspMetadata) originalMetaData.clone(); + newMetadata.setHeader(createHeader(request, metadataType)); +// //修改元数据extend标志位 +// newMetadata.setExtended(true); + // 添加扩展属性,唯一标识审批单据 + newMetadata.setExtendProperty("APPROVAL"); + // 修改Content节点 + IMetadataContent metadataContent = createMetadataContent(request, metadataType); + newMetadata.setContent(metadataContent); + + // 修改Refs节点中Metadata属性 + for (MetadataReference extendMetadataRef : newMetadata.getRefs()) { + extendMetadataRef.getMetadata().setCode(request.getCode()); + extendMetadataRef.getMetadata().setName(request.getName()); + extendMetadataRef.getMetadata().setId(getNewMetadataId(request, metadataType)); + } + + customizationService.save(newMetadata); + + // 保存关联关系到 gspmdbiztypemapping + createMatadataBizTypeMapping(request, metadataType); + if ("GSPViewModel".equals(metadataType)) { + if (newMetadata.getHeader().getNameSpace() != null && newMetadata.getHeader().getNameSpace() != "") { + //可能部署eapi失败的情况 + if (newMetadata.getHeader().getCode().indexOf('-') != -1) { + return; + } + //部署viewModel + deployViewModel(request, newMetadata); + //创建运行时Eapi元数据 + GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(newMetadata); + //无需save + //customizationService.save(RtEapiMetadata); + //部署Eapi元数据 + try { + eapiRuntimeDeployment.deploy(RtEapiMetadata.getHeader().getId()); + } catch (Exception e) { + throw new RuntimeException("部署eapi元数据失败!" + e.getMessage()); + } + //记录baseUri放置到表单元数据中 + SgMetadata sgMetadata = (SgMetadata) RtEapiMetadata.getContent(); + //"/api/scm/sd/v1.0/kuozhan_ebs" + String baseUri = sgMetadata.getRouter(); + + //更新Eapi元数据id到表单元数据中 + ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent()); + ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0"); + voContent.put("eapiId", RtEapiMetadata.getHeader().getId()); + voContent.put("getDataMethod", "byEapi"); + voContent.put("baseUri", baseUri); + //更新表单元数据 + GspMetadata formMetadata = customizationService.getMetadata(request.getFormId()); + GspMetadata metadata = (GspMetadata) formMetadata.clone(); + metadata.setContent(new FormMetadataContent() { + { + this.setId(request.getFormId()); + this.setContents(formModule); + } + }); + customizationService.save(newMetadata); + } + } + + } + + /** + * 获取元数据 + * + * @param metadataId 元数据 + * @return 查询到的元数据 + */ + private static GspMetadata getMetadata(String metadataId) { + return customizationService.getMetadata(metadataId); + } + + private static String getNewMetadataId(ApprovalFormatCreateRequestBody requestBody, String metadataType) { + String metaDataId = null; + switch (metadataType) { + case "Form": + metaDataId = requestBody.getFormId(); + break; + case "GSPViewModel": + metaDataId = requestBody.getVoId(); + break; + default: + break; + } + return metaDataId; + } + + private static String appendSuffix(String originalString, String metadataType) { + String metadataSuffix = "_maf"; + String resultString = originalString; + if (metadataType.equals("GSPViewModel")) { + resultString = originalString + metadataSuffix; + } + return resultString; + } + + private static MetadataHeader createHeader(ApprovalFormatCreateRequestBody requestBody, String metaDataType) { + String metaDataId = getNewMetadataId(requestBody, metaDataType); + + MetadataHeader header = new MetadataHeader(); + header.setId(metaDataId); + //有效避免Eapi的baseUrl重复 + header.setCode(appendSuffix(requestBody.getCode(), metaDataType)); + header.setName(appendSuffix(requestBody.getName(), metaDataType)); + header.setType(metaDataType); + header.setBizobjectID(requestBody.getBizObjectId()); + header.setNameSpace(requestBody.getNameSpace()); + return header; + } + + private static IMetadataContent createMetadataContent(ApprovalFormatCreateRequestBody requestBody, String metaDataType) { + switch (metaDataType) { + case "Form": + return new FormMetadataContent() { + { + this.setId(requestBody.getFormId()); + //this.setName(requestBody.getName()); + //this.setCode(requestBody.getCode()); + //String转换为JsonNode + //this.setContents(requestBody.getFormContent()); + this.setContents(JsonUtil.toJsonNode(requestBody.getFormContent())); + + } + }; + case "GSPViewModel": + try { + return mapper.readValue(requestBody.getVoContent(), GspViewModel.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("创建" + metaDataType + "元数据失败"); + } + default: + return null; + } + } + + private static void createMatadataBizTypeMapping(ApprovalFormatCreateRequestBody req, String metaDataType) { + switch (metaDataType) { + case "Form": + mdBizTypeMappingService.save(req.getBillCategoryId(), req.getFormId()); + break; + case "GSPViewModel": + mdBizTypeMappingService.save(req.getBillCategoryId(), req.getVoId()); + break; + default: + break; + } + } + + /** + * 根据请求信息部署eapi元数据并同步到表单元数据中 + * + * @param request ApprovalFormatCreateRequestBody + * @param rtEapiMetadata 运行时eapi元数据 + */ + private static void DeployEapiMetadataAndSyncToFormMetadata(ApprovalFormatCreateRequestBody request, GspMetadata rtEapiMetadata) { + eapiRuntimeDeployment.deploy(rtEapiMetadata.getHeader().getId()); + SgMetadata sgMetadata = (SgMetadata) rtEapiMetadata.getContent(); + //"/api/scm/sd/v1.0/kuozhan_ebs" + String baseUri = sgMetadata.getRouter(); + ObjectNode formModule = (ObjectNode) JsonUtil.toJsonNode(request.getFormContent()); + ObjectNode voContent = (ObjectNode) formModule.at("/module/schemas/0"); + voContent.put("eapiId", rtEapiMetadata.getHeader().getId()); + voContent.put("getDataMethod", "byEapi"); + voContent.put("baseUri", baseUri); + //更新表单元数据 + GspMetadata formMetadata = customizationService.getMetadata(request.getFormId()); + GspMetadata newMetadata = (GspMetadata) formMetadata.clone(); + newMetadata.setContent(new FormMetadataContent() { + { + this.setId(request.getFormId()); + this.setContents(formModule); + } + }); + customizationService.save(newMetadata); + } + + /** + * 部署设计器上手工创建的VO和Eapi + * + * @param request ApprovalFormatCreateRequestBody + * @param viewModelId 视图对象编号 + * @param bizEntityId 业务实体编号 + */ + public static void deployManualVOandEapi(ApprovalFormatCreateRequestBody request, String viewModelId, String bizEntityId) { + GspMetadata voMetadata = customizationService.getMetadata(viewModelId); + + GspMetadata voMetadataCopy = (GspMetadata) voMetadata.clone(); + //重新赋值header里的code和name + String code = voMetadataCopy.getHeader().getCode(); + String name = voMetadataCopy.getHeader().getName(); + voMetadataCopy.getHeader().setCode(appendSuffix(code, "GSPViewModel")); + voMetadataCopy.getHeader().setName(appendSuffix(name, "GSPViewModel")); + voMetadataCopy.setContent(voMetadata.getContent()); + try { + GspMetadata RtEapiMetadata = eapiMetadataRtService.createRtEapi(voMetadataCopy); + DeployEapiMetadataAndSyncToFormMetadata(request, RtEapiMetadata); + } catch (Exception e) { + throw new RuntimeException("只支持使用手工创建且没有部署过Eapi的视图对象来创建审批格式!"); + } + } + + /** + * 部署VO + * + * @param viewModelId 视图对象编号 + * @param bizEntityId 业务实体编号 + */ + private static void deployViewModelByVOIdAndBEId(String viewModelId, String bizEntityId) { + GspMetadata ViewModelMetadata = customizationService.getMetadata(viewModelId); + GspViewModel vo = (GspViewModel) ViewModelMetadata.getContent(); + Date date = new Date(); + GspVoExtendInfo gspVoExtendInfo = new GspVoExtendInfo(ViewModelMetadata.getHeader().getId(), "", vo.getGeneratedConfigID(), null, date, null, date, bizEntityId); + List gspVoExtendInfoList = new ArrayList<>(); + gspVoExtendInfoList.add(gspVoExtendInfo); + gspVoExtendInfoService.saveGspVoExtendInfos(gspVoExtendInfoList); + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatPermission.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatPermission.java new file mode 100644 index 00000000..48892fb8 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatPermission.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.licservice.api.manager.StandardControlFactory; + + +public class ApprovalFormatPermission { + + private final StandardControlFactory standardControlFactory; + private final String moduleName = "CTMD"; + private final String moduleDisplayName = "动态建模"; + + public ApprovalFormatPermission() { + this.standardControlFactory = SpringBeanUtils.getBean(StandardControlFactory.class); + } + + /** + * 动态建模模块权限控制 + */ + public void checkModulePermission() { + standardControlFactory.licStandardControl(this.moduleName); + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatTreeUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatTreeUtil.java new file mode 100644 index 00000000..47cdc557 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatTreeUtil.java @@ -0,0 +1,281 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.metadata.rtcustomization.api.entity.DimensionExtendEntity; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormat; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatEnum; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatTreeNode; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 审批格式服务 + * @author Xu‘fa Wang + * @date 2020/5/16 14:27 + */ +public class ApprovalFormatTreeUtil { + /** + * Level 1.2.3是静止的 返回的map里Level1,2,3是不连续的 + * 返回的map可能情形 [Level1, Level2, Level3]: + * [1,1,1],[1,1,0],[1,0,1],[1,0,0],[0,0,0],[0,1,1],[0,0,1],[0,1,0] + * 子树(不包含系统预制表单)层级有3种情况:3层,2层,1层 + * 从底向上构建树 + * @param root 根节点 + * @param levelMap 子树Map + * @Return + * * { + * * data: { + * * tplName: '采购订单系统预置模板', + * * tplType: '系统预制', + * * billCategory: '', + * * orgName: '', + * * operator: 'System', + * * optTime: '2019.07.10' + * * }, + * * children: [ + * * { + * * data: { + * * tplName: '设备采购订单公共模板', + * * tplType: '公共模板', + * * billCategory: '设备采购订单', + * * orgName: '', + * * operator: '周小洁', + * * optTime: '2019.08.10' + * * }, + * * children: [ + * * { + * * data: { + * * tplName: '浪潮软件设备采购订单模板', + * * tplType: '项目新增', + * * billCategory: '设备采购订单', + * * orgName: '浪潮软件', + * * operator: '周小洁', + * * optTime: '2019.09.10' + * * }, + * * children: [] + * * } + * * ] + * * } + * * ] + * * } + * */ + public static ApprovalFormatTreeNode assembleTree(ApprovalFormat root, Map> levelMap) { + ApprovalFormatTreeNode rtcTplTreeRoot = new ApprovalFormatTreeNode(root, new ArrayList<>()); + List level1List = levelMap.get(ApprovalFormatEnum.LEVEL.ONE.name()); + List level2List = levelMap.get(ApprovalFormatEnum.LEVEL.TWO.name()); + List level3List = levelMap.get(ApprovalFormatEnum.LEVEL.THREE.name()); + switch (getDepth(levelMap)){ + case 1: + rtcTplTreeRoot = handleChildTreeWithDepthOne(rtcTplTreeRoot, level1List, level2List, level3List); + break; + case 2: + rtcTplTreeRoot = handleChildTreeWithDepthTwo(rtcTplTreeRoot, level1List, level2List, level3List); + break; + case 3: + rtcTplTreeRoot = handleChildTreeWithDepthThree(rtcTplTreeRoot, level1List, level2List, level3List); + break; + default: + break; + } + return rtcTplTreeRoot; + } + + public static ApprovalFormat convertToApprovalFormat(MetadataHeader mdInfo, ApprovalFormat approvalFormatFromDatabase, String firstDimension, String secondDimension, boolean isSys) { + ApprovalFormat approvalFormat = new ApprovalFormat(); + + if(approvalFormatFromDatabase != null) { + approvalFormat.setId(approvalFormatFromDatabase.getId()); + + approvalFormat.setAttributeName(approvalFormatFromDatabase.getAttributeName()); + approvalFormat.setFirstDimension(approvalFormatFromDatabase.getFirstDimension()); + approvalFormat.setSecondDimension(approvalFormatFromDatabase.getSecondDimension()); + approvalFormat.setBillCategoryId(approvalFormatFromDatabase.getBillCategoryId()); + approvalFormat.setBizEntityId(approvalFormatFromDatabase.getBizEntityId()); + approvalFormat.setViewObjectId(approvalFormatFromDatabase.getViewObjectId()); + approvalFormat.setApprovalFormId(approvalFormatFromDatabase.getApprovalFormId()); + approvalFormat.setApprovalFormPublishUri(approvalFormatFromDatabase.getApprovalFormPublishUri()); + } else { + approvalFormat.setId(mdInfo.getId()); + + //""可以作为map的key + approvalFormat.setFirstDimension(StringUtility.isNullOrEmpty(firstDimension) ? "" : firstDimension); + approvalFormat.setSecondDimension(StringUtility.isNullOrEmpty(secondDimension) ? "" : secondDimension); + } + + approvalFormat.setCode(mdInfo.getCode()); + approvalFormat.setName(mdInfo.getName()); + approvalFormat.setAttributeName(isSys ? ApprovalFormatEnum.TEMPLATE_ATTRIBUTES.SYS.name() : ApprovalFormatEnum.TEMPLATE_ATTRIBUTES.NEW.name()); + + return approvalFormat; + } + + /** + * Level 1: 两维度都为空 + * Level 2: 1st维度不空,2nd维度空 + * Level 3: 两维度都不空 + * */ + public static Map> groupByDimensions(List children) { + Map> levelMap = new HashMap<>(); + if(children == null || children.size() <= 0) { + return levelMap; + } + // 遍历children,处理纬度值为null的场景(如""在oracle数据库返回为null) + for (ApprovalFormat child: children) { + if(child.getFirstDimension() == null) { + child.setFirstDimension(""); + } + + if(child.getSecondDimension() == null) { + child.setSecondDimension(""); + } + } + + Map> firstDimensionMap = children.stream().collect(Collectors.groupingBy(ApprovalFormat::getFirstDimension)); + + Map> secondDimensionMap; + List level1List, level2List, level3List; + level1List = new ArrayList<>(); + level2List = new ArrayList<>(); + level3List = new ArrayList<>(); + for(Map.Entry> entry : firstDimensionMap.entrySet()) { + if("".equals(entry.getKey())) { + //99%只有一个节点,不排除有多个。当有多个时,默认第一个为构造下级树结构的根节点 + //业务上规则,维度1为空的,维度2必定空 + level1List.addAll(entry.getValue()); + } else { + secondDimensionMap = entry.getValue().stream().collect(Collectors.groupingBy(ApprovalFormat::getSecondDimension)); + for(Map.Entry> innerEntry : secondDimensionMap.entrySet()){ + // 维度1 不空,维度2 空 + if("".equals(innerEntry.getKey())) { + level2List.addAll(innerEntry.getValue()); + }else{ + level3List.addAll(innerEntry.getValue()); + } + } + } + levelMap.put(ApprovalFormatEnum.LEVEL.ONE.name(), level1List.stream().map(item -> new ApprovalFormatTreeNode(item, new ArrayList<>())).collect(Collectors.toList())); + levelMap.put(ApprovalFormatEnum.LEVEL.TWO.name(), level2List.stream().map(item -> new ApprovalFormatTreeNode(item, new ArrayList<>())).collect(Collectors.toList())); + levelMap.put(ApprovalFormatEnum.LEVEL.THREE.name(), level3List.stream().map(item -> new ApprovalFormatTreeNode(item, new ArrayList<>())).collect(Collectors.toList())); + } + return levelMap; + } + + public static List convertToRtcTemplateList(List list, HashMap formIdApprovalFormatMap) { + List retList = new ArrayList<>(); + list.forEach(item -> { + MetadataHeader mdInfo = item.getExtendMetadataEntity().getHeader(); + ApprovalFormat approvalFormat = formIdApprovalFormatMap.get(mdInfo.getId()); + retList.add(convertToApprovalFormat(mdInfo, approvalFormat, item.getFirstDimension(), item.getSecondDimension(), false)); + }); + return retList; + } + + private static int getDepth(Map> levelMap) { + int depth = 0; + + if(levelMap.get(ApprovalFormatEnum.LEVEL.ONE.name()).size() > 0){ + depth ++; + } + + if(levelMap.get(ApprovalFormatEnum.LEVEL.TWO.name()).size() > 0) { + depth ++; + } + + if(levelMap.get(ApprovalFormatEnum.LEVEL.THREE.name()).size() > 0) { + depth ++; + } + + return depth; + } + + /** + * 只有一级子树,直接把子节点接到root + * */ + private static ApprovalFormatTreeNode handleChildTreeWithDepthOne(ApprovalFormatTreeNode root, + List level1List, + List level2List, + List level3List){ + if(level1List.size() > 0) { + root.setChildren(level1List); + } + + if(level2List.size() > 0) { + root.setChildren(level2List); + } + + if(level3List.size() > 0) { + root.setChildren(level3List); + } + + return root; + } + + /** + * 只有两级子树: + * 当Level1不为空时,直接把Level2 或 Level3 子节点接到Level1[0]节点 + * 当Level1为空时,把level3节点与level2节点有相同维度1的元素归集到当前Level2节点; + * Level3中维度1信息没有与Level2中任何节点匹配,成为孤儿节点; + * Level2中没有任何子节点的节点,成为孤儿节点。 + * 重新构造一个数组,包含所有的Level2节点,和Level3的孤儿节点,并把该数组设置为root的子树 + * */ + private static ApprovalFormatTreeNode handleChildTreeWithDepthTwo(ApprovalFormatTreeNode root, + List level1List, + List level2List, + List level3List){ + if(level1List.size() > 0){ + if (level2List.size() > 0) { + level1List.get(0).setChildren(level2List); + } + + if(level3List.size() > 0) { + level1List.get(0).setChildren(level3List); + } + + root.setChildren(level1List); + } else { + root.setChildren(groupLevel2And3(level2List,level3List)); + } + return root; + } + + /** + * 有三级子树: + * 先把Level2和Level3归集,再把归集后List设置为Level1[0]的子树 + * */ + private static ApprovalFormatTreeNode handleChildTreeWithDepthThree(ApprovalFormatTreeNode root, + List level1List, + List level2List, + List level3List){ + level1List.get(0).setChildren(groupLevel2And3(level2List, level3List)); + root.setChildren(level1List); + return root; + } + + private static List groupLevel2And3(List level2List, List level3List) { + List result = new ArrayList<>(); + List children; + //拥有Level3子节点的维度一信息 + Map firstDimensionWithChildren = new HashMap<>(); + for(ApprovalFormatTreeNode r : level2List) { + //把level3中与当前level2节点相同维度1的元素归集到当前节点(children) + children = level3List.stream().filter(item -> item.getData().getFirstDimension().equals(r.getData().getFirstDimension())).collect(Collectors.toList()); + r.setChildren(children); + firstDimensionWithChildren.put(r.getData().getFirstDimension(), null); + } + + //包含全部Level2节点 + result.addAll(level2List); + + //查找Level3孤儿节点 + List orphanList = level3List.stream().filter(item -> !firstDimensionWithChildren.containsKey(item.getData().getFirstDimension())).collect(Collectors.toList()); + result.addAll(orphanList); + + return result; + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatUtil.java new file mode 100644 index 00000000..6f282689 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApprovalFormatUtil.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormat; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormatQueryResponseBody; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +/** + * 审批格式通用类 + * @author Xu‘fa Wang + * @date 2020/5/19 21:13 + */ +public class ApprovalFormatUtil { + /** + * 比较两个ApprovalFormat实例是否相等 + * @param source 待比较ApprovalFormat实例 + * @param destination 比较ApprovalFormat实例 + * @return true: 两个值相同; false:两个值不同 + */ + public static boolean isEqual(ApprovalFormat source, ApprovalFormat destination) { + return source.getId().equals(destination.getId()) + && source.getFirstDimension().equals(destination.getFirstDimension()) + && source.getSecondDimension().equals(destination.getSecondDimension()) + && source.getBillCategoryId().equals(destination.getBillCategoryId()) + && source.getBizEntityId().equals(destination.getBizEntityId()) + && source.getViewObjectId().equals(destination.getViewObjectId()) + && source.getApprovalFormId().equals(destination.getApprovalFormId()) + && source.getApprovalFormPublishUri().equals(destination.getApprovalFormPublishUri()); + } + + + /** + * 转换帮助元数据内容 + * @param approvalFormat 审批格式实例 + */ + public static ApprovalFormatQueryResponseBody convertToApprovalFormatQueryResponseBody(ApprovalFormat approvalFormat) { + if(approvalFormat == null) { + return null; + } + + ApprovalFormatQueryResponseBody approvalFormatQueryResponseBody = new ApprovalFormatQueryResponseBody(); + + approvalFormatQueryResponseBody.setId(approvalFormat.getId()); + approvalFormatQueryResponseBody.setCode(approvalFormat.getCode()); + approvalFormatQueryResponseBody.setName(approvalFormat.getName()); + approvalFormatQueryResponseBody.setAttributeName(approvalFormat.getAttributeName()); + approvalFormatQueryResponseBody.setFirstDimension(approvalFormat.getFirstDimension()); + // 维度名称默认等于维度编号 + approvalFormatQueryResponseBody.setFirstDimensionName(approvalFormat.getFirstDimension()); + approvalFormatQueryResponseBody.setSecondDimension(approvalFormat.getSecondDimension()); + approvalFormatQueryResponseBody.setSecondDimensionName(approvalFormat.getSecondDimension()); + approvalFormatQueryResponseBody.setBillCategoryId(approvalFormat.getBillCategoryId()); + approvalFormatQueryResponseBody.setBizEntityId(approvalFormat.getBizEntityId()); + approvalFormatQueryResponseBody.setViewObjectId(approvalFormat.getViewObjectId()); + approvalFormatQueryResponseBody.setApprovalFormId(approvalFormat.getApprovalFormId()); + approvalFormatQueryResponseBody.setApprovalFormPublishUri(approvalFormat.getApprovalFormPublishUri()); + + return approvalFormatQueryResponseBody; + } + + public static ObjectNode getVoContent(GspMetadata formMetaData) { + FormMetadataContent formMetaDataContent = (FormMetadataContent)formMetaData.getContent(); + ObjectNode voContent = (ObjectNode)formMetaDataContent.getContents().get("module").get("schemas").get(0); + return voContent; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApproveFormatPreviewUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApproveFormatPreviewUtil.java new file mode 100644 index 00000000..b42bf90f --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/ApproveFormatPreviewUtil.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.common.io.FileUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * description: + * + * @author Noah Guo + * @date 2020/05/17 + */ +public class ApproveFormatPreviewUtil { + private static final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + + /** + * 根据formId获取元数据 + * + * @param formId + * @return + * @throws Exception + */ + + public static GspMetadata getGspMetadataWithFormId(String formId) throws Exception { + GspMetadata gspMetadata = customizationService.getMetadata(formId); + if (gspMetadata == null) { + throw new Exception("根据formId 获取元数据为空"); + } + return gspMetadata; + } + + + /** + * 获取移动审批对应表单路径 + * + * @param formCode + * @return + */ + public static String generateMobileApproveDevBasePath(String formCode) { + String currentWorkSpace = FileUtility.getCurrentWorkPath(); + String projectRuntimeAppPath = currentWorkSpace + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "web" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "runtime" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "projects" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + "mobileapproval" + FileUtility.DIRECTORY_SEPARATOR_CHAR + + formCode; + return projectRuntimeAppPath; + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/FieldUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/FieldUtil.java new file mode 100644 index 00000000..1ed43494 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/FieldUtil.java @@ -0,0 +1,320 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.cef.designtime.api.IGspCommonField; +import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection; +import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection; +import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection; +import com.inspur.edp.cef.designtime.api.element.GspAssociation; +import com.inspur.edp.cef.designtime.api.element.GspElementObjectType; +import com.inspur.edp.formserver.viewmodel.GspViewModelElement; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.element.ElementCollection; +import com.inspur.edp.udt.designtime.api.entity.element.UdtElement; +import com.inspur.edp.web.approvalformat.api.entity.schema.ComplexField; +import com.inspur.edp.web.approvalformat.api.entity.schema.Field; +import com.inspur.edp.web.approvalformat.api.entity.schema.SimpleField; +import com.inspur.edp.web.approvalformat.api.entity.schema.editor.*; +import com.inspur.edp.web.approvalformat.api.entity.schema.type.*; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * @author Xu‘fa Wang + * @date 2020/7/7 17:09 + */ +public class FieldUtil { + private static final CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + + public static Field createField(IGspCommonField element, TypeBuildingContext parentContext) { + Field createdField; + // 按照从子类到父类的方式检查使用的类型 + if(element instanceof GspViewModelElement) { + createdField = constructField((GspViewModelElement) element, parentContext); + } else if(element instanceof UdtElement) { + createdField = constructField((UdtElement) element, parentContext); + } else { + throw new RuntimeException("不支持类型,请联系开发人员支持。当前字段是: " + + element.getCode() + " : " + element.getName()); + } + + return createdField; + } + + private static Field constructField(SimpleDataTypeDef udtTypeDef, TypeBuildingContext parentContext) { + TypeBuildingContext elementContext = TypeBuildingContext.create(udtTypeDef, parentContext); + return constructField(elementContext, parentContext); + } + + private static Field constructField(GspViewModelElement element, TypeBuildingContext parentContext) { + TypeBuildingContext elementContext = TypeBuildingContext.create(element, parentContext); + return constructField(elementContext, parentContext); + } + + private static Field constructField(UdtElement element, TypeBuildingContext parentContext) { + TypeBuildingContext elementContext = TypeBuildingContext.create(element, parentContext); + return constructField(elementContext, parentContext); + } + + public static Field constructField(TypeBuildingContext elementContext, TypeBuildingContext parentContext){ + String prefix = constructBindingFieldPrefix(parentContext); + Map elementParams = elementContext.getParams(); + String id = (String) elementParams.get("id"); + String code = (String) elementParams.get("code"); + String name = (String) elementParams.get("name"); + String label = (String) elementParams.get("label"); + Boolean multiLanguageInput = (Boolean) elementParams.get("multiLanguageInput"); + + elementParams.put("bindingField", prefix + label); + String bindingField = (String) elementParams.get("bindingField"); + + elementParams.put("id", elementContext.reviseElementId(id)); + String revisedElementId = (String) elementParams.get("id"); + + elementParams.put("path", constructFieldPath(elementContext, parentContext)); + String path = (String) elementParams.get("path"); + + elementParams.put("bindingPath", constructBindingPath(elementContext, parentContext)); + String bindingPath =(String) elementParams.get("bindingPath"); + + if(elementContext.hasAssociation() || elementContext.hasUnifiedDataType() || elementContext.isDynamicField()){ + return new ComplexField(){ + { + this.setId(revisedElementId); + this.setOriginalId(id); + this.setCode(code); + this.setName(name); + this.setLabel(StringUtility.toCamelCase(label)); + this.setBindingField(StringUtility.toCamelCase(bindingField)); + this.setPath(path); + this.setBindingPath(bindingPath); + this.setType(constructFieldType(elementContext, parentContext)); + } + }; + } + Boolean require = (Boolean) elementContext.getParams().get("require"); + String defaultValue = (String) elementContext.getParams().get("defaultValue"); + Boolean isReadOnly = (Boolean) elementContext.getParams().get("readonly"); + return new SimpleField(){ + { + this.setId(revisedElementId); + this.setOriginalId(id); + this.setCode(code); + this.setName(name); + this.setLabel(StringUtility.toCamelCase(label)); + this.setBindingField(StringUtility.toCamelCase(bindingField)); + this.setPath(path); + this.setBindingPath(bindingPath); + this.setReadonly(isReadOnly); + this.setRequire(require); + this.setDefaultValue(defaultValue); + this.setMultiLanguage(multiLanguageInput); + this.setType(constructFieldType(elementContext, parentContext)); + this.setEditor(constructFieldEditor(elementContext)); + } + }; + } + + private static String constructBindingFieldPrefix(TypeBuildingContext context){ + String prefix = ""; + if (context != null){ + prefix = context.getParams().get("bindingField") + "_"; + } + return prefix; + } + + private static String constructFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext) { + String label = (String) elementContext.getParams().get("label"); + String prefix = ""; + if (parentTypeBuildingContext != null) { + prefix = (String) parentTypeBuildingContext.getParams().get("path"); + } + if (!prefix.isEmpty()) { + return prefix+"."+label; + } + return label; + } + + private static String constructBindingPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext){ + String label = StringUtility.toCamelCase((String) elementContext.getParams().get("label")); + String prefix = ""; + if (parentTypeBuildingContext != null) { + prefix = (String) parentTypeBuildingContext.getParams().get("bindingPath"); + } + if (!prefix.isEmpty()) { + return prefix+"."+label; + } + return label; + } + + private static FieldType constructFieldType(TypeBuildingContext elementContext, TypeBuildingContext parentContext) { + if(elementContext.hasUnifiedDataType()) { + return constructObjectFieldType(elementContext); + } + + if(elementContext.hasAssociation()) { + return constructEntityFieldType(elementContext,parentContext); + } + + if(elementContext.getObjectType() == GspElementObjectType.Enum) { + return constructEnumFieldType(elementContext); + } + + if(elementContext.isDynamicField()) { + return constructDynamicFieldType(elementContext); + } + + return constructSimpleFieldType(elementContext); + } + + private static FieldType constructObjectFieldType(TypeBuildingContext elementContext) { + UnifiedDataTypeDef udtTypeDef = constructUnifiedDataType(elementContext.getUnifiedDataType()); + List fields = new ArrayList<>(); + String typeName = "", displayTypeName = ""; + if(udtTypeDef instanceof SimpleDataTypeDef) { + Field field = constructField((SimpleDataTypeDef) udtTypeDef, elementContext); + if(field instanceof SimpleField){ + ((SimpleField) field).setRequire((Boolean) elementContext.getParams().get("require")); + ((SimpleField) field).setReadonly((Boolean) elementContext.getParams().get("readonly")); + } + typeName = elementContext.reviseTypeName(field.getId(), field.getCode()); + displayTypeName = udtTypeDef.getName(); + fields.add(field); + } + if(udtTypeDef instanceof ComplexDataTypeDef) { + typeName = elementContext.reviseTypeName(udtTypeDef.getID(),udtTypeDef.getCode()); + displayTypeName = udtTypeDef.getName(); + + ElementCollection elementCollection = ((ComplexDataTypeDef) udtTypeDef).getElements(); + if(elementCollection != null && elementCollection.size() > 0) { + elementCollection.forEach(field -> { + Field createdField = createField(field, elementContext); + fields.add(createdField); + }); + } + } + if(!(udtTypeDef instanceof SimpleDataTypeDef)&&!(udtTypeDef instanceof ComplexDataTypeDef)) { + throw new RuntimeException("Id为"+udtTypeDef.getId()+"的统一数据类型元数据为未识别的类型。"); + } + + ObjectType objectType = new ObjectType(typeName, displayTypeName, fields); + if("dbfbe55d-ba65-4a7f-a9d4-4f664ec6ec68".equals(udtTypeDef.getId()) + || "12be876c-368c-4262-88ab-4112688540b0".equals(udtTypeDef.getId())) { + objectType = new HierarchyType(typeName, displayTypeName, fields); + } + + return objectType; + } + + private static FieldType constructEntityFieldType(TypeBuildingContext elementContext, TypeBuildingContext parentContext) { + GspAssociationCollection associations = elementContext.getAssociations(); + if (associations == null || associations.size() == 0) { + throw new RuntimeException("字段" + elementContext.getParams().get("name") + "不包含关联实体信息。"); + } + TypeBuildingContext originalFieldContext = TypeBuildingContext.createSimpleTypeContextFromAssociation(elementContext, parentContext); + Field originalField = constructField(originalFieldContext, parentContext); + List typeFields = new ArrayList<>(); + typeFields.add(originalField); + GspAssociationCollection associationCollection = elementContext.getAssociations(); + if(associationCollection != null && associationCollection.size() > 0) { + associationCollection.forEach(association -> { + GspFieldCollection refElementCollection = association.getRefElementCollection(); + List fieldCollection = new LinkedList<>(); + if(refElementCollection != null && refElementCollection.size() > 0) { + refElementCollection.forEach(refEle -> { + Field createdField = createField(refEle, elementContext); + fieldCollection.add(createdField); + }); + } + if(fieldCollection.size() > 0) { + typeFields.addAll(fieldCollection); + } + }); + } + + GspAssociation anyAss = elementContext.getAssociations().get(0); + String typeName = elementContext.reviseTypeName(originalField.getId(), anyAss.getRefModelCode()); + String displayTypeName = anyAss.getRefModelName(); + return new EntityType(typeName, displayTypeName, originalField.getLabel(), typeFields, new ArrayList<>()); + } + + private static UnifiedDataTypeDef constructUnifiedDataType(String uri) { + GspMetadata udtMetadata = customizationService.getMetadata(uri); + if(udtMetadata == null) { + throw new RuntimeException("未获取到id为" + uri + "的统一数据类型(UDT)元数据。"); + } + + UnifiedDataTypeDef typeDef = (UnifiedDataTypeDef) udtMetadata.getContent(); + return typeDef; + } + + private static FieldType constructEnumFieldType(TypeBuildingContext elementContext) { + FieldType valueType = constructSimpleFieldType(elementContext); + + List enumValues = new ArrayList<>(); + GspEnumValueCollection enumValueCollection = elementContext.getEnums(); + if(enumValueCollection != null && enumValueCollection.size() > 0) { + enumValueCollection.forEach(item -> enumValues.add(new EnumItem(item.getValue(), item.getName()))); + } + + return new EnumType(valueType, enumValues); + } + + private static FieldType constructDynamicFieldType(TypeBuildingContext elementContext) { + return new DynamicObjectType(); + } + + private static FieldType constructSimpleFieldType(TypeBuildingContext elementContext) { + switch (elementContext.getDataType()) { + case Boolean: + return new BooleanType(); + case Date: + case DateTime: + return new DateType(); + case Decimal: + case Integer: + return new NumericType((Integer)elementContext.getParams().get("length"), (Integer)elementContext.getParams().get("precision")); + case Text: + return new TextType((Integer)elementContext.getParams().get("length")); + default: + return new StringType((Integer)elementContext.getParams().get("length")); + } + } + + private static FieldEditor constructFieldEditor(TypeBuildingContext elementContext) { + if(elementContext.getObjectType() == GspElementObjectType.Enum) { + return new EnumField(); + } + + if(elementContext.isMultiLanguageField()) { + return new LanguageTextBox(); + } + + if(elementContext.getObjectType() == GspElementObjectType.None) { + switch (elementContext.getDataType()){ + case Boolean: + return new CheckBox(); + case Date: + case DateTime: + return new DateBox("yyyy-MM-dd"); + case Decimal: + case Integer: + return new NumericBox(); + case Text: + return new MultiTextBox(); + default: + return new TextBox(); + } + } + + return new TextBox(); + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/HelpProviderUtil.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/HelpProviderUtil.java new file mode 100644 index 00000000..6ee1956b --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/HelpProviderUtil.java @@ -0,0 +1,37 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.web.approvalformat.api.entity.HelpMetadataSimpleContent; +import com.inspur.edp.web.help.metadata.HelpMetadataContent; + +/** + * 帮助工具类 + * @author Xu‘fa Wang + * @date 2020/5/18 11:07 + */ +public class HelpProviderUtil { + /** + * 转换帮助元数据内容 + * @param helpMetadataContent 帮助元数据内容 + */ + public static HelpMetadataSimpleContent convertToHelpMetadataSimpleContent(HelpMetadataContent helpMetadataContent) { + if(helpMetadataContent == null) { + return null; + } + + HelpMetadataSimpleContent helpMetadataSimpleContent = new HelpMetadataSimpleContent(); + helpMetadataSimpleContent.setVersion(helpMetadataContent.getVersion()); + helpMetadataSimpleContent.setId(helpMetadataContent.getId()); + helpMetadataSimpleContent.setCode(helpMetadataContent.getCode()); + helpMetadataSimpleContent.setName(helpMetadataContent.getName()); + helpMetadataSimpleContent.setTitle(helpMetadataContent.getTitle()); + helpMetadataSimpleContent.setIdField(helpMetadataContent.getIdField()); + helpMetadataSimpleContent.setIdFieldName(helpMetadataContent.getIdFieldName()); + helpMetadataSimpleContent.setTextField(helpMetadataContent.getTextField()); + helpMetadataSimpleContent.setTextFieldName(helpMetadataContent.getTextFieldName()); + helpMetadataSimpleContent.setValueField(helpMetadataContent.getValueField()); + helpMetadataSimpleContent.setValueFieldName(helpMetadataContent.getValueFieldName()); + helpMetadataSimpleContent.setDisplayType(helpMetadataContent.getDisplayType()); + helpMetadataSimpleContent.setDescription(helpMetadataContent.getDescription()); + return helpMetadataSimpleContent; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/TypeBuildingContext.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/TypeBuildingContext.java new file mode 100644 index 00000000..dcbe37f1 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/util/TypeBuildingContext.java @@ -0,0 +1,261 @@ +package com.inspur.edp.web.approvalformat.core.util; + +import com.inspur.edp.cef.designtime.api.IGspCommonField; +import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection; +import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection; +import com.inspur.edp.cef.designtime.api.element.GspElementDataType; +import com.inspur.edp.cef.designtime.api.element.GspElementObjectType; +import com.inspur.edp.das.commonmodel.entity.GspCommonElement; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.element.UdtElement; +import com.inspur.edp.web.common.utility.StringUtility; +import lombok.Data; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Xu‘fa Wang + * @date 2020/6/8 16:52 + */ +@Data +public class TypeBuildingContext { + private GspElementObjectType objectType = GspElementObjectType.None; + private GspEnumValueCollection enums; + private GspAssociationCollection associations; + private String unifiedDataType; + private GspElementDataType dataType; + private Map params = new HashMap<>(); + private Map typeNameMaps = new HashMap<>(); + private Map elementIdMaps = new HashMap<>(); + private TypeBuildingContext root; + private TypeBuildingContext parent; + + public boolean hasUnifiedDataType() { + return this.getUnifiedDataType() != null && !StringUtils.isEmpty(this.getUnifiedDataType().trim()); + } + + public boolean inUnifiedDataType() { + return this.getParent() != null && (this.getParent().hasUnifiedDataType() || this.getParent().inUnifiedDataType()); + } + + public boolean hasAssociation() { + return this.getObjectType() == GspElementObjectType.Association && this.getAssociations() != null && this.getAssociations().size() > 0; + } + + public boolean isDynamicField() { + return this.getObjectType() == GspElementObjectType.DynamicProp; + } + + public boolean isMultiLanguageField() { + return (boolean) this.getParams().get("multiLanguageInput"); + } + + public boolean isMixinUDTAssociation() { + return this.hasAssociation() && this.hasUnifiedDataType(); + } + + public String reviseElementId(String elementId) { + String revisedElementId = elementId; + if (this.parent != null && this.inUnifiedDataType()) { + String parentId = (String) this.parent.getParams().get("id"); + revisedElementId = parentId.substring(0, 8) + elementId.substring(8); + } + Map elementIdMaps = this.getRoot() != null ? this.getRoot().getElementIdMaps() : this.getElementIdMaps(); + if (elementIdMaps.containsKey(revisedElementId)) { + elementIdMaps.put(revisedElementId, elementIdMaps.get(revisedElementId) + 1); + revisedElementId = revisedElementId.substring(0, revisedElementId.length() - 2) + elementIdMaps.get(revisedElementId); + } else { + elementIdMaps.put(revisedElementId, 0); + } + return revisedElementId; + } + + public String reviseTypeName(String suffixFieldId, String typeName) { + String suffix = suffixFieldId.length() > 3 ? suffixFieldId.substring(0, 4) : suffixFieldId; + String revisedTypeName = suffix.length() > 0 ? typeName + suffix.replace(suffix.substring(0, 1), suffix.substring(0, 1).toUpperCase()) : typeName; + Map typeNameMaps = this.getRoot() != null ? this.getRoot().getTypeNameMaps() : this.getTypeNameMaps(); + if (typeNameMaps.containsKey(revisedTypeName)) { + typeNameMaps.put(revisedTypeName, typeNameMaps.get(revisedTypeName) + 1); + return revisedTypeName + typeNameMaps.get(revisedTypeName); + } else { + typeNameMaps.put(revisedTypeName, 0); + return revisedTypeName; + } + } + + public static TypeBuildingContext createTypeBuildingContext(IGspCommonField element, TypeBuildingContext parentContext) { + if (element instanceof GspCommonElement) { + return create((GspCommonElement) element, parentContext); + } else if (element instanceof UdtElement) { + return create((UdtElement) element, parentContext); + } + + return null; + } + + public static TypeBuildingContext create(GspCommonElement element, TypeBuildingContext parentContext) { + if (element.getIsUdt()) { + if (StringUtils.isEmpty(element.getUdtID()) || StringUtils.isEmpty(element.getUdtID().trim())) { + throw new RuntimeException("标识为" + element.getId() + ",标签为" + element.getLabelID() + "的字段" + element.getName() + "被定义为'UnifiedDataType'字段,但是没有指定'UnifiedDataType'标识,请检查业务实体。"); + } + } + TypeBuildingContext context = new TypeBuildingContext() { + { + this.setObjectType(element.getObjectType()); + this.setEnums(element.getContainEnumValues()); + this.setAssociations(element.getChildAssociations()); + this.setDataType(element.getMDataType()); + this.setUnifiedDataType(element.getUdtID()); + this.setParams(new HashMap() { + { + this.put("id", element.getId() == null ? "" : element.getId()); + this.put("code", element.getCode() == null ? "" : element.getCode()); + this.put("name", element.getName() == null ? "" : element.getName()); + this.put("label", element.getLabelID() == null ? "" : element.getLabelID()); + this.put("bindingField", element.getLabelID() == null ? "" : element.getLabelID()); + this.put("path", element.getLabelID() == null ? "" : element.getLabelID()); + this.put("require", element.isRequired()); + this.put("readonly", element.getReadonly()); + this.put("defaultValue", element.getDefaultValue() == null ? "" : element.getDefaultValue()); + this.put("length", element.getLength()); + this.put("precision", element.getPrecision()); + this.put("multiLanguageInput", false); + } + }); + this.setRoot(parentContext != null && parentContext.getRoot() != null ? parentContext.getRoot() : parentContext); + this.setParent(parentContext); + } + }; + return context; + } + + public static TypeBuildingContext create(SimpleDataTypeDef udtTypeDef, TypeBuildingContext parentContext) { + TypeBuildingContext context = new TypeBuildingContext() { + { + this.setObjectType(udtTypeDef.getObjectType()); + this.setEnums(udtTypeDef.getContainEnumValues()); + this.setAssociations(udtTypeDef.getChildAssociations()); + this.setDataType(udtTypeDef.getMDataType()); + this.setParams(new HashMap() { + { + this.put("id", udtTypeDef.getId() == null ? "" : udtTypeDef.getId()); + this.put("code", udtTypeDef.getCode() == null ? "" : udtTypeDef.getCode()); + this.put("name", udtTypeDef.getName() == null ? "" : udtTypeDef.getName()); + this.put("label", udtTypeDef.getCode() == null ? "" : udtTypeDef.getCode()); + this.put("bindingField", udtTypeDef.getCode() == null ? "" : udtTypeDef.getCode()); + this.put("path", udtTypeDef.getCode() == null ? "" : udtTypeDef.getCode()); + this.put("require", udtTypeDef.getIsRequired()); + this.put("readonly", false); + this.put("defaultValue", udtTypeDef.getDefaultValue() == null ? "" : udtTypeDef.getDefaultValue()); + this.put("length", udtTypeDef.getLength()); + this.put("precision", udtTypeDef.getPrecision()); + this.put("multiLanguageInput", false); + } + }); + this.setRoot(parentContext != null && parentContext.getRoot() != null ? parentContext.getRoot() : parentContext); + this.setParent(parentContext); + } + }; + + updateTypeBuildingContext(context, parentContext); + + return context; + } + + public static TypeBuildingContext create(UdtElement udtTypeDef, TypeBuildingContext parentContext) { + if (udtTypeDef.getIsUdt()) { + if (StringUtility.isNullOrEmpty(udtTypeDef.getUdtID()) || StringUtility.isNullOrEmpty(udtTypeDef.getUdtID().trim())) { + throw new RuntimeException("标识为" + udtTypeDef.getId() + ",标签为" + udtTypeDef.getLabelID() + "的字段" + udtTypeDef.getName() + "被定义为'UnifiedDataType'字段,但是没有指定'UnifiedDataType'标识,请检查业务实体。"); + } + } + TypeBuildingContext typeBuildingContext = new TypeBuildingContext() { + { + this.setObjectType(udtTypeDef.getObjectType()); + this.setEnums(udtTypeDef.getContainEnumValues()); + this.setAssociations(udtTypeDef.getChildAssociations()); + this.setDataType(udtTypeDef.getMDataType()); + this.setUnifiedDataType(udtTypeDef.getUdtID()); + this.setParams(new HashMap(16) { + { + this.put("id", udtTypeDef.getId() == null ? "" : udtTypeDef.getId()); + this.put("code", udtTypeDef.getCode() == null ? "" : udtTypeDef.getCode()); + this.put("name", udtTypeDef.getName() == null ? "" : udtTypeDef.getName()); + this.put("label", udtTypeDef.getLabelID() == null ? "" : udtTypeDef.getLabelID()); + this.put("bindingField", udtTypeDef.getLabelID() == null ? "" : udtTypeDef.getLabelID()); + this.put("path", udtTypeDef.getLabelID() == null ? "" : udtTypeDef.getLabelID()); + this.put("require", udtTypeDef.getIsRequire()); + this.put("readonly", false); + this.put("defaultValue", udtTypeDef.getDefaultValue() == null ? "" : udtTypeDef.getDefaultValue()); + this.put("length", udtTypeDef.getLength()); + this.put("precision", udtTypeDef.getPrecision()); + this.put("multiLanguageInput", false); + } + }); + this.setRoot(parentContext != null && parentContext.getRoot() != null ? parentContext.getRoot() : parentContext); + this.setParent(parentContext); + } + }; + + return typeBuildingContext; + } + + private static void updateTypeBuildingContext(TypeBuildingContext typeBuildingContext, TypeBuildingContext parentContext) { + if (parentContext == null || !parentContext.isMixinUDTAssociation()) { + return; + } + + if (parentContext.getAssociations() == null || parentContext.getAssociations().size() == 0) { + return; + } + + parentContext.getAssociations().forEach(association -> { + if (association.getRefElementCollection() == null || association.getRefElementCollection().size() == 0) { + return; + } + + association.getRefElementCollection().forEach(refElement -> { + if (refElement.getIsFromAssoUdt()) { + GspAssociationCollection associationCollection = typeBuildingContext.getAssociations(); + if (associationCollection != null && associationCollection.size() > 0) { + if (!refElement.getIsFromAssoUdt()) { + associationCollection.get(0).getRefElementCollection().add(refElement); + } + } + } + }); + }); + } + + public static TypeBuildingContext createSimpleTypeContextFromAssociation(TypeBuildingContext context, TypeBuildingContext parent) { + GspAssociationCollection associations = context.getAssociations(); + if (associations == null || associations.size() == 0) { + throw new RuntimeException("字段" + context.getParams().get("name") + "不包含关联实体信息。"); + } + Map params = context.getParams(); + return new TypeBuildingContext() { + { + this.setDataType(context.getDataType()); + this.setParams(new HashMap() { + { + this.put("id", associations.get(0).getId() == null ? "" : associations.get(0).getId()); + this.put("code", params.get("code") == null ? "" : params.get("code")); + this.put("name", params.get("name") == null ? "" : params.get("name")); + this.put("label", params.get("label") == null ? "" : params.get("label")); + this.put("bindingField", params.get("label") == null ? "" : params.get("label")); + this.put("path", params.get("label") == null ? "" : params.get("label")); + this.put("require", params.get("require")); + this.put("readonly", params.get("readonly")); + this.put("defaultValue", params.get("defaultValue") == null ? "" : params.get("defaultValue")); + this.put("length", params.get("length")); + this.put("precision", params.get("precision")); + this.put("multiLanguageInput", false); + } + }); + this.setRoot(parent != null && parent.getRoot() != null ? parent.getRoot() : parent); + this.setParent(parent); + } + }; + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormMetadataWebServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormMetadataWebServiceImpl.java new file mode 100644 index 00000000..a263589f --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormMetadataWebServiceImpl.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.approvalformat.core.webservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalFormUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.entity.ApprovalViewObjectUpdateRequestBody; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormMetadataService; +import com.inspur.edp.web.approvalformat.api.webservice.ApprovalFormMetadataWebService; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 审批单据元数据Web服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/17 18:05 + */ +public class ApprovalFormMetadataWebServiceImpl implements ApprovalFormMetadataWebService { + private ApprovalFormMetadataService approvalFormMetadataService = SpringBeanUtils.getBean(ApprovalFormMetadataService.class); + + public ApprovalFormMetadataWebServiceImpl(ApprovalFormMetadataService approvalFormMetadataService) { + if(approvalFormMetadataService != null) { + this.approvalFormMetadataService = approvalFormMetadataService; + } + } + + @Override + public void updateApprovalFormMetadata(ApprovalFormUpdateRequestBody approvalFormUpdateRequestBody) { + this.approvalFormMetadataService.updateApprovalFormMetadata(approvalFormUpdateRequestBody); + } + + @Override + public void updateApprovalViewModelMetadata(ApprovalViewObjectUpdateRequestBody approvalViewObjectUpdateRequestBody) { + this.approvalFormMetadataService.updateApprovalViewModelMetadata(approvalViewObjectUpdateRequestBody); + } + + @Override + public FormMetadataContent getApprovalFormMetadataContent(String approvalFormMetadataId) { + return this.approvalFormMetadataService.getApprovalFormMetadataContent(approvalFormMetadataId); + } + + @Override + public String createSchemaFromVo(@RequestBody JsonNode voContent) { + return this.approvalFormMetadataService.createSchemaFromVo(voContent); + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormatWebServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormatWebServiceImpl.java new file mode 100644 index 00000000..65e3b062 --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/ApprovalFormatWebServiceImpl.java @@ -0,0 +1,149 @@ +package com.inspur.edp.web.approvalformat.core.webservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.web.approvalformat.api.entity.*; +import com.inspur.edp.web.approvalformat.api.service.ApprovalFormatService; +import com.inspur.edp.web.approvalformat.api.webservice.ApprovalFormatWebService; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +/** + * 审批格式Web服务实现 + * @author Xu‘fa Wang + * @date 2020/5/14 9:25 + */ +public class ApprovalFormatWebServiceImpl implements ApprovalFormatWebService { + private final ApprovalFormatService approvalFormatService; + + public ApprovalFormatWebServiceImpl(ApprovalFormatService approvalFormatService) { + this.approvalFormatService = approvalFormatService; + } + + @Override + public ApprovalFormatForestByDimension getApprovalFormatByDimension(String billCategoryId, String billCategoryExtendCode) { + return this.approvalFormatService.getApprovalFormatByDimension(billCategoryId, billCategoryExtendCode); + } + + @Override + public Map getEntityDataByBizEntityId(String dataId, String bizEntityId) { + return this.approvalFormatService.getEntityDataByBizEntityId(dataId, bizEntityId); + } + + @Override + public IEntityData getEntityDataByBizEntityConfigId(String dataId, String bizEntityConfigId) { + return this.approvalFormatService.getEntityDataByBizEntityConfigId(dataId, bizEntityConfigId); + } + + @Override + public List queryEntityData(String bizEntityId) { + return this.approvalFormatService.queryEntityData(bizEntityId); + } + + @Override + public List queryEntityDataWithCondition(JsonNode condition) { + return this.approvalFormatService.queryEntityDataWithCondition(condition); + } + + @Override + @Transactional(rollbackFor=Exception.class, propagation = Propagation.REQUIRED) + public ApprovalFormatCreateResponseBody createApprovalFormat(ApprovalFormatCreateRequestBody approvalFormatCreateRequestBody) { + return this.approvalFormatService.createApprovalFormat(approvalFormatCreateRequestBody); + } + + + @Override + public void deleteApprovalFormat(String approvalFormatId) { + this.approvalFormatService.deleteApprovalFormat(approvalFormatId); + } + + @Override + public void deleteApprovalFormatAndRelation(String billCategoryId, String metadataId, String firstDimension, String secondDimension) { + this.approvalFormatService.deleteApprovalFormatAndRelation(billCategoryId, metadataId, firstDimension, secondDimension); + } + + @Override + public void deleteApprovalFormatAndRelationById(String approvalFormatId) { + this.approvalFormatService.deleteApprovalFormatAndRelationById(approvalFormatId); + } + + @Override + public ApprovalFormat updateApprovalFormat(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody) { + return this.approvalFormatService.updateApprovalFormat(approvalFormatUpdateRequestBody); + } + + @Override + public ApprovalFormat updateApprovalFormatFormUrl(ApprovalFormatUpdateRequestBody approvalFormatUpdateRequestBody) { + return this.approvalFormatService.updateApprovalFormatFormUrl(approvalFormatUpdateRequestBody); + } + + @Override + public ApprovalFormat updateApprovalFormatDimension(ApprovalFormatDimensionUpdateRequestBody approvalFormatDimensionUpdateRequestBody) { + return this.approvalFormatService.updateApprovalFormatDimension(approvalFormatDimensionUpdateRequestBody); + } + + @Override + public ApprovalFormat getApprovalFormatEntityById(String approvalFormatId) { + return this.approvalFormatService.getApprovalFormatEntityById(approvalFormatId); + } + + @Override + public List getApprovalFormatCollection(String billCategoryId) { + return this.approvalFormatService.getApprovalFormatCollection(billCategoryId); + } + + @Override + public List getApprovalFormatCollectionOrderByDimension(String billCategoryId) { + return this.approvalFormatService.getApprovalFormatCollectionOrderByDimension(billCategoryId); + } + + @Override + public List getApprovalFormatCollectionOrderByDimension(String billCategoryId, String billCategoryExtendCode) { + return this.approvalFormatService.getApprovalFormatCollectionOrderByDimension(billCategoryId, billCategoryExtendCode); + } + + @Override + public void replicateApprovalFormat(String approvalFormatId) { + this.approvalFormatService.replicateApprovalFormat(approvalFormatId); + } + + @Override + public ApprovalFormat getApprovalFormatByBizEntityIdWithDimension(String businessEntityId, String firstDimension, String secondDimension) { + return this.approvalFormatService.getApprovalFormatByBizEntityIdWithDimension(businessEntityId, firstDimension, secondDimension); + } + + @Override + public String getApprovalFormUri(String businessEntityId, String firstDimension, String secondDimension) { + String localFirstDimension = firstDimension; + if("null".equalsIgnoreCase(firstDimension)) { + localFirstDimension = null; + } + String localSecondDimension = secondDimension; + if("null".equalsIgnoreCase(localSecondDimension)) { + localSecondDimension = null; + } + return this.approvalFormatService.getApprovalFormUri(businessEntityId, localFirstDimension, localSecondDimension); + } + + @Override + public String getApprovalFormUriByBillCategoryId(String billCategoryId, String firstDimension, String secondDimension) { + String localFirstDimension = firstDimension; + if("null".equalsIgnoreCase(firstDimension)) { + localFirstDimension = null; + } + String localSecondDimension = secondDimension; + if("null".equalsIgnoreCase(localSecondDimension)) { + localSecondDimension = null; + } + return this.approvalFormatService.getApprovalFormUriByBillCategoryId(billCategoryId, localFirstDimension, localSecondDimension); + } + + @Override + public HelpProviderResult getHelpProviderData(String billCategoryId, String billCategoryExtendCode, String dimensionId, String billCategoryDimensionItemId) { + return this.approvalFormatService.getHelpProviderData(billCategoryId, billCategoryExtendCode, dimensionId, billCategoryDimensionItemId); + } + +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/BusinessEntityWebServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/BusinessEntityWebServiceImpl.java new file mode 100644 index 00000000..27d2cd8d --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/BusinessEntityWebServiceImpl.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.approvalformat.core.webservice; + +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.approvalformat.api.service.BusinessEntityService; +import com.inspur.edp.web.approvalformat.api.webservice.BusinessEntityWebService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * 业务实体服务实现类 + * @author Xu‘fa Wang + * @date 2020/5/16 19:12 + */ +public class BusinessEntityWebServiceImpl implements BusinessEntityWebService { + private BusinessEntityService businessEntityService = SpringBeanUtils.getBean(BusinessEntityService.class); + + public BusinessEntityWebServiceImpl(BusinessEntityService businessEntityService) { + if(businessEntityService != null) { + this.businessEntityService = businessEntityService; + } + } + + @Override + public GspBusinessEntity getBusinessEntity(String bizEntityId) { + return this.businessEntityService.getBusinessEntity(bizEntityId); + } + + @Override + public GspMetadata getBusinessEntityMetadata(String bizEntityId) { + return this.businessEntityService.getBusinessEntityMetadata(bizEntityId); + } +} diff --git a/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/DimensionWebServiceImpl.java b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/DimensionWebServiceImpl.java new file mode 100644 index 00000000..afcb6e4c --- /dev/null +++ b/web-approval-format-core/src/main/java/com/inspur/edp/web/approvalformat/core/webservice/DimensionWebServiceImpl.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.approvalformat.core.webservice; + +import com.inspur.edp.bcc.billcategory.entity.dimension.BillCategoryDimension; +import com.inspur.edp.web.approvalformat.api.service.DimensionService; +import com.inspur.edp.web.approvalformat.api.webservice.DimensionWebService; + +import java.util.List; + +/** + * @author Xu‘fa Wang + * @date 2020/5/14 9:25 + */ +public class DimensionWebServiceImpl implements DimensionWebService { + private final DimensionService dimensionService; + + public DimensionWebServiceImpl(DimensionService dimensionService) { + this.dimensionService = dimensionService; + } + + @Override + public BillCategoryDimension getDimension(String billCategoryId, String billCategoryExtendCode) { + return this.dimensionService.getDimension(billCategoryId, billCategoryExtendCode); + } + + @Override + public List getDimensionCollection(String billCategoryId) { + return this.dimensionService.getDimensionCollection(billCategoryId); + } +} diff --git a/web-approval-format-core/src/main/resources/META-INF/spring.factories b/web-approval-format-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..5e09cbfb --- /dev/null +++ b/web-approval-format-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.approvalformat.core.config.ApprovalFormatConfiguration diff --git a/web-approval-format-rpc/pom.xml b/web-approval-format-rpc/pom.xml new file mode 100644 index 00000000..3faf14a4 --- /dev/null +++ b/web-approval-format-rpc/pom.xml @@ -0,0 +1,48 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-approval-format-rpc + + + + com.inspur.edp + bef-bizentity + + + com.inspur.edp + cef-entity + + + com.inspur.edp + web-help-api + + + io.iec.edp + caf-rpc-api + + + com.inspur.edp + metadata-rtcustomization-core + + + com.inspur.edp + bef-api + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache + + + diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcDeployApprovalFormatConfiguration.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcDeployApprovalFormatConfiguration.java new file mode 100644 index 00000000..567a8340 --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcDeployApprovalFormatConfiguration.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.approvalformat.rpc.config; + +import com.inspur.edp.web.approvalformat.rpc.service.deployapprovalformat.DeployApprovalFormat; +import com.inspur.edp.web.approvalformat.rpc.service.deployapprovalformat.DeployApprovalFormatImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration(proxyBeanMethods = false) +@EnableTransactionManagement +public class RtcDeployApprovalFormatConfiguration { + @Bean + DeployApprovalFormat deployApprovalFormat(){ + return new DeployApprovalFormatImpl(); + } +} + diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcValidationApproveConfiguration.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcValidationApproveConfiguration.java new file mode 100644 index 00000000..f7e45d2e --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/RtcValidationApproveConfiguration.java @@ -0,0 +1,59 @@ +package com.inspur.edp.web.approvalformat.rpc.config; + +import com.inspur.edp.web.approvalformat.rpc.webservice.impl.RtcValidationApproveWebServiceImpl; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.rest.RESTEndpoint; +import io.iec.edp.caf.rest.RESTServiceRegistrar; +import io.iec.edp.caf.sumgr.api.IServiceUnitAware; +import io.iec.edp.caf.sumgr.api.entity.ServiceUnitInfo; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.util.List; +import java.util.Optional; + +@Configuration(proxyBeanMethods = false) +@EnableTransactionManagement +public class RtcValidationApproveConfiguration { + + private final IServiceUnitAware suService = SpringBeanUtils.getBean(IServiceUnitAware.class); + private final Logger logger = LoggerFactory.getLogger(RtcValidationApproveConfiguration.class); + + public RtcValidationApproveConfiguration() { + RESTServiceRegistrar restServiceRegistrar = RESTServiceRegistrar.getSingleton(); + List serverUnits = suService.getEnabledServiceUnits(); + List allServiceUnitList = suService.getAllServiceUnits(); + for (String su : serverUnits) { + Optional findServiceUnitInfo = allServiceUnitList.stream().filter(t -> t.getName().equalsIgnoreCase(su)).findFirst(); + if (findServiceUnitInfo.isPresent()) { + if (!StringUtils.isEmpty( findServiceUnitInfo.get().getApplicationName())) { + String ep = "/" + findServiceUnitInfo.get().getApplicationName().toLowerCase() + "/" + su.toLowerCase() + "/v1.0/mobileapprove/check"; + logger.info("MAF register before navigate approve web api: " + ep); + restServiceRegistrar.registerRestEndpoint(new RESTEndpoint(ep, new RtcValidationApproveWebServiceImpl())); + } else { + logger.info("MAF:关键应用为空,对应SU为:" + su.toLowerCase()); + } + } + } + } + + +// @Bean +// public CustomFormServletFilter getCustomFormFilter() { +// return new CustomFormServletFilter(); +// } +// +// @Bean +// public FilterRegistrationBean filterRegistrationBean() { +// //注册过滤器 +// FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); +// registrationBean.setFilter(new CustomFormServletFilter()); +// +// //设置过滤器执行次序,值越小越靠后 +// registrationBean.setOrder(Integer.MIN_VALUE); +// return registrationBean; +// } +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/WebApprovalFormatRpcConfiguration.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/WebApprovalFormatRpcConfiguration.java new file mode 100644 index 00000000..2aed192f --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/config/WebApprovalFormatRpcConfiguration.java @@ -0,0 +1,14 @@ +package com.inspur.edp.web.approvalformat.rpc.config; + +import com.inspur.edp.web.approvalformat.rpc.rpcservice.ApprovalFormatRpcServiceImpl; +import com.inspur.edp.web.approvalformat.rpc.rpcservice.IApprovalFormatRpcService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(value = "com.inspur.edp.web.approvalformat.rpc.config.WebApprovalFormatRpcConfiguration",proxyBeanMethods = false) +public class WebApprovalFormatRpcConfiguration { + @Bean("com.inspur.edp.web.approvalformat.rpc.config.WebApprovalFormatRpcConfiguration.iApprovalFormatRpcService") + public IApprovalFormatRpcService iApprovalFormatRpcService() { + return new ApprovalFormatRpcServiceImpl(); + } +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/ApprovalFormatRpcServiceImpl.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/ApprovalFormatRpcServiceImpl.java new file mode 100644 index 00000000..a567a13a --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/ApprovalFormatRpcServiceImpl.java @@ -0,0 +1,123 @@ +package com.inspur.edp.web.approvalformat.rpc.rpcservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.bef.api.lcp.ILcpFactory; +import com.inspur.edp.bef.api.lcp.IStandardLcp; +import com.inspur.edp.bef.api.services.IBefSessionManager; +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.cdp.common.utils.json.JsonUtil; +import com.inspur.edp.cef.entity.condition.EntityFilter; +import com.inspur.edp.cef.entity.dependenceTemp.Pagination; +import com.inspur.edp.cef.entity.entity.IEntityData; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.List; + +/** + * 审批格式RPC服务实现类 + * + * @author Xu‘fa Wang + * @date 2020/5/20 12:43 + */ +public class ApprovalFormatRpcServiceImpl implements IApprovalFormatRpcService { + @Autowired + private CustomizationService customizationService; + + @Override + public IEntityData getEntityDataByBizEntityId(String dataId, String bizEntityId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = null; + + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + // 优先基于bizEntityConfigId创建lcp实例 + if (bizEntityMetadata != null) { + GspBusinessEntity businessEntity = (GspBusinessEntity) bizEntityMetadata.getContent(); + String bizEntityConfigId = businessEntity.getGeneratedConfigID(); + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + } else { + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcpByBEId(bizEntityId); + } + return lcp.retrieve(dataId).getData(); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + @Override + public List queryEntityData(String bizEntityId) { + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = null; + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + // 优先基于bizEntityConfigId创建lcp实例 + if (bizEntityMetadata != null) { + GspBusinessEntity businessEntity = (GspBusinessEntity) bizEntityMetadata.getContent(); + String bizEntityConfigId = businessEntity.getGeneratedConfigID(); + + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + } else { + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcpByBEId(bizEntityId); + } + return dividePage(lcp, 20, 1); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + @Override + public List queryEntityDataWithCondition(JsonNode queryStringMap) { + String bizEntityId = queryStringMap.get("bizEntityId").asText(); + String entityFilterStr = queryStringMap.get("entityFilterStr").asText(); + + EntityFilter filter = new EntityFilter(); + if (entityFilterStr != "") { + JsonNode node = null; + try { + node = JsonUtil.getMapper().readTree(entityFilterStr); + } catch (IOException e) { + throw new RuntimeException(e); + } + try { + filter = JsonUtil.toObject(node, EntityFilter.class); + } catch (Exception e) { + throw new RuntimeException( + MessageFormat.format("{0}", new Object[]{e.getMessage()})); + } + } + SpringBeanUtils.getBean(IBefSessionManager.class).createSession(); + try { + IStandardLcp lcp = null; + + GspMetadata bizEntityMetadata = this.customizationService.getMetadata(bizEntityId); + // 优先基于bizEntityConfigId创建lcp实例 + if (bizEntityMetadata != null) { + GspBusinessEntity businessEntity = (GspBusinessEntity) bizEntityMetadata.getContent(); + String bizEntityConfigId = businessEntity.getGeneratedConfigID(); + + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcp(bizEntityConfigId); + } else { + lcp = SpringBeanUtils.getBean(ILcpFactory.class).createLcpByBEId(bizEntityId); + } + return lcp.query(filter); + } finally { + SpringBeanUtils.getBean(IBefSessionManager.class).closeCurrentSession(); + } + } + + private List dividePage(IStandardLcp lcp, int numberInPage, int pageIndex) { + Pagination pagination = new Pagination(); + pagination.setPageSize(numberInPage); + pagination.setPageIndex(pageIndex); + EntityFilter entityFilter = new EntityFilter(); + entityFilter.setIsUsePagination(true); + entityFilter.setPagination(pagination); + return lcp.query(entityFilter); + + } +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/IApprovalFormatRpcService.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/IApprovalFormatRpcService.java new file mode 100644 index 00000000..00f0658a --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/rpcservice/IApprovalFormatRpcService.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.approvalformat.rpc.rpcservice; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.cef.entity.entity.IEntityData; +import io.iec.edp.caf.rpc.api.annotation.GspServiceBundle; +import io.iec.edp.caf.rpc.api.annotation.RpcParam; + +import java.util.List; + +/** + * 审批格式rpc服务 + * @author Xu‘fa Wang + * @date 2020/5/20 12:39 + */ +@GspServiceBundle(applicationName = "runtime", serviceName = "approval_format") +public interface IApprovalFormatRpcService { + /** + * 基于业务实体id获取实体数据 + * @param dataId 数据id + * @param bizEntityId 业务实体id + * @return 实体数据 + */ + IEntityData getEntityDataByBizEntityId(@RpcParam(paramName = "dataId") String dataId, + @RpcParam(paramName = "bizEntityId") String bizEntityId); + + /** + * 基于业务实体id(含维度)获取数据 + * @param bizEntityId 业务实体id + * @return 实体数据集合 + */ + List queryEntityData(@RpcParam(paramName = "bizEntityId") String bizEntityId); + + List queryEntityDataWithCondition(@RpcParam(paramName = "queryStringMap") JsonNode queryStringMap); + +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormat.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormat.java new file mode 100644 index 00000000..8584f1f8 --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormat.java @@ -0,0 +1,9 @@ +package com.inspur.edp.web.approvalformat.rpc.service.deployapprovalformat; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Map; + +public interface DeployApprovalFormat { + Map deployApprovalFormat(JsonNode queryStringMap); +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormatImpl.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormatImpl.java new file mode 100644 index 00000000..70024320 --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/service/deployapprovalformat/DeployApprovalFormatImpl.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.approvalformat.rpc.service.deployapprovalformat; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerVersionManager; + +import java.util.HashMap; +import java.util.Map; + +public class DeployApprovalFormatImpl implements DeployApprovalFormat { + @Override + public Map deployApprovalFormat(JsonNode queryStringMap) { + //两个参数 projectName 和相对地址 + String projectName = queryStringMap.get("projectName").asText(); + String projectrelativepath = queryStringMap.get("projectrelativepath").asText(); + + ScriptCacheResponse scriptCacheResponse = ScriptCacheResponse.getInstance(); + Map result = new HashMap<>(); + scriptCacheResponse = LocalServerVersionManager.getSingleInstance().checkVersionWithProjectNameAndRelativePath(projectName, projectrelativepath); + + if (scriptCacheResponse != null) { + if (scriptCacheResponse.isSuccess()) { + result.put("flag", "true"); // 是否解析型 + return result; + } else { + throw new RuntimeException(scriptCacheResponse.getErrorMessage()); + } + } else { + throw new RuntimeException("beforeNavigate 参数转换失败"); + } + } +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/RtcValidationApproveWebService.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/RtcValidationApproveWebService.java new file mode 100644 index 00000000..4ac4d402 --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/RtcValidationApproveWebService.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.approvalformat.rpc.webservice; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.Map; + +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface RtcValidationApproveWebService { + /** + * 脚本加载前的处理 + * @param queryStringMap + * @return + */ + @POST + @Path("/beforeNavigateApprove") + Map beforeNavigateApprove(@RequestBody JsonNode queryStringMap); +} diff --git a/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/impl/RtcValidationApproveWebServiceImpl.java b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/impl/RtcValidationApproveWebServiceImpl.java new file mode 100644 index 00000000..d2429e4a --- /dev/null +++ b/web-approval-format-rpc/src/main/java/com/inspur/edp/web/approvalformat/rpc/webservice/impl/RtcValidationApproveWebServiceImpl.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.approvalformat.rpc.webservice.impl; + +import com.fasterxml.jackson.databind.JsonNode; + +import com.inspur.edp.web.approvalformat.rpc.service.deployapprovalformat.DeployApprovalFormat; +import com.inspur.edp.web.approvalformat.rpc.webservice.RtcValidationApproveWebService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.Map; + +public class RtcValidationApproveWebServiceImpl implements RtcValidationApproveWebService { + private final DeployApprovalFormat deployApprovalFormat = SpringBeanUtils.getBean(DeployApprovalFormat.class); + + @Override + public Map beforeNavigateApprove(JsonNode queryStringMap) { + return deployApprovalFormat.deployApprovalFormat(queryStringMap); + } + + +} diff --git a/web-approval-format-rpc/src/main/resources/META-INF/spring.factories b/web-approval-format-rpc/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..a82c0195 --- /dev/null +++ b/web-approval-format-rpc/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.approvalformat.rpc.config.WebApprovalFormatRpcConfiguration,\ +com.inspur.edp.web.approvalformat.rpc.config.RtcValidationApproveConfiguration,\ +com.inspur.edp.web.approvalformat.rpc.config.RtcDeployApprovalFormatConfiguration + + diff --git a/web-common/pom.xml b/web-common/pom.xml new file mode 100644 index 00000000..bf41dfa6 --- /dev/null +++ b/web-common/pom.xml @@ -0,0 +1,61 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-common + + + com.fasterxml.jackson.core + jackson-databind + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + lcm-metadata-common + + + com.inspur.edp + lcm-metadata-manager + + + org.apache.commons + commons-lang3 + + + com.inspur.edp + metadata-rtcustomization-api + + + com.inspur.edp + metadata-rtcustomization-server-api + + + com.inspur.edp + web-component-metadata + + + com.inspur.edp + web-command-coponent-metadata + + + io.iec.edp + caf-boot-commons-environment + + + org.junit.jupiter + junit-jupiter-api + + + + + diff --git a/web-common/src/main/java/com/inspur/edp/web/common/GSPException.java b/web-common/src/main/java/com/inspur/edp/web/common/GSPException.java new file mode 100644 index 00000000..d5eee595 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/GSPException.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.common; + +import io.iec.edp.caf.commons.exception.CAFRuntimeException; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +/** + * web自定义异常类 + * @author noah + */ +public class GSPException extends CAFRuntimeException { + public GSPException(String exceptionCode, String exceptionMessage){ + super("", exceptionCode, exceptionMessage, null); + } + + public GSPException(String exceptionCode, String exceptionMessage, Exception innerException){ + super("", exceptionCode, exceptionMessage, innerException); + } + + public GSPException(String exceptionCode, String exceptionMessage, Exception cause, ExceptionLevel errorLevel, boolean bizException) { + super("", exceptionCode, exceptionMessage, cause, errorLevel, bizException); + } + + public GSPException(String exceptionCode, String exceptionMessage, RuntimeException exception, ExceptionLevel errorLevel) { + super("", exceptionCode, exceptionMessage, exception, errorLevel); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/GspProjectUtil.java b/web-common/src/main/java/com/inspur/edp/web/common/GspProjectUtil.java new file mode 100644 index 00000000..dccb156c --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/GspProjectUtil.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.common; + +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.service.GspProjectService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +public class GspProjectUtil { + public static GspProject getGspProject(String projectPath) { + try { + GspProjectService gspProjectService = SpringBeanUtils.getBean(GspProjectService.class); + GspProject currentProject = gspProjectService.getGspProjectInfo(projectPath); + return currentProject; + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + /** + * 根据工程路径获取工程名称 + * @param projectPath + * @return + */ + public static String getProjectName(String projectPath) { + GspProject currentProject = getGspProject(projectPath); + + return (currentProject.getMetadataProjectName()).toLowerCase(); + } + + public static String getProjectPath(String projectPath) { + GspProject currentProject = getGspProject(projectPath); + + return (currentProject.getMetadataProjectName()).toLowerCase(); + } + + public static String GetProjectBizobjectID(String projectPath) { + GspProject currentProject = GspProjectUtil.getGspProject(projectPath); + if (currentProject == null) { + throw new GSPException("WEB_GetProjectBizobjectID", String.format("Error When Getting Project Bizobject ID. Current Project Path is:%1$s", projectPath)); + } + + return currentProject.getBizobjectID(); + } + + public static String GetProjectNameSpace(String projectPath) { + GspProject currentProject = GspProjectUtil.getGspProject(projectPath); + if (currentProject == null) { + throw new GSPException("WEB_GetProjectNameSpace", String.format("Error When Getting Project Namespace. Current Project Path is:%1$s", projectPath)); + } + + return currentProject.getProjectNameSpace(); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/JITEngineConstants.java b/web-common/src/main/java/com/inspur/edp/web/common/JITEngineConstants.java new file mode 100644 index 00000000..92567d96 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/JITEngineConstants.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.common; + +/** + * JITEngine执行常量参数 + */ +public class JITEngineConstants { + private JITEngineConstants() { + } + + /** + * 工程路由文件后缀格式 + */ + public static final String ProjectRouteFileExtension = ".route.json"; + + /** + * 当前执行编译的NG版本 当前为Ng7 不可更改 + */ + public static final String NgVersion = "ng7"; + + /** + * 当前执行UI类库Kendo 不可更改 + */ + public static final String UiLibrary = "kendo"; + + /** + * Node_Modules文件目录 + */ + public static final String Node_ModulesPathName = "node_modules"; + + /** + * jit-engine form 工程版本文件 + */ + public static final String ProjectVersionFileName = "projectversionserver.json"; + + /** + * 是否需要重新编译标识 + */ + public static final String ProjectVersionNeedRecompile = "ProjectVersionNeedRecompile"; + + + /** + * jit 执行命令js文件相对于server nodejs路径的相对路径 + */ + public static final String JitCommandJsRelativePath = "node_modules/@farris/jit-engine/bin/index.js"; + + /** + * ng 执行命令相对于server的nodejs路径的相对路径 + */ + public static final String NgCommandRelativePath = "node_modules/@angular/cli/bin/ng"; + + + public static final String ServerScriptsPath = "serverscripts"; + + public static final String TscCommandRelativePath = "typescript/bin/tsc"; + + public static final String RollupCommandRelativePath = "rollup/bin/rollup"; + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/constant/FrontendProjectConstant.java b/web-common/src/main/java/com/inspur/edp/web/common/constant/FrontendProjectConstant.java new file mode 100644 index 00000000..3a0e5582 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/constant/FrontendProjectConstant.java @@ -0,0 +1,190 @@ +package com.inspur.edp.web.common.constant; + +import com.inspur.edp.web.common.io.FileUtility; + +public final class FrontendProjectConstant { + private FrontendProjectConstant() { + } + ///工程常量 + + /** + * 前端工程类型 + */ + public static final String FRONTEND_PROJECT_TYPE = "frontend"; + + /** + * 非前端工程类型 + */ + public static final String NON_FRONTEND_PROJECT_TYPE = "non-frontend"; + + /** + * 路由元数据文件后缀 .pf + */ + public static final String ROUTE_METADATA_SUFFIX = ".pf"; + + /** + * 移动路由元数据文件后缀 .mpf + */ + public static final String MOBILE_ROUTE_METADATA_SUFFIX = ".mpf"; + + ///表单常量 + + /** + * PC表单元数据文件后缀 .frm + */ + public static final String FORM_METADATA_SUFFIX = ".frm"; + + /** + * 移动表单元数据文件后缀 .frm + */ + public static final String MOBILE_FORM_METADATA_SUFFIX = ".mfrm"; + + /** + * 前端工程PC表单编译目录 + */ + public static final String FRONTEND_PROJECT_COMPILE_PATH = "src"; + + /** + * 前端工程PC表单生成目录 + */ + public static final String PROJECT_GENERATE_PATH = "app"; + + /** + * 前端工程PC表单生成目录(Babel) + */ + public static final String PROJECT_GENERATE_PATH_FOR_BABEL = "appforbabel"; + + /** + * appforjiexi 常量 + */ + public static final String PROJECT_GENERATE_PATH_FOR_Dynamic = "appfordynamic"; + + public static final String PROJECT_GENDER_PATH_FOR_DYNAMIC_FORM = "dynamicform"; + + /** + * 前端工程移动表单生成目录 + */ + public static final String PROJECT_MOBILE_GENERATE_PATH = "mobileapp"; + + /** + * 前端工程构建目录 + */ + public static final String PROJECT_BUILD_PATH = "dist-rollup"; + + /** + * 表单解析目录 + */ + public static final String FORM_RESOLVE_PATH = "webdev"; + + /** + * 移动表单解析目录 + */ + public static final String MOBILE_FORM_RESOLVE_PATH = "mobiledev"; + + /** + * 命令服务生成目录 + */ + public static final String COMMAND_SERVICES_PRODUCT_PATH = "services"; + + /** + * 多语资源存放目录 + */ + public static final String I18N_SRESOURCE_PATH = "i18n"; + + /** + * 工程发布目录 + */ + public static final String PROJECT_PUBLISH_PATH = "publish"; + + /** + * PC表单部署路径 + */ + public static final String FORM_PUBLISH_PATH = "web"; + + /** + * 移动表单部署路径 + * mobile 简写 + */ + public static final String MOBILE_FORM_PUBLISH_PATH = "mob"; + + /** + * 服务相对当前工程的生成目录 + */ + public static final String SERVICES_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, FORM_RESOLVE_PATH, COMMAND_SERVICES_PRODUCT_PATH); + + /** + * 服务相对当前工程的生成目录 + */ + public static final String SERVICES_RELATIVE_PRODUCT_Dynamic_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, PROJECT_GENERATE_PATH_FOR_Dynamic, COMMAND_SERVICES_PRODUCT_PATH); + + /** + * 移动服务相对当前工程的生成目录 + */ + public static final String MOBILE_SERVICES_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, MOBILE_FORM_RESOLVE_PATH, COMMAND_SERVICES_PRODUCT_PATH); + + /** + * 待部署工程相对当前工程的生成目录 + */ + public static final String DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, PROJECT_GENERATE_PATH, PROJECT_BUILD_PATH); + + /** + * 待部署工程相对当前工程的生成目录 + */ + public static final String DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_Dynamic_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, PROJECT_GENERATE_PATH_FOR_Dynamic, "dynamicform"); + + /** + * 移动表单待部署工程相对当前工程的生成目录 + */ + public static final String MOBILE_DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, PROJECT_MOBILE_GENERATE_PATH, PROJECT_BUILD_PATH); + + /** + * PC表单多语资源相对工程的生成目录 + */ + public static final String PC_I18N_RESOURCE_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, FORM_RESOLVE_PATH, I18N_SRESOURCE_PATH); + + /** + * 移动表单多语资源相对工程的生成目录 + */ + public static final String MOBILE_I18N_RESOURCE_RELATIVE_PRODUCT_PATH = FileUtility.combine(FRONTEND_PROJECT_COMPILE_PATH, MOBILE_FORM_RESOLVE_PATH, I18N_SRESOURCE_PATH); + + /** + * PC表单相对工程的部署目录 + */ + public static final String PROJECT_PC_RELATIVE_PUBLISH_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(FORM_PUBLISH_PATH).toString(); + + /** + * 移动表单相对工程的部署目录 + */ + public static final String PROJECT_MOBILE_RELATIVE_PUBLISH_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(MOBILE_FORM_PUBLISH_PATH).toString(); + + /** + * PC表单相对工程的解析目录 + */ + public static final String PROJECT_PC_RELATIVE_RESOLVE_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(FORM_RESOLVE_PATH).toString(); + + /** + * PC 解析表单相对工程的解析目录 + */ + public static final String PROJECT_PC_RELATIVE_RESOLVE_Dynamic_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(PROJECT_GENERATE_PATH_FOR_Dynamic).toString(); + + /** + * 移动表单相对工程的解析目录 + */ + public static final String PROJECT_MOBILE_RELATIVE_RESOLVE_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(MOBILE_FORM_RESOLVE_PATH).toString(); + + /** + * PC表单相对工程的生成目录 + */ + public static final String PROJECT_PC_RELATIVE_GENERATE_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(PROJECT_GENERATE_PATH).toString(); + + /** + * PC表单相对工程的生成目录 + */ + public static final String PROJECT_PC_RELATIVE_GENERATE_Dynamic_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(PROJECT_GENERATE_PATH_FOR_Dynamic).toString(); + + /** + * 移动表单相对工程的生成目录 + */ + public static final String PROJECT_MOBILE_RELATIVE_GENERATE_PATH = java.nio.file.Paths.get(FRONTEND_PROJECT_COMPILE_PATH).resolve(PROJECT_MOBILE_GENERATE_PATH).toString(); + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/constant/LanguageConstant.java b/web-common/src/main/java/com/inspur/edp/web/common/constant/LanguageConstant.java new file mode 100644 index 00000000..016d045b --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/constant/LanguageConstant.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.common.constant; + + +/** + * 语言代码表 + */ +public class LanguageConstant { + private LanguageConstant() { + } + ///语言代码表,参考 ISO 639-1:2002 + + /** + * 中文 + */ + public static final String ZH = "zh"; + + /** + * 英文 + */ + public static final String EN = "en"; +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/constant/MetadataConstant.java b/web-common/src/main/java/com/inspur/edp/web/common/constant/MetadataConstant.java new file mode 100644 index 00000000..8c25a0c6 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/constant/MetadataConstant.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.common.constant; + +/** + * 元数据 + */ +public class MetadataConstant { + private MetadataConstant() { + } + ///元数据相关常量 + + /** + * 表单元数据类型 + */ + public static final String FORM_METADATA_TYPE = "Form"; + + /** + * 移动表单元数据类型 + */ + public static final String MOBILE_FORM_METADATA_TYPE = "MobileForm"; + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/core/EnumValueParsable.java b/web-common/src/main/java/com/inspur/edp/web/common/core/EnumValueParsable.java new file mode 100644 index 00000000..3149dd97 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/core/EnumValueParsable.java @@ -0,0 +1,73 @@ +package com.inspur.edp.web.common.core; + +import java.text.MessageFormat; +import java.util.Objects; +import java.util.Optional; + +/** + * 枚举值转换接口 + * 有其他工程引用 不能删除 不能更改 + * + * @author Xu‘fa Wang + * @date 2020/3/20 10:09 + */ +public interface EnumValueParsable { + /** + * 获取枚举值 + * + * @return 返回值 + */ + T getValue(); + + /** + * 通用的自定义枚举类型转换方法,凡是实现{@link EnumValueParsable}接口的枚举类,并通过泛型指定枚举的值的类型, 即可通过此方法来将给定的值转换为对应的枚举类型。 + * + * @param value 给定的值 + * @param clazz 要转换的枚举类的class类型 + * @param 给定值的类型 + * @param 要转换的枚举类 + * @return 转换后的枚举类型对象 + * @throws EnumValueParseException 无法在给定枚举类型中找到对应枚举值或者给定值为{@code null}时,会抛出此异常 + */ + static > E parse(T value, Class clazz) + throws EnumValueParseException { + return Optional.ofNullable(value) + .map( + val -> { + for (E item : clazz.getEnumConstants()) { + if (Objects.equals(item.getValue(), val)) { + return item; + } + } + return null; + }) + .orElseThrow( + () -> + new EnumValueParseException( + MessageFormat.format( + "Could not parse value {0} to type {1}.", + value, clazz.getCanonicalName()))); + } + + class EnumValueParseException extends RuntimeException { + + private static final long serialVersionUID = -2557475060594463395L; + + EnumValueParseException(String message) { + super(message); + } + + EnumValueParseException(String message, Throwable cause) { + super(message, cause); + } + + EnumValueParseException(Throwable cause) { + super(cause); + } + + EnumValueParseException( + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptConstant.java b/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptConstant.java new file mode 100644 index 00000000..06708e29 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptConstant.java @@ -0,0 +1,18 @@ +package com.inspur.edp.web.common.encrypt; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/12 + */ +public class EncryptConstant { + private EncryptConstant() { + } + + /** + * 加密key + */ + public static final String EncryptKey = "NoahGuo"; +} + diff --git a/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptUtility.java new file mode 100644 index 00000000..1f5b8166 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/encrypt/EncryptUtility.java @@ -0,0 +1,335 @@ +package com.inspur.edp.web.common.encrypt; + +import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.SecureRandom; + +/** + * description:des 加解密 + * + * @author Noah Guo + * @date 2020/09/24 + */ +public class EncryptUtility { + public static final String MD5 = "MD5"; + public static final String SHA1 = "SHA1"; + public static final String HmacMD5 = "HmacMD5"; + public static final String HmacSHA1 = "HmacSHA1"; + public static final String DES = "DES"; + public static final String AES = "AES"; + + /** + * 编码格式;默认使用uft-8 + */ + public String charset = "utf-8"; + /** + * DES + */ + public int keysizeDES = 0; + + private EncryptUtility() { + //单例 + } + + private static final class _instanceHolder { + static final EncryptUtility _instance = new EncryptUtility(); + } + + //双重锁 + public static EncryptUtility getInstance() { + return _instanceHolder._instance; + } + + /** + * 使用MessageDigest进行单向加密(无密码) + * + * @param res 被加密的文本 + * @param algorithm 加密算法名称 + * @return + */ + private String messageDigest(String res, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return base64(md.digest(resBytes)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator进行单向/双向加密(可设密码) + * + * @param res 被加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密使用的秘钥 + * @return + */ + private String keyGeneratorMac(String res, String algorithm, String key) { + try { + SecretKey sk = null; + if (key == null) { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + sk = kg.generateKey(); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + sk = new SecretKeySpec(keyBytes, algorithm); + } + Mac mac = Mac.getInstance(algorithm); + mac.init(sk); + byte[] result = mac.doFinal(res.getBytes()); + return base64(result); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 使用KeyGenerator双向加密,DES/AES,注意这里转化为字符串的时候是将2进制转为16进制格式的字符串,不是直接转,因为会出错 + * + * @param res 加密的原文 + * @param algorithm 加密使用的算法名称 + * @param key 加密的秘钥 + * @param keysize + * @param isEncode + * @return + */ + private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) { + try { + KeyGenerator kg = KeyGenerator.getInstance(algorithm); + if (keysize == 0) { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + kg.init(new SecureRandom(keyBytes)); + } else if (key == null) { + kg.init(keysize); + } else { + byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset); + kg.init(keysize, new SecureRandom(keyBytes)); + } + SecretKey sk = kg.generateKey(); + SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm); + Cipher cipher = Cipher.getInstance(algorithm); + if (isEncode) { + cipher.init(Cipher.ENCRYPT_MODE, sks); + byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset); + return parseByte2HexStr(cipher.doFinal(resBytes)); + } else { + cipher.init(Cipher.DECRYPT_MODE, sks); + return new String(cipher.doFinal(parseHexStr2Byte(res))); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private String base64(byte[] res) { + return Base64.encode(res); + } + + /** + * 将二进制转换成16进制 + */ + public static String parseByte2HexStr(byte[] buf) { + StringBuilder sb = new StringBuilder(); + for (byte b : buf) { + String hex = Integer.toHexString(b & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /** + * 将16进制转换为二进制 + */ + public static byte[] parseHexStr2Byte(String hexStr) { + if (hexStr.length() < 1) { + return null; + } + byte[] result = new byte[hexStr.length() / 2]; + for (int i = 0; i < hexStr.length() / 2; i++) { + int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); + int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String MD5(String res) { + return messageDigest(res, MD5); + } + + /** + * md5加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String MD5(String res, String key) { + return keyGeneratorMac(res, HmacMD5, key); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @return + */ + public String SHA1(String res) { + return messageDigest(res, SHA1); + } + + /** + * 使用SHA1加密算法进行加密(不可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String SHA1(String res, String key) { + return keyGeneratorMac(res, HmacSHA1, key); + } + + /** + * 使用DES加密算法进行加密(可逆) + * + * @param res 需要加密的原文 + * @param key 秘钥 + * @return + */ + public String DESencode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, true); + } + + /** + * 对使用DES加密算法的密文进行解密(可逆) + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String DESdecode(String res, String key) { + return keyGeneratorES(res, DES, key, keysizeDES, false); + } + + /** + * 使用异或进行加密 + * + * @param res 需要加密的密文 + * @param key 秘钥 + * @return + */ + public String XORencode(String res, String key) { + byte[] bs = res.getBytes(); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return parseByte2HexStr(bs); + } + + /** + * 使用异或进行解密 + * + * @param res 需要解密的密文 + * @param key 秘钥 + * @return + */ + public String XORdecode(String res, String key) { + byte[] bs = parseHexStr2Byte(res); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) ((bs[i]) ^ key.hashCode()); + } + return new String(bs); + } + + /** + * 直接使用异或(第一调用加密,第二次调用解密) + * + * @param res 密文 + * @param key 秘钥 + * @return + */ + public int XOR(int res, String key) { + return res ^ key.hashCode(); + } + + /** + * 使用Base64进行加密 + * + * @param res 密文 + * @return + */ + public String Base64Encode(String res) { + if (res == null || res.trim().isEmpty()) { + return ""; + } + String result = ""; + try { + result = Base64.encode(res.getBytes(charset)); + } catch (Exception e) { + throw new RuntimeException("编码失败:" + res, e); + } + return result; + } + + /** + * 使用Base64进行解密 + * + * @param res + * @return + */ + public String Base64Decode(String res) { + if (res == null || res.trim().isEmpty()) { + return ""; + } + try { + return new String(Base64.decode(res), charset); + } catch (Exception e) { + throw new RuntimeException("base64Decode失败", e); + } + } + + /** + * 判断字符串是否经过base64编码 + * + * @param source + * @return + */ + public boolean isBase64(String source) { + if (source == null || source.trim().length() == 0) { + return false; + } else { + if (source.length() % 4 != 0) { + return false; + } + + char[] strChars = source.toCharArray(); + for (char c : strChars) { + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || c == '+' || c == '/' || c == '=') { + } else { + return false; + } + } + return true; + } + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/NodeJsCommandEnum.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/NodeJsCommandEnum.java new file mode 100644 index 00000000..4b412bc0 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/NodeJsCommandEnum.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.common.entity; + +/** + * nodejs常用命令 + * @author guozhiqi + */ +public enum NodeJsCommandEnum { + /** + * 执行命令的node命令 + */ + Node, + /** + * 执行npm包的npm命令 + */ + Npm, + /** + * 可以执行npm command的npx命令 + */ + Npx + + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java new file mode 100644 index 00000000..6d9bd6bc --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.common.entity; + +/** + * 返回结果定义 + * + * @author noah + */ +public class ResultCode { + private ResultCode() { + } + + public static ResultMessage success() { + return new ResultMessage(1, ""); + } + + public static ResultMessage failure(String errorMessage) { + return new ResultMessage(0, errorMessage); + } + + public static ResultMessage custom(Integer code, String errorMessage) { + return new ResultMessage(code, errorMessage); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessage.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessage.java new file mode 100644 index 00000000..492831e1 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessage.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.common.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * rest api 返回值格式 + * + * @author noah + */ +@Data +public class ResultMessage implements Serializable { + + @JsonProperty("code") + private Integer code; + + /** + * 是否执行成功标识 + */ + @JsonProperty("success") + private boolean success = true; + + @JsonProperty("message") + private String message; + + @JsonProperty("data") + private Object data; + + ResultMessage(Integer code, String message) { + this(code, message, null); + } + + ResultMessage(boolean success, String message) { + this(success, message, null); + } + + ResultMessage(boolean success, String message, Object data) { + this.success = success; + this.message = message; + this.code = success ? 1 : 0; + this.data = data; + } + + ResultMessage(Integer code, String message, Object data) { + this.code = code; + this.message = message; + this.data = data; + this.success = this.code == 1 ? true : false; + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/TerminalType.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/TerminalType.java new file mode 100644 index 00000000..135b9ec2 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/TerminalType.java @@ -0,0 +1,115 @@ +package com.inspur.edp.web.common.entity; + +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.io.FileUtility; + +public enum TerminalType { + /** + * 个人电脑 + */ + PC { + @Override + public String getFormMetadataSuffix() { + return FrontendProjectConstant.FORM_METADATA_SUFFIX; + } + + @Override + public String getFormName() { + return "pc表单"; + } + + @Override + public String getAppPathName() { + return "app"; + } + + @Override + public String getWebDevPathName() { + return "webdev"; + } + + @Override + public String getResolveBasePath(String projectPath, boolean isDynamicForm) { + String resolveBasePath; + if (isDynamicForm) { + resolveBasePath = FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, FrontendProjectConstant.PROJECT_GENDER_PATH_FOR_DYNAMIC_FORM); + } else { + resolveBasePath = FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.FORM_RESOLVE_PATH); + } + return resolveBasePath; + } + }, + /** + * 移动设备 + */ + MOBILE { + /** + * 获取对应类型的表单元数据的后缀格式 + * + * @return + */ + @Override + public String getFormMetadataSuffix() { + return FrontendProjectConstant.MOBILE_FORM_METADATA_SUFFIX; + } + + @Override + public String getFormName() { + return "移动表单"; + } + + @Override + public String getAppPathName() { + return "mobileapp"; + } + + @Override + public String getWebDevPathName() { + return "mobiledev"; + } + + @Override + public String getResolveBasePath(String projectPath, boolean isDynamicForm) { + return FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.MOBILE_FORM_RESOLVE_PATH); + } + }; + + /** + * 获取对应类型的表单元数据的后缀格式 + * + * @return + */ + public abstract String getFormMetadataSuffix(); + + /** + * 获取表单类型对应的name参数值 + * @return + */ + public abstract String getFormName(); + + /** + * 获取对应的app路径名称 + * @return + */ + public abstract String getAppPathName(); + + /** + * 获取关联的webdev 目录路径名称 + * @return + */ + public abstract String getWebDevPathName(); + + /** + * 获取指定类型的resolve 基础路径 + * PC projectPath/src/webdev + * PC 解析表单 projectPath/src/appfordynamic + * Mobile projectPath/src/mobiledev + * + * @param projectPath + * @param isDynamicForm + * @return + */ + public abstract String getResolveBasePath(String projectPath, boolean isDynamicForm); + +} + diff --git a/web-common/src/main/java/com/inspur/edp/web/common/environment/EnvironmentException.java b/web-common/src/main/java/com/inspur/edp/web/common/environment/EnvironmentException.java new file mode 100644 index 00000000..d7d85e67 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/environment/EnvironmentException.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.common.environment; + +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +/** + * 环境检查自定义异常 + * 用以进行自定义异常捕获 + * + * @author guozhiqi + */ +public class EnvironmentException extends RuntimeException { + + /** + * 级别 主要用于在客户端进行展现 + */ + private ExceptionLevel level = ExceptionLevel.Error; + + public String getLevel() { + return this.level.name().toLowerCase(); + } + + public void setLevel(ExceptionLevel exceptionLevel) { + this.level = exceptionLevel; + } + + /** + * 用于界面展现的title标题展示 + */ + private String title = "错误提示"; + + public String getTitle() { + return this.title; + } + + public void setTitle(String title) { + this.title = title; + } + + public EnvironmentException(String exceptionMessage, String title, ExceptionLevel exceptionLevel) { + super(exceptionMessage); + this.title = title; + this.level = exceptionLevel; + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironment.java b/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironment.java new file mode 100644 index 00000000..86dfac00 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironment.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.common.environment; + +/** + * 运行环境 位置 分为设计时及运行时、元数据部署工具 + * + * @author guozhiqi + */ +public class ExecuteEnvironment { + private ExecuteEnvironment() { + } + + /** + * 设计时 + */ + public static final String Design = "Design"; + + + /** + * 运行时定制 + */ + public static final String Runtime = "Runtime"; + + /** + * 元数据部署工具 + */ + public static final String UpgradeTool = "UpgradeTool"; +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironmentEnum.java b/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironmentEnum.java new file mode 100644 index 00000000..1cd90d32 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/environment/ExecuteEnvironmentEnum.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.common.environment; + +/** + * 运行位置枚举 + * @author guozhiqi + */ +public enum ExecuteEnvironmentEnum { + /** + * 设计时 + */ + Design, + /** + * 运行时定制 + */ + Runtime, + /** + * 元数据部署工具 + */ + UpgradeTool, + /** + * 未指定具体运行位置 + */ + None +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckResult.java b/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckResult.java new file mode 100644 index 00000000..fca9dbd1 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckResult.java @@ -0,0 +1,40 @@ +package com.inspur.edp.web.common.environment.checker; + +/** + * @Title: ExecuteEnvironmentCheckResult 运行环境检测结果值 + * @Description: com.inspur.edp.web.common.environment.checker + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/29 15:23 + */ +public class ExecuteEnvironmentCheckResult { + /** + * 是否检测成功标识 + */ + private boolean success = true; + + /** + * 如果检测失败 对应的提示信息 + */ + private String errorMessage = ""; + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public static ExecuteEnvironmentCheckResult getInstance() { + return new ExecuteEnvironmentCheckResult(); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentChecker.java b/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentChecker.java new file mode 100644 index 00000000..5fe3211c --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentChecker.java @@ -0,0 +1,163 @@ +package com.inspur.edp.web.common.environment.checker; + +import com.inspur.edp.web.common.environment.EnvironmentException; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.OperatingSystemUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +/** + * @Title: EnvironmentChecker 运行环境检测 + * @Description: com.inspur.edp.web.common.environment + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/29 15:20 + */ +public class ExecuteEnvironmentChecker { + private static final String endMessage = "若已安装,请尝试重启Igix服务。"; + + private static final String prefixMessage = "当前环境"; + /** + * 默认的弹窗标题 + */ + private static final String defaultModalTitle = "提示"; + /** + * 默认的弹窗级别 + */ + private static final ExceptionLevel defaultModalLevel = ExceptionLevel.Warning; + + /** + * 根据不同系统版本返回对应的提示url地址 + * + * @return + */ + private static String getKnowledgeUrl() { + if (OperatingSystemUtility.isLinux()) { + return "https://open.inspuronline.com/iGIX/#/document/mddoc/igix_2110%2Fdev-guide-beta%2Fquickstart%2Fbuilding-development-environment%2F%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83Linux%E6%90%AD%E5%BB%BA.md"; + } + return "https://open.inspuronline.com/iGIX/#/document/mddoc/igix_2110%2Fdev-guide-beta%2Fquickstart%2Fbuilding-development-environment%2F%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83Windows%E6%90%AD%E5%BB%BA.md"; + } + + /** + * 检测是否部署node命令 + * + * @return + */ + public static ExecuteEnvironmentCheckResult checkGlobalNodeInstalled() { + ExecuteEnvironmentCheckResult checkResult = ExecuteEnvironmentCheckResult.getInstance(); + String errorMessage; + try { + errorMessage = CommandLineUtility.runCommandWithoutThrows("node -v"); + } catch (RuntimeException ex) { + errorMessage = ex.getMessage(); + } + + if (StringUtility.isNullOrEmpty(errorMessage)) { + return checkResult; + } + checkResult.setSuccess(false); + checkResult.setErrorMessage(prefixMessage + "node命令不可用,请安装Nodejs,请参考:Nodejs安装。 " + endMessage); + return checkResult; + } + + /** + * 检测是否部署npm命令 + * + * @return + */ + public static ExecuteEnvironmentCheckResult checkGlobalNpmInstalled() { + ExecuteEnvironmentCheckResult checkResult = ExecuteEnvironmentCheckResult.getInstance(); + String errorMessage; + try { + errorMessage = CommandLineUtility.runCommandWithoutThrows("npm -v"); + } catch (RuntimeException ex) { + errorMessage = ex.getMessage(); + } + + if (StringUtility.isNullOrEmpty(errorMessage)) { + return checkResult; + } + checkResult.setSuccess(false); + checkResult.setErrorMessage(String.format(prefixMessage + "npm命令不可用,请安装Nodejs,请参考:Nodejs安装。%s ", endMessage)); + return checkResult; + } + + /** + * 检测是否部署jit命令 + * + * @return + */ + public static ExecuteEnvironmentCheckResult checkGlobalJitEngineInstalled() { + ExecuteEnvironmentCheckResult checkResult = ExecuteEnvironmentCheckResult.getInstance(); + String errorMessage; + try { + errorMessage = CommandLineUtility.runCommandWithoutThrows("jit --version "); + } catch (RuntimeException ex) { + errorMessage = ex.getMessage(); + } + + if (StringUtility.isNullOrEmpty(errorMessage)) { + return checkResult; + } + checkResult.setSuccess(false); + checkResult.setErrorMessage(prefixMessage + "Jit-Engine未部署,请先部署。请参考:Jit-Engine安装。" + endMessage); + return checkResult; + } + + /** + * 检测是否不是ng命令 + * + * @return + */ + public static ExecuteEnvironmentCheckResult checkGlobalNgInstalled() { + ExecuteEnvironmentCheckResult checkResult = ExecuteEnvironmentCheckResult.getInstance(); + String errorMessage; + try { + errorMessage = CommandLineUtility.runCommandWithoutThrows("ng --version"); + } catch (RuntimeException ex) { + errorMessage = ex.getMessage(); + } + if (StringUtility.isNullOrEmpty(errorMessage)) { + return checkResult; + } + checkResult.setSuccess(false); + checkResult.setErrorMessage(prefixMessage + "未部署依赖ng命令,请先部署,请参考:" + "Angular-Cli安装。" + endMessage); + return checkResult; + } + + /** + * 编译前环境检查 + */ + public static void beforeCompile() { + /// 不考虑npm使用安装盘的情况 + ExecuteEnvironmentCheckResult nodeCheckResult = ExecuteEnvironmentChecker.checkGlobalNodeInstalled(); + if (!nodeCheckResult.isSuccess()) { + throw new EnvironmentException(nodeCheckResult.getErrorMessage(), defaultModalTitle, defaultModalLevel); + } + ExecuteEnvironmentCheckResult npmCheckResult = ExecuteEnvironmentChecker.checkGlobalNpmInstalled(); + if (!npmCheckResult.isSuccess()) { + throw new EnvironmentException(npmCheckResult.getErrorMessage(), defaultModalTitle, defaultModalLevel); + } + + ExecuteEnvironmentCheckResult ngCheckResult = ExecuteEnvironmentChecker.checkGlobalNgInstalled(); + if (!ngCheckResult.isSuccess()) { + throw new EnvironmentException(ngCheckResult.getErrorMessage(), defaultModalTitle, defaultModalLevel); + } + } + + /** + * 生成前环境检查 + */ + public static void beforeGenerate() { + /// 不考虑npm使用安装盘的情况 + ExecuteEnvironmentCheckResult nodeCheckResult = ExecuteEnvironmentChecker.checkGlobalNodeInstalled(); + if (!nodeCheckResult.isSuccess()) { + throw new EnvironmentException(nodeCheckResult.getErrorMessage(), defaultModalTitle, defaultModalLevel); + } + + ExecuteEnvironmentCheckResult jitCheckResult = ExecuteEnvironmentChecker.checkGlobalJitEngineInstalled(); + if (!jitCheckResult.isSuccess()) { + throw new EnvironmentException(jitCheckResult.getErrorMessage(), defaultModalTitle, defaultModalLevel); + } + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/io/FileUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/io/FileUtility.java new file mode 100644 index 00000000..2137a7e6 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/io/FileUtility.java @@ -0,0 +1,802 @@ +package com.inspur.edp.web.common.io; + +import com.inspur.edp.web.common.utility.OperatingSystemUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.common.environment.EnvironmentUtil; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; + +/** + * 平台无关的文件类 + */ +public class FileUtility { + private static final String ENCODING = "UTF-8"; + private static final String UTF8_BOM_HEADER = "\ufeff"; + + /** + * 平台无关的路径分隔符 + */ + public static final String DIRECTORY_SEPARATOR_CHAR = File.separator; + + private FileUtility() { + + } + + + /** + * Combine Path + * + * @param path1 the path 1 + * @param path2 the path 2 + * @return the string + * @description 合并路径 + */ + public static String combine(String path1, String path2) { + return Paths.get(path1).resolve(path2).toString(); + } + + /** + * Combine Path + * + * @param path1 the path 1 + * @param path2 the path 2 + * @param path3 the path 3 + * @return the string + * @description 合并路径 + */ + public static String combine(String path1, String path2, String path3) { + return combine(combine(path1, path2), path3); + } + + /** + * Combine Path + * + * @param path1 the path 1 + * @param path2 the path 2 + * @param path3 the path 3 + * @param path4 the path 4 + * @return the string + * @description 合并路径 + */ + public static String combine(String path1, String path2, String path3, String path4) { + return combine(combine(path1, path2), combine(path3, path4)); + } + + /** + * Combine Path + * + * @param path1 the path 1 + * @param path2 the path 2 + * @param path3 the path 3 + * @param path4 the path 4 + * @param path5 the path 5 + * @return the string + * @description 合并路径 + */ + public static String combine(String path1, String path2, String path3, String path4, String path5) { + return combine(combine(path1, path2), combine(path3, path4), path5); + } + + /** + * Combine Path + * + * @param path1 the path 1 + * @param path2 the path 2 + * @param path3 the path 3 + * @param path4 the path 4 + * @param path5 the path 5 + * @param path6 the path 6 + * @return the string + * @description 合并路径 + */ + public static String combine(String path1, String path2, String path3, String path4, String path5, String path6) { + return combine(combine(path1, path2), combine(path3, path4), combine(path5, path6)); + } + + /** + * Check file or directory exists + * + * @return true if and only if the file or directory denoted + * by this abstract pathname exists; false otherwise + * @description 检查文件或目录是否存在 + */ + public static boolean exists(String path) { + File file = new File(path); + + return exists(file); + } + + /** + * 判断一个文件夹是否是空 + * + * @param path + * @return + */ + public static boolean isEmptyFolder(String path) { + File file = new File(path); + if (file.isDirectory()) { + return file.list().length == 0; + } + return false; + } + + /** + * 检测文件或目录是否存在 + * + * @param fileHandler 文件或目录句柄 + * @return + */ + private static boolean exists(File fileHandler) { + return fileHandler.exists(); + } + + /** + * Read file content as string + * + * @param path the full file path + * @return the string + * @description 根据文件的完整路径,读取文件内容(UTF-8编码) + */ + public static String readAsString(String path) { + File file = new File(path); + long fileLength = file.length(); + byte[] fileContent = new byte[(int) fileLength]; + try { + FileInputStream in = new FileInputStream(file); + in.read(fileContent); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("readAsString failed", e); + } + + try { + // 判断有没有utf-8 bom头, 有则去除。 + String fileContents = new String(fileContent, ENCODING); + if (fileContents.startsWith(UTF8_BOM_HEADER)) { + fileContents = fileContents.substring(1); + } + return fileContents; + } catch (UnsupportedEncodingException e) { + System.err.println("The OS does not support " + ENCODING); + e.printStackTrace(); + return null; + } + } + + /** + * Delete a file. + * + * @description 删除文件 + */ + public static boolean deleteFile(String filePath) { + File file = new File(filePath); + if (!exists(file) || !file.isFile()) { + return false; + } + + return file.delete(); + } + + /** + * 设置目前权限 + * 当前设置的可读、可写、可执行权限,即linux的 777 + * + * @param filePath + */ + public static void setPermission(String filePath) { + if (StringUtility.isNullOrEmpty(filePath)) { + return; + } + File file = new File(filePath.trim()); + if (file.exists()) { + try { + file.setReadable(true, false); + file.setWritable(true, false); + file.setExecutable(true, false); + } catch (Exception ex) { + + } + } + } + + /** + * Delete a directory. + */ + public static boolean deleteDirectory(String directoryPath) { + File directory = new File(directoryPath); + if (!exists(directory) || !directory.isDirectory()) { + return false; + } + + return directory.delete(); + } + + /** + * 使用fileutils方法的强制删除方法 强制删除文件目录 + * + * @param directoryPath + */ + public static void forceDelete(String directoryPath) { + if ((new File(directoryPath)).isDirectory() && (new File(directoryPath)).exists()) { + try { + FileUtils.forceDelete(new File(directoryPath)); + } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + } + + public static void deleteFolder(String directoryPath) { + File file = new File(directoryPath); + deleteFolder(file); + } + + + /** + * 删除文件夹及其子文件夹 + * + * @param folder + * @ + */ + public static void deleteFolder(File folder) { + if (!folder.exists()) { + return; + } + File[] files = folder.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + //递归直到目录下没有文件 + deleteFolder(file); + } else { + //删除 + file.delete(); + } + } + } + //删除 + folder.delete(); + + } + + + /** + * 将文本写入指定文件; 如果文件不存在先创建文件,再执行写入操作; 如果文件存在,删除后重新创建并写入。 + * + * @param path 目标文件路径 + * @param fileName 目标文件名称 + * @param contents 写入文件的内容 + */ + public static void writeFile(String path, String fileName, String contents) { + String filePath = combine(path, fileName); + + filePath = getPlatformIndependentPath(filePath); + // 如果文件路径不存在 那么创建对应的文件目录 + if (!exists(path)) { + createDirectory(path); + } + File file = new File(filePath); + + if (exists(file)) { + clear(file); + } else { + createFile(file); + } + // 如果写入的内容为null 那么转换成空字符串写入 + if (StringUtility.isNullOrEmpty(contents)) { + contents = ""; + } + updateFile(filePath, contents); + } + + /** + * 将文本写入指定文件; 如果文件不存在先创建文件,再执行写入操作; 如果文件存在,删除后重新创建并写入。 + * + * @param fileNameAndPath 目标文件路径 + * @param contents 写入文件的内容 + */ + public static void writeFile(String fileNameAndPath, String contents) { + // 如果文件路径不存在 那么创建对应的文件目录 + File file = new File(fileNameAndPath); + + File fileParent = file.getParentFile(); + if (!fileParent.exists()) { + fileParent.mkdirs(); + } + + if (exists(file)) { + clear(file); + } else { + createFile(file); + } + // 如果写入的内容为null 那么转换成空字符串写入 + if (StringUtility.isNullOrEmpty(contents)) { + contents = ""; + } + updateFile(fileNameAndPath, contents); + } + + public static void reName(String source, String dest) { + if (!StringUtility.isNullOrEmpty(source) && !StringUtility.isNullOrEmpty(dest)) { + File sourceFile = new File(source); + if (sourceFile.exists()) { + // 重命名文件目录 + File destFile = new File(dest); + if (destFile.exists()) { + destFile.delete(); + } + sourceFile.renameTo(destFile); + } + } + } + + + /** + * 获取当前运行目录 + * + * @return + */ + public static String getCurrentWorkPath(boolean isUpdradeTool) { + // 如果运行在tool中 那么运行目录需要进行调整 + if (isUpdradeTool) { + String caf_boot_home = System.getenv("CAF_BOOT_HOME"); + + String targetPath = null; + if (caf_boot_home == null) { + targetPath = toAbsolutePath("../../../../"); + } else { + targetPath = toAbsolutePath(Paths.get(caf_boot_home).resolve("..").toString()); + } + + return targetPath; + } + + return EnvironmentUtil.getBasePath(); + } + + /** + * 获取安装盘server path + * + * @return + */ + public static String getServerRTPath() { + return EnvironmentUtil.getServerRTPath(); + } + + + /** + * 将路径转换成为绝对路径 + * + * @param maybeRelative + * @return + */ + private static String toAbsolutePath(String maybeRelative) { + try { + Path path = Paths.get(maybeRelative); + Path effectivePath = path; + if (!path.isAbsolute()) { + Path base = Paths.get(""); + effectivePath = base.resolve(path).toAbsolutePath(); + } + return effectivePath.normalize().toString(); + } catch (Exception e) { + return maybeRelative; + } + } + + /** + * 移动审批调用 不能删除 + * + * @return + */ + public static String getCurrentWorkPath() { + + return EnvironmentUtil.getBasePath(); + //return System.getProperty("user.dir"); + } + + /** + * 清空文件中内容 + * + * @param file 待清空文件句柄 + */ + private static void clear(File file) { + try { + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(""); + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 更新文件 + * + * @param fullPath + * @param content + */ + public static void updateFile(String fullPath, String content) { + try { + byte[] buffer = content.getBytes(StandardCharsets.UTF_8); + FileOutputStream fos = new FileOutputStream(fullPath, true); + fos.write(buffer); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 创建文件 + * + * @param path 待创建文件路径 + */ + public static void createFile(String path) { + try { + path = getPlatformIndependentPath(path); + File file = new File(path); + if (!exists(file)) { + file.createNewFile(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * 创建文件 + * + * @param file 待创建文件句柄 + */ + private static boolean createFile(File file) { + try { + file.createNewFile(); + return true; + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + } + + public static void createDirectory(String path) { + if (path == null || path.isEmpty()) { + return; + } + + try { + path = getPlatformIndependentPath(path); + File file = new File(path); + if (!exists(file)) { + file.mkdirs(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * 判断路径是否是绝对路径 + * + * @param dirPath + * @return + */ + public static boolean isAbsolute(String dirPath) { + File file = new File(dirPath); + return file.isAbsolute(); + } + + /** + * 路径转换,获取平台无关的路径 + * + * @param path 待转换路径 + */ + public static String getPlatformIndependentPath(String path) { + + if (path == null) { + return null; + } + // 如果文件路径为空字符串 那么不进行任何的转换处理 + if (path.isEmpty()) { + return path; + } + + + return path.replace("\\\\", "/").replace("\\", "/"); + } + + /** + * 文件夹拷贝,遇到同名文件覆盖 + * + * @param sourceFolderFullPath 源文件夹路径 + * @param destFolderFullPath 目标文件夹路径 + * | + */ + public static void copyFolder(String sourceFolderFullPath, String destFolderFullPath) { + copyFolder(sourceFolderFullPath, destFolderFullPath, true); + } + + /** + * 文件夹拷贝 + * + * @param sourceFolderFullPath 源文件夹路径 + * @param destFolderFullPath 目标文件夹路径 + * @param isOverWrite 是否覆盖同名文件 + */ + public static void copyFolder(String sourceFolderFullPath, String destFolderFullPath, boolean isOverWrite) { + if (sourceFolderFullPath == null || sourceFolderFullPath.isEmpty() || destFolderFullPath == null || destFolderFullPath.isEmpty()) { + return; + } + + sourceFolderFullPath = getPlatformIndependentPath(sourceFolderFullPath); + destFolderFullPath = getPlatformIndependentPath(destFolderFullPath); + + if (!exists(destFolderFullPath)) { + createDirectory(destFolderFullPath); + } + + ArrayList files = getFiles(sourceFolderFullPath, false); + for (File file : files) { + String fileName = file.getName(); + String dest = combine(destFolderFullPath, fileName); + copyFile(file.getAbsolutePath(), dest, isOverWrite); + } + + ArrayList folders = getDirectories(sourceFolderFullPath); + for (File folder : folders) { + String name = folder.getName(); + String dest = combine(destFolderFullPath, name); + // 递归拷贝 + copyFolder(folder.getAbsolutePath(), dest); + } + } + + /** + * 获取某一文件夹下的所有文件 + **/ + public static ArrayList getFiles(String path, boolean rescure) { + ArrayList filesInFolder = new ArrayList<>(); + if (rescure) { + rescureGetFiles(path, filesInFolder); + } else { + File file = new File(path); + // 如果这个路径是文件夹 + File[] files = file.listFiles(); + if (files != null) { + for (File f : files) { + if (f.isFile()) { + filesInFolder.add(f); + } + } + } + } + + return filesInFolder; + } + + /** + * 递归获取文件目录下的所有文件列表 + * + * @param path + * @param fileList + */ + private static void rescureGetFiles(String path, List fileList) { + File file = new File(path); + File[] files = file.listFiles(); + if (files != null) { + for (File fileItem : files) { + // 如果为文件目录 + if (fileItem.isDirectory()) { + rescureGetFiles(fileItem.getPath(), fileList); + } else { + fileList.add(fileItem); + } + } + } + } + + /** + * 获取某一文件夹下的所有文件夹 + */ + public static ArrayList getDirectories(String path) { + // 初始化制定路径 + File file = new File(path); + ArrayList fileList = new ArrayList<>(); + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (File value : files) { + if (value.isDirectory()) { + fileList.add(value); + } + } + } + return fileList; + } + + /** + * 拷贝文件:支持覆盖已存在文件 + **/ + public static void copyFile(String sourcePath, String destinationPath, boolean isOverWrite) { + if (sourcePath != null && destinationPath != null) { + fileCopy(new File(sourcePath), new File(destinationPath)); + } + } + + + private static void fileCopy(File file1, File file2) { + try { + FileUtils.copyFile(file1, file2); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 判断两个文件的内容是否相同,文件名要用绝对路径 + * + * @param fileName1 :文件1的绝对路径 + * @param fileName2 :文件2的绝对路径 + * @return 相同返回true,不相同返回false + */ + public static boolean isSameFile(String fileName1, String fileName2) { + FileInputStream fis1 = null; + FileInputStream fis2 = null; + try { + fis1 = new FileInputStream(fileName1); + fis2 = new FileInputStream(fileName2); + + //返回总的字节数 + int len1 = fis1.available(); + int len2 = fis2.available(); + + //长度相同,则比较具体内容 + if (len1 == len2) { + //建立两个字节缓冲区 + byte[] data1 = new byte[len1]; + byte[] data2 = new byte[len2]; + + //分别将两个文件的内容读入缓冲区 + fis1.read(data1); + fis2.read(data2); + + //依次比较文件中的每一个字节 + for (int i = 0; i < len1; i++) { + //只要有一个字节不同,两个文件就不一样 + if (data1[i] != data2[i]) { + System.out.println("文件内容不一样"); + return false; + } + } + System.out.println("两个文件完全相同"); + return true; + } else { + //长度不一样,文件肯定不同 + return false; + } + } catch (IOException e) { + e.printStackTrace(); + } finally {//关闭文件流,防止内存泄漏 + if (fis1 != null) { + try { + fis1.close(); + } catch (IOException e) { + //忽略 + e.printStackTrace(); + } + } + if (fis2 != null) { + try { + fis2.close(); + } catch (IOException e) { + //忽略 + e.printStackTrace(); + } + } + } + return false; + } + + + public static String getFileNameWithPath(String filePath) { + String _filePath = filePath.trim(); + return _filePath.substring(_filePath.lastIndexOf("/") + 1); + } + + + /** + * 求取两个路径得相对路径 + * + * @param path1 + * @param path2 + * @param replaceSeparator 是否替换路径分隔符 + * @return + */ + public static String getRelativePath(String path1, String path2, boolean replaceSeparator) { + if (StringUtility.isNullOrEmpty(path1) || StringUtility.isNullOrEmpty(path2)) { + return ""; + } + + if (replaceSeparator) { + path1 = getPlatformIndependentPath(path1); + path2 = getPlatformIndependentPath(path2); + } + + String strRelativePath = Paths.get(path1).relativize(Paths.get(path2)).toString(); + // 转换成路径无关的文件路径 + if (replaceSeparator) { + strRelativePath = getPlatformIndependentPath(strRelativePath); + } + return strRelativePath; + } + + /** + * 获取绝对路径的头 + * windows下为 "盘符 + :" + * nix下为 "\" + * + * @param currentPath + * @return + */ + public static String getAbsolutePathHead(String currentPath) { + String absolutePathHead = ""; + if (StringUtils.isEmpty(currentPath)) { + return absolutePathHead; + } + currentPath = currentPath.replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + + if (OperatingSystemUtility.isWindows()) { + //TODO N转J 此处N版获取路径中盘符是通过以下代码实现的,在java中无对等方法,因此采用获取绝对路径:前的第一个字符解决,可能存在bug + String absolutePath = new File(currentPath).getAbsolutePath(); + int index = absolutePath.indexOf(':'); + if (index <= 0) { + throw new RuntimeException("Get Directory Root Failed When doing the GetPathVolume function"); + } + absolutePathHead = absolutePath.substring(index - 1, 2); + } else { + absolutePathHead = DIRECTORY_SEPARATOR_CHAR; + } + + return absolutePathHead; + } + + /** + * 获取执行的临时目录 + * + * @return + */ + public static String getTmpDir() { + return System.getProperty("java.io.tmpdir"); + } + + + /** + * Fail for below cases + *

+ * "/path/../makefile", + * "/path/dir.test/makefile" + */ + public static String getFileExtension(String fileName) { + if (fileName == null) { + throw new IllegalArgumentException("fileName must not be null!"); + } + + String extension = ""; + + int index = fileName.lastIndexOf('.'); + if (index > 0) { + extension = fileName.substring(index); + } + + return extension; + + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/io/NodeJsCommandResult.java b/web-common/src/main/java/com/inspur/edp/web/common/io/NodeJsCommandResult.java new file mode 100644 index 00000000..80b3b364 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/io/NodeJsCommandResult.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.common.io; + +import lombok.Data; + +/** + * @Title: NodeJsCommandResult + * @Description: com.inspur.edp.web.common.io nodejs命令结果 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/6 16:19 + */ +@Data +public class NodeJsCommandResult { + /** + * Nodejs 命令或对应路径 + */ + private String nodeJsCommand; + /** + * 是否使用全局命令 如果当前路径下不存在对应命令执行文件,那么使用其环境变量配置命令 + */ + private boolean isUseGlobal; + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/io/NodejsFunctionUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/io/NodejsFunctionUtility.java new file mode 100644 index 00000000..7fc7059d --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/io/NodejsFunctionUtility.java @@ -0,0 +1,217 @@ +package com.inspur.edp.web.common.io; + +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.utility.OperatingSystemUtility; + +/** + * nodejs 功能汇总 + * + * @author noah + */ +public class NodejsFunctionUtility { + private NodejsFunctionUtility() { + } + + /** + * 获取node命令执行 + * + * @param isUpgradeTool + * @return + */ + public static String getNodeJsCommandInServerWithOS(NodeJsCommandEnum nodeJsCommandEnum, boolean isUpgradeTool) { + String nodeJsPath = getNodeJsPathInServer(); + String serverPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + if (OperatingSystemUtility.isWindows()) { + nodeJsPath = FileUtility.combine(nodeJsPath, "amd64-win"); + } else { + nodeJsPath = FileUtility.combine(nodeJsPath, "x86_64-linux", "bin"); + } + return getNodeJsCommandWithNodeJsPath(nodeJsCommandEnum, nodeJsPath, serverPath); + } + + /** + * 获取node命令执行 + * + * @param currentServerPath + * @return + */ + public static String getNodeJsCommandInServerWithOS(NodeJsCommandEnum nodeJsCommandEnum, String currentServerPath) { + String nodeJsPath = getNodeJsPathInServer(); + if (OperatingSystemUtility.isWindows()) { + nodeJsPath = FileUtility.combine(nodeJsPath, "amd64-win"); + } else { + if (nodeJsCommandEnum == NodeJsCommandEnum.Node) { + nodeJsPath = FileUtility.combine(nodeJsPath, "x86_64-linux", "bin"); + } else { + // 由于通过补丁安装 linux下的npm、npx是通过link执行 无法通过windows进行补丁制作,因此移除link,使用link的具体js文件进行执行 + nodeJsPath = FileUtility.combine(nodeJsPath, "x86_64-linux"); + } + + FileUtility.setPermission(nodeJsPath); + } + return getNodeJsCommandWithNodeJsPath(nodeJsCommandEnum, nodeJsPath, currentServerPath); + } + + + private static String getNodeJsCommandWithNodeJsPath(NodeJsCommandEnum nodeJsCommandEnum, String nodeJsPath, String currentServerPath) { + boolean hasNodePackage = FileUtility.exists(nodeJsPath); + String nodeCommand = "node"; + // 如果是linux系统 移除link 指定npm、npx命令 且在linux环境下 + boolean needUseLinuxJs = hasNodePackage && OperatingSystemUtility.isLinux() && (nodeJsCommandEnum == NodeJsCommandEnum.Npm || nodeJsCommandEnum == NodeJsCommandEnum.Npx); + if (needUseLinuxJs) { + String currentNodeCommand = getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, currentServerPath); + String npmCommandJsName = "npm-cli.js"; + String npxCommandJsName = "npx-cli.js"; + String npmCommandJs = FileUtility.combine(nodeJsPath, "lib", "node_modules", "npm", "bin", npmCommandJsName); + String npxCommandJs = FileUtility.combine(nodeJsPath, "lib", "node_modules", "npm", "bin", npxCommandJsName); + + if (nodeJsCommandEnum == NodeJsCommandEnum.Npm) { + nodeCommand = currentNodeCommand + " " + npmCommandJs; + } else { + nodeCommand = currentNodeCommand + " " + npxCommandJs; + } + + // 设置文件权限 + + FileUtility.setPermission(currentNodeCommand); + + } else { + String nodeCommandName = getNodeJsCommandFromEnum(nodeJsCommandEnum); + nodeCommand = nodeCommandName; + if (hasNodePackage) { + nodeCommand = FileUtility.combine(nodeJsPath, nodeCommandName); + } + nodeCommand = nodeCommand + " "; + } + + FileUtility.setPermission(nodeCommand); + return nodeCommand; + } + + /** + * 根据命令枚举获取对应的实际命令值 + * + * @param nodeJsCommandEnum + * @return + */ + private static String getNodeJsCommandFromEnum(NodeJsCommandEnum nodeJsCommandEnum) { + String result = "node"; + switch (nodeJsCommandEnum) { + case Node: + result = "node"; + break; + case Npm: + result = "npm"; + break; + case Npx: + result = "npx"; + break; + } + return result; + } + + /** + * 获取在server中执行jit命令的操作 + * + * @param isUpgradeTool + * @return + */ + public static String getNgCommandInServer(boolean isUpgradeTool) { + String nodeJsPath = getNodeJsPathInServer(); + String ngCommandFilePath = FileUtility.combine(nodeJsPath, JITEngineConstants.NgCommandRelativePath); + if (!FileUtility.exists(ngCommandFilePath)) { + return "ng"; + } + String nodeCommand = getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, isUpgradeTool); + String ngCommand = nodeCommand + ngCommandFilePath; + + FileUtility.setPermission(ngCommand); + + return ngCommand; + } + + /** + * 获取nodejs路径 + * * + * + * @return + */ + public static String getNodeJsPathInServer() { + String currentServerRTPath = FileUtility.getServerRTPath(); + String nodejsPath = FileUtility.combine(currentServerRTPath, "runtime", "nodejs"); + + FileUtility.setPermission(nodejsPath); + + return nodejsPath; + } + + /** + * 获取在server中执行jit命令的操作 + * + * @param isUpgradeTool + * @return + */ + public static String getJitCommandInServer(boolean isUpgradeTool) { + String nodeJsPath = getNodeJsPathInServer(); + String jitCommandJsPath = FileUtility.combine(nodeJsPath, JITEngineConstants.JitCommandJsRelativePath); + if (!FileUtility.exists(jitCommandJsPath)) { + return "jit"; + } + String nodeCommand = getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, isUpgradeTool); + String jitCommand = nodeCommand + " " + jitCommandJsPath; + + FileUtility.setPermission(jitCommand); + return jitCommand; + } + + /** + * 获取在server中执行tsc命令的操作 + * + * @param isUpgradeTool + * @return + */ + public static NodeJsCommandResult getTscCommandInServer(boolean isUpgradeTool) { + String nodeJsPath = getNodeJsPathInServer(); + String jitCommandJsPath = FileUtility.combine(nodeJsPath, JITEngineConstants.ServerScriptsPath, JITEngineConstants.TscCommandRelativePath); + NodeJsCommandResult nodeJsCommandResult = new NodeJsCommandResult(); + if (!FileUtility.exists(jitCommandJsPath)) { + nodeJsCommandResult.setNodeJsCommand("tsc"); + nodeJsCommandResult.setUseGlobal(true); + return nodeJsCommandResult; + } + String nodeCommand = getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, isUpgradeTool); + String tscCommand = nodeCommand + " " + jitCommandJsPath; + + FileUtility.setPermission(tscCommand); + nodeJsCommandResult.setNodeJsCommand(tscCommand); + nodeJsCommandResult.setUseGlobal(false); + return nodeJsCommandResult; + } + + /** + * 获取在server中执行rollup命令的操作 + * + * @param isUpgradeTool + * @return + */ + public static NodeJsCommandResult getRollupCommandInServer(boolean isUpgradeTool) { + String nodeJsPath = getNodeJsPathInServer(); + String rollupCommandJsPath = FileUtility.combine(nodeJsPath, JITEngineConstants.ServerScriptsPath, JITEngineConstants.RollupCommandRelativePath); + NodeJsCommandResult nodeJsCommandResult = new NodeJsCommandResult(); + if (!FileUtility.exists(rollupCommandJsPath)) { + nodeJsCommandResult.setNodeJsCommand("rollup"); + nodeJsCommandResult.setUseGlobal(false); + return nodeJsCommandResult; + } + String nodeCommand = getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, isUpgradeTool); + String rollupCommand = nodeCommand + " " + rollupCommandJsPath; + + FileUtility.setPermission(rollupCommand); + nodeJsCommandResult.setNodeJsCommand(rollupCommand); + nodeJsCommandResult.setUseGlobal(false); + return nodeJsCommandResult; + } +} + + diff --git a/web-common/src/main/java/com/inspur/edp/web/common/logger/WebLogger.java b/web-common/src/main/java/com/inspur/edp/web/common/logger/WebLogger.java new file mode 100644 index 00000000..27e0e3a1 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/logger/WebLogger.java @@ -0,0 +1,188 @@ +package com.inspur.edp.web.common.logger; + +import com.inspur.edp.web.common.utility.StringUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @Title: WebLogger + * @Description: com.inspur.edp.web.common.logger + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/11 9:41 + */ +public enum WebLogger { + /** + * 使用枚举的单例特性 + */ + Instance; + + /** + * 内部定义枚举类 标识日志级别 + */ + private enum WebLoggerLevel { + Debug { + /** + * 抽象类 使用各个枚举参数进行日志写入 + * + * @param loggerInstance + */ + @Override + void write(String message, Logger loggerInstance) { + if (loggerInstance.isDebugEnabled()) { + loggerInstance.debug(message); + } + } + }, Info { + /** + * 抽象类 使用各个枚举参数进行日志写入 + * + * @param message + * @param loggerInstance + */ + @Override + void write(String message, Logger loggerInstance) { + if (loggerInstance.isInfoEnabled()) { + loggerInstance.info(message); + } + } + }, Warn { + /** + * 抽象类 使用各个枚举参数进行日志写入 + * + * @param message + * @param loggerInstance + */ + @Override + void write(String message, Logger loggerInstance) { + if (loggerInstance.isWarnEnabled()) { + loggerInstance.warn(message); + } + } + }, Error { + /** + * 抽象类 使用各个枚举参数进行日志写入 + * + * @param message + * @param loggerInstance + */ + @Override + void write(String message, Logger loggerInstance) { + if (loggerInstance.isErrorEnabled()) { + loggerInstance.error(message); + } + } + }; + + /** + * 抽象类 使用各个枚举参数进行日志写入 + * + * @param loggerInstance + */ + abstract void write(String message, Logger loggerInstance); + } + + /** + * 根据指定class获取对应的logger实例 + * 内置包含对logger实例的缓存动作, + * 尽量使用默认logger,避免重复创建logger实例带来的内存开销 + * + * @param name + * @return + */ + private Logger getLoggerInstance(String name) { + // 内置包含对logger实例的缓存操作 + if (StringUtility.isNullOrEmpty(name)) { + return LoggerFactory.getLogger(this.defaultLoggerName); + } + return LoggerFactory.getLogger(name); + } + + private String defaultLoggerName = WebLogger.class.getName(); + + /** + * 设置默认LoggerName 此参数无需单独调用。 + * 若需调整,请使用完毕后重置 + * + * @param defaultLoggerName + */ + public void setDefaultLoggerName(String defaultLoggerName) { + if (!StringUtility.isNullOrEmpty(defaultLoggerName)) { + this.defaultLoggerName = defaultLoggerName; + } + } + + /** + * 获取默认的loggerName + * + * @return + */ + public String getDefaultLoggerName() { + return this.defaultLoggerName; + } + + /** + * 充值defaultLoggerName 默认的日志名称 + */ + public void resetDefaultLoggerName() { + this.defaultLoggerName = WebLogger.class.getName(); + } + + + /** + * 执行debug级别日志消息写入 + * + * @param message 待写入的消息内容 + * @param loggerName 自定义的日志名称 + */ + public void debug(String message, String... loggerName) { + this.write(message, WebLoggerLevel.Debug, loggerName); + } + + /** + * 执行info级别的日志写入 + * + * @param message 待写入的消息内容 + * @param loggerName 自定义的日志写入名称 + */ + public void info(String message, String... loggerName) { + this.write(message, WebLoggerLevel.Info, loggerName); + } + + /** + * @param message + * @param loggerName + */ + public void error(String message, String... loggerName) { + this.write(message, WebLoggerLevel.Error, loggerName); + } + + public void warn(String message, String... loggerName) { + this.write(message, WebLoggerLevel.Warn, loggerName); + } + + /** + * 执行日志消息写入 + * + * @param message + * @param loggerLevel + * @param loggerName + */ + private void write(String message, WebLoggerLevel loggerLevel, String... loggerName) { + if (StringUtility.isNullOrEmpty(message)) { + return; + } + String useLoggerName = null; + if (loggerName != null && loggerName.length > 0) { + useLoggerName = loggerName[0]; + } + + Logger logger; + logger = getLoggerInstance(useLoggerName); + + if (logger != null) { + loggerLevel.write(message, logger); + } + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/metadata/MetadataUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/metadata/MetadataUtility.java new file mode 100644 index 00000000..a7ec08d8 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/metadata/MetadataUtility.java @@ -0,0 +1,471 @@ +package com.inspur.edp.web.common.metadata; + + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.entity.uri.MetadataURI; +import com.inspur.edp.lcm.metadata.api.service.GspProjectService; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.lcm.metadata.api.service.RefCommonService; +import com.inspur.edp.lcm.metadata.devcommon.ManagerUtils; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.metadata.rtcustomization.serverapi.CustomizationServerService; +import com.inspur.edp.web.command.component.metadata.*; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * 元数据工具类 + * + * @author noah + */ +public final class MetadataUtility { + + @Autowired + MetadataService metadataService; + + @Autowired + RefCommonService refCommonService; + + @Autowired + MetadataProjectService metadataProjectService; + + @Autowired + GspProjectService gspProjectService; + + @Autowired + CustomizationService customizationService; + + @Autowired + CustomizationServerService customizationServerService; + + public MetadataService getMetadataService() { + if (metadataService == null) { + metadataService = SpringBeanUtils.getBean(MetadataService.class); + } + return metadataService; + } + + public RefCommonService getRefCommonService() { + if (refCommonService == null) { + refCommonService = SpringBeanUtils.getBean(RefCommonService.class); + } + return refCommonService; + } + + public MetadataProjectService getMetadataProjectService() { + if (metadataProjectService == null) { + metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + } + return metadataProjectService; + } + + public GspProjectService getGspProjectService() { + if (gspProjectService == null) { + gspProjectService = SpringBeanUtils.getBean(GspProjectService.class); + } + return gspProjectService; + } + + public CustomizationService getCustomizationService() { + if (customizationService == null) { + customizationService = SpringBeanUtils.getBean(CustomizationService.class); + } + return customizationService; + } + + public CustomizationServerService getCustomizationServerService() { + if (customizationServerService == null) { + customizationServerService = SpringBeanUtils.getBean(CustomizationServerService.class); + } + return customizationServerService; + } + + + private MetadataUtility() { + + } + + private static final MetadataUtility metadataUtilityInstance = new MetadataUtility(); + + public static MetadataUtility getInstance() { + return metadataUtilityInstance; + } + + + @FunctionalInterface + public interface AfterGetReferenceWebComponentMetadata { + void invoke(GspMetadata commandMetadata, CmpMethodRefering methodReferingItem, GspMetadata webComponentMetadata, Object... outParameterArray); + } + + /** + * 根据元数据名称及元数据所在路径获取元数据信息。该方法不支持跨工程引用 + * + * @param metadataFileName + * @param metadataPath + * @return + */ + public GspMetadata getMetadata(String metadataFileName, String metadataPath) { + if (StringUtility.isNullOrEmpty(metadataFileName) || StringUtility.isNullOrEmpty(metadataPath)) { + return null; + } + + return this.getMetadataService().loadMetadata(metadataFileName, metadataPath); + } + + public GspMetadata getMetadataWithIdAndPath(String metadataId, String spacePath) { + return this.getMetadataService().getRefMetadata(spacePath, metadataId); + } + + /** + * 判断指定路径 指定文件名称元数据是否存在 + * + * @param spacePath + * @param metadataId + * @return + */ + public boolean isMetaDataExistsWithMetadataIDAndPath(String spacePath, String metadataId) { + return this.getMetadataService().isMetadataExistInProject(spacePath, metadataId); + } + + /** + * 根据元数据id获取元数据信息 + * + * @param metadataId + * @return + */ + public GspMetadata getMetadataWithEnvironment(String metadataId, String executeEnvironment, boolean isInUpgradeTool) { + if (StringUtility.isNullOrEmpty(metadataId)) { + return null; + } + + // 如果在升级工具中执行 + if (isInUpgradeTool) { + if (this.getCustomizationServerService() != null) { + return this.getCustomizationServerService().getMetadata(metadataId); + } else { + // 如果获取不到 那么设定执行运行时获取 + executeEnvironment = ExecuteEnvironment.Runtime; + } + } + + if (executeEnvironment.equals(ExecuteEnvironment.Design)) { + // 设计时元数据获取 + return this.getRefCommonService().getRefMetadata(new MetadataURI(metadataId), null, null); + //return this.getRefCommonService().getRefMetadata(metadataId); + } else { + return this.getCustomizationService().getMetadata(metadataId); + } + } + + /** + * 运行时获取元数据接口方法 + * 作为公共方法 会在别处进行使用 定义后不允许更改 + * + * @param metadataId + * @return + */ + public GspMetadata getMetadataInRuntime(String metadataId) { + return getMetadataWithEnvironment(metadataId, ExecuteEnvironment.Runtime, false); + } + + + public void createMetadata(GspMetadata metadata) { + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.createMetadata(metadata.getRelativePath(), metadata); + } + + public GspMetadata getMetadataInDesignTime(String metadataId, String metadataRelativePath) { + // 基于id获取元数据的前置条件 + //SetMetadataContextInDesignTime(metadataRelativePath); + + return getMetadataWithEnvironment(metadataId, ExecuteEnvironment.Design, false); + } + + /** + * 获取关联的资源元数据 + * + * @param formMetadataId + * @param formMetadataPath + * @return + */ + public GspMetadata getRefResourceMetadata(String formMetadataId, String formMetadataPath) { + List resourceMetadataCollection = getRefResourceMetadataCollection(formMetadataId, formMetadataPath); + if (resourceMetadataCollection == null || resourceMetadataCollection.size() == 0) { + return null; + } + + // 一个表单元数据仅能关联一个资源元数据 + return resourceMetadataCollection.get(0); + } + + private List getRefResourceMetadataCollection(String formMetadataId, String formMetadataPath) { + List resourceMetadataHeaderCollection = getRefResourceMetadataHeaderCollection(formMetadataId, formMetadataPath); + + // 获取资源元数据 + return getResourceMetadata(resourceMetadataHeaderCollection, formMetadataPath); + } + + private List getRefResourceMetadataHeaderCollection(String formMetadataId, String formMetadataPath) { + return this.getMetadataService().getResourceMetadata(formMetadataId, formMetadataPath); + } + + private List getResourceMetadata(List resourceMetadataHeaderArrayList, String formMetadataPath) { + if (resourceMetadataHeaderArrayList == null || resourceMetadataHeaderArrayList.size() == 0 || formMetadataPath == null || formMetadataPath.isEmpty()) { + return null; + } + + ArrayList resourceMetadataArrayList = new ArrayList(); + for (MetadataHeader resourceMetadataHeader : resourceMetadataHeaderArrayList) { + String resourceMetadataFileName = resourceMetadataHeader.getFileName(); + GspMetadata resourceMetadata = this.getMetadata(resourceMetadataFileName, formMetadataPath); + if (resourceMetadata != null) { + resourceMetadataArrayList.add(resourceMetadata); + } + } + + return resourceMetadataArrayList; + } + + /** + * 根据元数据相对路径获取工程信息 + * + * @param metadataRelativePath + * @return + */ + public MetadataProject getMetadataProject(String metadataRelativePath) { + if (StringUtility.isNullOrEmpty(metadataRelativePath)) { + return null; + } + + return this.getMetadataProjectService().getMetadataProjInfo(metadataRelativePath); + } + + /** + * 获取开发元数据绝对路径 + * + * @param relativePath + * @return + */ + public String getAbsolutePath(String relativePath) { + //开发根路径 + String devRootPath = ManagerUtils.getDevRootPath(); + if (relativePath.startsWith(devRootPath)) { + return relativePath; + } + + return Paths.get(devRootPath).resolve(relativePath).toString(); + } + + /** + * 根据元数据相对路径获取工程路径 + * + * @param metadataRelativePath + * @return + */ + public String getMetadataProjectPath(String metadataRelativePath) { + MetadataProject projectInfo = getMetadataProject(metadataRelativePath); + if (projectInfo != null) { + return projectInfo.getProjectPath(); + } + return null; + } + + /** + * 获取工程信息 + * + * @param projectPath + * @return + */ + private GspProject getProjectInformation(String projectPath) { + try { + return this.getGspProjectService().getGspProjectInfo(projectPath); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 从工程路径中获取工程名称,统一使用小写 + * + * @param projectPath + * @return + */ + public String getProjectName(String projectPath) { + GspProject currentProject = getProjectInformation(projectPath); + return currentProject.getMetadataProjectName().toLowerCase(); + } + + public void saveMetadata(GspMetadata metadata) { + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.saveMetadata(metadata, Paths.get(metadata.getRelativePath()).resolve(metadata.getHeader().getFileName()).toString()); + } + + /** + * 从工程路径中获取su路径,统一使用小写 + * + * @param projectPath + * @return + */ + public String getServiceUnitPath(String projectPath) { + GspProject currentProject = getProjectInformation(projectPath); + return currentProject.getSuDeploymentPath().toLowerCase(); + } + + public List getMetadataList(String spacePath, List metadataTypes) { + return this.getMetadataService().getMetadataList(spacePath, metadataTypes); + } + + public List getMetadataList(String spacePath) { + return this.getMetadataService().getMetadataList(spacePath); + } + + // TODO:迁移到WebCommmand项目中 + public HashMap getReferenceComponentMetadata(GspMetadata commandMetadata, AfterGetReferenceWebComponentMetadata afterGetReferenceWebComponentMetadata, Object... parameterArray) { + if (commandMetadata == null) { + return null; + } + + HashMap componentMetadataCollection = new HashMap<>(); + getReferenceWebComponentMetadata(commandMetadata, componentMetadataCollection, null, null, afterGetReferenceWebComponentMetadata, parameterArray); + return componentMetadataCollection; + } + + private void getReferenceWebComponentMetadata(GspMetadata commandMetadata, HashMap cmpList, List items, HashMap componentCacheList, AfterGetReferenceWebComponentMetadata afterGetReferenceWebComponentMetadata, Object... parameterArray) { + WebCommandsMetadata commandMetadataContent = null; + try { + commandMetadataContent = (WebCommandsMetadata) commandMetadata.getContent(); + } catch (RuntimeException e) { + throw new GSPException("Web_GetReferenceWebComponent", "当前元数据非命令元数据。元数据id是:" + commandMetadata.getHeader().getId()); + } + + if (commandMetadataContent == null) { + return; + } + + if (items == null || items.isEmpty()) { + if (commandMetadataContent.getCommands() != null && commandMetadataContent.getCommands().size() > 0) { + for (WebCommand webCommandItem : commandMetadataContent.getCommands()) { + getReferenceWebComponentCommandItemList(commandMetadata, webCommandItem.getItems(), cmpList, componentCacheList, afterGetReferenceWebComponentMetadata, parameterArray); + } + } + } else { + for (BranchCommandItem branchCommandItem : items) { + getReferenceWebComponentCommandItemList(commandMetadata, branchCommandItem.getItems(), cmpList, componentCacheList, afterGetReferenceWebComponentMetadata, parameterArray); + } + } + } + + + private void getReferenceWebComponentCommandItemList(GspMetadata commandMetadata, List commandItemList, HashMap componentMetadataCollection, HashMap componentCacheList, AfterGetReferenceWebComponentMetadata afterGetReferenceWebComponentMetadata, Object... parameterArray) { + if (commandItemList == null || commandItemList.size() == 0) { + return; + } + + for (CommandItem item : commandItemList) { + switch (item.getItemType()) { + case MethodRefer: + CmpMethodRefering methodReferingItem = (CmpMethodRefering) item; + GspMetadata webComponentMetadata = getMetadataWithIdAndPath(methodReferingItem.getComponentId(), commandMetadata.getRelativePath()); + + if (!componentMetadataCollection.containsKey(methodReferingItem.getComponentId())) { + if (componentCacheList != null && componentCacheList.containsKey(methodReferingItem.getComponentId())) { + GspMetadata cmpMetadata = componentCacheList.get(methodReferingItem.getComponentId()); + componentMetadataCollection.put(cmpMetadata.getHeader().getId(), cmpMetadata); + } else { + WebComponentMetadata cmpMetadataContent = (WebComponentMetadata) webComponentMetadata.getContent(); + if (cmpMetadataContent == null) { + throw new GSPException("", String.format("标识为'%1$s'的服务构件为null。", methodReferingItem.getComponentId())); + } + + + componentMetadataCollection.put(webComponentMetadata.getHeader().getId(), webComponentMetadata); + if (componentCacheList != null) { + componentCacheList.put(webComponentMetadata.getHeader().getId(), webComponentMetadata); + } + } + } + + afterGetReferenceWebComponentMetadata.invoke(commandMetadata, methodReferingItem, webComponentMetadata, parameterArray); + break; + case Branch: + break; + case BranchCollection: + getReferenceWebComponentMetadata(null, componentMetadataCollection, ((BranchCollectionCommandItem) item).getItems(), componentCacheList, afterGetReferenceWebComponentMetadata, parameterArray); + break; + default: + break; + } + } + } + + public String getTypeScriptFileName(GspMetadata weComponentMetadata) { + // 最理想的方式:路径来自webcmp构件路径,名称来自path(即元数据的Source属性) + // 先用webcmp的文件名构造,后续可以考虑调整 + + String path = weComponentMetadata.getRelativePath(); + String cmpFileName = weComponentMetadata.getHeader().getFileName(); + // 后缀为.webcmp + int suffixIndex = cmpFileName.lastIndexOf(".webcmp"); + String fileName; + if (suffixIndex > 0 && suffixIndex + 7 == cmpFileName.length()) { + fileName = cmpFileName.substring(0, suffixIndex); + } else if (cmpFileName.contains(weComponentMetadata.getHeader().getCode())) { + fileName = cmpFileName; + } else { + throw new RuntimeException("获取ts文件名出错,web构件上获取的文件名不对。"); + } + return String.format("%1$s/%2$s.ts", path, fileName); + } + + /** + * 获取开发期的根路径 + * + * @return + */ + public String getDevRootPath() { + return FileUtility.getPlatformIndependentPath(ManagerUtils.getDevRootPath()); + } + + /** + * 获取开发时工作空间绝对路径 + * + * @return + */ + public String getDevRootAbsolutePath() { + String devRootPath = getDevRootPath(); + if (!FileUtility.isAbsolute(devRootPath)) { + devRootPath = FileUtility.getAbsolutePathHead(devRootPath) + devRootPath; + } + return devRootPath; + } + + /** + * 获取指定类型的元数据 + * + * @param projectPath + * @param metadataType + * @return + */ + public List getMetadataListInProject(String projectPath, String metadataType) { + ArrayList searchedMetadataTypes = new ArrayList<>(); + searchedMetadataTypes.add(metadataType); + return this.getMetadataService().getMetadataList(projectPath, searchedMetadataTypes); + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/serialize/MyPropertyNamingStrategy.java b/web-common/src/main/java/com/inspur/edp/web/common/serialize/MyPropertyNamingStrategy.java new file mode 100644 index 00000000..7e44459b --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/serialize/MyPropertyNamingStrategy.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.common.serialize; + +import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.introspect.AnnotatedField; +import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class MyPropertyNamingStrategy extends PropertyNamingStrategy { + @Override + public String nameForField(MapperConfig< ? > config, AnnotatedField field, String defaultName) { + return convert(defaultName); + } + + @Override + public String nameForGetterMethod(MapperConfig< ? > config, AnnotatedMethod method, String defaultName) { + return convert(defaultName); + } + + @Override + public String nameForSetterMethod(MapperConfig< ? > config, AnnotatedMethod method, String defaultName) { + return convert(defaultName); + } + + private String convert(String input) { + return input; + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java new file mode 100644 index 00000000..1613b45c --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java @@ -0,0 +1,279 @@ +package com.inspur.edp.web.common.serialize; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.*; + +import java.io.IOException; +import java.util.Objects; + +/** + * The type Serializer utility. + * + * @author wangxufa + * @description Json序列化工具类 + */ +public class SerializeUtility { + // region 单例 + + private final ObjectMapper defaultObjectMapper; + + private SerializeUtility() { + defaultObjectMapper = this.createDefaultObjectMapper(); + } + + private static SerializeUtility serializeUtilityInstance = null; + + public static SerializeUtility getInstance() { + if (Objects.isNull(serializeUtilityInstance)) { + synchronized (SerializeUtility.class) { + if (Objects.isNull(serializeUtilityInstance)) { + serializeUtilityInstance = new SerializeUtility(); + } + } + } + + return serializeUtilityInstance; + } + + private ObjectMapper createDefaultObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy()); + setDefaultConfiguration(mapper); + return mapper; + } + + public void setDefaultConfiguration(ObjectMapper mapper) { + mapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true); + mapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true); + mapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES, true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // 大小写脱敏 默认为false 需要时可改为true + mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); + + } + + // endregion + + // region默认配置 + + /** + * 获取默认ObjectMapper实例 + * + * @return 返回默认ObjectMapper实例 + */ + public ObjectMapper getDefaultObjectMapper() { + return this.defaultObjectMapper; + } + + /** + * Deserialize string to an object. + * 将一个对象字符串反序列化成对象 + * + * @param contentString the content string + * @return the t + * @description Json反序列化 + */ + public T deserialize(String contentString, Class valueType) { + return deserialize(this.defaultObjectMapper, contentString, valueType); + } + + public T deserialize(String contentString, TypeReference valueTypeRef) { + try { + return defaultObjectMapper.readValue(contentString, valueTypeRef); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + + /** + * Serialize an object to string. + * 保持属性名称一致 + * + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(Object entity) { + return serialize(entity,false); + } + + /** + * Serialize an object to string. + * 保持属性名称一致 + * + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(Object entity, boolean usePretty) { + PropertyNamingStrategy currentNameStrategy = this.defaultObjectMapper.getPropertyNamingStrategy(); + this.defaultObjectMapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy()); + String result = serialize(this.defaultObjectMapper, entity, usePretty); + this.defaultObjectMapper.setPropertyNamingStrategy(currentNameStrategy); + return result; + } + + /** + * Serialize an object to string. + * + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(Object entity, PropertyNamingStrategy strategy, boolean usePretty) { + ObjectMapper mapper = this.getDefaultObjectMapper(); + PropertyNamingStrategy originalStrategy = mapper.getPropertyNamingStrategy(); + boolean changeStrategy = !originalStrategy.equals(strategy); + if (changeStrategy) { + mapper.setPropertyNamingStrategy(strategy); + } + + String result = serialize(mapper, entity, usePretty); + + if (changeStrategy) { + mapper.setPropertyNamingStrategy(originalStrategy); + } + return result; + + } + + /** + * 将序列化对象转换成JsonNode + * + * @param objectContent + * @return + */ + public JsonNode readTree(String objectContent) { + return readTree(this.defaultObjectMapper, objectContent); + } + + public T toObject(JsonNode jsonNode, Class valueType) { + if (jsonNode == null) { + return null; + } + String jsonNodeString = jsonNode.toString(); + return deserialize(jsonNodeString, valueType); + + } + + /** + * 字符串转JsonNode + * + * @param source + * @return + */ + public JsonNode toJsonNode(String source) { + return readTree(source); + } + + + // endregion + + // region 自定义配置 + + /** + * Deserialize string to an object. + * 将一个对象字符串反序列化成对象 + * + * @param objectMapper + * @param contentString + * @param valueType + * @param + * @return + * @description Json反序列化 + */ + public T deserialize(ObjectMapper objectMapper, String contentString, Class valueType) { + if (contentString == null || contentString.isEmpty()) { + return null; + } + + try { + return (T) (objectMapper.readValue(contentString, valueType)); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Serialize an object to string. + * + * @param objectMapper the objectMapper + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(ObjectMapper objectMapper, Object entity, boolean usePretty) { + if (entity == null) { + return null; + } + + String serializeStr = null; + + try { + if (!usePretty) { + serializeStr = objectMapper.writeValueAsString(entity); + } else { + serializeStr = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity); + } + + return serializeStr; + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 将序列化对象转换成JsonNode + * + * @param objectMapper + * @param objectContent + * @return + */ + public JsonNode readTree(ObjectMapper objectMapper, String objectContent) { + if (objectContent == null || objectContent.isEmpty()) { + return null; + } + + JsonNode objectJsonNode = null; + try { + objectJsonNode = objectMapper.readTree(objectContent); + return objectJsonNode; + } catch (JsonProcessingException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public T jsonToValue(JsonNode json, Class valueType) { + ObjectMapper mapper = this.getDefaultObjectMapper(); + return mapper.convertValue(json, valueType); + } + + public JsonNode valueToJson(Object metadataContent, PropertyNamingStrategy strategy) { + ObjectMapper mapper = this.getDefaultObjectMapper(); + PropertyNamingStrategy originalStrategy = mapper.getPropertyNamingStrategy(); + boolean changeStrategy = !originalStrategy.equals(strategy); + if (changeStrategy) { + mapper.setPropertyNamingStrategy(strategy); + } + + JsonNode result = mapper.valueToTree(metadataContent); + + if (changeStrategy) { + mapper.setPropertyNamingStrategy(originalStrategy); + } + return result; + } + + public JsonNode valueToJson(Object metadataContent) { + return valueToJson(metadataContent, PropertyNamingStrategy.LOWER_CAMEL_CASE); + } + + // endregion +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/Base64Utility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/Base64Utility.java new file mode 100644 index 00000000..ed261fb6 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/Base64Utility.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.common.utility; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * description: + * + * @author Noah Guo + * @date 2020/06/16 + */ +public class Base64Utility { + private Base64Utility() { + } + + /** + * 解码base64 编码后的字符串 + * + * @param content + * @return + * @throws UnsupportedEncodingException + */ + public static String decode(String content) throws UnsupportedEncodingException { + final Base64.Decoder decoder = Base64.getDecoder(); + return new String(decoder.decode(content), StandardCharsets.UTF_8); + } + + + /** + * 编码字符串 + * + * @param content + * @return + * @throws UnsupportedEncodingException + */ + public static String encode(String content) throws UnsupportedEncodingException { + if (StringUtility.isNullOrEmpty(content)) { + content = ""; + } + + final Base64.Encoder encoder = Base64.getEncoder(); + final byte[] textByte = content.getBytes(StandardCharsets.UTF_8); +//编码 + return encoder.encodeToString(textByte); + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteInterceptor.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteInterceptor.java new file mode 100644 index 00000000..289b65fb --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteInterceptor.java @@ -0,0 +1,148 @@ +package com.inspur.edp.web.common.utility; + +import org.apache.commons.lang3.SystemUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; + +/** + * @author guozhiqi + */ +public class CommandExecuteInterceptor extends Thread { + + private final InputStream inputStream; + private final StringBuilder errorSB; + /** + * 是否需要重新执行安装操作 + */ + private boolean needReInstall = false; + + private boolean isErrorStream = false; + + public CommandExecuteInterceptor(InputStream is, StringBuilder errorSB, boolean isErrorStream) { + this.inputStream = is; + this.errorSB = errorSB; + this.isErrorStream = isErrorStream; + } + + @Override + public void run() { + BufferedReader br = null; + try { + Charset charset = Charset.defaultCharset(); + if (SystemUtils.IS_OS_WINDOWS) { + charset = Charset.forName("GBK"); + } + InputStreamReader inputStreamReader = new InputStreamReader(this.inputStream, charset); + //读取进程输入流中的内容 + String line = null; + br = new BufferedReader(inputStreamReader); + boolean needAddErrorMessage = true; + while ((line = br.readLine()) != null) { + LoggerUtility.logToBrowser(line, LoggerLevelEnum.Info, false); + //判断是否存在错误描述 + if (CommandLineUtility.checkHasError(line) || checkCommandIsNotExists(line)) { + // 针对特定的输出标识 继续查找下一个输出信息 + if (line.contains("npm ERR! code ETARGET")) { + addErrorMessage(errorSB, line, needAddErrorMessage); + } else if (line.contains("npm ERR! notarget No matching version found for")) { + // 针对特定异常进行提取 + if (!needAddErrorMessage) { + continue; + } + String notMatchingVersionTest = "npm ERR! notarget No matching version found for"; + String notMatchedPackageVersion = line.substring(line.indexOf(notMatchingVersionTest) + notMatchingVersionTest.length()).trim(); + errorSB.delete(0, errorSB.length()); + addErrorMessage(errorSB, "npm ERR! ", needAddErrorMessage); + addErrorMessage(errorSB, notMatchedPackageVersion, needAddErrorMessage); + addErrorMessage(errorSB, " 未找到对应版本,请修正后重新执行安装!", needAddErrorMessage); + + needAddErrorMessage = false; + } else if (line.contains("npm ERR! 404") && line.contains("is not in the npm registry")) { + // 如果当前仓库不存在指定npm包 + if (!needAddErrorMessage) { + continue; + } + String notMatchingVersionTest = "npm ERR! 404"; + String lastIndexText = "is not in the npm registry"; + String notExistsPackage = line.substring(line.indexOf(notMatchingVersionTest) + notMatchingVersionTest.length(), line.indexOf(lastIndexText)); + errorSB.delete(0, errorSB.length()); + addErrorMessage(errorSB, "npm ERR! ", needAddErrorMessage); + addErrorMessage(errorSB, "当前仓库" + notExistsPackage + "包不存在,请切换至其他仓库或修正包版本,然后重新进行安装!", needAddErrorMessage); + needAddErrorMessage = false; + } else if (line.contains("npm ERR! errno ERR_SOCKET_TIMEOUT")) { + if (!needAddErrorMessage) { + continue; + } + errorSB.delete(0, errorSB.length()); + addErrorMessage(errorSB, "npm ERR! ", needAddErrorMessage); + addErrorMessage(errorSB, "连接服务器超时,请重新安装或切换至其他仓库,然后重新进行安装!", needAddErrorMessage); + needAddErrorMessage = false; + + needReInstall = true; + } else if (line.contains("Error: EPERM: operation not permitted, unlink")) { + if (!needAddErrorMessage) { + continue; + } + errorSB.delete(0, errorSB.length()); + addErrorMessage(errorSB, "npm ERR! ", needAddErrorMessage); + addErrorMessage(errorSB, "权限不足,请以管理员权限运行以进行Npm在线安装!", needAddErrorMessage); + needAddErrorMessage = false; + + needReInstall = true; + } else if (line.contains("npm ERR! Maximum call stack size exceeded")) { + if (!needAddErrorMessage) { + continue; + } + errorSB.delete(0, errorSB.length()); + addErrorMessage(errorSB, "npm ERR! ", needAddErrorMessage); + addErrorMessage(errorSB, "Maximum call stack size exceeded", needAddErrorMessage); + needAddErrorMessage = false; + + needReInstall = true; + } else { + // 表示命令找不到的提示信息 进行截取 + if (line.contains("rollup build failed")) { + addErrorMessage(errorSB, line, needAddErrorMessage); + } else { + addErrorMessage(errorSB, line, needAddErrorMessage); + } + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + this.inputStream.close(); + br.close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + } + + /** + * 检测命令是否存在的方法 + * + * @param line + * @return + */ + private boolean checkCommandIsNotExists(String line) { + if (StringUtility.isNullOrEmpty(line)) { + return false; + } + return line.contains("不是内部或外部命令,也不是可运行的程序") || line.contains("command not found") || line.contains("exec: node: not found") + || line.contains("‘node’: No such file or directory") || line.contains("No such file or directory"); + } + + private void addErrorMessage(StringBuilder sb, String errorMessage, boolean needAddErrorMessage) { + if (!needAddErrorMessage) { + return; + } + sb.append(errorMessage); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteResult.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteResult.java new file mode 100644 index 00000000..a279b03c --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandExecuteResult.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.common.utility; + +/** + * 命令执行结果 + * + * @author noah + */ +public class CommandExecuteResult { + + /** + * 是否重新执行命令 + */ + private boolean reExecute = false; + + /** + * 重新执行命令最大次数 + * 默认为3 次 + */ + private int reExecuteMaxTime = 3; + + /** + * 重新执行命令 当前执行次数 + * 默认为0 + */ + private int reExecuteCurrentTime = 0; + + public boolean isReExecute() { + return reExecute; + } + + public void setReExecute(boolean reExecute) { + this.reExecute = reExecute; + } + + public int getReExecuteMaxTime() { + return reExecuteMaxTime; + } + + public void setReExecuteMaxTime(int reExecuteMaxTime) { + this.reExecuteMaxTime = reExecuteMaxTime; + } + + public int getReExecuteCurrentTime() { + return reExecuteCurrentTime; + } + + public void setReExecuteCurrentTime(int reExecuteCurrentTime) { + this.reExecuteCurrentTime = reExecuteCurrentTime; + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java new file mode 100644 index 00000000..449c0d41 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java @@ -0,0 +1,137 @@ +package com.inspur.edp.web.common.utility; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; + +import java.util.Arrays; + +/** + * 命令行参数 + * + * @author noah + */ +public class CommandLineUtility { + private CommandLineUtility() { + } + + public static boolean runCommand(String[] commands) { + return runCommand(commands, true); + } + + public static boolean runCommand(String[] commands, boolean isWait) { + String command = String.join(" && ", commands); + String errorMsg = runCommand(command, isWait); + return StringUtils.isNotEmpty(errorMsg); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + */ + public static String runCommand(String command) { + return runCommand(command, true); + } + + public static String runCommandWithoutThrows(String command) { + StringBuilder errorSB = new StringBuilder(); + String errorMessage = executeCommand(command, errorSB); + if (!StringUtility.isNullOrEmpty(errorMessage)) { + return errorMessage; + } + return errorSB.toString(); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + public static String runCommand(String command, boolean isWait) { + + StringBuilder errorSB = new StringBuilder(); + String errorMessage = executeCommand(command, errorSB); + // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出 + // 增加自定义异常抛出 进行特定异常捕获 + if (!StringUtility.isNullOrEmpty(errorMessage)) { + throw new RuntimeException("jit command executed failed!" + errorMessage); + } + + // 如果存在输出异常 那么不再继续执行 + if (!StringUtility.isNullOrEmpty(errorSB.toString())) { + throw new RuntimeException("jit command executed failed!" + errorSB); + } + + return errorMessage; + } + + /** + * 执行具体命令 + * + * @param command 具体命令参数 + * @param errorSB 错误信息返回 + * @return + */ + public static String executeCommand(String command, StringBuilder errorSB) { + String errorMessage = ""; + try { + LoggerUtility.logToBrowser(command, LoggerLevelEnum.Info, false); + Process process = null; + String updateCommand = command; + if (SystemUtils.IS_OS_WINDOWS) { + updateCommand = "cmd.exe" + " /C" + " " + command; + process = Runtime.getRuntime().exec(updateCommand); + } else if (SystemUtils.IS_OS_UNIX) { + updateCommand = command; + process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", updateCommand}); + } + if (updateCommand == null) { + throw new RuntimeException("不支持的操作系统类型,请联系开发人员处理"); + } + + CommandExecuteInterceptor errorCommandInterceptor = new CommandExecuteInterceptor(process.getErrorStream(), errorSB, true); + CommandExecuteInterceptor inputCommandInterceptor = new CommandExecuteInterceptor(process.getInputStream(), errorSB, false); + errorCommandInterceptor.start(); + inputCommandInterceptor.start(); + + int waitCode = process.waitFor(); + if (waitCode != 0) { + LoggerUtility.logToBrowser("进程执行完毕", LoggerLevelEnum.Info); + } + //process.destroy(); + } catch (Exception e) { + e.printStackTrace(); + errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace()); + } + return errorMessage; + } + + + /** + * 判断是否包含错误描述信息 + * + * @param message + * @return + */ + public static boolean checkHasError(String message) { + if (StringUtils.isEmpty(message)) { + return false; + } + // 表示以error开头 + return message.toLowerCase().contains("error:") || message.toLowerCase().contains("rollup build failed") || message.toLowerCase().contains("build error") || message.toLowerCase().contains("npm err!"); + } + + private static String getCommandLineToolName() { + if (SystemUtils.IS_OS_WINDOWS) { + return "cmd.exe"; + } else if (SystemUtils.IS_OS_UNIX) { + return "/bin/bash"; + } + + throw new RuntimeException("未识别的操作系统系统。请联系开发人员处理。"); + } +} + + + diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommonUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommonUtility.java new file mode 100644 index 00000000..f295c32f --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommonUtility.java @@ -0,0 +1,57 @@ +package com.inspur.edp.web.common.utility; + +import java.lang.management.ManagementFactory; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; + +/** + * description: + * + * @author Noah Guo + * @date 2020/10/01 + */ +public class CommonUtility { + private CommonUtility() { + } + + /** + * 获取当前时间 + * + * @return + */ + public static Date getCurrentDate() { + return new Date(); + } + + /** + * 获取当前时间字符串表示形式 + * + * @return + */ + public static String getCurrentDateString() { + // 格式化时间 + SimpleDateFormat sdf = new SimpleDateFormat(); + // a为am/pm的标记 + sdf.applyPattern("yyyy-MM-dd HH:mm:ss"); + return sdf.format(getCurrentDate()); + } + + /** + * 生成随机化id + * + * @return + */ + public static String generateRandomId() { + return UUID.randomUUID().toString(); + } + + /** + * 获取程序启动时间 + * + * @return + */ + public static long getServerStartTime() { + return ManagementFactory.getRuntimeMXBean().getStartTime(); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/DesigntimeLoggerUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/DesigntimeLoggerUtility.java new file mode 100644 index 00000000..c239ff8a --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/DesigntimeLoggerUtility.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.common.utility; + +public class DesigntimeLoggerUtility { + public static void log(String message, LoggerLevelEnum level){ + LoggerUtility.log(message,level,true,true); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/EqualsUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/EqualsUtility.java new file mode 100644 index 00000000..4e07ae78 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/EqualsUtility.java @@ -0,0 +1,76 @@ +package com.inspur.edp.web.common.utility; + + +/** + * description: 字符串比较 + * + * @author Noah Guo + * @date 2020/09/25 + */ +public class EqualsUtility { + private boolean isLinux = false; + + private EqualsUtility() { + // 当前运行环境是否是linux环境 + this.isLinux = OperatingSystemUtility.isLinux(); + } + + private static EqualsUtility instance; + + public static EqualsUtility getInstance() { + if (instance == null) { + synchronized (EqualsUtility.class) { + instance = new EqualsUtility(); + } + } + return instance; + } + + /** + * 依据操作系统进行的字符串比较 + * 如果是windows 那么字符串不区分大小写 + * 如果是linux 那么字符串区分大小写 + * + * @param value1 + * @param value2 + * @return + */ + public boolean equalsWithOS(String value1, String value2) { + // 如果是linux 那么比较区分大小写 + if (isLinux) { + return value1.equals(value2); + } + + // 如果是windows 那么转换成小写形式进行比较 + return value1.equalsIgnoreCase(value2); + } + + + /** + * 依据操作系统进行的字符串比较* + * + * @param value1 + * @param value2 + * @return + */ + public boolean equalsWithoutOS(String value1, String value2) { + // 如果是windows 那么转换成小写形式进行比较 + return value1.equals(value2); + } + + /** + * 字符串比较 + * + * @param value1 + * @param value2 + * @param useCaseSensitive 是否区分大小写 + * @return + */ + public boolean equalsWithCaseSensitive(String value1, String value2, boolean useCaseSensitive) { + if (!useCaseSensitive) { + return equalsWithoutOS(value1.toLowerCase(), value2.toLowerCase()); + } + return equalsWithoutOS(value1, value2); + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/ListUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/ListUtility.java new file mode 100644 index 00000000..3a2c7cf5 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/ListUtility.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.common.utility; + +import org.springframework.util.CollectionUtils; + +import java.util.List; + +public class ListUtility { + private ListUtility() { + } + + /** + * 判断集合是否为空 + * + * @param sourceList 源集合列表 + * @return + */ + public static boolean isEmpty(List sourceList) { + return CollectionUtils.isEmpty(sourceList); + } + + /** + * 判断集合非空 + * + * @param sourceList + * @return + */ + public static boolean isNotEmpty(List sourceList) { + return !isEmpty(sourceList); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerLevelEnum.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerLevelEnum.java new file mode 100644 index 00000000..1ad135b2 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerLevelEnum.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.common.utility; + +/** + * 日志记录级别 + */ +public enum LoggerLevelEnum { + Debug, + Warning, + Info, + Error, + Success, + Fatal +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerUtility.java new file mode 100644 index 00000000..06de8f38 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/LoggerUtility.java @@ -0,0 +1,120 @@ +package com.inspur.edp.web.common.utility; + + +//import com.inspur.lcm.metadata.logging.LoggerDisruptorQueue; + +import com.inspur.edp.web.common.logger.WebLogger; + +/** + * 日志输出service + */ +public class LoggerUtility { + + private LoggerUtility() { + } + + /** + * 日志输出 + * + * @param message + * @param level + */ + public static void log(String message, LoggerLevelEnum level) { + log(message, level, true); + } + + /** + * 日志输出 + * + * @param message + * @param level + */ + public static void log(String message, LoggerLevelEnum level, boolean includeMessageHeader) { + if (!StringUtility.isNullOrEmpty(message)) { + switch (level) { + case Info: + logInfo(message, includeMessageHeader); + break; + case Error: + logError(message, includeMessageHeader); + break; + default: + logDefault(message, includeMessageHeader); + break; + } + } + } + + public static void log(String message, LoggerLevelEnum level, boolean printToBrowser, boolean includeMessageHeader) { + log(message, level, includeMessageHeader); + if (printToBrowser) { + try { + if (!StringUtility.isNullOrEmpty(message)) { + // 由于分su问题 在运行时不存在此jar包 因此移除该jar包调用 + // LoggerDisruptorQueue.publishEvent(message); + } + } catch (Exception ignored) { + + } + } + } + + public static void logToBrowser(String message, LoggerLevelEnum level) { + logToBrowser(message, level, true); + } + + public static void logToBrowser(String message, LoggerLevelEnum level, boolean includeMessageHeader) { + log(message, level, true, includeMessageHeader); + } + + /** + * 默认的数据输出 + * + * @param message + */ + private static void logDefault(String message) { + logDefault(message, true); + } + + /** + * 默认的数据输出 + * + * @param message + */ + private static void logDefault(String message, boolean includeMessageHeader) { + WebLogger.Instance.info(message, LoggerUtility.class.getName()); + } + + + /** + * Error 级别的输出输出 + * + * @param message + */ + private static void logError(String message) { + logError(message, true); + } + + /** + * Error 级别的输出输出 + * + * @param message + */ + private static void logError(String message, boolean includeMessageHeader) { + WebLogger.Instance.error(message, LoggerUtility.class.getName()); + } + + /** + * Info 级别的消息输出 + * + * @param message + */ + private static void logInfo(String message, boolean includeMessageHeader) { + if (includeMessageHeader) { + WebLogger.Instance.info("Info:" + message, LoggerUtility.class.getName()); + } else { + WebLogger.Instance.info(message, LoggerUtility.class.getName()); + } + } + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/OperatingSystemUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/OperatingSystemUtility.java new file mode 100644 index 00000000..f05adff4 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/OperatingSystemUtility.java @@ -0,0 +1,42 @@ +package com.inspur.edp.web.common.utility; + +import org.apache.commons.lang3.SystemUtils; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/12 + */ +public class OperatingSystemUtility { + private OperatingSystemUtility() { + } + + /** + * 判断当前运行操作系统 是否是Linux + * + * @return + */ + public static boolean isLinux() { + return SystemUtils.IS_OS_LINUX; + } + + /** + * 判断当前运行操作系统 是否是windows + * + * @return + */ + public static boolean isWindows() { + return SystemUtils.IS_OS_WINDOWS; + } + + + /** + * 换行符 + * + * @return + */ + public static String lineSeperator() { + return System.getProperty("line.separator"); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/RandomUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/RandomUtility.java new file mode 100644 index 00000000..e82bb66c --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/RandomUtility.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.common.utility; + +import java.util.UUID; + +/** + * 随机数构造器 + */ +public class RandomUtility { + private RandomUtility() { + } + + /** + * 生成随机数 + * + * @return + */ + public static String newGuid() { + return UUID.randomUUID().toString(); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/RuntimeLoggerUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/RuntimeLoggerUtility.java new file mode 100644 index 00000000..7aa3ec84 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/RuntimeLoggerUtility.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.common.utility; + +/** + * @author guozhiqi + */ +public class RuntimeLoggerUtility { + private RuntimeLoggerUtility() { + } + + public static void log(String message, LoggerLevelEnum level) { + LoggerUtility.log(message, level, false, true); + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/StringUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/StringUtility.java new file mode 100644 index 00000000..43bcf8d0 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/StringUtility.java @@ -0,0 +1,305 @@ +package com.inspur.edp.web.common.utility; + +import org.apache.commons.lang3.StringUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/03/17 + */ +public class StringUtility { + + private static final Pattern pattern = Pattern.compile("[0-9]*"); + + private StringUtility() { + } + + /** + * 判断字符串是不是以数字开头 + * @param str + * @return + */ + public static boolean isStartWithNumber(String str) { + if (isNullOrEmpty(str)) { + return false; + } + Matcher isNum = pattern.matcher(str.charAt(0) + ""); + return isNum.matches(); + } + + /** + * + */ + public static String contactByRemovingRepeat(String firstStr, String secondStr) { + return contactByRemovingRepeat(firstStr, secondStr, true); + } + + /** + * 合并两个字符串,并移除头尾连接时的重复字符串。 + * 实例: + * ContactByRemoveRepeat("1234", "456")的返回结果是 "123456" + * + * @param firstStr 第一个字符串 + * @param secondStr 第二个字符串 + * @param isCaseSensitive 是否大小写敏感 + * @return 合并后字符串 + */ + public static String contactByRemovingRepeat(String firstStr, String secondStr, boolean isCaseSensitive) { + if (isNullOrEmpty(firstStr)) { + return secondStr; + } + + if (isNullOrEmpty(secondStr)) { + return firstStr; + } + + char[] firstArray = firstStr.toCharArray(); + char[] secondArray = secondStr.toCharArray(); + int index = -1; + + for (int i = 0; i < firstArray.length; i++) { + if (secondArray[0] != firstArray[i]) { + } else { + boolean containSameSubString = false; + int j = i, k = 0; + for (; j < firstArray.length; j++) { + if (isEqual(firstArray[j], secondArray[k], isCaseSensitive)) { + k++; + } else { + break; + } + } + if (j == firstArray.length) { + containSameSubString = true; + } + if (containSameSubString) { + index = i; + break; + } + } + } + + if (index > -1) { + return firstStr.substring(0, index) + secondStr; + } else { + return firstStr + secondStr; + } + } + + /** + *

+     * StringUtils.isBlank(null)      = true
+     * StringUtils.isBlank("")        = true
+     * StringUtils.isBlank(" ")       = true
+     * StringUtils.isBlank("bob")     = false
+     * StringUtils.isBlank("  bob  ") = false
+     * 
+ * + * @param source + * @return + */ + public static boolean isBlank(String source) { + return StringUtils.isBlank(source); + } + + + /** + * 判断字符串是否是null或empty + * + * @param source 源字符串 + * @return + */ + public static boolean isNullOrEmpty(String source) { + return source == null || source.isEmpty(); + } + + /** + * 判断字符串是否是null或empty + * + * @param source 源字符串 + * @return + */ + public static boolean isNull(String source) { + return source == null; + } + + /** + * 比较两个字符是否相等,如果字符是字母且禁用大小写敏感开关,那字母的相等不区分大小写。 + * 如在禁用大小写敏感开关时,a等于A + */ + private static boolean isEqual(char c1, char c2, boolean isCaseSensitive) { + if (Character.isLetter(c1) && Character.isLetter(c2) && !isCaseSensitive) { + // 大小写字母Unicode码值差为 32 或 0 + return Math.abs(c1 - c2) == 32 || c1 == c2; + } else { + // 非字母(直接比较) + return c1 == c2; + } + } + + /** + * 将null 转换成空字符串 + * + * @param source + * @return + */ + public static String convertNullToEmptyString(String source) { + if (isNullOrEmpty(source)) { + return ""; + } + return source; + } + + public static boolean startWith(String a, String b) { + if (a == null || b == null) { + return false; + } + if (a.indexOf(':') > -1 && b.indexOf(':') > -1) { + if (a.substring(0, 1).equalsIgnoreCase(b.substring(0, 1))) { + a = a.substring(a.indexOf(':') + 1); + b = b.substring(b.indexOf(':') + 1); + } else { + return false; + } + } else if (a.indexOf(':') > -1) { + a = a.substring(a.indexOf(':') + 1); + } else if (b.indexOf(':') > -1) { + b = b.substring(b.indexOf(':') + 1); + } + + return a.startsWith(b); + } + + + /** + * 判断两个字符串是否相同 + * + * @param source 源字符串 + * @param target 目标字符串 + * @return 是否相同的标识 + */ + public static boolean equals(String source, String target) { + return StringUtils.equals(source, target); + } + + /** + * 不区分大小写的字符串比较 + * + * @param source 源字符串 + * @param target 目标字符串 + * @return + */ + public static boolean equalsIgnoreCase(String source, String target) { + return StringUtils.equalsIgnoreCase(source, target); + } + + /** + * 首字母小写32为是char类型大小写的差数,-32是小写变大写,+32是大写变小写 + * + * @param str + * @return + */ + public static String lowerFirstCase(String str) { + if (isNullOrEmpty(str)) { + return str; + } + char[] chars = str.toCharArray(); + //首字母小写方法,大写会变成小写,如果小写首字母会消失 + chars[0] += 32; + return String.valueOf(chars); + } + + /** + * 首字母大写 32为是char类型大小写的差数,-32是小写变大写,+32是大写变小写 + * + * @param str + * @return + */ + public static String upperFirstCase(String str) { + if (isNullOrEmpty(str)) { + return str; + } + char[] chars = str.toCharArray(); + //首字母小写方法,大写会变成小写,如果小写首字母会消失 + chars[0] -= 32; + return String.valueOf(chars); + } + + /** + * 将字符串转换成为小写形式 + * 如果传递的字符串为null 那么返回空字符串而不会引起空引用问题 + * + * @param source + * @return + */ + public static String toLowerCase(String source) { + if (isNullOrEmpty(source)) { + return ""; + } + return source.toLowerCase(); + } + + /** + * 将字符串转换成为大写形式 + * 如果字符串为null,那么返回空字符串,避免引起空引用异常 + * + * @param source + * @return + */ + public static String toUpperCase(String source) { + if (isNullOrEmpty(source)) { + return ""; + } + return source.toUpperCase(); + } + + /** + * 转换成为camel形式 + * + * @param s + * @return + */ + public static String toCamelCase(String s) { + if (StringUtils.isEmpty(s) || !Character.isUpperCase(s.charAt(0))) { + return s; + } + + char[] chars = s.toCharArray(); + + for (int i = 0; i < chars.length; i++) { + if (i == 1 && !Character.isUpperCase(chars[i])) { + break; + } + + boolean hasNext = (i + 1 < chars.length); + if (i > 0 && hasNext && !Character.isUpperCase(chars[i + 1])) { + // if the next character is a space, which is not considered uppercase + // (otherwise we wouldn't be here...) + // we want to ensure that the following: + // 'FOO bar' is rewritten as 'foo bar', and not as 'foO bar' + // The code was written in such a way that the first word in uppercase + // ends when if finds an uppercase letter followed by a lowercase letter. + // now a ' ' (space, (char)32) is considered not upper + // but in that case we still want our current character to become lowercase + if (Character.isSpaceChar(chars[i + 1])) { + chars[i] = toLower(chars[i]); + } + + break; + } + + chars[i] = toLower(chars[i]); + } + + return new String(chars); + } + + private static char toLower(char c) { + c = Character.toLowerCase(c); + return c; + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleFour.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleFour.java new file mode 100644 index 00000000..9261c0e1 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleFour.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.common.utility; + +public class TupleFour { + private T item1; + private S item2; + private M item3; + private N item4; + + public TupleFour(T item1, S item2, M item3, N item4) { + this.item1 = item1; + this.item2 = item2; + this.item3 = item3; + this.item4 = item4; + } + + public T getItem1() { + return item1; + } + + public void setItem1(T item1) { + this.item1 = item1; + } + + public S getItem2() { + return item2; + } + + public void setItem2(S item2) { + this.item2 = item2; + } + + public M getItem3() { + return item3; + } + + public void setItem3(M item3) { + this.item3 = item3; + } + + public N getItem4() { + return item4; + } + + public void setItem4(N item4) { + this.item4 = item4; + } +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleTwo.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleTwo.java new file mode 100644 index 00000000..159eb8d1 --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/TupleTwo.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.common.utility; + +public class TupleTwo { + private final T item1; + private final S item2; + + public TupleTwo(T item1, S item2) { + this.item1 = item1; + this.item2 = item2; + } + + public T getItem1() { + return item1; + } + + public S getItem2() { + return item2; + } + +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/OSHelperTest.java b/web-common/src/test/java/com/inspur/edp/web/common/OSHelperTest.java new file mode 100644 index 00000000..16058036 --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/OSHelperTest.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.common; + +import com.inspur.edp.web.common.utility.OperatingSystemUtility; +import org.junit.jupiter.api.Test; + +import java.nio.file.Path; +import java.nio.file.Paths; + +class OSHelperTest { + + @Test + void isWindows() { + boolean isWindows = OperatingSystemUtility.isWindows(); + + + System.out.println(toAbsolutePath("../../")); + + } + + private String toAbsolutePath(String maybeRelative) { + Path path = Paths.get(maybeRelative); + Path effectivePath = path; + if (!path.isAbsolute()) { + Path base = Paths.get(""); + effectivePath = base.resolve(path).toAbsolutePath(); + } + return effectivePath.normalize().toString(); + } +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckerTest.java b/web-common/src/test/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckerTest.java new file mode 100644 index 00000000..27d95f05 --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/environment/checker/ExecuteEnvironmentCheckerTest.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.common.environment.checker; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @Title: ExecuteEnvironmentCheckerTest + * @Description: com.inspur.edp.web.common.environment.checker + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/29 15:35 + */ +public class ExecuteEnvironmentCheckerTest { + + @Test + public void checkGlobalNodeInstalled() { + ExecuteEnvironmentCheckResult result = ExecuteEnvironmentChecker.checkGlobalNodeInstalled(); + System.out.println(result.getErrorMessage()); + assertTrue(result.isSuccess()); + } + + @Test + public void checkGlobalNpmInstalled() { + ExecuteEnvironmentCheckResult result = ExecuteEnvironmentChecker.checkGlobalNpmInstalled(); + System.out.println(result.getErrorMessage()); + assertTrue(result.isSuccess()); + } + + @Test + public void checkGlobalJitEngineInstalled() { + ExecuteEnvironmentCheckResult result = ExecuteEnvironmentChecker.checkGlobalJitEngineInstalled(); + System.out.println(result.getErrorMessage()); + assertTrue(result.isSuccess()); + } + + @Test + public void checkGlobalNgInstalled() { + ExecuteEnvironmentCheckResult result = ExecuteEnvironmentChecker.checkGlobalNgInstalled(); + System.out.println(result.getErrorMessage()); + assertTrue(result.isSuccess()); + } +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/io/FileUtilityTest.java b/web-common/src/test/java/com/inspur/edp/web/common/io/FileUtilityTest.java new file mode 100644 index 00000000..ea5b8e66 --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/io/FileUtilityTest.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.common.io; + +import junit.framework.TestCase; +import org.junit.Assert; +import org.junit.Test; + +public class FileUtilityTest extends TestCase { + + + public void testFileCopy() { + String sourceFile = "D:\\InspurCode\\N转J之后代码\\npm安装\\web\\web-common\\src\\test\\java\\com\\inspur\\edp\\web\\common\\io\\sourcefile\\package.json"; + String targetFile = "D:\\InspurCode\\N转J之后代码\\npm安装\\web\\web-common\\src\\test\\java\\com\\inspur\\edp\\web\\common\\io\\targetfile\\package.json"; + FileUtility.copyFile(sourceFile, targetFile, true); + + Assert.assertTrue(FileUtility.isSameFile(sourceFile, targetFile)); + } + + @Test + public void testGetCurrentWorkPath() { + String path = FileUtility.getCurrentWorkPath(true); + System.out.println(path); + } +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json b/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json new file mode 100644 index 00000000..d74c41ca --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json @@ -0,0 +1,212 @@ +{ + "name": "@farris/jit-engine", + "version": "0.0.1", + "description": "npm auto install", + "engines": { + "node": ">= 6.9.0", + "npm": ">= 3.0.0" + }, + "keywords": [ + "node_modules" + ], + "author": "Noah", + "license": "ISC1", + "dependencies": { + "@angular-devkit/core": "7.3.9", + "@angular/compiler-cli": "7.2.15", + "@angular/common": "7.2.13", + "@angular/core": "7.2.13", + "@angular/forms": "7.2.13", + "@angular/router": "7.2.13", + "@ant-design/icons-angular": "2.1.0", + "@ecp-caf/caf-common": "^2.0.5", + "@edp-aif/common-api": "^0.6.1", + "@edp-aif/runtime-api": "^0.6.0", + "@edp-bif/common-api": "^0.7.1", + "@edp-bif/runtime-api": "^0.7.2", + "@farris/bef": "0.0.12-20210428112135-dev", + "@farris/command-services": "0.0.12-20210508093120-dev", + "@farris/component-querycondition": "^0.1.46", + "@farris/devkit": "0.0.12-20210428112050-dev", + "@farris/discussion-group": "0.0.22", + "@farris/dynamic-control-group": "^0.1.11", + "@farris/extend-file-upload": "^0.1.9", + "@farris/extend-fileupload-adapt-unifile": "^0.1.4", + "@farris/farris-rollup": "^1.0.80", + "@farris/header-group-editor": "0.0.15", + "@farris/ide-devkit": "^1.0.33", + "@farris/ide-enum-editor": "0.0.3", + "@farris/ide-publish-menu": "0.0.17", + "@farris/kendo-binding": "0.0.12-20210428112252-dev", + "@farris/mobile-bef": "0.0.6", + "@farris/mobile-business-ui": "0.0.27", + "@farris/mobile-cli": "latest", + "@farris/mobile-command-services": "0.0.16", + "@farris/mobile-devkit": "0.0.5", + "@farris/mobile-ui": "0.0.19", + "@farris/mobile-vue-adapter": "0.0.10", + "@farris/tags": "0.0.9", + "@farris/ui-area-response": "0.0.2", + "@farris/ui-avatar": "0.0.17", + "@farris/ui-batch-edit-dialog": "0.0.12", + "@farris/ui-button": "0.0.16", + "@farris/ui-calculator": "0.0.1", + "@farris/ui-calendar": "0.0.5", + "@farris/ui-combo-list": "^0.1.37", + "@farris/ui-combo-lookup": "^0.1.21", + "@farris/ui-common": "^0.2.6", + "@farris/ui-datagrid": "^0.8.21", + "@farris/ui-datagrid-editors": "^0.2.43", + "@farris/ui-datagrid-filter": "0.0.15", + "@farris/ui-datagrid-settings": "0.0.16", + "@farris/ui-datalist": "0.0.16", + "@farris/ui-datatable": "^0.1.25", + "@farris/ui-datepicker": "^0.3.7", + "@farris/ui-dialog": "0.0.13", + "@farris/ui-draggable": "0.0.4", + "@farris/ui-dropdown": "0.0.12", + "@farris/ui-editor": "0.0.10", + "@farris/ui-enum-editor": "0.0.3", + "@farris/ui-field-group": "0.0.21", + "@farris/ui-filter": "0.0.8", + "@farris/ui-filter-editor": "^0.1.15", + "@farris/ui-filter-panel": "0.0.10", + "@farris/ui-flex-layout": "0.0.3", + "@farris/ui-footer": "0.0.2", + "@farris/ui-forms": "0.0.35", + "@farris/ui-html-editor": "0.0.23", + "@farris/ui-input-group": "^0.2.5", + "@farris/ui-language-textbox": "^0.1.14", + "@farris/ui-layout": "0.0.6", + "@farris/ui-list-filter": "0.0.63", + "@farris/ui-list-nav": "0.0.12", + "@farris/ui-list-view": "0.0.26", + "@farris/ui-loading": "^0.1.9", + "@farris/ui-locale": "0.2.12", + "@farris/ui-lookup": "^0.4.7", + "@farris/ui-messager": "^0.2.10", + "@farris/ui-modal": "^0.1.3", + "@farris/ui-multi-select": "^0.2.1", + "@farris/ui-nav": "0.0.4", + "@farris/ui-notify": "^0.1.6", + "@farris/ui-number-spinner": "^0.2.32", + "@farris/ui-pagination": "^0.1.10", + "@farris/ui-panel": "0.0.4", + "@farris/ui-perfect-scrollbar": "0.0.7", + "@farris/ui-popover": "0.0.4", + "@farris/ui-progress": "0.0.2", + "@farris/ui-progress-step": "0.0.23", + "@farris/ui-property-panel": "0.0.7", + "@farris/ui-response-toolbar": "^0.1.15", + "@farris/ui-responsive": "0.0.2", + "@farris/ui-scrollspy": "0.0.24", + "@farris/ui-section": "^0.1.2", + "@farris/ui-shortcuts": "0.0.4", + "@farris/ui-sidebar": "^0.1.4", + "@farris/ui-sort-editor": "^0.1.7", + "@farris/ui-splitter": "0.0.2", + "@farris/ui-switch": "0.0.6", + "@farris/ui-tabs": "^0.2.12", + "@farris/ui-tag": "0.0.2", + "@farris/ui-text": "^0.1.28", + "@farris/ui-time-picker": "^0.1.4", + "@farris/ui-time-spinner": "0.0.9", + "@farris/ui-tooltip": "0.0.17", + "@farris/ui-tree": "0.0.4", + "@farris/ui-treetable": "^0.3.4", + "@farris/ui-verify-detail": "0.0.6", + "@farris/ui-view-change": "0.0.5", + "@farris/ui-wizard": "0.0.29", + "@gsp-aif/common-api": "0.0.10", + "@gsp-aif/runtime-api": "0.0.11", + "@gsp-bef/gsp-be-metadata": "0.0.25", + "@gsp-bef/gsp-cm-metadata": "0.0.22", + "@gsp-bef/gsp-udt-metadata": "0.0.13", + "@gsp-bef/gsp-vo-metadata": "0.0.17", + "@gsp-cmp/chgdr": "0.0.2", + "@gsp-cmp/querysolution": "^0.1.28", + "@gsp-cmp/webcommand": "0.0.15", + "@gsp-dip/data-imp-exp": "^1.1.48", + "@gsp-lcm/bo-dt-service": "0.0.7", + "@gsp-lcm/bo-rt-service": "0.0.7", + "@gsp-lcm/bo-tree": "0.0.26", + "@gsp-lcm/dbo-selector": "0.0.4", + "@gsp-lcm/dbo-selectrt": "0.0.1", + "@gsp-lcm/metadata-selector": "0.0.50", + "@gsp-lcm/metadatart-selector": "0.0.6", + "@gsp-lcm/metadatart-selector4biztype": "0.0.12", + "@gsp-svc/cloudprint": "^0.4.19", + "@gsp-svc/expression": "0.0.53", + "@gsp-svc/file-load": "0.0.1", + "@gsp-svc/file-viewer": "0.0.74", + "@gsp-svc/filtercondition": "0.0.30", + "@gsp-svc/formdoc-upload": "^0.1.8", + "@gsp-sys/rtf-apphelp": "^1.0.9", + "@gsp-sys/rtf-common": "^2.0.8", + "@gsp-sys/rtf-ui": "0.0.7", + "@gsp-sys/sysmgr-common": "0.0.8", + "@gsp-sys/sysmgr-ui": "0.0.94", + "@gsp-wf/rtdevkit": "^1.0.5", + "@gsp-wf/task-action-impl": "0.0.17", + "@gsp-wf/task-impl-api": "0.0.8", + "@gsp-wf/ui-comment": "^0.1.8", + "@gsp-wf/ui-flowchart": "^1.1.1", + "@gsp-wf/wf-approval-logs": "^0.2.0", + "@gsp-wf/wf-process-editor": "^0.1.8", + "@gsp-wf/wf-sign": "0.0.5", + "@gsp-wf/wf-task-handler": "0.0.26", + "@gspwidget/portlet": "^1.5.0", + "@gspwidget/util": "^1.5.0", + "@gspwidget/widget-core": "^1.5.0", + "@gspwidget/widget-devkit": "^1.5.0", + "@progress/kendo-angular-buttons": "^4.4.0", + "@progress/kendo-angular-dateinputs": "^3.7.3", + "@progress/kendo-angular-dropdowns": "^3.5.3", + "@progress/kendo-angular-grid": "^3.14.1", + "@progress/kendo-angular-inputs": "^4.2.1", + "@progress/kendo-angular-intl": "^1.7.0", + "@progress/kendo-angular-l10n": "^1.4.0", + "@progress/kendo-angular-label": "^1.3.0", + "@progress/kendo-angular-layout": "^3.3.0", + "@progress/kendo-angular-pdf-export": "^1.3.1", + "@progress/kendo-angular-resize-sensor": "^3.2.0", + "@progress/kendo-angular-treeview": "^3.1.1", + "@progress/kendo-data-query": "^1.5.1", + "@progress/kendo-drawing": "^1.5.11", + "@progress/kendo-theme-default": "^2.57.1", + "@progress/kendo-theme-bootstrap": "^2.14.2", + "@progress/kendo-angular-dialog": "3.12.0", + "@qdp/command-services": "0.0.1-0.0.16dev", + "@qdp/common": "0.0.1-0.0.37dev", + "@qdp/condition-schema": "0.0.1-0.0.14dev", + "@qdp/echarts": "0.0.1-0.0.18dev", + "@qdp/formular": "0.0.1-0.0.19dev", + "@qdp/ide-cmp": "0.0.1-0.0.44dev", + "@qdp/localize": "0.0.1-0.0.14dev", + "@qdp/query-framework": "0.0.1-0.0.27dev", + "@qdp/search-join": "0.0.1-0.0.20dev", + "@qdp/spread": "0.0.1-0.0.34dev", + "bignumber.js": "^9.0.1", + "chalk": "2.4.2", + "date-fns": "2.6.0", + "lodash": "^4.17.10", + "moment": "^2.29.1", + "moment-timezone": "^0.5.33", + "prettier": "^1.18.2", + "rxjs": "~6.3.3", + "signature_pad": "^3.0.0-beta.4", + "dayjs": "1.10.3", + "vant": "3.0.3", + "vue": "3.0.5", + "vue-router": "4.0.3", + "reflect-metadata": "0.1.13", + "typescript": "3.2.4", + "tslib": "1.9.3" + }, + "devDependencies": { + "@babel/core": "^7.12.9", + "@babel/preset-env": "^7.12.7", + "@babel/preset-typescript": "^7.12.7", + "cross-env": "^7.0.3" + } +} \ No newline at end of file diff --git a/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json b/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json new file mode 100644 index 00000000..d74c41ca --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json @@ -0,0 +1,212 @@ +{ + "name": "@farris/jit-engine", + "version": "0.0.1", + "description": "npm auto install", + "engines": { + "node": ">= 6.9.0", + "npm": ">= 3.0.0" + }, + "keywords": [ + "node_modules" + ], + "author": "Noah", + "license": "ISC1", + "dependencies": { + "@angular-devkit/core": "7.3.9", + "@angular/compiler-cli": "7.2.15", + "@angular/common": "7.2.13", + "@angular/core": "7.2.13", + "@angular/forms": "7.2.13", + "@angular/router": "7.2.13", + "@ant-design/icons-angular": "2.1.0", + "@ecp-caf/caf-common": "^2.0.5", + "@edp-aif/common-api": "^0.6.1", + "@edp-aif/runtime-api": "^0.6.0", + "@edp-bif/common-api": "^0.7.1", + "@edp-bif/runtime-api": "^0.7.2", + "@farris/bef": "0.0.12-20210428112135-dev", + "@farris/command-services": "0.0.12-20210508093120-dev", + "@farris/component-querycondition": "^0.1.46", + "@farris/devkit": "0.0.12-20210428112050-dev", + "@farris/discussion-group": "0.0.22", + "@farris/dynamic-control-group": "^0.1.11", + "@farris/extend-file-upload": "^0.1.9", + "@farris/extend-fileupload-adapt-unifile": "^0.1.4", + "@farris/farris-rollup": "^1.0.80", + "@farris/header-group-editor": "0.0.15", + "@farris/ide-devkit": "^1.0.33", + "@farris/ide-enum-editor": "0.0.3", + "@farris/ide-publish-menu": "0.0.17", + "@farris/kendo-binding": "0.0.12-20210428112252-dev", + "@farris/mobile-bef": "0.0.6", + "@farris/mobile-business-ui": "0.0.27", + "@farris/mobile-cli": "latest", + "@farris/mobile-command-services": "0.0.16", + "@farris/mobile-devkit": "0.0.5", + "@farris/mobile-ui": "0.0.19", + "@farris/mobile-vue-adapter": "0.0.10", + "@farris/tags": "0.0.9", + "@farris/ui-area-response": "0.0.2", + "@farris/ui-avatar": "0.0.17", + "@farris/ui-batch-edit-dialog": "0.0.12", + "@farris/ui-button": "0.0.16", + "@farris/ui-calculator": "0.0.1", + "@farris/ui-calendar": "0.0.5", + "@farris/ui-combo-list": "^0.1.37", + "@farris/ui-combo-lookup": "^0.1.21", + "@farris/ui-common": "^0.2.6", + "@farris/ui-datagrid": "^0.8.21", + "@farris/ui-datagrid-editors": "^0.2.43", + "@farris/ui-datagrid-filter": "0.0.15", + "@farris/ui-datagrid-settings": "0.0.16", + "@farris/ui-datalist": "0.0.16", + "@farris/ui-datatable": "^0.1.25", + "@farris/ui-datepicker": "^0.3.7", + "@farris/ui-dialog": "0.0.13", + "@farris/ui-draggable": "0.0.4", + "@farris/ui-dropdown": "0.0.12", + "@farris/ui-editor": "0.0.10", + "@farris/ui-enum-editor": "0.0.3", + "@farris/ui-field-group": "0.0.21", + "@farris/ui-filter": "0.0.8", + "@farris/ui-filter-editor": "^0.1.15", + "@farris/ui-filter-panel": "0.0.10", + "@farris/ui-flex-layout": "0.0.3", + "@farris/ui-footer": "0.0.2", + "@farris/ui-forms": "0.0.35", + "@farris/ui-html-editor": "0.0.23", + "@farris/ui-input-group": "^0.2.5", + "@farris/ui-language-textbox": "^0.1.14", + "@farris/ui-layout": "0.0.6", + "@farris/ui-list-filter": "0.0.63", + "@farris/ui-list-nav": "0.0.12", + "@farris/ui-list-view": "0.0.26", + "@farris/ui-loading": "^0.1.9", + "@farris/ui-locale": "0.2.12", + "@farris/ui-lookup": "^0.4.7", + "@farris/ui-messager": "^0.2.10", + "@farris/ui-modal": "^0.1.3", + "@farris/ui-multi-select": "^0.2.1", + "@farris/ui-nav": "0.0.4", + "@farris/ui-notify": "^0.1.6", + "@farris/ui-number-spinner": "^0.2.32", + "@farris/ui-pagination": "^0.1.10", + "@farris/ui-panel": "0.0.4", + "@farris/ui-perfect-scrollbar": "0.0.7", + "@farris/ui-popover": "0.0.4", + "@farris/ui-progress": "0.0.2", + "@farris/ui-progress-step": "0.0.23", + "@farris/ui-property-panel": "0.0.7", + "@farris/ui-response-toolbar": "^0.1.15", + "@farris/ui-responsive": "0.0.2", + "@farris/ui-scrollspy": "0.0.24", + "@farris/ui-section": "^0.1.2", + "@farris/ui-shortcuts": "0.0.4", + "@farris/ui-sidebar": "^0.1.4", + "@farris/ui-sort-editor": "^0.1.7", + "@farris/ui-splitter": "0.0.2", + "@farris/ui-switch": "0.0.6", + "@farris/ui-tabs": "^0.2.12", + "@farris/ui-tag": "0.0.2", + "@farris/ui-text": "^0.1.28", + "@farris/ui-time-picker": "^0.1.4", + "@farris/ui-time-spinner": "0.0.9", + "@farris/ui-tooltip": "0.0.17", + "@farris/ui-tree": "0.0.4", + "@farris/ui-treetable": "^0.3.4", + "@farris/ui-verify-detail": "0.0.6", + "@farris/ui-view-change": "0.0.5", + "@farris/ui-wizard": "0.0.29", + "@gsp-aif/common-api": "0.0.10", + "@gsp-aif/runtime-api": "0.0.11", + "@gsp-bef/gsp-be-metadata": "0.0.25", + "@gsp-bef/gsp-cm-metadata": "0.0.22", + "@gsp-bef/gsp-udt-metadata": "0.0.13", + "@gsp-bef/gsp-vo-metadata": "0.0.17", + "@gsp-cmp/chgdr": "0.0.2", + "@gsp-cmp/querysolution": "^0.1.28", + "@gsp-cmp/webcommand": "0.0.15", + "@gsp-dip/data-imp-exp": "^1.1.48", + "@gsp-lcm/bo-dt-service": "0.0.7", + "@gsp-lcm/bo-rt-service": "0.0.7", + "@gsp-lcm/bo-tree": "0.0.26", + "@gsp-lcm/dbo-selector": "0.0.4", + "@gsp-lcm/dbo-selectrt": "0.0.1", + "@gsp-lcm/metadata-selector": "0.0.50", + "@gsp-lcm/metadatart-selector": "0.0.6", + "@gsp-lcm/metadatart-selector4biztype": "0.0.12", + "@gsp-svc/cloudprint": "^0.4.19", + "@gsp-svc/expression": "0.0.53", + "@gsp-svc/file-load": "0.0.1", + "@gsp-svc/file-viewer": "0.0.74", + "@gsp-svc/filtercondition": "0.0.30", + "@gsp-svc/formdoc-upload": "^0.1.8", + "@gsp-sys/rtf-apphelp": "^1.0.9", + "@gsp-sys/rtf-common": "^2.0.8", + "@gsp-sys/rtf-ui": "0.0.7", + "@gsp-sys/sysmgr-common": "0.0.8", + "@gsp-sys/sysmgr-ui": "0.0.94", + "@gsp-wf/rtdevkit": "^1.0.5", + "@gsp-wf/task-action-impl": "0.0.17", + "@gsp-wf/task-impl-api": "0.0.8", + "@gsp-wf/ui-comment": "^0.1.8", + "@gsp-wf/ui-flowchart": "^1.1.1", + "@gsp-wf/wf-approval-logs": "^0.2.0", + "@gsp-wf/wf-process-editor": "^0.1.8", + "@gsp-wf/wf-sign": "0.0.5", + "@gsp-wf/wf-task-handler": "0.0.26", + "@gspwidget/portlet": "^1.5.0", + "@gspwidget/util": "^1.5.0", + "@gspwidget/widget-core": "^1.5.0", + "@gspwidget/widget-devkit": "^1.5.0", + "@progress/kendo-angular-buttons": "^4.4.0", + "@progress/kendo-angular-dateinputs": "^3.7.3", + "@progress/kendo-angular-dropdowns": "^3.5.3", + "@progress/kendo-angular-grid": "^3.14.1", + "@progress/kendo-angular-inputs": "^4.2.1", + "@progress/kendo-angular-intl": "^1.7.0", + "@progress/kendo-angular-l10n": "^1.4.0", + "@progress/kendo-angular-label": "^1.3.0", + "@progress/kendo-angular-layout": "^3.3.0", + "@progress/kendo-angular-pdf-export": "^1.3.1", + "@progress/kendo-angular-resize-sensor": "^3.2.0", + "@progress/kendo-angular-treeview": "^3.1.1", + "@progress/kendo-data-query": "^1.5.1", + "@progress/kendo-drawing": "^1.5.11", + "@progress/kendo-theme-default": "^2.57.1", + "@progress/kendo-theme-bootstrap": "^2.14.2", + "@progress/kendo-angular-dialog": "3.12.0", + "@qdp/command-services": "0.0.1-0.0.16dev", + "@qdp/common": "0.0.1-0.0.37dev", + "@qdp/condition-schema": "0.0.1-0.0.14dev", + "@qdp/echarts": "0.0.1-0.0.18dev", + "@qdp/formular": "0.0.1-0.0.19dev", + "@qdp/ide-cmp": "0.0.1-0.0.44dev", + "@qdp/localize": "0.0.1-0.0.14dev", + "@qdp/query-framework": "0.0.1-0.0.27dev", + "@qdp/search-join": "0.0.1-0.0.20dev", + "@qdp/spread": "0.0.1-0.0.34dev", + "bignumber.js": "^9.0.1", + "chalk": "2.4.2", + "date-fns": "2.6.0", + "lodash": "^4.17.10", + "moment": "^2.29.1", + "moment-timezone": "^0.5.33", + "prettier": "^1.18.2", + "rxjs": "~6.3.3", + "signature_pad": "^3.0.0-beta.4", + "dayjs": "1.10.3", + "vant": "3.0.3", + "vue": "3.0.5", + "vue-router": "4.0.3", + "reflect-metadata": "0.1.13", + "typescript": "3.2.4", + "tslib": "1.9.3" + }, + "devDependencies": { + "@babel/core": "^7.12.9", + "@babel/preset-env": "^7.12.7", + "@babel/preset-typescript": "^7.12.7", + "cross-env": "^7.0.3" + } +} \ No newline at end of file diff --git a/web-common/src/test/java/com/inspur/edp/web/common/logger/WebLoggerTest.java b/web-common/src/test/java/com/inspur/edp/web/common/logger/WebLoggerTest.java new file mode 100644 index 00000000..9724430e --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/logger/WebLoggerTest.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.common.logger; + +import org.junit.Before; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @Title: WebLoggerTest + * @Description: com.inspur.edp.web.common.logger + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/11 11:47 + */ +class WebLoggerTest { + + + @Before + void init() { + + } + + @Test + void debug() { + WebLogger.Instance.setDefaultLoggerName("guozhiqi"); + WebLogger.Instance.debug("test debug message"); + } + + @Test + void info() { + WebLogger.Instance.info("test info message"); + } + + @Test + void error() { + WebLogger.Instance.error("test error message"); + } + + @Test + void warn() { + WebLogger.Instance.warn("test warn message"); + } +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/utility/CommandLineUtilityTest.java b/web-common/src/test/java/com/inspur/edp/web/common/utility/CommandLineUtilityTest.java new file mode 100644 index 00000000..e5ebc2ac --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/utility/CommandLineUtilityTest.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.common.utility; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * @Title: CommandLineUtilityTest + * @Description: com.inspur.edp.web.common.utility + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/29 10:17 + */ +public class CommandLineUtilityTest { + + @Test + public void executeCommand() { + assertTrue(true); + } +} diff --git a/web-common/src/test/java/com/inspur/edp/web/common/utility/OperatingSystemUtilityTest.java b/web-common/src/test/java/com/inspur/edp/web/common/utility/OperatingSystemUtilityTest.java new file mode 100644 index 00000000..8f22a377 --- /dev/null +++ b/web-common/src/test/java/com/inspur/edp/web/common/utility/OperatingSystemUtilityTest.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.common.utility; + +import junit.framework.TestCase; +import org.apache.commons.lang3.SystemUtils; + +public class OperatingSystemUtilityTest extends TestCase { + + public void testIsWindows() { + boolean isWindowx= SystemUtils.IS_OS_WINDOWS; + + System.out.println(isWindowx); + } +} diff --git a/web-designschema-api/pom.xml b/web-designschema-api/pom.xml new file mode 100644 index 00000000..a330b6d5 --- /dev/null +++ b/web-designschema-api/pom.xml @@ -0,0 +1,21 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-designschema-api + + + + com.inspur.edp + web-jitengine-common + + + + diff --git a/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/entity/DesignSchemaCreateEntity.java b/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/entity/DesignSchemaCreateEntity.java new file mode 100644 index 00000000..cf97b21d --- /dev/null +++ b/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/entity/DesignSchemaCreateEntity.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.designschema.api.entity; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/16 + */ +public class DesignSchemaCreateEntity { + private String ID; + private String Code; + + public String getID() { + return ID; + } + + public void setID(String ID) { + this.ID = ID; + } + + public String getCode() { + return Code; + } + + public void setCode(String code) { + Code = code; + } +} diff --git a/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/webservice/DesignSchemaWebService.java b/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/webservice/DesignSchemaWebService.java new file mode 100644 index 00000000..35ff9117 --- /dev/null +++ b/web-designschema-api/src/main/java/com/inspur/edp/web/designschema/api/webservice/DesignSchemaWebService.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.designschema.api.webservice; + +import com.alibaba.fastjson.JSONObject; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + + +/** + * schema 同步webservice + * @author noah + */ +@Path("/") +public interface DesignSchemaWebService +{ + + /** + * 创建designschema + * @param content + * @return + */ + @POST + @Path("/create") + @Consumes({MediaType.APPLICATION_JSON,MediaType.TEXT_PLAIN}) + String CreateDesignSchema(JSONObject content); + + @POST + @Path("/createByScene") + String CreateDesignSchemaByScene(JSONObject content); +} diff --git a/web-designschema/libs/caf-cef-schema.jar b/web-designschema/libs/caf-cef-schema.jar new file mode 100644 index 0000000000000000000000000000000000000000..9348fe19b9dae93f7c55a78e8aaa0e067bb6d131 GIT binary patch literal 14357 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 N?tL?k<2A;pURj30rS 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

{7KCT#{2jIP)Z{ zMk~CZpJdkwrT{(dqzst;X`j^a`usPzvWNFG+u#QZbNO*1^Zma(9sWJcv`EoP1yKaa zn>f%?6GcBj6}fJxJ7}=INxdAp`}c1F!0;>^h0iGuT zA4Qq#NosI_V=$)UgR3l#XYS{;_sJ`s@9tN~UTDr{y0Ca=6=}Q}8Y<1HeyjnNR^xpO z&6&MmZO?)!Pn7Mo)-Vk<&lDlG5ERReVXO@DYxP!>U2XwmJ`nj$Jv6dOCbW5pJQ6f} zCiKuKZxancnU`jnI8Q1|`<_06vcF=qRo;nQ!Rt-ND|SY+=T8JGu39bEWPcI4+7L-s z;i<31TQ(s9T_zNebsPnA&-{HoUo%3-ffQWL-CN$eXL_^gH9wf*#TB#3;9V)?U$*eC z!$jm(kmKB^Zv^@rEpM|C<{F}}o89h7HgnO1`?Uyclz{N}$Ro!=+n9vTaa+#JYdVme z+4XeYlbF(OpS+QR_ij1nUk=toq5gh@MiC6lqIz4f21l+E+ZR-|PPl5pS2=A-J)|*$ zYy7tIn9#f>ndv}kI@jYd4@WLjn8qm@TVnnW;$RIRvns}-)DQ0C>K^~oNpPZHSe_k3 z1UgZws%lpo4hp3lWdqrB##WlYrwfe?qWZGM2Yn7TZ7?SergSR0%C!ZFk<{G>ct)#a@3CDx3US3Ut{0^z{KW%u{EFIqz- z4$4{d^VQ()&)us0d`aDL)P=`$Vc#b=c$Zte%Mo100Q_hCileWp6uVF~ij9TKn=bs6 z#K*>Q`o5wb&cVQCvuXJqX4flBUM1}H85hP>$4G4n95kz0PYADprfZISyDxdrv817aSOj+&iL-s(i0 zn3Q63|BuWq_9{r1+dc^aC5BExoZqp>a3c*C-@Jj+CZybXv%gVB(lJ)Dnm|BQuf8F{y!)Pf(2#+j(zah9>?u`Olj zL3uuwcctb-$BLVsWO2SrjWV^>vWVO!pC@0f5m_!5UJVyYU$#}Dz+g*f;p1@}Y*VaI z^d5U!VuVbnrA(yN%d7Mc0}l@HsTrf?3hXiGfgl-1=~9c+RtPBunN2A+CR~-Y2bY{G zQO!dvnI!$waji=eW*M$eM|M^!-v|OAX%I}$g>p1JSu>l>U`+6rGe+IqI$mAjY_p5S zbYRX{Ug^MP&o#oro>z(=S{GcLECr*Pf_tsYg#}auG4#2a4nl0&(H#M>&f%_~guG za~;MF%z?$xh?v@>3)4nTflnOG`{73kKP zk0BGrt5<7R{-((4mRh@=kL+iS9^r#>TDlrP5|y0dugTecFQo1Ztv7WM`AGs96vq8VQAJ!-Zyl0n9`Wd0unY-ChColf5Ue{3Y?1>Qe`zi0W%_G_^d0b| zRB+l-vFw%MCX;icvulaby{D7nfPt+qplg>KiE(r*Isi2d7Wo9NI$*T1w_g`bCTTH> zSF@wiZD_hOhzO0$dFV@l@uRuM3lQ^L6q7fVRw_A_XW7?jCcUw;?5QoscJeH6nXZUl zJw?jzCMS_Q-7;MCzEKr^e~J%~Xbbf!5^MI9(ZyTWQR^Y9_Y7N>-r)!06@0m4dXvK` z`Hon*V^jc%ova-sJ4!7a-}miZ?Pcbm9{?@WC$v09@G{lnA2m6M7n44u$>tKI=XvK?B!HU2 z=9|FLeK}n>SaF1N$<{rl6-IYxi@LevAJqvz%gB3!i4EVmv4<5WCj}PWA+`=8jRDKZskp|oDUy+x z#}j^{!!R{dgK4Z=$te`~Kx1k?;EF_lhqH+>SwD11JwRhBlYO$TfNaGY#rX#L*ADlO z=>6UOZCmo6-Oc?c7L(&=hcmFTqA{~}uywMhF*3BJaWZtIF*I^8GqH9wvofO5vo)jn z=ZaUf*Ryu8GIRXbO3zZ*wwaej`l6;nYKH+KZ)fw70WMx7(qQCIrZOa+7=8K`Psyz{ zp5$Z(Np=bKon#QkfH9T*SrB=QqK`|>JsaZSe)T&2+U?-}e*WB&^NabG92nVxJ$o-L zxH9;d9SW(CjJU2;p`H}Jh>(81#=^Bvx3Lv5d=31$J%8Y)-TF~;;R)n(mPM$%jiL^K$alFz*8q&4Q z(v@4DMwWxGm3$$Kd!9|0OLJm&mUIeHm>-c_OFf8o{$wo^YMdXZB%n*3xh}jJAbKJC ze1ib(AXUk6TzE#%-lDI_rGg%Cp`(Sn5mN{(NYZ)tq2=H4X^>5?0B+(3S9imDoIe7mn4d+6sv$Bh_T*w{gVdIP)=#!%1k?L6#b z#zTZL$ijSHl>%M7uK;`_!IpDXEWJFt-_Bnyt&W8F(h~Ec`TUiG8;(?2yGUP-_}a!64s`%+Sks51Pbi=vTyG?g0@ z&E|GJ^UmOJHJoX#H=r*CkpmE*2wZ4p2`mgWS#C8_Jlxw`zcCFe!U34aO%v9qVslqJaf-9)PGG}C`ZJ<`@)E#^Xc3A6-44Pw! zCi8Y>mEAE}(MYIeN9GrbmQD!w40=mdj;IXzC8oxuIZ0;pmNOHaMGR%wU** zK^|Hd1}73adxRTk@Bok6lXIQmw{bn1RXx9I{uyJ9-(DZZkE8=Q5nN)MFd5upq0^sy zD2c6D*bcmctvWAz5QM52@uLdJTHVxVjuPnfg?8?p!{rkIWU_-H4CizS5 zwkc+}#1@2U10HPnq5u!ui5}7^g@U^-8EFNBq~uacXwwzx%p#50%$^xAi;&$3Ex~Jd zdz|(~LXAWe=vnTt%(Mr>6|H~&5&t?pbr0tTySfsa50gDeqH}E*TvKm}eWG`s7kVMp zjuxBxzRFe}OGV8CyCIcAw`C=3=~+g0RZEMlf3Xj)?Wpo-CihK1aa#|ZM9Tn6!nse4 z`s?4$nEeZ&Qd-nszxID(!~e5}i2sj5{r_{PUF!eEopK)=8E+ZhA;j|n=rPm>S3-cL z4*=9Tb2XT6weYv$eR)e!4CWzQn!0AX~a=I}ywTeB@N|I&0 ztC{UhM`I{3=T-VYG8B6rHD0X9w!*iLcmTPCOB!Q^_A4B94oQ2 zc$oT`{w--JbBLI(vi|AJ`<$K+x4>sD>o z#NVb#I-=*JK|O&u^)3pj*@I^H`724Gb^LUicv(=A%T%a!XaYPp@O#s{O?ZzA@wX4`!?Bz0rup*fSEVp3CO8W z3gwga>6<}a9rXM+3Hx@zy-b=WRi14J%Xp$r%UZ{<20W8YjPm4z@RVA(_E6#_AoD_G zs$LJv4$lBo0HXs=yxbqC^xZRG76dv1$w#NDyr*y!8$$D785>x|$|vR=3~*qI-ieNJ zoCl>BLq{RPvx<``3i@&uVE%&^H-ZSsni{eT8!M&(sW0aSGp&%Z!HL>nvaeho_9U_@ z(+vb-5vS1*n$NQjzJ|O8FXVO)6=2@6Do7>|K#9&B$PHrld@FA-&q{<9oJdEP>5w!Qj%|qHSp#+!}Dj`>=NKX;E^L8rPSyPkHxUxIubu44v>k4py~9 zgN_ToF9-U|9ul^KNxzH}*)O&tRTu#8#TtNYfYk*)Q{ z2Yv>$j!*L>D2$7VX@^yl$#6WvXCFCpjISCciL|Did#=FmNa*K`F4}EfTtr0_w z-zMsH6})rqL_JK5pR#t-4_3mnEz2)**MyABzi~<}zX5VT3?Z<+v95fC=T2VNj6@3@e?@^rky1g)Z@dcuw!g?sCU`-Sf5g@6@N$bA zw6Vd5A#P6}*-2!f&Q9&-I(5aE%WWn7(tGTmf9hJ`F+1m`X^Xoq;FwQsCrms}@$VT= zxYZG9*Xb}ab{GMTt6=9^&~plmYgR@Wt4?IkSDn6d*lo5K!FV9PXDmLe&5kSHG{%Ds zpZvW!y2Bd4=DO_JeWPUZKvqp<3`!X`ET``xPGL`+a>-HspxYy^j4?Kxl&v0GT!1F4 z5h=K<2evg}H&k@KpJ1t|MO(FB%*354bJ`$&U=w8gchjT;BO8R;ZMWDQsU2-#7Uf8^|&2()# z(&tWLUnXn&dIAzZJhr0V$~SgUf!+fq@9}#KZzeuOh@~(m@J0YJiGQqoTS~^i=HSk) zVBR?@EsIqmwu59nO-MzpNZvZm1-MtW+K_7b-Xr2l!Kj7-<^KwyYpDUNdSA|sfS{(q z8==h`@U2+h=2TlU*=f?f$l$-`7(v&F-j_4h+@6DU@!4Q}pn4DNu*}U$JkV5uTl7qnBJDQ4^w!7uMRkPZ^oAXUaN6$b1ESnVFvU_Zpa@ ze{}xlP76*ZqSM{$ORVU>^IF{P@&u7?%3asf?wtQqdHV_v5_5jfNQ~fuG>LGJ-Y9Zz zV!Emxop)&d32pU@Q+Q(G4%#Z0dGx2)R;OKA*EE1=a+39-UyjvV-&EiPauGk6S@Dmt z=|B@f>|Vt>2O)ynjkc}1g?`W_7Ro^;&XZUwdTjgrh0dQk*aBmx(k=p|K+IX)8vg!S z2qPyEaR&bMxHVFNKUGn5Ckk(qv%~sB7r8PQmUgLU7y=aY!(rJG&{cuorlv*toAjyC z%GFA^w6k8UwOAWTgbG8yjjfBz1w=Pl5uc@*Bn#dZyJ)c-WDg-176m%SMF%spO`MA} zy~fp$Qp>DqWb>7s2DyX|md^-9hkhrH`XAG$Q zl`L?lhulwc1{?IVbgssv7#Ce!)HWg^=z@zh=L=PNT1))wS`WqEZ)BktI@K3fEcVNh zN}#T5m#2wW%&NgmHtKV&i>S%qJ;S0Xk0GoX0(NgY*u44mmGdiSzC-w*Z*b zv*zk!&1&YBC)FxTQCL>sK~z>zUm$?WfCtHBrq!48Vlyi_oEau94&OUVWJ43l#e3o zPYDX}NDsBE@HgQY#?C*&lp|;s@l6nDrOTM?c@ByYsqnkC*w zX0TOs9-qVa+fd`R38M6)Q5?SOi(4YdZ5*2{8{((Kjh!Q zP6G7$I2-Z^d9BANNEaQQN_n!q4o}96o$@)=8WTe*2#jE6C`9h9l{RFQ7&Wr zfX9GCP4#b?_x7*~vr;pfqcEQn5JS%e-J0XHJ#lO~?d)v|9^S_kGM#yhEafzP{F!qy zO+{h>GaY(87+q5qu-icu2lixmiaf$FVcN)mr|n~#4R?0Yj(=Uo@3Epo6RndqP_j@+ ze=25ZH3!(^3Rq{pQS|>>I!YQM^C3(3lZcpuArDjdDYW(^F+xd6OtLP(tLwTBSdjJn z^Thf%F@=CDJ-{+gO3MiV1%A;Dbi$yY-DkCxvlRk1f>+&0jB8D39s1M;uMG-uJ-b%=Vz%ZKa(_ ztP;m}@ijt~NNphP${Q0*|8EG_uznYI;BA;r#ogytpl`ez`k?JXNN=ti`yicDln?zK zWC$J-4QN%!e!1}3>?+|#U)x6f%*3i-N)WwH{K*Mv)P6}gVp4viW)Uz%-qcdC{d$H# zT7Wu$d)SYlO`m zH>eq#n~ULlbuwma`^@O5IV@&Z%}C}|U8Bfqgj$GU?1D$;CY{LTRbA&u|DqwHbyM-o z=$JY3j7-#mBJjIKv?)aMqMs(OT$=(j+q8KAE@_fMQ%^f^PXqVJVKQCeNC+z!1N}r5 zO?7{((r7u5ZWPu%MhA&`cpGMw74V-5*0||7amrsR0erlL^5rJ3@ z*dYV@+UzYzyXB1Vp3)Rb+HG0pf?f^eS$nAsEen~fOIP`ANz|=q3vP zvH}=XQFC-j)mV+cG+tD(q{mOL2 z&rcvCyCDjgOR3lZ^SUw1c2XW#Cks*Z&cNT0bA^FFF=iovxxh=6_+);wOY!ymX8gs# zS;cI^dgK}GT@gRtHkRsEy(X<3Ygt!}Yhhr-K@z)OhYG)5w9pWm$<9@>aBuG7BT~6= zZQ-;Qbqvhu(|f;%npo{O_H(W4DhblZ(_K`K?;w(3%$*A4xtLuVII?P5YLH;xLE7rq4 zQbPpqc3AbneyG_Q9~)W(*tx76q*#R-gH zj%q&z?Um^p!QzQvWV)13K2OEsLb9U4pDzCz*4ele?V`WAzhSc^YXXeR>}cD%izTzZ z@U`ng!f(XC--`E1sb20$KC$bb5%*ny2NqZZ2DJ2O&}w=`&&!(a5d^O?y& znMU;AFB?=Wm7t#S=d6a-e1d77`!cR&h$o;%pV_;DZa?E(b8=gdOY+8)pqjcg359_h zL`!<|M>rl>G}=q(Vk$NG^&*ro8@I%iR{d0aKyAld_C&V4U|0Q1yfSU|pxvTxE zr`!&`3pT%f{xF*-b-Gae=>}|7y4%XNe0lG!ihrgr*+Ko)BEG?(Yqb~y6#*>ra$fmwZ&^J zzyu?I9I8pOod*GXbeS_{bKJX;~Z7 zz}oxCI>^?U?C=VO-Fs|@t8Zc0qHpqb*S9fZjWZ#Bu1CHeoV!N+VPD(%6Wf&#(F zt$U5P%HveXx(o7<&r({~8-Lb2G}^KSPRmrAlS$$tNEASDBvw5!p%29|#*`e9Wb(#5 zIi&!rf`6u279gE4et~y1*j~P$sEs@mYmynErbBa=H>#9~_7_6FNv~@+e-Goq^%(2< z_n!tIsb#nAv!=h!J9vrBsFqdj7i?K_QFQnKQ9@FE2y;x*1N)+`&h+ZxR2#K%m>TW* zN3d6gzx72CXl(*THX9k6pRGY%cpZ#)ehi&yGU*tb54$utu7pXL#nNZpG|~kvrn=}vusO* zNg$l({}62w@SEvTTxS)*_+?@9mQjYad0T0YC3i}sN$&%w3;*6BX20bhg!n_}H2zR+ z|C#6RpL!;-|54Wb!?HP>8T?b=Q6$%8K0u4cS!BIY=p#1F-vTo&PqnE@PY4Hw#*W60 zqIf<)%35DXD4<;>fRhWWMBXwRpMzJpCcS-n<+wd^yw2eZ8p#jE4}~7gwpzv@o3^*-nnE zdZIFMkY!^pETwyMj8Srr5|1oD%)4W?J$?nAOMxR4W%VW!om1DQU zknLc2Xe+hBxjOfKlVET4cJ_ic@{cWRls|!qXTnB~+h4wV_O%n*$T~ARh%z-2zyAzX!kpVr00^a?kBT8+11ATVot#3|o7PdJJ0MvNe7F%~Tr`@NG~C|La#A&97fP z{}G4w&tQ7nA2E^9KV4-1s8Idif|?%Yu;={tw;K#CaF&vysRTre4~o>z4+kP9f3 zzxNlu?4sBaurM(L9YerQb#A_snT1yE^1P57lI$$FKjdQjqPa#z)w}hg^~3pJn>wnb zuNjYow6S8f59I!?<7|)XAO7RB`=%fDJqL(ZE`75V`?~Fxo7tvZaQblpZi!hNKOR#hp>vDM;i9edUvzAc z{7qZEYFolR(fgy3qv||niBzS~OQ`PwyTPUgb%z$D(Qo)e+!Pl&h>qH=VKXn(Nu)jHQ-Mf)ziCGm2G{ zkRHn7s^cs=Jj9=3LKHh^b=L^DprnwL#&+s8(WYZRI>l_lB=Wi2IgeR|vzmDnZ6=#E zA>RmpK!V&di}g`KuRZ{=I1SvbNAz?hJ&mhgwC=Q2u{7k(mEYUsDpNiB zxXiZO`n3#0lx{+~e6(^ZZo}0w7na)C8I<;!N4_v^e2i$ebNzYZO56{GHCm)TFSc^# zRkE#jxFzz=IzQM-`6#*CjE-o1JK@oCOny0Kyi(h>EnVK;qf}^bX~RdW;+gmps=kp9 z-weDNl{){0K}mA*@n!2qiWbf2{#oA3(1Ew~gtXo|Om4#^^|7)hYs(eV z$s5iJ7@2F{l}wVK(gH?$o(piTDI)K8N<_y)KrAX8t1@LWo;}~14u|>Rv;m+Md+`3moXa7F> zq;L(LPMenJx`Mz3^`TJtL#ZSRF>|hAft^(Pf%iFHwy|zG{aoc0+FIop`BaYBx;JXl zr`WYCoW&>$DAh7ax{Hi&!&F=p1FEezQ5ZY}A&wNW zj_mx9UxE2Vt%z%;q1aOKh$cP)x@|B~;*ef}I)wtNZ9cKWFd_H*LY6eYuUsz=S?$kV z(7Vz2(U(1XN5%UDQ?Vw622|U0;`w1l@dj?hL7gB+p4;(d&V~C!0!K3wPh;EbSy#># z*UfErR?b%2>U9S5o4$f|(z@vT{M=w6iZ0G|N1fX-)|AVp$@pa_sCBN=4pXP~IF>n% zMpK&t33gvWv8T+{e6fa$Wlp!$#faaPDqjbq{vH`7IKW8FK6|gXMZBeA(;ZqIG%vF`S`*egF<$k3AEdE;_=~eaA$7{-^8ILXUH)+GOB7H zQ(TjOU=iCefMKpia|qi8~4IICo_eS|+e#QG~Vw`C1Y6=-=6QJ&(}ZPUMbhDfF}Z^ zEo7yaD?M2Wc^KQ6oxBhF#2NVjR1{{tA`)}A3bj>9>hOqEJ_c7*Lc@E&R^&wHa@A6$ zKBWz9!SHt;#ws%!GcmifP~U_s34=KM9^F=^6L@X~uBW8n2x%b$;9ct zf=|PrJlflkzG)VZcmt*2H>q56P=c+nc2WGSM=_GaxZyZ$M#ESmQws^rwlfYmY4~ba z$)2XAbd-Vdf_p5FDgN|RJ#~^=mL&>i0wtL`cQ=VKJ*Nnl?$V%E_xd1roCp zkuO_|{6nt$bENd~v&F4J5cX&J4zRSX^;D+PB4?>GfPwPFD;0k-Bz3aZJqtV}lclm0 zglpb<_8QPi;-?n<#t#eJ{Z0_aeEO3HX4Y}?^JMhqwaS?YTMmDP4g>$H)23FjyRwUe zz(G~S5%G2Yj&sf`9v;|Tyd^Ae{^i2vmG#sc@V-Q9tff8)k=izj-GT-kQ6H~3l7#+y zb0+<2F|rsaw~<7bLqJ5ET`NSJ9jU$>L&rzZzah(NLy#9UEs#~AEz=qk^qvJ@*lcX{ z2LzwAh!9l~%wXD*RQr2CnKaS&U3@yd5HYsO&JPiN(#-5O!`YJTBHpiCbeAR*U4Fd? z-0b5}ud1~563=FC+m7upB>U`|u%8Lgb2T%THhZP1UA5N<+dyuqycpKT8D<1ALoF-m z(*T}-w)J>^wd{0EA3X$(^6Ky|$54gh{q%!eGU%T$Fb7YfMV9vq*jfe2wPK;$!%=@F z8rxD!5Q4avd8#$*>(jQi*g%bJP^G~v)-Wz4yrR89Ht*R$K*M1QN|)`@>7%Kh-5GL5 zXmD{_$BrNm)M?ZSfd(u*>xGUq;f(x_=}QBy+;)rL7)67F)%3f$G%%jd!PZGDbZ${){$=bShZ~!PkaSqAxr7a=0F2jEu=Y zru;C0qhSk2B$Zl=1sImzid-C(z7i-_UgfBv@z;QLJImk6V6(xF!n&ZXE3l075@u}Gf9 z1wVo$s_)qr_2;=q*)5~V%;tgU;t&#XoOw`50J@OrbnprI@oQbTv}?#pE)U0E+44l> zg|6zEl?{|<*X)!ucEJwzswgU(oS_!$Cr<79xOhFz3#bHbg)ZT{yB7!$7R`0Gcey^0XcI$=k0`(Q+S7Z^B(u@V(OA8(6GX!}$q9EF~xfMWc-FaYGRg&*R$9D#;>6!m_ zJ2ej{xOGC(-6y1qZ-sB3(q+cgL6g91!VUCum9~Sjh0Da~!Fx5EbG%{kUP0ueudf1C33Eqbb*GAP=y_ z-&G9bHlLeT{yv!14Z#b92Q$FLcl0Bj?ggP78A?1U(zHW2p(Z(k`09ets13W@kR0d= zzUxRnY6tE>YtS&{%rW7#mWTro7xi$7ctvyvkde=vICY+8PqNc7Jc2@V60CA`*@Bbi z83Hqx;HXNiFFq?QZE93$NqAyQboS<(Zj)lAiN2L*9$X}(Yf40*>n0q|?+h(#pmQNN zh8Ds}!4$E`5lVBWd$}HV1!eCkr^UW79 z$6&!)xP(h_(VNp(01BX|Pa3m$jpulhr%vQew+78sFxr3ziEen8n5@uUBU1m*{srDg zVmhZJH_WctBMzCk;7GopBW3^04b)?eFdev;1IWz`e56U~8>ldLpXr}bEo0D9$-)+( zQj<92XOHfT#tm4&?2E_={D@1gf;&f}eo}Ot>l>~bN3Jq_EWJ&{NVdc9J%FykhVJz7j zQHJ&<))DEpMG0;>w}zaFvUi45HaGM_pAeicRLCC~!+TD}<1C~BEa(K=`Jg=lIo=sx zA1I$MTAESMR_K!^m|9anANYv5eOQpU5*)y{+2C!KeKn=rb$C&6W|`YaGCJ78F*@tx zN<~#dNAM3agjHf7+SX#~Znmp$?yJg6(SwnE9^wssS|Vb3_d=)B`2INtxNfe%HN%gU z@I(raQd62m>0?sn!_*P}^NL|G%|thJ>oTqbGo-uQ3`5_2$t#Y> zm4S}N@_W*b8R#=aUb4xt)21KM4d{hC%?;rR8&ZWthl8#k7)^&8Mi?rjReqqgW8kpXQ48w-x6%rQ z3F`%3B(8)(yM*)yA;7~;t#t7$DV8Ex#qe0(T|D*roRtOIGA@JF{m>6&TsQRG z4ZHkMeCF7oWA3AkeTSMFpO23xtX}TsjGNk}Ug!-Yb~*gFM@7G;UHY1_7K znbL|d5esU9!`cNZZ|6Lo7-3~ z4zn~Zo0I2aK(zn+jFMItZA`$#)Br)rq{~zY@kO*)n@4K-k~^6h=c^&2CEi=nqcE2> z=~+=}Br7X;W8Fh3X|{VDRf2bUU0pwUjwChp@`R{`$unori=;nt(~Rzz;45=~C0)YU zgnaNgT2wo({z!^T>kYpj-xY1~s$1Y;5k-R{hl+i7*-PG&m=O&yW%kydy_feD@cb4N z?#uHTrXnV3LiV!&Qrc ztqzRPtmZ;P`~ejy+gx@TSH8o`v4`smy$4%(;cvy}l2Xi~2ewl2l0!`m$4~VC9WKAi zgk1rD#-)XRmLUZHt$N{qhKq`gxrw>4(f@5G(1!Fvd3y4-O_;J`112H#+q;JmN76<_ z02FNlAqoEl09qsKLauK|@9KhBtMgQA|Z{5)$>r77sS zvfb45wevn@YiepjPX1AG%+74<)AQ2Z^Wxd#`eDM~eY-P~4d9n9DGGAGsuGSpTN&iC zS-RhbNHGG!Ptqn)mKGzB_IFk|B;&#DSIP}d_k?}o$%u@XE8mW_s=XA5*m_{IgCih2 z{>ibB&CkxHfeoF)-8@88ONWop&;*ekgNx|to`X%b{M|SNj!n-O3ADzUM{s)$B58kjf;s@CF z)D*A&M{&f9L&+ot9*vwD{nrtaL7On-2g5NtLnP`7GhoWTp zOVqjI84Ng?vm)pu$rH~O_q843g^7y?!p{PxGvj|Ju|8(*5j7Scn4F*?bx6ovwyZXJ z^i!v#c@!#})E|=p)$+v1Z`3R76pABzlvA%~Py8vP!%`sSrjZy*gC`IP1ivnBDOq-bfk8KJE9GUvU8YCP;Z38Hiv)>JI6)S(5Df9Tm}16iCBbc z>{bDZ{=m`@V49LPjY(4If}U&q4m!9u$RPIX3JRDJcK+oTy(m?uz;8Vbv3laVq2{o^ z{ZPe@l*A|AYKddT%wlXU!7oeq%BFvo^$RW6QqGn`RC$Flrm2d+)F*q{AF(DVMp0bY zqT1=!GMN=qtYL|@@2x=EQ<+50KoRGH+l?#j$51G!p#Ktpki&X01uM)Y-w!wRL1zTA zbz{=2dxmE{PkSda(`g#*#pj~(gfxwxiu68J)Bce?Or)tDRC}Uh*zTJ^Y6|rL!6j*< zlQ?ViMz@tXlVBcB6yqq=GZEdVB2H|Uc0eeMC2>yY1aPG!Y#cTx>*qj#qdn5z#G6bv zVIMcf`C-_2M?Shy2b_+;f`Vs^1pN$l;%8_YtDkwXkWe4BT|l;UR)pb|GH|yElvwBVL3n3Uv7_L+nHdrz=U$;B9+@k(8DGqGL#e-9 zDJV|rHlECrd2UoOFdR^$J&7@6a?l9wfS5x=>sPlHEar}bwVa8kCZi`f;VdguqTi!2 zXj6~P+&`H#6Zb@wkc<-|d+z`r*F(dS>)mYEywSuXf3i$DspAneq_oLc7HXK#5w2_R zwA4tnad=C5nnd6}#btaF)1MI6>*6F#H$CTpq3@&&f~rw9cEYoH^KeHY;bKgqGEjvP zRY`d_7rDziWbCKPb9x&@cPSZjJa*@!Va4VjNW8&}-M zfEZ^?atk1eq9ZHEVvY%O^K}rudJ}mxTx?mj+FF)rQ=CE)MRG@&K9V#Jb6YSW#}qBH zIlw!)dG!mmIa8}SVk!GxZ(5J+h#FxvzjO0g7L$mX?ahKs+;*(aO<>`s<+QX}l7pU7 zkjrftrhORfs*Kj665vmTZr-E)3-xTdbp|eH&DeeRT1Ql z#%MB7G3%?9#83vM0n&z_QQ0&UN$g4TDX%ZqY7F#f?y#2keHJgm@6=l3E7@BhI*Ey4 zx6DdzMoU;9=Eud!bL=reB_RJ>l64?mSVTzXN>lI^sR(u3r>~f3V}y`(qN z{*OKy&#_nc<|fcvUVVfKopDvGYIVvL!BbiY>KkFqUuD0bBq>7C;zZ+(LKV|(j-!l1 z>Uq{xg^%1s0XqF3m=xcPV$x94;Ji(aIP14{Ie$i63&Q4pOul?GnXM zRfh%&pixF5wHvoVmN;3F*naf<5to=hZsFM|x0FOs5>z@>EJcta_qW^s5_UiJt?mWR z?V0xX<3oTRQUT9_4A%*$x}p|yP$?*Rq=OY>8=>09?)a6o%IKF zkh#_%GT2O+ZaQI3cS<>*Ak8oo6DyX0FLkSl;4VwLWKpu$&?BJ14SRqu=Sb1SlWH??p)+5@}M(<|?!o(X=RxqDh^hgRWQME?u0$92rWWON~x3 z?vXKbtJLe7x1ll=b*$cnG?D38C-y!u{ArI&TT%FG>Nq^_ffu;0i*MG!iYcOtANIq$ zafWMKi}spN&9+5fjb?-gta03sUZ%`5XXHszE&3;2aNf}P5^*CSs_Hk=XyVuyaCs3l z2Rs7~1sS|DYbcf`$|T4+fRoSEsvK}|BNgn=Tv3_!aITFAf_fe>bu7+$&ecLVyZBLh zEfcGj7`Z{OjbKTIM9uCI5!}~vf`3xO@I{x||765X;mFYOdkO`#kPi1L^pds-W-y zP142E9>}UbIu^6BIX?b*I0SF7yfSSHqInTaFR-*CUkjsz@i9H|ez)m1+!l@iqaCQ0u3C&rIsR8R7 z>zm7PMN)+Ig@{+sB@L1uSN=*4yED?j`oY|Txy|qiaWNWF(3Wlw@=n>KJG%>8FPAyo zb#f*CM;tSdknt1rJHqb6$C&(5PtwKu(`!qB615f& zc&F?Y9`-x@J0C=L0De~#_IpaZ7@iA$ad)M%;d?jq@FR9{SH_16sQ~LMbqParT2q|E z;q^g929tUR6hwlQqj=dLwF{2w?%7& z{WKl}-_E1N`$!U;++f07Vf+GTeq!W$Nq7z{$4GJ~7km@5&SCrb z56>wUOlMAf(*qq=pm-A*TXWOdaz8Xf_^Q1f%`*;Lq9`9btrx>W@hh zPe6Wg69eeW2k^JuAd|1yV!yU%XuF)(Ihx-%$ng3R?0!>7DzW0;Fs>^xqI5#3g@q6MX%+CG&urx%o@@68 zBA_O@JM={4-leWX?=Lm!fOKI=R`uUsqY-OB!$>8ye*-2Mi zE~n`I!q5)bYr6Z5XU-;x*Y>>SWUBsz_Fi%+h4>x%Q9L>8!HfG-fspLFEDTAlTzxS4 z-qn7KEQb;lU2VKS>+WTK$6IJxy)~yA0v_V8g~#@_2VYh;z7uavfp0vuiUmGl1SDZQ za2VS)fRz_Sk`0CBCg{-xm8(E0HkI}Z)mG@rmEX8c7!O67vl90o3;^lkqYNk&5O)|J z;7}#7HDTo`6IgCN^52%N?TH2jPDieJ!{WIX9Rrm@2q&#zp_zTksN;PPWi9<(*ct74 ztVNXo1H0HXCch_O{g*l@;6tqF~)2J5GStH%Y^j&e6}qijUjm66*m_}dpCw$A)d zv!TS)22RUAPp3(oOc5s<-bF%htzY4~42w-?InX$=<(IDg!4?E z^*Y9I6l-5u6`!14gPLki&9k9CVw-G(s>g3ea`as6YEzj3s0W!bxAua<-t`NDX|s zqWJFa@*no9&hdUf5FjY{6zIl)I3({A5PSFE6g0fP1Rs^#GX)f&`VhE=1-Xan!~!Yo zhd1JmcCS?GE5_Wh-!lH?1 zo=#!TK9oKUv6sG^c%vVCgRnq+PYCpSq-rCcV^q>q2JTBwO8u#^E5gBl5Ka61OKhXwU28k6&YnH}uRJRSVwb@6Q49 zOL}AFqDL5gHwpsu%$tNi1Oaj|s1cw;2>2EnwtCQ{wJy!}lU^4tTcS&o{*zVTjZIbu zD08ntNkS{Yf&IY?aYe$vt`gMTrPhcJ)%Xn|!o3vfLRFA;F5Zzn zn=NQIbB=w*A2=ubR1l4^OhL@7^4qH<`18A#|JjAT;OG8w(rEBur7% z7EG?EdxqOo6+n$&p-?As!6txt7Z`nJ9-DG^!}9cIoT7GMuF05NOXOyh15r!C0Mf5k zUWNSy`qeRwVjDgMJRnA6bo@7I{X{5)C`koko`Bt%0Ky>pP&O^>FyP?JlVhHiBwulX z9-V6ZUeo%tsJEc&G5QcmintgW(hoxadgV@A1TbfC`eb?M5OlA)dJSsgKz5gp>Nf68 z2&y11?@^d`fU1eUTG*)s6^O>jhl1;O8P$dSwZmgJK%Xq)WvppR2l}#~5+!L)d?yXM zlfekFg&YoD6~-ARwyR82Nz>lrz>y=?7zCj-0Ooc4)Fu~glrcnH_~W_jmg-u|oYh5Q zia+L_TA%e2R4L|JNn9a2zTXj^6iz{+f~+_Zv?yG-D0K>peJE_?iQ+fWEn3Aj+ z+`s_oAJ5X*amy}fSppXF>8jEi0v70VYKW=+zY*rVwWZzp-JRfQD{4_tPrV5qYNBlM zBUGsJWu**4kOLG&NW+wf9MWY0Wf5cybPaFZ7#X-xQ*Iz^5K&VckmQj~mT0XLL%0WU zh}Q#4c+4uW&A85>}Ub;B>XNQ zZYcm=x~CQaH+KE3?Rwcb^sq@*B{Ap;LO=$G=YyLG*P*)vXdZ>?W~C(2G|R}X3?Vl- z`q{E;WiDOwpj$hkd4uhi^b&v6FryG0Cg_?tDEa!dz9+8rwi_Km)+E+ncMZVxH&|cev?DpfRD0%f)x1Uf zTD1wu(DqHEqIatsPz~GHFodC5{tqh5&8-) ziQr4%)mP8Fp)E=Etv?~SJ$n0>pJ=UcA+>g5YcYY*n!9cF8IjO#lrZ+CPmDSxT0iGo zb2BeAt(+#U(eQ}D@ALR?ehSIKepz$%u>Dnyk<%6)Q0um!P3G812R3FU-_1&LF6M|F zN@Av-Gg`S6?()e~2nuY1$qsy1byc#nrTKRaW&1zVFF*OM9mG|^*kJ5KWnk_Hadtz5 zqjDy6>3-+^X!t%_?7#u(^o8+{98#0#U4a8Uujx(U6{Ek(j$!K*q9d=M%6z>5;h>+# zhdQX(dgpl#TV49airtR$>z8G}K4H&cZIQ;Us13H+S7Bh^#TWo;)$GkRN?(UlRv%R#xlio=3#ty8Pj~#&}ay zWu)}j%m*3z1DNR%`T^3I7j;=6D_1y&b5q>+=B%b=3ObE5rk3dj-D+#Kx#j~L#|nCL zGQIGxwm{Vn+51A*w*F@lN=lH>eTmj2qr2}MQ_M2?yvz0oi}?vo(UHU~iRV8sl&;`p z!qk}!wo1iDhKCA1Qc4E}aq_z?eEq-J-lmn4-U%yt0G7sGpa8BD#{On_0DqaQ-cQR2 zI2on5V_XEbXbQ`j(&}2az+HlVHFYPI_8>Un$IsRt2RShKjPD1_C&Y01!vEj(_1K3Z z@7^EW)#Q&v{NIz@{5Nmtrxo*Kw=uSHG`F=8{tx({<3Fczt5hvr7nM=A@*d7vju^ew z<63H5B*`NvEb`?4%8$!ifJgX6m>*9+_DdrratnMye*NI|brtGpE;Y}|e^2P{-PpA) zdMBFy{aE(-b=^gNa@{b)cS82|u#@8pXa}c*C(e*Qq>T5@uoeze{B(6d!#C!5m{{R{ z$dEn|g;#SVzkKk7WAfxC%su72r!;vYKXyQ7V_X*}PEXc!=Yq~Rfa~2+(RE{d*XEz; zBy8Lf!@!{9(pfyzv;#$>@KmL$qM?E~-dd2Q$6sHSk^oylBP?1o4aI1^1cmW4`*{G}VZ_Ka43G{zpKLKHFtR%v;J+B8 zW?Twvd={~$>Zkz1el-L}8(e>~8V$-F=ds0ByqG|8Q{67FhHOs;7WyoZEo7Oo)_b&N zVwKyGZ*{WgykT21D}1drz|7^isv4QG5#_1qpKV7D#v7;wd3yh7TisvZqZ+QIwe{ln z2TpyJE*6alZn<`=T}8p)>7t;cs?A2UBsxb?TDoPknL@)$pFsCc)1SDwNY+a)^qKO^ z8w_ryC4Uu~DG9}V)0x+px?N%W!I-{OE3Zbu(tisjwre*}6exm(mfODR7-$CFUo*xq z!T4|dmf0Dx!Ml$zSG<~e+Zsb$)mqGbfH82Q@tKAqM?6BzZ(_TKvDOqf5^dulcTHrS zg%_c+!DEaCMkryKt6vUt56bJ3+i@im^@l1dXJB0Owr9A}~22)#Y1zt2L!Ke`{AJu763~FaJ zkYqYU9zm+8EJ(XtiBAh5KxgEHeTadOb$m5xt}{LMA#_ELN)5wdZG`sy!$Zx|%=(W^^}T1Je;OMKJXja39pxZW*PxFZuSDUo z@;kER$s_F<)$wq$18`5+nHQ4v>pgEO{kDO>t84%x)1%)`Tsz6 zeaY0!u&!IpTqfX7D{h}+i*zPo(|W9Yun!wH{%xjV_iSD;ax{I71^B{0bS4&Oc439d z3_B)|Kh6~Qds#8V6b3i#?c0aO7*e_HcmTrXCw%fg{N%d%s|$Q87SU>JXEOZd#w>I* zsD)u==q)ApY4r$R_}$y4Vg!-$iFl@R$Z^rBN^__-t3s1TeM*P+T(b+ntA_DT3U@VN zO_y!&DUR~Y;w$Ks1_O7e(+l8{CPtt0lo#fcSz;VL4UmYPkBSlVjD2Em#GDX&Y;0fT zUKBYK?~y{15*{_eMv`npjw+>+Kh?is9mg4?876JtN-H-4<}Pc0a|Thy|7<~gra|+~ zErDXqnT~QuV|sJHLzi;PNlO{SJkT?MLx-X|`+)Mh;b}x*hdqgo#yrWB?n#dQuAgfv_I6A{j zt(u^;*MGSp+hQvkkbZVV@_syEzy7TjlK6gI^0FE*-dGxh;jd_$%*%cgwMWpsXHaF$Fcq>jh zg%ad&100$uED+M|Z!ACO1m_)S4BRhAS;@p(;9-0Fu3}EF>_3jw|-BJHTeDufA$fX zg)-p>H75-Z03h~n#od39!h~(D?W~O5{;To*uMof{H7z9+ag;9)4NMmtc^A>!5Jq-; z^h}cc;mU~mus#BdR+2xZm@Xdrb}lB&%oTcc$9RdMJY*{Fx3n{5g+%h2Meh5AJ(S6Z zPBS#MxyhhNrGK*dyyy_)H_0L%PYhR zf}UVA6z&7jMU0RpvuvYK4?srgH3Aw6eWb*7R_!xYv+UyLJygeOTlcau>e%*rLcySN z+sT&3LhI`UQ!cgz1VnTZ9R>wRg#0~7F$5*YJm-RoVjOg=9>Z*g(S*aNLLX^kH;CFG zk$`J=AHZYgk(wmd=Sgey3fb=K)LNt+p-<+`${_8s0&5@hw(N(jBwC41D3W`tE;!jV z7&~6@7SoHGOnPM?w{3RL@YDzy-s>IR;jm3Av<(oy=C1xF9b9kCTuU9apJEE?wFomU z4Zg_;o*6K~uta!(4#U5@?KHPsG8zw&>dIT4Q_#||xtERDs?!Wsn5h$p>AhG7g~m>; z{_aLd-Mc6Sf+yVmoC^bMau~8V7(#%6?JnsnW20J2w<$lsNMc0gEf_C(YU4M+Lthz{ z>1v&E0!&@$KIcp!X`?_E9+km#TfVK)!49^hdr1=Vg~c;&<0M6tM^&?gOZmoW_&|hs z_O0vv9CQxhaqbl_MXQq17DkH*R3#~h>oTE}{i0>i(#-Gtj+@D3gN2nn@Bl>vtJIp; zyDT46&^IJlH$N7)B_N9>>6Rl{!<$7|FdF{&x7)sM0@V%63j}MtwQP^XgJrY7F#r>` zPw~>~3CY<^_ls*XZ)1hzc1DlqfVkV*Al4R$0r3 z52wtm(5hbJiUkm|b1P-Eh-RL<3oE*uWjyJZ7^q~3iTkwnqsR>ibN&sc$Fjq6*jB|x z2y-4hc=nO>D6o-u@(SYs-NOa?aLMVUcFW7Gw#Sap;25r2W5BHrcQe}Glnf;2&=up+ z+_6T7M39&a81WTYg0??2AyU}oeTnWHR9H4|8Y1Eo7W>PN;MF`J%a?)GMmg<@*YSYo z;|OQ<4RxBToR}&STjn#&W(GA+5!zLh-ATi=BT4HMbPaKGb#+gI6Yy)B(rzhmb6-tP z1n^Ujqn#1s+tHqRvG?AO#`Iro{^1$P+4QrQR0fY=jfE$@$B0@2hJQjd7PrJd&^1d3 zA|IuR@OYKv>!QE3YI8_5&7$CNav5EBK|s z%!>H?sS2%t-6;uj?BJD)PY-FK!zDCuICY|M8Ly1W3V3e5ai53I_Yi&&FIH<%K$}gI zAV0`68?ebKF#mR(6^gbdvD6l*!0-`WkTaVkX$c$SX{Ix0q1S7{Fp2LBH6lwVvNhkU zc8A+YS=1D2N{Lv1j?k1!*0d~L)>N>pC~ZnuM_TwaD?YIyGJv<=l2yJ;9@>yQx*%i& zFLeSd;uBma%|E7#f52t@2EO}XMs&)d@CZsJ^*@XIBMO9{_<^cXH^L#(17L`91PFHk zF@)A+8SRTH-k}&==1xrrck^O;*4)>T#wNysx0eS zVT8E>2My+eB%;wr$aH32$6T>=G)zrb&avOZcHS-jtUim#cmeDP;|;i(_!kPY=qF?` zJ0555q~91lpZw#EQF)LJ56{j+vuL*<4%yRi}K z{82nhc}jDj8%KnKgutDDYhlVYM@JaTiJf{9b6bAeV5FA)KiUOg*h3~Gl!D|-Fj8I!e=5X19 zR&^_l#S}8`aG65;PKryM7+wm{BEwkitt}01ci!E_#fi)N>E{Lom&c2~xved+1Y4B- znJe(*F4Vw!u+|8JZ?ze?3 zW|Cd_vBjQOxZm+E2Y^x<*+k}O;-Pau8}m1}B>nl3urgmZA2pe27o@;OX^$iIbsxip#>EIMM&N=P3U%Ir;z5s|B5% zZ2y_F|1(~S6t$$V1u=M$9WAAoimO(-UrmCp1t^1&%FH@DgP?SPhDye+TX8e8G)zpb zeO0}Ys2;%|#Zh~*M5qn=mVduqpIow=KCj&1^89)iq0^eMU1yo2oGW zFnagPglbuqG$B&?u3*%9OPS5Vv|TKxv~_@?gBsVlrH8YO+4!+kuyHH-893~SHD*Ux z=n?w84gb1AdTt(D6Pp|-dKO*hB`VrIMYHGtnHuSBX_cObWgU?koxQ+I2}(vg8aQ!7 z{$(pm%2dgpNtcd_nz4?vge z4Y^TO?>a&HSsYls1S0tl6eSiFza2NGT%Yjy5@>0!o_lI|t<(`cOp}`b@jP_$Gf|@FlO)>t34o#>q0SFW_P=!u*7`2SHuOL2a=L%A%jy1; zT~7Po>~h+Fu*>a!PPkcHO(n_LZZN=v+yLI=v*@}c999l6fJ8*%s#Xd#p#5Th9RC$n zFr5G+WnS;g|3;jiSft^(s+nVTU-TA6L^;h~OaQO$esxKLS;s$~))9|EG z;F(%X?8DymXGj28Sqr~cQaS{<-rL}CmHnEUoRB5RS4Ij?$*R*Lx^b@VHOt7FO+hG_ z&8Wu_x->w?4YAq~l zZf!-5y@7tECBXIy7iFj5ryfqz?V4~55pc71uEjMao3{x5@jDDOP<$x50J$qKNn3kc zh99{NB!hU)A4I$#Nn!=ZmRI9o^TID^-g>p1s($YTd~y?@--3VX|+Xp1u+FwsiW&~y1fq50~>r|dXragQ>KU!t&z?N{VTSYYuoH= zR(U@6nGK`4YW;KD;+m)L$wunJ_xJTf2f*Lk76>lJ4L`I(A{6ts#iCY%RLAJFP{JWm z&{V8BKWPw+G^k3CN3pm8WB270BKqKhTmn>6V);4()8+tnBC|y9tX85S70T_To$ZAE zKPa|RcQGg{sGIV3N_`zbQ=A*>vpBrzIkQcVt?6x41k+H9xQx;RoKy%=E;7(TU{#HD zwa$YKPjx~rsx2jrYcQ^wVwFiL>C0Ba)t^&w%(jQ1vN45~R{abQZ2?)c3vD8VS0wWu z+iA?W#1-U?nenrn&edd(QQ1cNvI0H=Ypnr~?Olf(Dh)Av5j`B1BlW(lTUwTrvuZ{9m;AixhJlsYgfOJ~vHMloi zyhg$NOxS;m6p0+F`gt}vDf>ZIdUuBED_}+W0~NoF!!Jb>kJuUa@T2}0#n(@vQ{Dm4jW}|jtbv||SiH6CV zKhDdYyl7oMZMnv)$L~HLWOU7me+pzQF^R7P&19x7%A^KTcvVM@$R45Ft1>9JkI$%v zREy#?C`T;Jw=VGJ%Y&yv&`7Y8+$p2iJv3ptULk$!oQZnv@n7X90*+?JRi`z2lH?qd zcPThR45<-v?2rVK>ZiA?gwTu5aRp%PW2R2U_dnDGKcC-q;bnM9=n$^mg#DhP*9^h+*^v_J~isFS*;AnxBfBRQu)! z#)ng`a}!FBhy#T8cV37KbVPiE&a=Ev0Kb7k?|=v&+mb+Th%0ly$7~^rHJZurGpCvs zH?Y6)7ey)VNP|EKZ+#m(iq4p=;&H4$TOmv$JwHgA4I!?q21pH_(SF}J@71oJwTeUq z2pmL0#ms-#$^6|>z4lFLE;;>{w*Jx`wBPw=4G{w?;dOJ8`?%(><9%Muez@c9k`8+b zG%$avxNqc`X-qr%;4xqMeZzPSj!}p#4HjO|6;^;7Xe8O%Kvrzds`O3b}yPGy+l(q`P-<`zGoLS>C$oF8O! z>2#&A9Mcek9G{7<3&$AZ;wCpb>GC7L^31EY_-yfgSI1>0vp5T~_}pZ_qk^Y9GHPpQ zY>?j~l3v$)=Ub+H9OU})`NK8!BlgMdi`%38vCntz6$$VoWBN-8CMM_}K!m*blW+B` zA5y+xEEriEUVJnMk1rDt4|>!h%(*f*%lcLovnHptd%aUwR2R0Jp3ryvwOH)4d3#iB zdZSYBMfyx5ycLY^=yit`h7Apt4XuxTUj@=G^|`M6fkyEi zV)||UJ<>JmA)qqo9^A6ZKO`UUOS{tTD&=l@ExDh(ZDgi#qdF;AsLiYon(DlnB2Y34#9Anf3@bp)0^bdLJx}&Z zr=ELb_2w`T3mX~#1HgykApK0!gZO7Tl)1(6>xBJe^6Ts20Uf}q{{SXUKFyD)Qbqvl zn)*Q?-5I$Q5*y_BL!dG3&=z>+#NX1@VlSLXu2f21PKBqVjMMFU`*i(6>hQ7c2h1)_LzR0iLv2Vj6mYPjN z`0#pXI`9idTl8TSl5e_sMN~wn$X4f%~_+w-vId^^<^hhD)8v1DdE;GcAC(x?1 z7l?^%7UVk|?7KWTj+=t~5q+@5o3t+Yii$l=T1X`%JgwVLdTf+br#BuT#UQBnz(Wt* zkeT#3r4XowXmYXHGK_s0WPJT9??`vSv1$hNi?P8y^ z%c1oFSojKyg!>CE8V*C(d6Z_|90eGKQ4chjjUbe|0vp7Up=JbBUBs63*PTdKQN#}6 zQxSQ>at5?_Um3?MlTTu+BWRBogw$y_jGAF5QV6-Sn|&2<8FF#d_Ef=WLW=gK$54Vr z%E$!rV;9)UNE~VCnCc8!hyOLT`YxlC{#&;j77bcohMBCoqL$ogH^qXQxCAK z_-G3F-&Io22qLYY1Lg^yT*F_`|2w3WC}=WTf6@!MpXTttN5}gAYYhMAD=|SvZsQ;7 zzb0Wm9B?7*ZvFvE`7+NlSQJ7)UeP0j-Ro5;^`uH-&%j;XCdCR#-be7;g7Rsu5I;j% zZ4;N_hiRUMixFSnFQC@|UT{$>RfbSn!{+EUO8u4~GGUob%RB>2s!s+a7<{gl?W_^- z?DL1}n8I^>rX)keH(>f0%uE64!2Nh-#TLxVJrbDGAt7<9J8PcH@YDVa*o5M| z8`$d3Uw=4c&>o`;@kVg@aU9C_=Q#F>Fz)PgIbq|yi;m>&Y)RgjiF;rk*Ocs#$}P=r z&%GI^WS7kvpC8c5MwpYOs@8-Wq?7-+vvH@*J6hX?ErBWva_+n6Rk z)});jf-mxe>LVi<;l^REUbeuhIJS;|V0m8AWL>WDUm(~i>0;y)Fw&iguSjYBgjxk* ziKd4qa6W;bzs8Tp&=L!yLF=yz0i0)i!$-sce**jLYHqJ_A^B zuSnLo%+V6zCKAgV13A;XCU=jt5xAk}M?p2l!0Q?aDhf3`feRA?DvtwD>IpL12rU1@ z14w87$JUR7a?~S#?G^riM@EZ5q}gopUT_NJl; zi`|b!x|s|qszN=ehlFvx-t;`qY)gHASV^@7xZah-rpl?7ZhSh$w8yol|aM3-U z>`rjI=fOXpuI$c!27>lZRbpCTl^T({XEUCC)E(3BL{5{m zr8ZscUM1;&tq)bOiX%bTu!8Eq&8FJRhr~kR6#~6RZD;$p1>u$|9jGgvH>!8tkLt%e zoX^6CpbGI(s?_6=x&&}ucP?O>K8=g%+jV`k^#1)DQYuTXQfv1aMFeD>9%ntJ{;JNy zD9^SVawi1()-KAD#rS|^D+z9;_nRHfHHztmd}_dMtIqsP8x6u_b_58%q-)Q>^fVEw%8^8u0p?VsHfAzKgUp5?QFQpUbZ+wmWEq6xd{Y&AW~h?vsa?EXVGLtd%bQY`*Vca)8PrY;6ud zWUMcVffMat1CZ!eubm+Z=<_oBg&|6GMrniQfVv0_WPa>EbK&%Dana=3Zb+t?uk}&7 z_WKpG9}URg`-4idUQ@w>9~FKz&~BQ&>>yrB11;L>QNE6Qm^{=t-@gYO>1c)^$-8L} zd?8+ALT=jSiT1x1f)y2xFnMbBJn59v246rw1Ta422YlP)!@pA&K4PW6e+|U`E=>py zbn6TL9*Ruoh)f0PtlUeMwi=WJ={)b3yJH5Vw|M18x48Rb_2vs((=ki%?i-_Pw43^x zEd9M6zQciNx8EY$xi`p3zU{P6i}>1H=_B6j4v3C{01^j~;l~nvNq4Eh6(7j1&<+sY zmYDc0fJx_|P&|1iJDyN<1HnPR8$ja+fTV{UM;2vbo>Zj(N9bKZzZ+>qR+wCQNwj(q zs1q2s^)u99O)ShSR=TioaFV{6qE|Dra|HPo)J%3252%|qJ3Eh!V| z=;~24$(Mg^6A9=SSV8>2^>0AkoSEBU(#NIIIvjA`FGN+hg(wchOr6L~vRQ3p4+S9ylnA-KVpBWSSmK%bsDYK%RB^5rxq*e)^MdQK0+s4d2H zd;QA73U)!Kt&Tp%DeB@*GEh~j!@;QR@XLh$Y66?OkkMKE8D-?4CGBG8gmmrZ-)Ra7 zzqJigL-3eG{_cEY{2`+LHF!$YJZB4YSC8UYF*M7--c~h*d|6Mrgfg|ZvYwNf13S0z|e zbHkwD%&JiWWgdEx8{b%~vxIX@op|@b0sAdWx>z#GnL@yquvG$N@i6&nS0IYfx|y4q zO>@VvP!BeNc@IjH0sBR0%_gWSW3laIj<+d}bUezr9-Sc;Wk-THKuP`=lRD2sT6Yj5 zK?qI%^c*54$RnC8=P^+<)eJ#R0y=j9ep{J2Fi3DU?%t+m{3`)@iYs>kXZ%2t^&zQJ ziErv?*`=6Nt_0{$iBg{58%rz$|2Ab)ECpS3s7JK^f?DS5WW7$jK%^C4u=&>OibHIa5!JuYesp{@vHAyK*b~4OSjwK zK(F(LksIGL@3{uoow5ZesyTDgWSwnXX|r(%nHyQ=VkOLEUA~q=G_evW&7#B%)r-au zs<&w4cApt>989QRq1Nf2R9VaOOI#{*i*^9yF};bY7iWlNqK{V)E=E-4o*h^>pL zGhabfFPN<7FQ}F;mCBZQ+#NrqY7IDBj7IO~%s(8o+T@sm^D1X2Uph#uBtN_xY`Zhc(Pet-=yvQy#$)KgFG{YoI`-(F z-n|P=bh$jmG|FS8?r``2OEUmnE~R=cwIvk3lxtFNs7<5mGU#Q1uFE5pMLjhudm$y9 zT3X-3$k6{e)SdL6_gZ)U`2nTSK(8<6W`C2)(kIx@Cc_he^UVZLZzA^s1CI?jjgG3c zHBm@e!8ATn`OA(6?_QFO{ty+@Aa`AUbfATgrwY&hp6ShD`2gB&X&&+>h4xNQxn9$2 zFN{m0IqW9PO$c$p6rzZ-WfO@ie8uv3=Fg(mbJ^q^z8peE@k6?eV#sb12W@OlIl;sQ zp(m2kKxOvXFXsh0EoAqIt;LstVL#W+Q%aOrsqT^bk~aehm+RINnP1&rXwePg8TJ(U z3E(GSo&t!-ybI&FCNN8wUwXN|+7qy4MtyD@3_6C3;Sa9{7vLOpNbLaA@KcF5uP@oW z{sTemZ^N#^h#88?unwj(GV}#kVmpOgf~7q$L*%|*>M4q)x4*+AiSrPs=P-HnYCn*q zzDU_Bl4%M#lAS;PtS)Y@&e!%-H8;iA@~9j?kdeRMMV;t@C-6x_NAeb#K$@69LRLU} zuhBG75T2>-Zd(=Yu~lo8=H3v+ArbCNmr>X zu@+Zc5qt0R(YuVi*@hbpY*=$+RyZ;)GUZ!T->&0&O0Ln3Th@%#SX!b=zTz;>?cT2~ zJwd{Y7kNBmA4@AJZ+6kZg?nBr8j&jXlFE4&RV*vpC1k5$S}T&3cfe5I(WocnoL_I{w8@6S*qn0zxXRUvh%L``y2X96t#9H0P+agEDd@?0HI%;`T zTJ$`w8(mk+j_&bSk!=iVsrqKFazO5+WsL{%T3i~NMcFs3O5MAYwN^#CuX<{4eVh1( z6EA(}Q@HnVLXoGU$IY&^i^(6a<3mQHB!&6b2#D;5NW&Z%a zFhVD#nk;m8XRUph6jDtDMlYCY8^pS(U3slodStYGKgVH- zfRmdZp7Hd)c>h1STf<_HzT}TN*WuXY?p{nvPj!52Ai3ryM$53QUEeXavq9;8w{Cuc zv9_9L`<0T0bJyjkiOcDgNkVboXDaNFzN)-NUI{YFP( z6UTAv*gE|;&of#gAOHJN?o1$Noy|TOAHFN%rYh_jS*>pG%7s2XF?Y7H95)^D(~p{H zi|>%X*b&((sWIZ`lgw!0)3~utuA_1>LOft4|qiwuFm6qFkB{$8mf8*K9W7)OMOJx2N)kr=o z=a~BV^VfzBT=-2c`IMzR4}YmQipt~~C8=(26W#rUrR&?)1`{W#+_>at8+cg<(y|kV zIGDv9Im`wt9&u;iZ_?|&J1Wb1gZr&<8rO};Yl9mz_1A0MtY_U0-eg!Ju2j1xZKJ4f zTS#|E^eeXY!!ON3G(%U^_N`AcUUn;{v8Jo9Eyjmeq(*+n_m9u*9$zZ$;AiK^uCdMg z=;Z$^vdx9tt9_F;A+W+d%7|^ne7x^T5`>1m^YedGw+(BMzENd zk7VD-NXM$~@*Q>?+;=}qTBn`x^#oT}rilBmweG+CtCAFmItP=M9ZcdnmqNT;oPF_f zW)EZDF2>^AGYf|jyF=a^O{58z{a)p7rXw8?`l9>5%9E037F%#f{Py=}P0kzKv@kEf z?d_0m)@y+ya${^0cI<+;&ZoO%r00FOwN{_Cx@b{StJ=89_^Id$o#IKw#$^{%1#k?J zOGOV}D94F}AByg5xuElD6dRfUes#zrsVsf_Iwxb!429cOD?-A02EtpMxc=LDK^|~Sx=6obAP(d>3yYnjNjWAYPL9-M%y4pcU2$x19iPTXVOV(=2>7w=%hH`|#j)e(o(3dU^l9yK_Ga<1u9q?H zRMj3GKc*)2@ad{Ar+Iw}_g6k{b)URYKAHI7;V0LP6A~Gt%xT}<%}=&;2!1oJj$-qk z#8nw`iK#_aaCrSwlOS`5r~j2nM*NKhq;Wxpk);7i#z9zXrb-Fppj;CMLNVt*0b+`~ z9hoYR%lalCSBN|m&QvA9DVkz(bxFEn&uOMAeooPWY{f#*US=V#Tc4qL^9Oy_d@Uhg;l`lhl@J79G9jR4%`aEmSbF7TjBM!#Al^#NcYUAeWWyZ|@{U4-Rd5ERe-<3Ws z-Vifxy(T24&|ppBg(A(vVI8Yf2R5b!v|e59TcxU&Oo{4%kUW69pNwVKZ6uO*r$ysj5y6^5D!9X)6&DO_0W z*#Exgdf}Ixq3?#G?8leyO(~7}IaaG7?|oy3X1dbHlhTffx_U~BPCSYDo)?}x=r4PE z_->ej%HqJd1@_@gTeVh{ix3zXw$^5NYs7G$F*8Z=UWt`0QXra_MIGhV*tcR0cg;4J zJ#0D?+pZSBp5V)MN%%}~{wmX~e#!4tJx9^_w?+2uM|NecX}~>O)wFoi<*U-)1H#8_ zv!eDGtM58cdD~wgBr|HmXl~YW{e2<*Pb6FLAsqMi|GAlfLU*1)gZ^TVccUZ8c z*Zd{>=%A&5XydnHo`_q9b`L(4_6H>G8bf$qScB=A5l~!A1!ZR?RK>+VydQwl2zT3% zyg}RzPn;(29{m>G{Xs&vxuY7c4w;->t-{K3bH}ADbHA7+Id{DPfo=*DC1Pe6^9EA|&+i3fn@y(5JHc83D(tb@{p#H)lqYR^G|!))jJjSQ;gM z_WWqEYrnAc`>tn4S{Rw_(qq(_Q{rv}zZDU=Lz)co)tA@4P%!#S$6?9nquP~+`k!OJ zoDF&Mqs8|N_Lkp)pDEhc6CZNe-de~e%jeh@d&21L+6H^Gf`L}{!JXY#`>uvL6)i|h z&*$*9Oo?YGM9fEL-EjOS4~$X1&z~H2C2=U>A~x2*ir}4b&%22a7ac%|Xu%lY z>DpQ+{GVe|%141745#?3mR_g81$_hls@H!oX{e?1Tm4+mXXqMRfB$LEB8I?grw@@% zq_h1~@5U}l!eYco%(Yx)HNhz%OPewZf+Etn+Ip^wZXR2xtHH1UJZHgRSXeNtz>b4) zZK4j^z?F2tH~1^{AQ7RDS}KN068p4OrL>f^_o=EF7)olXPD=nQ;#e?K5~!zu4~wb4 zEXNEe1%cnF5@=8J(@!v@{wMeV+?jkpr=@|i`p>>m;L+8_DPj;D-s&om;?6CmKu^v_B;Ebnrot`U|AV znR#VFU2U|=A>~QKT!TU3(CkC^EhWHUwT)M(%S8?iQ1n{d*-=q)hm<9{Qa(r!lY z;^CvYAN0Y_Z*599o3p2r2YBvI_wwQL6aPlOE5XGT45|-Z`P*RT>HQn|URI6{Hdavk z9bE*tKVrcggu+6U6}@yNi@>fu6qV$ur+~BrilmPuOy~>rLY?pgI|PA{vL#@$xj0lAGd)@G8Rzo6vOH}(kX_N!;yI?W2WS@FzbIUM zH;BcSd>9OrMNkeBu^)(^--*C~z~Tq!!dIU9lK~~97*XG5g~awLh+OUkuvZ98C&M$? zu`AJFQ)WAI?=FBQx9?6rZ%4v0M7Ob&fN5wS$Z_;2Sl}m#coYoM{Hl`SXeK9sXh?9d z1LQPxaKh`lI5>Mi?M`#UFWsIp$Pa=<3210nfx%xAL<2uX*F9G5cz{Z2F97=!5Ug+> zF60gaT8$wZ3ufMCIR?@IbpQ(=+_l1}A*W{u8c^_P8b@$&g{J4JH92#uyZ7YJ$$F4r z>aWIN)L`oV-hc*sY6>xMfEIgF)_Trk4}15M#SCEGEY?lznoY~W&eT{QsP4Zz@B zFavCy-!*2l-4nczM0D{a;P7}a;QK&bSa*&8V#;75Ig7k18o@Cu7{e(95Zv{RC)eI>Ii5P)H zgF~+4fQVsFz+2g9y5OwHFL^|2q!_V0bmdYE<_egj0S~ALiI|T^gGBaJvcJqsp0;xn z~c>e`1O*oz* z2n)d$FS29x~**iuy8Vd zA)^Q=?Q{Vv@ymWxMm!cNdqxd+eYI^+N&n+W~+T0ki}GiF%NTDwojU(K3-X zHqPFO205M#T-b~yz-!Kcv4l!rhWTak(Y@#EhdG#GPn^3U8zZp0QE z0gWU#BGDxC{{jtpJM)K#EcS*mV;dN)0^p>-)8{tc?}?CVQ~5%(ZG@C8hyO2ssrB9W;XTNff1{G9}A>G!okpq!9hOJ z+#b8T5*(cEB*6Wtt%IE>VQRLNaKd|7fy%O#BxFfsT)4N>?$LR0!gG@W0P}xlza_ME=?fs1Do59<)+Cgpz zPekKEri1c!6rj$}GeS#n$SR;_E-)~BDiK`3fC7o^`1@cvFR-nb1MUyy#K;rBaU@W) zIWL7Qp2RIggGdgtu7C}A@^k_v!Lum`MFr$r?Pf+Xo)ZlioEeZsY2I;%q#^R1Xft3H zTz>&JyBsyQZpbZSXW&GnP{C2T0raBgyrA?2rXBKzu}BS(TQ1H(?gw#ye!oPJf+qgZ zV*_%-y&2S}GH6hzf)ApqK#%^A;~=+tn!zlH|@fVC+y{C~w+uuBas3S>9rMkX^TtCi8HL?#@b{D1mpg+#1m;y + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-designschema + + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-jitengine-formmetadata + + + com.inspur.edp + cef-designtime-api + system + 0.2.14 + ${pom.basedir}/libs/com.inspur.edp.cef.designtime.api.jar + + + com.inspur.edp + web-designschema-api + + + com.inspur.edp + formserver-viewmodel + system + ${pom.basedir}/libs/com.inspur.edp.formserver.viewmodel.jar + + + com.inspur.edp + udt-designtime-api + 0.1.7 + system + ${pom.basedir}/libs/com.inspur.edp.udt.designtime.api.jar + + + com.inspur.edp + das-commonmodel + 0.1.7 + system + ${pom.basedir}/libs/com.inspur.edp.das.commonmodel.jar + + + + com.inspur.edp + caf-cef-schema + 0.1.7 + system + ${pom.basedir}/libs/caf-cef-schema.jar + + + com.inspur.edp + bef-bizentity + 0.2.17 + + + com.inspur.edp + cef-api + 0.2.85 + compile + + + com.inspur.edp + cef-api + 0.2.32 + compile + + + + + diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/config/DesignSchemaConfiguration.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/config/DesignSchemaConfiguration.java new file mode 100644 index 00000000..dc7d934b --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/config/DesignSchemaConfiguration.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.designschema.config; + +import com.inspur.edp.web.designschema.webservice.DesignSchemaWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/16 + */ +@Configuration("com.inspur.edp.web.designschema.config.DesignSchemaConfiguration") +public class DesignSchemaConfiguration { + @Bean() + public RESTEndpoint designSchemaWebServiceEndpoint(){ + return new RESTEndpoint("/dev/main/v1.0/designschema", new DesignSchemaWebServiceImpl()); + } +} + + diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/ComplexField.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/ComplexField.java new file mode 100644 index 00000000..df53e1a6 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/ComplexField.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.designschema.elements; + +/** + * 复杂类型字段,如:实体、值对象、枚举类型等。 + * @author noah + */ +public class ComplexField extends Field { + public ComplexField(){ + super("ComplexField"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/DynamicField.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/DynamicField.java new file mode 100644 index 00000000..846d31b4 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/DynamicField.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.designschema.elements; + +/** + * 动态field + * @author noah + */ +public class DynamicField extends Field +{ + public DynamicField(){ + super("DynamicField"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Entity.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Entity.java new file mode 100644 index 00000000..edb0925c --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Entity.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.designschema.elements; + +import com.inspur.edp.web.designschema.elements.type.EntityType; + +/** + * 实体元素 + * @author noah + */ +public class Entity { + /** + * 实体标识 + */ + private String Id; + + public final String getId() { + return Id; + } + + public final void setId(String value) { + Id = value; + } + + /** + * 实体编号 + */ + private String Code; + + public final String getCode() { + return Code; + } + + public final void setCode(String value) { + Code = value; + } + + /** + * 实体名称 + */ + private String Name; + + public final String getName() { + return Name; + } + + public final void setName(String value) { + Name = value; + } + + /** + * 实体标签,即别名 + */ + private String Label; + + public final String getLabel() { + return Label; + } + + public final void setLabel(String value) { + Label = value; + } + + /** + * 实体类型描述 + */ + private EntityType Type; + + public final EntityType getType() { + return Type; + } + + public final void setType(EntityType value) { + Type = value; + } +} \ No newline at end of file diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Field.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Field.java new file mode 100644 index 00000000..899efdbd --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Field.java @@ -0,0 +1,123 @@ +package com.inspur.edp.web.designschema.elements; + +import com.inspur.edp.web.designschema.elements.type.FieldType; + +/** + * 字段元素 + * @author noah + */ +public class Field { + + public Field(){} + + public Field(String _$type) { + this.$type = _$type; + } + + private String Id; + + public final String getId() { + return Id; + } + + public final void setId(String value) { + Id = value; + } + + + private String OriginalId; + + public final String getOriginalId() { + return OriginalId; + } + + public final void setOriginalId(String value) { + OriginalId = value; + } + + + private String Code; + + public final String getCode() { + return Code; + } + + public final void setCode(String value) { + Code = value; + } + + + private String Name; + + public final String getName() { + return Name; + } + + public final void setName(String value) { + Name = value; + } + + + private String Label; + + public final String getLabel() { + return Label; + } + + public final void setLabel(String value) { + Label = value; + } + + + private String BindingField; + + public final String getBindingField() { + return BindingField; + } + + public final void setBindingField(String value) { + BindingField = value; + } + + + private FieldType Type; + + public final FieldType getType() { + return Type; + } + + public final void setType(FieldType value) { + Type = value; + } + + + private String Path; + + public final String getPath() { + return Path; + } + + public final void setPath(String value) { + Path = value; + } + private String BindingPath; + + public final String getBindingPath() { + return BindingPath; + } + + public final void setBindingPath(String value) { + BindingPath = value; + } + + private String $type; + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } + +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Schema.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Schema.java new file mode 100644 index 00000000..49bc10fe --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Schema.java @@ -0,0 +1,93 @@ +package com.inspur.edp.web.designschema.elements; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.*; + +/** + * 表单Schema元素 + */ +@Data +public class Schema { + private String Id; + + public final String getId() { + return Id; + } + + public final void setId(String value) { + Id = value; + } + + private String Code; + + public final String getCode() { + return Code; + } + + public final void setCode(String value) { + Code = value; + } + + private String Name; + + public final String getName() { + return Name; + } + + public final void setName(String value) { + Name = value; + } + + private String SourceUri; + + public final String getSourceUri() { + return SourceUri; + } + + public final void setSourceUri(String value) { + SourceUri = value; + } + + private String SourceType; + + public final String getSourceType() { + return SourceType; + } + + public final void setSourceType(String value) { + SourceType = value; + } + + private ArrayList Entities = new ArrayList<>(); + + public final ArrayList getEntities() { + return Entities; + } + + public final void setEntities(ArrayList value) { + Entities = value; + } + + private ArrayList Variables = new ArrayList<>(); + + public final ArrayList getVariables() { + return Variables; + } + + public final void setVariables(ArrayList value) { + Variables = value; + } + + @JsonProperty("extendProperties") + public HashMap ExtendProperties = new HashMap<>(); + + public HashMap getExtendProperties() { + return ExtendProperties; + } + + public void setExtendProperties(HashMap extendProperties) { + ExtendProperties = extendProperties; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/SimpleField.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/SimpleField.java new file mode 100644 index 00000000..7f3eb45d --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/SimpleField.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.designschema.elements; + +import com.inspur.edp.web.designschema.elements.editor.DefaultEditor; +import com.inspur.edp.web.designschema.elements.editor.FieldEditor; + +/** + * 简单类型字段,如:字符串、数字、日期、布尔类型等。 + */ +public class SimpleField extends Field { + + public SimpleField(){ + super("SimpleField"); + } + + private String DefaultValue; + + public final String getDefaultValue() { + return DefaultValue; + } + + public final void setDefaultValue(String value) { + DefaultValue = value; + } + + + private boolean Require; + + public final boolean getRequire() { + return Require; + } + + public final void setRequire(boolean value) { + Require = value; + } + + + private boolean Readonly; + + public final boolean getReadonly() { + return Readonly; + } + + public final void setReadonly(boolean value) { + Readonly = value; + } + + + private FieldEditor Editor = new DefaultEditor(); + + public final FieldEditor getEditor() { + return Editor; + } + + public final void setEditor(FieldEditor value) { + Editor = value; + } + + + private boolean MultiLanguage = false; + + public final boolean getMultiLanguage() { + return MultiLanguage; + } + + public final void setMultiLanguage(boolean value) { + MultiLanguage = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Variable.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Variable.java new file mode 100644 index 00000000..dfaa1b4e --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/Variable.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.designschema.elements; + +/** + * 变量定义 + * @author noah + */ +public class Variable { + private String Id; + + public final String getId() { + return Id; + } + + public final void setId(String value) { + Id = value; + } + + private String Code; + + public final String getCode() { + return Code; + } + + public final void setCode(String value) { + Code = value; + } + + private String Name; + + public final String getName() { + return Name; + } + + public final void setName(String value) { + Name = value; + } + + private String Type; + + public final String getType() { + return Type; + } + + public final void setType(String value) { + Type = value; + } +} \ No newline at end of file diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/CheckBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/CheckBox.java new file mode 100644 index 00000000..ab2c6a2c --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/CheckBox.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * checkbox 编辑器 + * @author noah + */ +public class CheckBox extends FieldEditor { + public CheckBox() { + super("CheckBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DataSource.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DataSource.java new file mode 100644 index 00000000..e362f798 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DataSource.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * datasource 数据源实体配置 + * @author noah + */ +public class DataSource { + private String Uri; + + public final String getUri() { + return Uri; + } + + public final void setUri(String value) { + Uri = value; + } + + private String DisplayName; + + public final String getDisplayName() { + return DisplayName; + } + + public final void setDisplayName(String value) { + DisplayName = value; + } + + private String IdField; + + public final String getIdField() { + return IdField; + } + + public final void setIdField(String value) { + IdField = value; + } + + private String Type; + + public final String getType() { + return Type; + } + + public final void setType(String value) { + Type = value; + } +} \ No newline at end of file diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DateBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DateBox.java new file mode 100644 index 00000000..214042a2 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DateBox.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * datebox 实体 + * @author noah + */ +public class DateBox extends FieldEditor { + private String Format; + + public final String getFormat() { + return Format; + } + + public final void setFormat(String value) { + Format = value; + } + + public DateBox() { + super("DateBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DefaultEditor.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DefaultEditor.java new file mode 100644 index 00000000..0d9c9037 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/DefaultEditor.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * 同步schema 默认editor + * @author noah + */ +public class DefaultEditor extends FieldEditor { + public DefaultEditor() { + super("DefaultEditor"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/EnumField.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/EnumField.java new file mode 100644 index 00000000..e61e3ac4 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/EnumField.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * 枚举字段 + * @author noah + */ +public class EnumField extends FieldEditor { + + public EnumField() { + super("EnumField"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/FieldEditor.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/FieldEditor.java new file mode 100644 index 00000000..93c2fd5f --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/FieldEditor.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.designschema.elements.editor; + +/** + * 字段编辑器类型 + * @author noah + */ +public class FieldEditor { + private String $type; + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } + + protected FieldEditor(String _$type) { + this.$type = _$type; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LanguageTextBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LanguageTextBox.java new file mode 100644 index 00000000..1b470d5d --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LanguageTextBox.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class LanguageTextBox extends FieldEditor { + public LanguageTextBox() { + super("LanguageTextBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LookupEdit.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LookupEdit.java new file mode 100644 index 00000000..cd49e56e --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/LookupEdit.java @@ -0,0 +1,112 @@ +package com.inspur.edp.web.designschema.elements.editor; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.inspur.edp.cdp.common.utils.json.JsonUtil; + +import java.io.IOException; +import java.util.HashMap; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class LookupEdit extends FieldEditor { + private String HelpId; + + public final String getHelpId() { + return HelpId; + } + + public final void setHelpId(String value) { + HelpId = value; + } + + private String Uri; + + public final String getUri() { + return Uri; + } + + public final void setUri(String value) { + Uri = value; + } + + private String TextField; + + public final String getTextField() { + return TextField; + } + + public final void setTextField(String value) { + TextField = value; + } + + private String ValueField; + + public final String getValueField() { + return ValueField; + } + + public final void setValueField(String value) { + ValueField = value; + } + + private String DisplayType; + + public final String getDisplayType() { + return DisplayType; + } + + public final void setDisplayType(String value) { + DisplayType = value; + } + + private DataSource DataSource; + + public final DataSource getDataSource() { + return DataSource; + } + + public final void setDataSource(DataSource value) { + DataSource = value; + } + + private HashMap Map; + + @JsonSerialize(using = MapFieldsSerializer.class) + @JsonProperty(value = "mapFields") + public final HashMap getMap() { + return Map; + } + + public final void setMap(HashMap value) { + Map = value; + } + + @JsonInclude(JsonInclude.Include.NON_NULL) + private JsonNode options; + + public final JsonNode getOptions() { + return options; + } + + public final void setOptions(JsonNode options) { + this.options = options; + } + + public LookupEdit() { + super("LookupEdit"); + } +} + +class MapFieldsSerializer extends JsonSerializer> { + + @Override + public void serialize(HashMap map, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + String mapString = JsonUtil.toJson(map); + jsonGenerator.writeString(mapString); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/MultiTextBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/MultiTextBox.java new file mode 100644 index 00000000..406c8226 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/MultiTextBox.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class MultiTextBox extends FieldEditor { + public MultiTextBox() { + super("MultiTextBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/NumericBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/NumericBox.java new file mode 100644 index 00000000..8d5b1b95 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/NumericBox.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class NumericBox extends FieldEditor { + public NumericBox() { + super("NumericBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/RadioGroup.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/RadioGroup.java new file mode 100644 index 00000000..38eaab59 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/RadioGroup.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class RadioGroup extends FieldEditor { + public RadioGroup() { + super("RadioGroup"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/SwitchField.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/SwitchField.java new file mode 100644 index 00000000..d6ebb8b0 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/SwitchField.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class SwitchField extends FieldEditor { + public SwitchField() { + super("SwitchField"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/TextBox.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/TextBox.java new file mode 100644 index 00000000..1cdc6e34 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/editor/TextBox.java @@ -0,0 +1,8 @@ +package com.inspur.edp.web.designschema.elements.editor; + +public class TextBox extends FieldEditor { + + public TextBox() { + super("TextBox"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BigNumericType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BigNumericType.java new file mode 100644 index 00000000..7680cc46 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BigNumericType.java @@ -0,0 +1,56 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 大数类型 + * @author noah + */ +public class BigNumericType extends FieldType { + + public BigNumericType(){ + super("BigNumericType"); + } + + private String Name = "BigNumber"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "大数字"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } + + private int Length; + + public final int getLength() { + return Length; + } + + public final void setLength(int value) { + Length = value; + } + + private int Precision; + + public final int getPrecision() { + return Precision; + } + + public final void setPrecision(int value) { + Precision = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BooleanType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BooleanType.java new file mode 100644 index 00000000..21a7ddbf --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/BooleanType.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * @author noah + */ +public class BooleanType extends FieldType { + public BooleanType(){ + super("BooleanType"); + } + private String Name = "Boolean"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "布尔"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateTimeType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateTimeType.java new file mode 100644 index 00000000..0b421102 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateTimeType.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 日期类型 + * @author noah + */ +public class DateTimeType extends FieldType { + + public DateTimeType(){ + super("DateTimeType"); + } + private String Name = "DateTime"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "日期时间"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateType.java new file mode 100644 index 00000000..c7abe660 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DateType.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 日期类型 + * @author noah + */ +public class DateType extends FieldType { + public DateType() + { + super("DateType"); + } + private String Name = "Date"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "日期"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DynamicObjectType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DynamicObjectType.java new file mode 100644 index 00000000..3137b977 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/DynamicObjectType.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 动态对象类型 + * @author noah + */ +public class DynamicObjectType extends FieldType { + public DynamicObjectType(){ + super("DynamicObjectType"); + } + private String Name = "DynamicEntity"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EntityType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EntityType.java new file mode 100644 index 00000000..28ba294a --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EntityType.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.designschema.elements.type; + +import com.inspur.edp.web.designschema.elements.Entity; +import com.inspur.edp.web.designschema.elements.Field; + +import java.util.ArrayList; +import java.util.List; + +/** + * 实体类型 + * @author noah + */ +public class EntityType extends FieldType { + + public EntityType() { + super("EntityType"); + } + + private String Primary; + + public final String getPrimary() { + return Primary; + } + + public final void setPrimary(String value) { + Primary = value; + } + + private List Fields = new ArrayList<>(); + + public final List getFields() { + return Fields; + } + + public final void setFields(List value) { + Fields = value; + } + + private List Entities = new ArrayList<>(); + + public final List getEntities() { + return Entities; + } + + public final void setEntities(List value) { + Entities = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumItem.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumItem.java new file mode 100644 index 00000000..c34ff69f --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumItem.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 枚举项定义 + * @author noah + */ +public class EnumItem { + + private String Value; + + public final String getValue() { + return Value; + } + + public final void setValue(String value) { + Value = value; + } + + private String Name; + + public final String getName() { + return Name; + } + + public final void setName(String value) { + Name = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumType.java new file mode 100644 index 00000000..346f85c7 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/EnumType.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.designschema.elements.type; + +import java.util.ArrayList; + +/** + * 枚举类型 + * @author noah + */ +public class EnumType extends FieldType { + + public EnumType() { + super("EnumType"); + } + + private String Name = "Enum"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "枚举"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } + + private FieldType ValueType; + + public final FieldType getValueType() { + return ValueType; + } + + public final void setValueType(FieldType value) { + ValueType = value; + } + + //public Dictionary EnumValues { get; set; } = new Dictionary(); + + private ArrayList EnumValues = new ArrayList<>(); + + public final ArrayList getEnumValues() { + return EnumValues; + } + + public final void setEnumValues(ArrayList value) { + EnumValues = value; + } + +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/FieldType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/FieldType.java new file mode 100644 index 00000000..ff817053 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/FieldType.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.designschema.elements.type; + +/** + * 字段类型 + * @author noah + */ +public class FieldType { + private String $type; + + public String get$type() { + return $type; + } + + public void set$type(String $type) { + this.$type = $type; + } + + + public FieldType() { + + } + public FieldType(String _$type) { + this.$type = _$type; + } + + private String Name; + + public String getName() { + return Name; + } + + public void setName(String value) { + Name = value; + } + + private String DisplayName; + + public String getDisplayName() { + return DisplayName; + } + + public void setDisplayName(String value) { + DisplayName = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/HierarchyType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/HierarchyType.java new file mode 100644 index 00000000..c19889fe --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/HierarchyType.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.designschema.elements.type; + +public class HierarchyType extends ObjectType { + public HierarchyType() { + super("HierarchyType"); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/NumericType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/NumericType.java new file mode 100644 index 00000000..2473c54e --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/NumericType.java @@ -0,0 +1,51 @@ +package com.inspur.edp.web.designschema.elements.type; + +public class NumericType extends FieldType { + public NumericType() { + super("NumericType"); + } + + private String Name = "Number"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "数字"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } + + private int Length; + + public final int getLength() { + return Length; + } + + public final void setLength(int value) { + Length = value; + } + + private int Precision; + + public final int getPrecision() { + return Precision; + } + + public final void setPrecision(int value) { + Precision = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/ObjectType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/ObjectType.java new file mode 100644 index 00000000..e18eec92 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/ObjectType.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.designschema.elements.type; + +import com.inspur.edp.web.designschema.elements.Field; + +import java.util.ArrayList; +import java.util.List; + +public class ObjectType extends FieldType { + public ObjectType() { + super("ObjectType"); + } + + public ObjectType(String _$type) { + super(_$type); + } + + private String Name; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private List Fields = new ArrayList<>(); + + public final List getFields() { + return Fields; + } + + public final void setFields(List value) { + Fields = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/StringType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/StringType.java new file mode 100644 index 00000000..bf07cb51 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/StringType.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.designschema.elements.type; + +public class StringType extends FieldType { + public StringType() { + super("StringType"); + } + + private int Length; + + public final int getLength() { + return Length; + } + + public final void setLength(int value) { + Length = value; + } + + private String Name = "String"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "字符串"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } + + +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/TextType.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/TextType.java new file mode 100644 index 00000000..3480e714 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/elements/type/TextType.java @@ -0,0 +1,41 @@ +package com.inspur.edp.web.designschema.elements.type; + +public class TextType extends FieldType { + public TextType() { + super("TextType"); + } + + private String Name = "Text"; + + @Override + public String getName() { + return Name; + } + + @Override + public void setName(String value) { + Name = value; + } + + private String DisplayName = "文本"; + + @Override + public String getDisplayName() { + return DisplayName; + } + + @Override + public void setDisplayName(String value) { + DisplayName = value; + } + + private int Length; + + public final int getLength() { + return Length; + } + + public final void setLength(int value) { + Length = value; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/EntityBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/EntityBuilder.java new file mode 100644 index 00000000..01fcc869 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/EntityBuilder.java @@ -0,0 +1,87 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.das.commonmodel.IGspCommonObject; +import com.inspur.edp.formserver.viewmodel.GspViewModelElement; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.designschema.elements.Entity; +import com.inspur.edp.web.designschema.elements.Field; +import com.inspur.edp.web.designschema.elements.type.EntityType; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 实体builder + * @author noah + */ +public class EntityBuilder { + + public final Entity Build(IGspCommonObject commonObject) { + return Build(commonObject, null); + } + public final Entity Build(IGspCommonObject commonObject, String scene) { + return Build(commonObject, scene, false); + } + + public final Entity Build(IGspCommonObject commonObject, String scene, boolean isRuntime) { + Entity tempVar = new Entity(); + tempVar.setId(commonObject.getID()); + tempVar.setCode(commonObject.getCode()); + tempVar.setName(commonObject.getName()); + tempVar.setLabel(StringUtility.toCamelCase(commonObject.getCode()) + "s"); + tempVar.setType(this.GenerateEntityType(commonObject, scene, isRuntime)); + return tempVar; + } + + + private EntityType GenerateEntityType(IGspCommonObject viewObject, boolean isRuntime) { + return GenerateEntityType(viewObject, null, isRuntime); + } + + private EntityType GenerateEntityType(IGspCommonObject viewObject, String scene, boolean isRuntime) { + this.VerifyViewObject(viewObject); + + FieldBuilder fieldBuilder = new FieldBuilder(); + EntityBuilder entityBuilder = new EntityBuilder(); + + List fields = viewObject.getContainElements() + .stream() + .map((e) -> { + if (e instanceof GspViewModelElement) { + GspViewModelElement gspViewModelElement = (GspViewModelElement) e; + Field f = fieldBuilder.build(gspViewModelElement, null, scene, isRuntime); + return f; + } else if (e instanceof SimpleDataTypeDef) { + SimpleDataTypeDef simpleDataTypeDef = (SimpleDataTypeDef) e; + return fieldBuilder.build(simpleDataTypeDef, null, scene); + } else { + return fieldBuilder.build(e, null, scene); + } + + }).collect(Collectors.toList()); + + //N转J N版代码 LINQ + List entities = viewObject.getContainChildObjects() + .stream() + .map(childObject -> { + Entity entity = entityBuilder.Build(childObject, scene, isRuntime); + return entity; + }).collect(Collectors.toList()); + + EntityType tempVar = new EntityType(); + tempVar.setName(viewObject.getCode()); + tempVar.setDisplayName(viewObject.getName()); + tempVar.setPrimary(StringUtility.toCamelCase(viewObject.getIDElement().getLabelID())); + tempVar.setFields(fields); + tempVar.setEntities(entities); + return tempVar; + } + + private void VerifyViewObject(IGspCommonObject viewObject) { + if (viewObject.getIDElement() == null) { + throw new GSPException("", String.format("标识为'%1$s'的视图对象'%2$s'的IDElement属性不允许为null。", viewObject, viewObject.getName())); + } + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldBuilder.java new file mode 100644 index 00000000..5067733c --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldBuilder.java @@ -0,0 +1,630 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.bef.bizentity.GspBizEntityElement; +import com.inspur.edp.bef.bizentity.GspBizEntityObject; +import com.inspur.edp.bef.bizentity.GspBusinessEntity; +import com.inspur.edp.cef.api.RefObject; +import com.inspur.edp.cef.designtime.api.IGspCommonField; +import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection; +import com.inspur.edp.cef.designtime.api.element.GspAssociation; +import com.inspur.edp.cef.designtime.api.element.GspElementObjectType; +import com.inspur.edp.formserver.viewmodel.GspViewModelElement; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.RefCommonService; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.udt.designtime.api.nocode.BusinessField; +import com.inspur.edp.udt.designtime.api.nocode.IBusinessFieldService; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.designschema.elements.ComplexField; +import com.inspur.edp.web.designschema.elements.Field; +import com.inspur.edp.web.designschema.elements.SimpleField; +import com.inspur.edp.web.designschema.elements.editor.*; +import com.inspur.edp.web.designschema.elements.type.EntityType; +import com.inspur.edp.web.designschema.elements.type.FieldType; +import com.inspur.edp.web.designschema.elements.type.ObjectType; +import com.inspur.edp.web.designschema.udtextensiondef.FormUdtExtension; +import io.iec.edp.caf.commons.exception.CAFRuntimeException; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import org.springframework.util.StringUtils; + +import java.util.*; + +/** + * 字段构造 + * + * @author noah + */ +public class FieldBuilder { + private final FieldTypeBuilder fieldTypeBuilder; + + public FieldBuilder() { + this.fieldTypeBuilder = new FieldTypeBuilder(this); + } + + /** + * 运行时定制也进行了调用 不可随意更改参数及方法名大小写 + * + * @param element + * @param parentTypeBuildingContext + * @param scene + * @return + */ + public final Field build(IGspCommonField element, TypeBuildingContext parentTypeBuildingContext, String scene) { + TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext); + return this.build(elementContext, parentTypeBuildingContext, scene); + } + + public final Field build(GspViewModelElement element, TypeBuildingContext parentTypeBuildingContext, String scene, boolean isRuntime) { + TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext, isRuntime); + return this.build(elementContext, parentTypeBuildingContext, scene); + } + + /** + * 保留此方法 运行时定制会进行调用 + * + * @param element + * @param parentTypeBuildingContext + * @param scene + * @return + */ + public final Field build(GspViewModelElement element, TypeBuildingContext parentTypeBuildingContext, String scene) { + TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext); + return this.build(elementContext, parentTypeBuildingContext, scene); + } + + public final Field build(SimpleDataTypeDef element, TypeBuildingContext parentTypeBuildingContext, String scene) { + TypeBuildingContext elementContext = TypeBuildingContext.Create(element, parentTypeBuildingContext); + return this.build(elementContext, parentTypeBuildingContext, scene); + } + + public Field build(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, String scene) { + String bindingFieldPrefix = this.getBindingFieldPrefix(parentTypeBuildingContext); + String id = elementContext.Get("Id", String.class); + String code = elementContext.Get("Code", String.class); + String name = elementContext.Get("Name", String.class); + String label = elementContext.Get("Label", String.class); + boolean multiLanguageInput = elementContext.Get("MultiLanguageInput", Boolean.class); + + String generatedBindingField = String.format("%1$s%2$s", bindingFieldPrefix, label); + elementContext.getParams().put("BindingField", generatedBindingField); + + + String revisedElementId = elementContext.ReviseElementId(id); + elementContext.getParams().put("Id", revisedElementId); + + String generatedFieldPath = this.generateFieldPath(elementContext, parentTypeBuildingContext); + elementContext.getParams().put("Path", generatedFieldPath); + + String generatedBindingPath = this.GenerateBindingPath(elementContext, parentTypeBuildingContext); + elementContext.getParams().put("BindingPath", generatedBindingPath); + + if (elementContext.getHasAssociation() || elementContext.getHasUnifiedDataType() || elementContext.getIsDynamicField()) { + ComplexField tempVar = new ComplexField(); + tempVar.setId(revisedElementId); + tempVar.setOriginalId(id); + tempVar.setCode(code); + tempVar.setName(name); + tempVar.setLabel(StringUtility.toCamelCase(label)); + tempVar.setBindingField(StringUtility.toCamelCase(generatedBindingField)); + tempVar.setPath(generatedFieldPath); + tempVar.setBindingPath(generatedBindingPath); + tempVar.setType(this.fieldTypeBuilder.GenerateFieldType(elementContext, parentTypeBuildingContext, scene)); + if (elementContext != null && elementContext.getHasUnifiedDataType() && !elementContext.getIsRefElement()) { + this.handleUdtExtend(tempVar, elementContext); + } else if (elementContext != null && elementContext.getHasBusiFieldId() && !elementContext.getIsRefElement()) { + this.handleBusiFieldExtent(tempVar, elementContext); + } + return tempVar; + } + boolean require = elementContext.Get("Require", Boolean.class); + String defaultValue = elementContext.Get("DefaultValue", String.class); + boolean isReadOnly = elementContext.Get("Readonly", Boolean.class); + SimpleField tempVar2 = new SimpleField(); + tempVar2.setId(revisedElementId); + tempVar2.setOriginalId(id); + tempVar2.setCode(code); + tempVar2.setName(name); + tempVar2.setLabel(StringUtility.toCamelCase(label)); + tempVar2.setBindingField(StringUtility.toCamelCase(generatedBindingField)); + tempVar2.setPath(generatedFieldPath); + tempVar2.setBindingPath(generatedBindingPath); + tempVar2.setRequire(require); + tempVar2.setReadonly(isReadOnly); + tempVar2.setDefaultValue(defaultValue); + tempVar2.setMultiLanguage(multiLanguageInput); + tempVar2.setType(this.fieldTypeBuilder.GenerateFieldType(elementContext, parentTypeBuildingContext, scene)); + tempVar2.setEditor(this.GenerateFieldEditor(elementContext, scene)); + return tempVar2; + } + + protected final String getBindingFieldPrefix(TypeBuildingContext context) { + String prefix = ""; + + if (context != null) { + String bindingField = context.Get("BindingField", String.class); + if (bindingField != null) { + prefix = String.format("%1$s_", bindingField); + } + } + return prefix; + } + + + protected final String generateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext) { + return generateFieldPath(elementContext, parentTypeBuildingContext, false); + } + + //C# TO JAVA CONVERTER NOTE: Java does not support optional parameters. Overloaded method(s) are created above: +//ORIGINAL LINE: protected string GenerateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, bool toCamel = false) + protected final String generateFieldPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext, boolean toCamel) { + String fieldPath = elementContext.Get("Label", String.class); + // 如果已经在Context中预制了BindingPath,直接返回预制结果。 + // 适用于BE关联类型字段中存储自身值的特殊字段场景。 + String presetPath = elementContext.Get("Path", String.class); + if (elementContext.getHasPresetValue() && !StringUtility.isNullOrEmpty(presetPath)) { + fieldPath = presetPath; + } + //var label = elementContext.Get("Label"); + if (toCamel) { + fieldPath = StringUtility.toCamelCase(fieldPath); + } + String prefix = ""; + if (parentTypeBuildingContext != null) { + prefix = parentTypeBuildingContext.Get("Path", String.class); + } + if (!StringUtility.isNullOrEmpty(prefix)) { + return String.format("%1$s.%2$s", prefix, fieldPath); + } + return fieldPath; + } + + protected final String GenerateBindingPath(TypeBuildingContext elementContext, TypeBuildingContext parentTypeBuildingContext) { + String label = StringUtility.toCamelCase(elementContext.Get("Label", String.class)); + // 如果已经在Context中预制了BindingPath,直接返回预制结果。 + // 适用于BE关联类型字段中存储自身值的特殊字段场景。 + String presetBindingPath = elementContext.Get("BindingPath", String.class); + if (elementContext.getHasPresetValue() && !StringUtility.isNullOrEmpty(presetBindingPath)) { + label = presetBindingPath; + } + + String prefix = ""; + if (parentTypeBuildingContext != null) { + prefix = parentTypeBuildingContext.Get("BindingPath", String.class); + } + if (!StringUtility.isNullOrEmpty(prefix)) { + return String.format("%1$s.%2$s", prefix, label); + } + return label; + } + + protected final FieldEditor GenerateFieldEditor(TypeBuildingContext context, String scene) { + if (context.getObjectType() == GspElementObjectType.Enum) { + return new EnumField(); + } else if (context.getIsMultiLanguageField()) { + return new LanguageTextBox(); + } else if (context.getObjectType() == GspElementObjectType.None) { + switch (context.getDataType()) { + case Boolean: + if (!StringUtility.isNullOrEmpty(scene) && "mobile".equals(scene)) { + return new SwitchField(); + } + return new CheckBox(); + case Date: + case DateTime: + DateBox tempVar = new DateBox(); + tempVar.setFormat("'yyyy-MM-dd'"); + return tempVar; + case Decimal: + case Integer: + return new NumericBox(); + case Text: + return new MultiTextBox(); + default: + return new TextBox(); + } + } else { + return new TextBox(); + } + } + + /** + * + */ + private void handleBusiFieldExtent(ComplexField bizField, TypeBuildingContext elementContext) { + FormUdtExtension extendProperty = elementContext.Get("ExtendBusiFieldProp", FormUdtExtension.class); + if (extendProperty == null) { + return; + } + + String beBindingFieldId = extendProperty.getControlBindingFieldId(); + if (beBindingFieldId == null) { + return; + } + + EntityType entityType = (EntityType) bizField.getType(); + if (entityType == null || entityType.getFields().size() == 0) { + return; + } + + Map bizFieldsMap = getBizFieldMap(bizField); + IGspCommonField helpField = null; + if (bizField != null && !bizFieldsMap.isEmpty()) { + // 需要找出业务字段对应的实体上的原本字段。 + RefObject schemaFieldRef = new RefObject<>(null); + String schemaBindingFieldId = transferBindingFieldId(beBindingFieldId, bizField, elementContext, schemaFieldRef); +// List associations = elementContext.getAssociations(); +// if (associations != null && associations.size() > 0) { +// GspAssociation gspAssociation = associations.get(0); +// if (gspAssociation != null) { +// List refElementCollections = gspAssociation.getRefElementCollection(); +// if (refElementCollections != null && refElementCollections.size() > 0) { +// helpField = refElementCollections.stream().filter(item -> { +// return beBindingFieldId.equals(item.getRefElementId()); +// }).findFirst().orElse(null); +// } +// } +// } +// if (helpField != null) { +// List childAssoFields = entityType.getFields(); +// for (int i = 0; i < childAssoFields.size(); i++) { +// Field field = childAssoFields.get(i); +// if (helpField.getID().equals(field.getId())) { +// setBusiFieldEditor(field, extendProperty, elementContext, bizFieldsMap); +// break; +// } +// } +// } + if (schemaBindingFieldId != null) { + setBusiFieldEditor(schemaFieldRef.argvalue, extendProperty, elementContext, bizFieldsMap); + } + } + } + + private Map getBizFieldMap(ComplexField complexField) { + Map bizFieldsMap = new HashMap<>(); + FieldType type = complexField.getType(); + List children = new ArrayList<>(); + if (type instanceof ObjectType) { + children = ((ObjectType) type).getFields(); + } else if (type instanceof EntityType) { + children = ((EntityType) type).getFields(); + } + if (children != null && children.size() > 0) { + List finalChildren = children; + Queue queue = new LinkedList() {{ + addAll(finalChildren); + }}; + + while (!queue.isEmpty()) { + Field field = queue.poll(); + bizFieldsMap.put(field.getCode(), field.getBindingPath()); + if (field instanceof ComplexField) { + FieldType childType = field.getType(); + if (childType instanceof ObjectType) { + List childFields = ((ObjectType) childType).getFields(); + for (Field childField : childFields) { + childField.setCode(field.getCode() + '.' + childField.getCode()); + } + queue.addAll(childFields); + } else if (childType instanceof EntityType) { + List childFields = ((EntityType) childType).getFields(); + for (Field childField : childFields) { + childField.setCode(field.getCode() + '.' + childField.getCode()); + } + queue.addAll(childFields); + } + } + } + } + + return bizFieldsMap; + + } + + private void setBusiFieldEditor(Field helpField, FormUdtExtension extendProperty, TypeBuildingContext elementContext, Map bizFieldsMap) { + GspViewModelElement belongedElement = elementContext.Get("Element", GspViewModelElement.class); + String uri = String.format("%1$s.%2$s", belongedElement.getBelongObject().getCode(), helpField.getBindingField()); + String displayName = extendProperty.getLookupConfig().getDisplayName(); + String idField = extendProperty.getLookupConfig().getIdField(); + String dataSourceType = "ViewObject"; + DataSource dataSource = new DataSource() {{ + this.setUri(uri); + this.setDisplayName(displayName); + this.setIdField(idField); + this.setType(dataSourceType); + }}; + LookupEdit editor = new LookupEdit(); + editor.setDataSource(dataSource); + + String valueField = extendProperty.getLookupConfig().getValueField(); + editor.setValueField(valueField); + + String textField = extendProperty.getLookupConfig().getTextField(); + editor.setTextField(textField); + + String helpId = extendProperty.getLookupConfig().getHelpId(); + editor.setHelpId(helpId); + String helpDisplayType = extendProperty.getLookupConfig().getDisplayType(); + editor.setDisplayType(helpDisplayType); + HashMap mapFieldsNode = extendProperty.getLookupConfig().getMapFields(); + String rootFieldName = elementContext.Get("BindingPath", String.class); + HashMap mapFields = new HashMap<>(); + if (mapFieldsNode != null) { + Iterator keys = mapFieldsNode.keySet().iterator(); + while (keys.hasNext()) { + + String key = keys.next(); + String fieldPathInUdt = mapFieldsNode.get(key); + String bindingPath = bizFieldsMap.get(fieldPathInUdt); + // 没有转换后的名称说明扩展属性里的信息有误,跳过。 + if (bindingPath != null) { + mapFields.put(key, bindingPath); + } + } + mapFields.put("id", rootFieldName + "." + rootFieldName); + } + editor.setMap(mapFields); + + ((SimpleField) helpField).setEditor(editor); + } + + /** + * 处理udt上的扩展属性,根据扩展属性修正关联字段的editor属性 + * + * @param udtField Udt业务字段 + * @param elementContext 类型构建上下文 + */ + private void handleUdtExtend(ComplexField udtField, TypeBuildingContext elementContext) { + if (!elementContext.getHasUnifiedDataType()) { + return; + } + + FormUdtExtension extendProperty = elementContext.Get("ExtendProperty", FormUdtExtension.class); + if (extendProperty == null) { + return; + } + + String lookupBindingFiledId = extendProperty.getControlBindingFieldId(); + if (lookupBindingFiledId == null) { + return; + } + + ObjectType entityType = (ObjectType) udtField.getType(); + if (entityType == null || entityType.getFields().size() == 0) { + return; + } + + Map udtFieldsMap = new HashMap<>(); + UdtFieldTreeNode udtFieldNode = new UdtFieldTreeNode(udtField, null); + collectUdtSchemaFields(udtFieldsMap, udtFieldNode, udtField); + + String[] lookupBindingFieldIds = lookupBindingFiledId.split(","); + if (lookupBindingFieldIds.length == 0) { + return; + } + UdtFieldTreeNode currentNode = udtFieldNode; + /* + * 1. 关联型udt: field - object - list object id为udt id + * 2. 非关联单值udt: field - field2 field2 id为udt id + * 3. 多值udt: field - list schema结构中没有udt id + */ + String udtId = elementContext.getUnifiedDataType(); + UdtFieldTreeNode udtObjectNode = udtFieldNode.getChild(udtId); + if (udtObjectNode != null) { + currentNode = udtObjectNode; + } + int cursor = 0; + if (udtId.equals(lookupBindingFieldIds[0])) { + cursor = 1; + } + for (; cursor < lookupBindingFieldIds.length; cursor++) { + String fieldId = lookupBindingFieldIds[cursor]; + currentNode = currentNode.getChild(fieldId); + if (currentNode == null) { + return; + } + } + + Field lookupBindingField = currentNode.getField(); + // 指定的关联字段不是简单字段,无法修改editor属性,退出 + if (!(lookupBindingField instanceof SimpleField)) { + return; + } + + // 处理的当前字段是帮助指定的显示字段,当前字段的默认editor指定为LookupEdit + LookupEdit editor = new LookupEdit(); + + String controlType = extendProperty.getControlType(); + if (!StringUtils.isEmpty(controlType)) { + editor.set$type(controlType); + } + + String bindingField = lookupBindingField.getBindingField(); + GspViewModelElement belongedElement = elementContext.Get("Element", GspViewModelElement.class); + String objCode; + if (belongedElement == null) { + // 增加从BelongObjectCode中获取参数的方式主要是为了零代码 不存在对应的vo element情况 + // 优先仍然采用从对应的viewModelElement中获取的形式 + objCode = elementContext.Get("BelongObjectCode", String.class); + } else { + objCode = belongedElement.getBelongObject().getCode(); + } + if (StringUtils.isEmpty(objCode)) { + System.out.println("belonged element is null"); + return; + } + // String objectCode = belongedElement.getBelongObject().getCode(); + String uri = String.format("%1$s.%2$s", objCode, bindingField); + String displayName = extendProperty.getLookupConfig().getDisplayName(); + String idField = extendProperty.getLookupConfig().getIdField(); + String dataSourceType = "ViewObject"; + DataSource dataSource = new DataSource() {{ + this.setUri(uri); + this.setDisplayName(displayName); + this.setIdField(idField); + this.setType(dataSourceType); + }}; + editor.setDataSource(dataSource); + + String valueField = extendProperty.getLookupConfig().getValueField(); + editor.setValueField(valueField); + + String textField = extendProperty.getLookupConfig().getTextField(); + editor.setTextField(textField); + + String helpId = extendProperty.getLookupConfig().getHelpId(); + editor.setHelpId(helpId); + String helpDisplayType = extendProperty.getLookupConfig().getDisplayType(); + editor.setDisplayType(helpDisplayType); + HashMap mapFields = new HashMap<>(); + HashMap mapFieldsNode = extendProperty.getLookupConfig().getMapFields(); + if (mapFieldsNode != null) { + Iterator keys = mapFieldsNode.keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + String fieldPathInUdt = mapFieldsNode.get(key); + String fieldPath = udtField.getPath() + "." + fieldPathInUdt; + String transformValue = udtFieldsMap.get(fieldPath); + // 没有转换后的名称说明扩展属性里的信息有误,跳过。 + if (transformValue != null) { + mapFields.put(key, transformValue); + } + } + } + + editor.setMap(mapFields); + editor.setOptions(extendProperty.getLookupConfig().getOptions()); + + ((SimpleField) lookupBindingField).setEditor(editor); + } + + private void collectUdtSchemaFields(Map fieldsMap, UdtFieldTreeNode fieldNode, ComplexField complexField) { + FieldType type = complexField.getType(); + List children; + if (type instanceof ObjectType) { + children = ((ObjectType) type).getFields(); + } else if (type instanceof EntityType) { + children = ((EntityType) type).getFields(); + } else { + return; + } + for (Field childField : children) { + fieldsMap.put(childField.getPath(), childField.getBindingPath()); + UdtFieldTreeNode childFieldNode = new UdtFieldTreeNode(childField, fieldNode); + if (childField instanceof ComplexField) { + collectUdtSchemaFields(fieldsMap, childFieldNode, (ComplexField) childField); + } + } + } + + + private enum BeFieldGenType { + Origin, + Single, + Multi, + Relation + } + + private String transferBindingFieldId(String beBindingFieldId, ComplexField bizField, TypeBuildingContext elementContext, RefObject refObject) { + Objects.requireNonNull(beBindingFieldId, "beBindingFieldId不能为空"); + // 找到业务字段 + IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class); + BusinessField businessField = businessFieldService.getBusinessField(elementContext.getBusinessFieldId()); + // 找到be + GspAssociationCollection associations = (GspAssociationCollection) businessField.getUnifiedDataTypeDef().getPropertys().getPropertyName("ChildAssociations").getPropertyValue(); + + String bizFieldBeId = associations.get(0).getRefModelID(); + GspMetadata beMeta = getMetadata(bizFieldBeId, elementContext.isRuntime()); + GspBusinessEntity be = (GspBusinessEntity) beMeta.getContent(); + // 找到be上的字段 + GspBizEntityElement beField = null; + GspBizEntityElement beParentField = null; + BeFieldGenType fieldGenType = BeFieldGenType.Origin; + GspBizEntityObject mainObject = be.getMainObject(); + for (IGspCommonField element : mainObject.getContainElements()) { + if (beBindingFieldId.equals(element.getID())) { + beField = (GspBizEntityElement) element; + fieldGenType = BeFieldGenType.Origin; + break; + } + if (element.getHasAssociation()) { + for (GspAssociation association : element.getChildAssociations()) { + for (IGspCommonField refElement : association.getRefElementCollection()) { + if (beBindingFieldId.equals(refElement.getID())) { + beField = (GspBizEntityElement) refElement; + beParentField = (GspBizEntityElement) element; + fieldGenType = BeFieldGenType.Relation; + break; + } + } + } + } else if (element.getChildElements().size() > 0) { + for (IGspCommonField childElement : element.getChildElements()) { + if (beBindingFieldId.equals(childElement.getID())) { + beField = (GspBizEntityElement) childElement; + beParentField = (GspBizEntityElement) element; + fieldGenType = element.getChildElements().size() == 1 ? BeFieldGenType.Single : BeFieldGenType.Multi; + break; + } + } + } + } + Objects.requireNonNull(beField, "未在实体上找到对应的字段,请检查业务字段配置信息"); + // 根据字段的belongField,判断类型: 1. 单值 2. 多值 3.关联 + + switch (fieldGenType) { + case Origin: + // 0. 原生字段 + IGspCommonField helpField = null; + EntityType entityType = (EntityType) bizField.getType(); + List contextAssociations = elementContext.getAssociations(); + if (contextAssociations != null && contextAssociations.size() > 0) { + GspAssociation gspAssociation = contextAssociations.get(0); + if (gspAssociation != null) { + List refElementCollections = gspAssociation.getRefElementCollection(); + if (refElementCollections != null && refElementCollections.size() > 0) { + helpField = refElementCollections.stream().filter(item -> beBindingFieldId.equals(item.getRefElementId())).findFirst().orElse(null); + } + } + } + if (helpField != null) { + List childAssoFields = entityType.getFields(); + for (Field field : childAssoFields) { + if (helpField.getID().equals(field.getId())) { + refObject.argvalue = field; + break; + } + } + } + return helpField.getID(); + case Single: + // 1. 单值 + case Multi: + // 2. 多值 + + GspBizEntityElement finalBeParentField = beParentField; + IGspCommonField voParentField = elementContext.getAssociations().get(0).getRefElementCollection() + .getItem(field -> finalBeParentField.getId().equals(field.getRefElementId())); + Field schemaParentField = ((EntityType) bizField.getType()).getFields().stream() + .filter(field -> field.getId().equals(voParentField.getID())).findFirst().orElse(null); + String schemaFieldId = beParentField.getMappingRelation().getMappingInfo(beBindingFieldId); + Field schemaField = ((ObjectType) schemaParentField.getType()).getFields().stream() + .filter(field -> field.getOriginalId().equals(schemaFieldId)).findFirst().orElse(null); + refObject.argvalue = schemaField; + return schemaField.getId(); + default: + throw new CAFRuntimeException("NOCODE", "BizFieldError", "不支持的业务字段嵌套层次,请联系技术人员", null); + } + } + + private GspMetadata getMetadata(String id, boolean isRuntime) { + if (isRuntime) { + CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + return customizationService.getMetadata(id); + } else { + RefCommonService refMetadataService = SpringBeanUtils.getBean(RefCommonService.class); + return refMetadataService.getRefMetadata(id); + } + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldTypeBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldTypeBuilder.java new file mode 100644 index 00000000..3d44b983 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/FieldTypeBuilder.java @@ -0,0 +1,229 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection; +import com.inspur.edp.cef.designtime.api.element.GspAssociation; +import com.inspur.edp.cef.designtime.api.element.GspElementObjectType; +import com.inspur.edp.cef.designtime.api.element.GspEnumValue; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.RefCommonService; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef; +import com.inspur.edp.udt.designtime.api.nocode.BusinessField; +import com.inspur.edp.udt.designtime.api.nocode.IBusinessFieldService; +import com.inspur.edp.web.designschema.elements.Field; +import com.inspur.edp.web.designschema.elements.SimpleField; +import com.inspur.edp.web.designschema.elements.type.*; +import com.inspur.edp.web.designschema.udtextensiondef.FormUdtExtension; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 字段类型 构造 + * + * @author noah + */ +public class FieldTypeBuilder { + private final FieldBuilder fieldBuilder; + + public FieldTypeBuilder(FieldBuilder fieldBuilder) { + this.fieldBuilder = fieldBuilder; + } + + public final FieldType GenerateFieldType(TypeBuildingContext context, TypeBuildingContext parentContext, String scene) { + if (context.getHasUnifiedDataType()) { + return GenerateObjectFieldType(context, parentContext, scene); + } + + if (context.getHasBusiFieldId()) { + return handleBusiField(context, parentContext, scene); + } + + if (context.getHasAssociation()) { + return GenerateEntityFieldType(context, parentContext, scene); + } + + if (context.getObjectType() == GspElementObjectType.Enum) { + return GenerateEnumFieldType(context); + } + + if (context.getIsDynamicField()) { + return GenerateDynamicFieldType(context); + } + + return GenerateSimpleFieldType(context); + } + + private EntityType handleBusiField(TypeBuildingContext context, TypeBuildingContext parentContext, String scene) { + + IBusinessFieldService businessFieldService = SpringBeanUtils.getBean(IBusinessFieldService.class); + BusinessField businessField = businessFieldService.getBusinessField(context.getBusinessFieldId()); + // 获取自定义业务字段扩展信息 + FormUdtExtension businessFiledInfo = (FormUdtExtension) businessField.getUnifiedDataTypeDef().getUdtExtensions().get("Form"); + // 自定以业务字段扩展信息塞入字段 + context.getParams().put("ExtendBusiFieldProp", businessFiledInfo); + // 业务字段中含有关联字段,走条件为context.getHasAssociation()逻辑 + return GenerateEntityFieldType(context, parentContext, scene); + } + + private FieldType GenerateSimpleFieldType(TypeBuildingContext context) { + switch (context.getDataType()) { + case Boolean: + return new BooleanType(); + case Date: + return new DateType(); + case DateTime: + return new DateTimeType(); + case Decimal: + case Integer: + if (context.Get("IsBigNumber", Boolean.class)) { + BigNumericType tempVar = new BigNumericType(); + tempVar.setLength(context.Get("Length", Integer.class)); + tempVar.setPrecision(context.Get("Precision", Integer.class)); + return tempVar; + } + NumericType tempVar2 = new NumericType(); + tempVar2.setLength(context.Get("Length", Integer.class)); + tempVar2.setPrecision(context.Get("Precision", Integer.class)); + return tempVar2; + case String: + StringType tempVar3 = new StringType(); + tempVar3.setLength(context.Get("Length", Integer.class)); + return tempVar3; + case Text: + TextType tempVar4 = new TextType(); + tempVar4.setLength(context.Get("Length", Integer.class)); + return tempVar4; + default: + StringType tempVar5 = new StringType(); + tempVar5.setLength(context.Get("Length", Integer.class)); + return tempVar5; + } + } + + private EnumType GenerateEnumFieldType(TypeBuildingContext context) { + EnumType enumType = new EnumType(); + enumType.setValueType(GenerateSimpleFieldType(context)); + for (int i = 0; i < context.getEnums().size(); i++) { + GspEnumValue item = context.getEnums().get(i); + EnumItem tempVar = new EnumItem(); + tempVar.setValue(item.getValue()); + tempVar.setName(item.getName()); + enumType.getEnumValues().add(tempVar); + } + return enumType; + } + + private EntityType GenerateEntityFieldType(TypeBuildingContext context, TypeBuildingContext parentContext, String scene) { + GspAssociationCollection associations = context.getAssociations(); + if (associations == null || associations.size() == 0) { + throw new RuntimeException(String.format("字段'%1$s'不包含关联实体信息。", context.Get("Name", String.class))); + } + TypeBuildingContext originalFieldContext = TypeBuildingContext.CreateSimpleTypeContextFromAssociation(context, parentContext); + Field originalField = fieldBuilder.build(originalFieldContext, parentContext, scene); + ArrayList typeFields = new ArrayList<>(Collections.singletonList(originalField)); + String typeName = ""; + String displayTypeName = ""; + for (GspAssociation association : context.getAssociations()) { + typeName = association.getRefModelCode(); + displayTypeName = association.getRefModelName(); + + List fields = association.getRefElementCollection() + .stream() + .map(e -> { + Field f = fieldBuilder.build(e, context, scene); + return f; + }).collect(Collectors.toList()); + typeFields.addAll(fields); + } + + typeName = context.ReviseTypeName(originalField.getId(), typeName); + EntityType tempVar = new EntityType(); + tempVar.setName(typeName); + tempVar.setDisplayName(displayTypeName); + tempVar.setPrimary(originalField.getLabel()); + tempVar.setFields(typeFields); + return tempVar; + } + + private ObjectType GenerateObjectFieldType(TypeBuildingContext context, TypeBuildingContext parentContext, String scene) { + UnifiedDataTypeDef unifiedDataType = GetUnifiedDataType(context); + List fields = new ArrayList<>(); + String typeName = ""; + String displayTypeName = ""; + if (unifiedDataType instanceof SimpleDataTypeDef) { + SimpleDataTypeDef simpleDataType = (SimpleDataTypeDef) unifiedDataType; + Field field = fieldBuilder.build(simpleDataType, context, scene); + if (field instanceof SimpleField) { + SimpleField simpleDataField = (SimpleField) field; + // 单值UDT的必填属性以VO字段的必填属性为准,按就近原则,与UI界面近的属性覆盖远的属性。 + simpleDataField.setRequire(context.Get("Require", Boolean.class)); + // 单值UDT的只读属性以VO字段的必填属性为准,按就近原则,与UI界面近的属性覆盖远的属性。 + simpleDataField.setReadonly(context.Get("Readonly", Boolean.class)); + + } + + typeName = context.ReviseTypeName(field.getId(), simpleDataType.getCode()); + displayTypeName = unifiedDataType.getName(); + fields.add(field); + } else if (unifiedDataType instanceof ComplexDataTypeDef) { + ComplexDataTypeDef complexDataType = (ComplexDataTypeDef) unifiedDataType; + typeName = context.ReviseTypeName(context.Get("Id", String.class), complexDataType.getCode()); + displayTypeName = unifiedDataType.getName(); + + fields = complexDataType.getElements() + .stream() + .map(e -> fieldBuilder.build(e, context, scene)).collect(Collectors.toList()); + + } else { + throw new ClassCastException("Id为'uri'的统一数据类型元数据为未识别的类型。"); + } + FormUdtExtension formUdtExtension = (FormUdtExtension) unifiedDataType.getUdtExtensions().get("Form"); + context.getParams().put("ExtendProperty", formUdtExtension); + + if ("dbfbe55d-ba65-4a7f-a9d4-4f664ec6ec68".equals(unifiedDataType.getId()) || + "12be876c-368c-4262-88ab-4112688540b0".equals(unifiedDataType.getId())) { + HierarchyType tempVar = new HierarchyType(); + tempVar.setName(typeName); + tempVar.setDisplayName(displayTypeName); + tempVar.setFields(fields); + return tempVar; + } + ObjectType tempVar2 = new ObjectType(); + tempVar2.setName(typeName); + tempVar2.setDisplayName(displayTypeName); + tempVar2.setFields(fields); + return tempVar2; + } + + private UnifiedDataTypeDef GetUnifiedDataType(TypeBuildingContext context) { + if (context.getUnifiedDataTypeDefInstance() != null) { + // 增加此参数的目的是因为零代码传递对应的实例 不传递uri + return context.getUnifiedDataTypeDefInstance(); + } + String uri = context.getUnifiedDataType(); + UnifiedDataTypeDef unifiedDataType; + GspMetadata typeMetadata = null; + if (context.isRuntime()) { + CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + typeMetadata = customizationService.getMetadata(uri); + } else { + RefCommonService refMetadataService = SpringBeanUtils.getBean(RefCommonService.class); + typeMetadata = refMetadataService.getRefMetadata(uri); + } + if (typeMetadata == null) { + throw new RuntimeException(String.format("未获取到id为'%1$s'的统一数据类型(UDT)元数据。", uri)); + } + unifiedDataType = (UnifiedDataTypeDef) ((typeMetadata.getContent() instanceof UnifiedDataTypeDef) ? typeMetadata.getContent() : null); + return unifiedDataType; + } + + private DynamicObjectType GenerateDynamicFieldType(TypeBuildingContext context) { + return new DynamicObjectType(); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/SchemaBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/SchemaBuilder.java new file mode 100644 index 00000000..36b92f6b --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/SchemaBuilder.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.web.designschema.elements.Schema; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class SchemaBuilder { + public final Schema build(GspViewModel model) { + return this.buildWithScene(model, ""); + } + + public final Schema buildWithScene(GspViewModel model, String scene) { + return buildWithScene(model, scene, false); + } + + public final Schema buildWithScene(GspViewModel model, String scene, boolean isRuntime) { + EntityBuilder entityBuilder = new EntityBuilder(); + VariableBuilder variableBuilder = new VariableBuilder(); + Schema tempVar = new Schema(); + tempVar.setId(model.getID()); + tempVar.setCode(model.getCode()); + tempVar.setName(model.getName()); + tempVar.setSourceType("vo"); + tempVar.setEntities(new ArrayList<>(Collections.singletonList(entityBuilder.Build(model.getMainObject(), scene, isRuntime)))); + tempVar.setVariables(variableBuilder.build(model.getVariables())); + tempVar.ExtendProperties = new HashMap<>(); + tempVar.ExtendProperties.put("enableStdTimeFormat", model.getEnableStdTimeFormat()); + return tempVar; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/TypeBuildingContext.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/TypeBuildingContext.java new file mode 100644 index 00000000..f6822fb7 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/TypeBuildingContext.java @@ -0,0 +1,458 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.cef.designtime.api.IGspCommonField; +import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection; +import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection; +import com.inspur.edp.cef.designtime.api.element.GspAssociation; +import com.inspur.edp.cef.designtime.api.element.GspElementDataType; +import com.inspur.edp.cef.designtime.api.element.GspElementObjectType; +import com.inspur.edp.das.commonmodel.IGspCommonElement; +import com.inspur.edp.formserver.viewmodel.GspViewModelElement; +import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef; +import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef; +import com.inspur.edp.web.common.utility.StringUtility; +import org.apache.commons.lang3.ObjectUtils; + +import java.util.HashMap; + +/** + * 类型构造上下文参数 + * + * @author noah + */ +public class TypeBuildingContext { + private boolean isRuntime; + + public boolean isRuntime() { + return isRuntime; + } + + public void setRuntime(boolean runtime) { + isRuntime = runtime; + } + + private GspElementObjectType ObjectType = GspElementObjectType.None; + + public final GspElementObjectType getObjectType() { + return ObjectType; + } + + public final void setObjectType(GspElementObjectType value) { + ObjectType = value; + } + + private GspEnumValueCollection Enums; + + public final GspEnumValueCollection getEnums() { + return Enums; + } + + public final void setEnums(GspEnumValueCollection value) { + Enums = value; + } + + private GspAssociationCollection Associations; + + public final GspAssociationCollection getAssociations() { + return Associations; + } + + public final void setAssociations(GspAssociationCollection value) { + Associations = value; + } + + private String UnifiedDataType; + + /** + * 增加此参数的目的是为了适应零代码 传递对应的实例形式 + */ + private UnifiedDataTypeDef unifiedDataTypeDefInstance; + + public UnifiedDataTypeDef getUnifiedDataTypeDefInstance() { + return unifiedDataTypeDefInstance; + } + + public void setUnifiedDataTypeDefInstance(UnifiedDataTypeDef unifiedDataTypeDefInstance) { + this.unifiedDataTypeDefInstance = unifiedDataTypeDefInstance; + } + + public String getRefElementId() { + return refElementId; + } + + public void setRefElementId(String refElementId) { + this.refElementId = refElementId; + } + + private String refElementId; + + public String getBusinessFieldId() { + return businessFieldId; + } + + public void setBusinessFieldId(String businessFieldId) { + this.businessFieldId = businessFieldId; + } + + private String businessFieldId; + + public final String getUnifiedDataType() { + return UnifiedDataType; + } + + public final void setUnifiedDataType(String value) { + UnifiedDataType = value; + } + + public final boolean getHasUnifiedDataType() { + return !StringUtility.isNullOrEmpty(this.getUnifiedDataType()); + } + + public final boolean getHasBusiFieldId() { + return !StringUtility.isNullOrEmpty(this.getBusinessFieldId()); + } + + private boolean isRefElement; + + public boolean getIsRefElement() { + return isRefElement; + } + + public void setIsRefElement(boolean isRefElement) { + this.isRefElement = isRefElement; + } + + public final boolean getInUnifedDataType() { + return (getParent() != null && (getParent().getHasUnifiedDataType() || getParent().getInUnifedDataType())); + } + + public final boolean getHasAssociation() { + return getObjectType() == GspElementObjectType.Association && getAssociations() != null && getAssociations().size() > 0; + } + + public final boolean getIsMixinUDTAssociation() { + return getHasAssociation() && getHasUnifiedDataType(); + } + + public final boolean getIsDynamicField() { + return getObjectType() == GspElementObjectType.DynamicProp; + } + + public final boolean getIsMultiLanguageField() { + return this.Get("MultiLanguageInput", Boolean.class); + } + + private boolean HasPresetValue; + + public final boolean getHasPresetValue() { + return HasPresetValue; + } + + public final void setHasPresetValue(boolean value) { + HasPresetValue = value; + } + + private GspElementDataType DataType; + + public final GspElementDataType getDataType() { + return DataType; + } + + public final void setDataType(GspElementDataType value) { + DataType = value; + } + + private HashMap Params = new HashMap<>(); + + public final HashMap getParams() { + return Params; + } + + public final void setParams(HashMap value) { + Params = value; + } + + public final T Get(String key, Class cls) { + if (getParams().containsKey(key)) { + Object value = getParams().get(key); + return (T) value; + } else { + //N转J N版代码 此处通过类型判断赋予初始值兼容Nbadefault(T) + //return default(T); + if (cls == Boolean.class) { + return (T) Boolean.FALSE; + } else if (cls == Character.class) { + return (T) Character.valueOf((char) 0); + } else if (cls == Byte.class) { + return (T) Byte.valueOf((byte) 0); + } else if (cls == Short.class) { + return (T) Short.valueOf((short) 0); + } else if (cls == Integer.class) { + return (T) Integer.valueOf(0); + } else if (cls == Long.class) { + return (T) Long.valueOf(0); + } else if (cls == Float.class) { + return (T) Float.valueOf(0); + } else if (cls == Double.class) { + return (T) Double.valueOf(0.0); + } else { + return null; + } + } + } + + public HashMap TypeNameMaps = new HashMap<>(); + + public HashMap ElementIdMaps = new HashMap<>(); + + private TypeBuildingContext Root; + + public final TypeBuildingContext getRoot() { + return Root; + } + + public final void setRoot(TypeBuildingContext value) { + Root = value; + } + + private TypeBuildingContext Parent; + + public final TypeBuildingContext getParent() { + return Parent; + } + + public final void setParent(TypeBuildingContext value) { + Parent = value; + } + + private boolean HasReviseTypeName(String revisedTypeName) { + HashMap typeNameMaps = this.getRoot() != null ? this.getRoot().TypeNameMaps : TypeNameMaps; + return typeNameMaps.containsKey(revisedTypeName); + } + + private void AddRevisedTypeName(String revisedTypeName) { + HashMap typeNameMaps = this.getRoot() != null ? this.getRoot().TypeNameMaps : TypeNameMaps; + if (!typeNameMaps.containsKey(revisedTypeName)) { + typeNameMaps.put(revisedTypeName, 0); + } else { + typeNameMaps.put(revisedTypeName, typeNameMaps.get(revisedTypeName) + 1); + } + } + + private String GenerateNewRevisedTypeName(String revisedTypeName) { + HashMap typeNameMaps = this.getRoot() != null ? this.getRoot().TypeNameMaps : TypeNameMaps; + return String.format("%1$s$%2$s", revisedTypeName, typeNameMaps.get(revisedTypeName)); + } + + public final String ReviseTypeName(String suffixFieldId, String typeName) { + String suffix = suffixFieldId.substring(0, 4); + String revisedTypeName = String.format("%1$s%2$s", typeName, suffix.replace(suffix.substring(0, 1), suffix.substring(0, 1).toUpperCase())); + if (!HasReviseTypeName(revisedTypeName)) { + AddRevisedTypeName(revisedTypeName); + return revisedTypeName; + } else { + AddRevisedTypeName(revisedTypeName); + return GenerateNewRevisedTypeName(revisedTypeName); + } + } + + private boolean HasReviseElementId(String elementId) { + HashMap elementIdMaps = this.getRoot() != null ? this.getRoot().ElementIdMaps : ElementIdMaps; + return elementIdMaps.containsKey(elementId); + } + + private void AddRevisedElementId(String elementId) { + HashMap elementIdMaps = this.getRoot() != null ? this.getRoot().ElementIdMaps : ElementIdMaps; + if (!elementIdMaps.containsKey(elementId)) { + elementIdMaps.put(elementId, 0); + } else { + elementIdMaps.put(elementId, elementIdMaps.get(elementId) + 1); + } + } + + private String GenerateNewRevisedElementId(String elementId) { + HashMap elementIdMaps = this.getRoot() != null ? this.getRoot().ElementIdMaps : ElementIdMaps; + return String.format("%1$s$%2$s", elementId.substring(0, elementId.length() - 2), elementIdMaps.get(elementId)); + } + + public final String ReviseElementId(String elementId) { + String revisedElementId = elementId; + if (this.getParent() != null && this.getInUnifedDataType()) { + String parentId = this.getParent().Get("Id", String.class); + revisedElementId = String.format("%1$s%2$s", parentId.substring(0, 8), elementId.substring(8, 36)); + } + if (!HasReviseElementId(revisedElementId)) { + AddRevisedElementId(revisedElementId); + return revisedElementId; + } else { + AddRevisedElementId(revisedElementId); + return GenerateNewRevisedElementId(revisedElementId); + } + } + + + public static TypeBuildingContext Create(SimpleDataTypeDef element, TypeBuildingContext parent) { + TypeBuildingContext context = new TypeBuildingContext(); + context.setObjectType(element.getObjectType()); + context.setEnums(element.getContainEnumValues()); + context.setAssociations(element.getChildAssociations()); + context.setDataType(element.getMDataType()); + + HashMap params = new HashMap<>(); + params.put("Id", (element.getId() != null) ? element.getId() : ""); + params.put("Code", (element.getCode() != null) ? element.getCode() : ""); + params.put("Name", (element.getName() != null) ? element.getName() : ""); + params.put("Label", (element.getCode() != null) ? element.getCode() : ""); + params.put("BindingField", (element.getCode() != null) ? element.getCode() : ""); + params.put("Path", (element.getCode() != null) ? element.getCode() : ""); + params.put("Require", parent != null ? (parent.Get("Require", Boolean.class) || element.getIsRequired()) : element.getIsRequired()); + params.put("Readonly", false); + params.put("DefaultValue", (element.getDefaultValue() != null) ? element.getDefaultValue() : ""); + params.put("Length", element.getLength()); + params.put("Precision", element.getPrecision()); + params.put("MultiLanguageInput", false); + params.put("IsBigNumber", parent != null ? parent.Get("IsBigNumber", Boolean.class) : false); + params.put("BelongObjectCode", parent != null ? parent.Get("BelongObjectCode", String.class) : ""); +// FormUdtExtension formUdtExtension = (FormUdtExtension) element.getUdtExtensions().get("Form"); +// params.put("ExtendProperty", formUdtExtension); + + context.setParams(params); + context.setRoot(parent != null && parent.getRoot() != null ? parent.getRoot() : parent); + context.setRuntime(parent != null && parent.isRuntime()); + context.setParent(parent); + if (parent != null && parent.getIsMixinUDTAssociation()) { + for (GspAssociation association : parent.getAssociations()) { + for (IGspCommonField refElement : association.getRefElementCollection()) { + if (!refElement.getIsFromAssoUdt()) { + context.getAssociations().get(0).getRefElementCollection().add(refElement); + } + } + } + } + return context; + } + + + public static TypeBuildingContext Create(GspViewModelElement element, TypeBuildingContext parent, boolean isRuntime) { + verifyFieldElement(element); + + TypeBuildingContext tempVar = new TypeBuildingContext(); + tempVar.setObjectType(element.getObjectType()); + tempVar.setEnums(element.getContainEnumValues()); + tempVar.setAssociations(element.getChildAssociations()); + tempVar.setDataType(element.getMDataType()); + tempVar.setUnifiedDataType(element.getUdtID()); + tempVar.setIsRefElement(element.getIsRefElement()); + tempVar.setBusinessFieldId(element.getRefBusinessFieldId()); + + HashMap params = new HashMap<>(); + params.put("Id", (element.getID() != null) ? element.getID() : ""); + params.put("Code", (element.getCode() != null) ? element.getCode() : ""); + params.put("Name", (element.getName() != null) ? element.getName() : ""); + params.put("Label", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("BindingField", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("Path", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("Require", element.getIsRequire()); + params.put("Readonly", ((element instanceof IGspCommonElement) ? element : null) != null && ((IGspCommonElement) ((element instanceof IGspCommonElement) ? element : null)).getReadonly()); + params.put("DefaultValue", (element.getDefaultValue() != null) ? element.getDefaultValue() : ""); + params.put("Length", element.getLength()); + params.put("Precision", element.getPrecision()); + params.put("MultiLanguageInput", element.getIsMultiLanguage() && element.isEnableMultiLanguageInput()); + params.put("IsBigNumber", element.isBigNumber()); + params.put("Element", element); + tempVar.setParams(params); + tempVar.setRoot(parent != null && parent.getRoot() != null ? parent.getRoot() : parent); + tempVar.setRuntime(parent != null ? parent.isRuntime() : isRuntime); + tempVar.setParent(parent); + return tempVar; + } + + /** + * 构造参数类型为IGspCommonField 的Context + * + * @param element IGspCommonField + * @param parent + * @return + */ + public static TypeBuildingContext Create(IGspCommonField element, TypeBuildingContext parent) { + verifyFieldElement(element); + + TypeBuildingContext tempVar = new TypeBuildingContext(); + tempVar.setObjectType(element.getObjectType()); + tempVar.setEnums(element.getContainEnumValues()); + tempVar.setAssociations(element.getChildAssociations()); + tempVar.setDataType(element.getMDataType()); + tempVar.setUnifiedDataType(element.getUdtID()); + tempVar.setRefElementId(element.getRefElementId()); + + HashMap params = new HashMap<>(); + params.put("Id", (element.getID() != null) ? element.getID() : ""); + params.put("Code", (element.getCode() != null) ? element.getCode() : ""); + params.put("Name", (element.getName() != null) ? element.getName() : ""); + params.put("Label", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("BindingField", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("Path", (element.getLabelID() != null) ? element.getLabelID() : ""); + params.put("Require", element.getIsRequire()); + params.put("Readonly", ((element instanceof IGspCommonElement) ? element : null) != null && ((IGspCommonElement) ((element instanceof IGspCommonElement) ? element : null)).getReadonly()); + params.put("DefaultValue", (element.getDefaultValue() != null) ? element.getDefaultValue() : ""); + params.put("Length", element.getLength()); + params.put("Precision", element.getPrecision()); + params.put("MultiLanguageInput", false); + params.put("IsBigNumber", element.isBigNumber()); + tempVar.setParams(params); + tempVar.setRoot(parent != null && parent.getRoot() != null ? parent.getRoot() : parent); + tempVar.setRuntime(parent != null && parent.isRuntime()); + tempVar.setParent(parent); + return tempVar; + } + + + public static TypeBuildingContext CreateSimpleTypeContextFromAssociation(TypeBuildingContext context, TypeBuildingContext parent) { + GspAssociationCollection associations = context.getAssociations(); + if (associations == null || associations.size() == 0) { + throw new RuntimeException(String.format("字段'%1$s'不包含关联实体信息。", context.Get("Name", String.class))); + } + + String tempVar = context.Get("Label", String.class); + String label = (tempVar != null) ? tempVar : ""; + + String camelLable = StringUtility.toCamelCase(label); + + TypeBuildingContext tempVar2 = new TypeBuildingContext(); + tempVar2.setDataType(context.getDataType()); + tempVar2.setHasPresetValue(true); + + HashMap params = new HashMap<>(); + params.put("Id", ObjectUtils.firstNonNull(associations.get(0).getId(), "")); + params.put("Code", ObjectUtils.firstNonNull(context.Get("Code", String.class), "")); + params.put("Name", ObjectUtils.firstNonNull(context.Get("Name", String.class), "")); + params.put("Label", label); + params.put("BindingField", label); + params.put("BindingPath", !StringUtility.isNullOrEmpty(camelLable) ? camelLable + "." + camelLable : ""); + params.put("Path", !StringUtility.isNullOrEmpty(label) ? label + "." + label : ""); + params.put("Require", context.Get("Require", Boolean.class)); + params.put("Readonly", context.Get("Readonly", Boolean.class)); + params.put("DefaultValue", ObjectUtils.firstNonNull(context.Get("DefaultValue", String.class), "")); + params.put("Length", context.Get("Length", Integer.class)); + params.put("Precision", context.Get("Precision", Integer.class)); + params.put("MultiLanguageInput", false); + params.put("IsBigNumber", context.Get("IsBigNumber", Boolean.class)); + tempVar2.setParams(params); + tempVar2.setRoot(parent != null && parent.getRoot() != null ? parent.getRoot() : parent); + tempVar2.setRuntime(parent != null && parent.isRuntime()); + tempVar2.setParent(parent); + return tempVar2; + } + + private static void verifyFieldElement(IGspCommonField element) { + VerifyUnifiedDataType(element); + } + + private static void VerifyUnifiedDataType(IGspCommonField element) { + if (element.getIsUdt()) { + if (StringUtility.isNullOrEmpty(element.getUdtID().trim())) { + throw new RuntimeException(String.format("标识为'%1$s',标签为'%2$s'的字段'%3$s'被定义为'UnifiedDataType'字段,但是没有指定'UnifiedDataType'标识,请检查业务实体。", element.getID(), element.getLabelID(), element.getName())); + } + } + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtExtBuildingContext.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtExtBuildingContext.java new file mode 100644 index 00000000..a2c36fa1 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtExtBuildingContext.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.web.designschema.udtextensiondef.FormUdtExtension; +import lombok.Getter; +import lombok.Setter; + +/** + * UDT扩展属性构造帮助Editor的上下文参数 + * @author liyz + * @date 2021/8/7 + */ +public class UdtExtBuildingContext { + @Getter @Setter + private FormUdtExtension formUdtExtension; +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtFieldTreeNode.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtFieldTreeNode.java new file mode 100644 index 00000000..c5540991 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/UdtFieldTreeNode.java @@ -0,0 +1,51 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.web.designschema.elements.Field; +import lombok.Getter; + +import java.util.HashMap; + +/** + * @author liyz + * @date 2021/8/7 + */ +public class UdtFieldTreeNode { + @Getter + private final Field field; + + @Getter + private UdtFieldTreeNode parent; + + private final HashMap children = new HashMap<>(); + + public UdtFieldTreeNode(Field field) { + this.field = field; + } + + public UdtFieldTreeNode(Field field, UdtFieldTreeNode parent) { + this.field = field; + this.setParent(parent); + } + + public void setParent(UdtFieldTreeNode parent) { + if (this.parent == parent) { + return; + } + if (this.parent != null) { + // todo: remove from parent's children node + } + this.parent = parent; + if (parent != null) { + parent.addChild(this); + } + } + + public UdtFieldTreeNode getChild(String id) { + return this.children.get(id); + } + + private void addChild(UdtFieldTreeNode child) { + String id = child.getField().getOriginalId(); + children.put(id, child); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableBuilder.java new file mode 100644 index 00000000..4a39dff0 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableBuilder.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.cef.designtime.api.variable.CommonVariableEntity; +import com.inspur.edp.web.designschema.elements.Field; + +import java.util.ArrayList; + +/** + * 变量构造器 + * @author noah + */ +public class VariableBuilder extends FieldBuilder { + public VariableBuilder() { + } + + public final ArrayList build(CommonVariableEntity variableEntity) { + FieldBuilder fieldBuilder = new FieldBuilder(); + + ArrayList variableList = new ArrayList<>(); + variableEntity.getContainElements().forEach(variableField -> + { + TypeBuildingContext variableContext = TypeBuildingContext.Create(variableField,null); + Field field = fieldBuilder.build(variableContext, null, null); + variableList.add(field); + }); + return variableList; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableTypeBuilder.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableTypeBuilder.java new file mode 100644 index 00000000..74a996c0 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/generator/VariableTypeBuilder.java @@ -0,0 +1,37 @@ +package com.inspur.edp.web.designschema.generator; + +import com.inspur.edp.cef.designtime.api.IGspCommonField; + +/** + * 变量类型构造器 + * @author noah + */ +public class VariableTypeBuilder { + public VariableTypeBuilder() { + } + + public final String build(IGspCommonField variableField) { + return generateFieldType(variableField); + } + + public final String generateFieldType(IGspCommonField variableField) { + return generateSimpleFieldType(variableField); + } + + private String generateSimpleFieldType(IGspCommonField variableField) { + switch (variableField.getMDataType()) { + case Boolean: + return "Boolean"; + case Date: + case DateTime: + return "Date"; + case Decimal: + case Integer: + return "Decimal"; + case Text: + case String: + default: + return "String"; + } + } +} \ No newline at end of file diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/BaseDesignSchemaChangeHandler.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/BaseDesignSchemaChangeHandler.java new file mode 100644 index 00000000..073183d3 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/BaseDesignSchemaChangeHandler.java @@ -0,0 +1,66 @@ +package com.inspur.edp.web.designschema.synchronization; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.designschema.elements.Schema; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +import java.util.List; + +/** + * @author liyz + * @date 2021-9-5 + */ +public abstract class BaseDesignSchemaChangeHandler { + public void handleFormSaving(FormMetadataContent content) { + if (content == null) { + return; + } + String formContent = SerializeUtility.getInstance().serialize(content.getContents()); + JsonNode formObject = null; + + String formString = (formContent instanceof String) ? formContent : null; + formObject = SerializeUtility.getInstance().toJsonNode(formString); + + JsonNode schemas=null; + JsonNode jsonNodeModules=formObject.get("module"); + if(jsonNodeModules!=null){ + schemas = jsonNodeModules.get("schemas"); + } + + if (schemas != null) { + String schemasString = schemas.toString(); + + List schemaList = SerializeUtility.getInstance().deserialize(schemasString, new TypeReference>() { + }); + Synchronizer synchronizer = new Synchronizer(); + for (Schema schema : schemaList) { + if ("vo".equals(schema.getSourceType())) { + GspMetadata metadata = this.getMetadata(schema.getId()); + GspViewModel viewObject = (GspViewModel) ((metadata.getContent() instanceof GspViewModel) ? metadata.getContent() : null); + metadata.setContent(synchronizer.synchronize(formObject, schema, viewObject)); + this.saveMetadata(metadata); + } + } + } else { + throw new RuntimeException("表单DOM结构错误:未到module.schemas节点"); + } + } + + /** + * 获取元数据 + * @param id 元数据id + * @return 元数据 + */ + protected abstract GspMetadata getMetadata(String id); + + /** + * 保存元数据的抽象方法 + * @param metadata 要保存的元数据 + * @param args 额外的参数 + */ + protected abstract void saveMetadata(GspMetadata metadata, Object ...args); +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListener.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListener.java new file mode 100644 index 00000000..315e668c --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListener.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.designschema.synchronization; + +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventListener; + +/** + * 元数据事件监听 + * + * @author noah + */ +public class DesignSchemaChangeListener implements MetadataEventListener { + + @Override + public void fireMetadataSavingEvent(MetadataEventArgs e) { + if (e != null && e.getMetadata() != null) { + FormMetadataUpdate.update(e.getMetadata()); + } + } + + @Override + public void fireMetadataSavedEvent(MetadataEventArgs metadataEventArgs) { + + } + + @Override + public void fireMetadataDeletingEvent(MetadataEventArgs metadataEventArgs) { + + } + + @Override + public void fireMetadataDeletedEvent(MetadataEventArgs metadataEventArgs) { + + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/FormMetadataUpdate.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/FormMetadataUpdate.java new file mode 100644 index 00000000..fca7dfb9 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/FormMetadataUpdate.java @@ -0,0 +1,54 @@ +package com.inspur.edp.web.designschema.synchronization; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.lcm.metadata.api.service.RefCommonService; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.designschema.elements.Schema; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.List; + +public class FormMetadataUpdate { + public static void update(GspMetadata formMetadata) { + FormMetadataContent content = (FormMetadataContent) ((formMetadata.getContent() instanceof FormMetadataContent) ? formMetadata.getContent() : null); + if (content == null) { + return; + } + String formContent = SerializeUtility.getInstance().serialize(content.getContents()); + JsonNode formObject = null; + + String formString = (formContent instanceof String) ? formContent : null; + formObject = SerializeUtility.getInstance().toJsonNode(formString); + + JsonNode schemas = null; + JsonNode jsonNodeModules = formObject.get("module"); + if (jsonNodeModules != null) { + schemas = jsonNodeModules.get("schemas"); + } + + if (schemas != null) { + String schemasString = schemas.toString(); + + List schemaList = SerializeUtility.getInstance().deserialize(schemasString, new TypeReference>() { + }); + Synchronizer synchronizer = new Synchronizer(); + for (Schema schema : schemaList) { + if ("vo".equals(schema.getSourceType())) { + RefCommonService metadataService = SpringBeanUtils.getBean(RefCommonService.class); + GspMetadata metadata = metadataService.getRefMetadata(schema.getId()); + GspViewModel viewObject = (GspViewModel) ((metadata.getContent() instanceof GspViewModel) ? metadata.getContent() : null); + metadata.setContent(synchronizer.synchronize(formObject, schema, viewObject)); + MetadataService service = SpringBeanUtils.getBean(MetadataService.class); + service.saveMetadata(metadata, metadata.getRelativePath() + "/" + metadata.getHeader().getFileName()); + } + } + } else { + throw new RuntimeException("表单DOM结构错误:未到module.schemas节点"); + } + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/LookupConfig.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/LookupConfig.java new file mode 100644 index 00000000..2f82e2ae --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/LookupConfig.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.designschema.synchronization; + +public class LookupConfig { + private String LookupId; + + public final String getLookupId() { + return LookupId; + } + + public final void setLookupId(String value) { + LookupId = value; + } + + private String Condition; + + public final String getCondition() { + return Condition; + } + + public final void setCondition(String value) { + Condition = value; + } + + private String Uri; + + public final String getUri() { + return Uri; + } + + public final void setUri(String value) { + Uri = value; + } +} \ No newline at end of file diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/NocodeDesignSchemaChangeListener.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/NocodeDesignSchemaChangeListener.java new file mode 100644 index 00000000..959b1a79 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/NocodeDesignSchemaChangeListener.java @@ -0,0 +1,54 @@ +package com.inspur.edp.web.designschema.synchronization; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.NoCodeService; +import com.inspur.edp.lcm.metadata.spi.event.NoCodeServiceEventListener; +import com.inspur.edp.lcm.metadata.spi.event.nodecode.NoCodeAfterDeleteArgs; +import com.inspur.edp.lcm.metadata.spi.event.nodecode.NoCodeAfterSaveArgs; +import com.inspur.edp.lcm.metadata.spi.event.nodecode.NoCodeBeforeDeleteArgs; +import com.inspur.edp.lcm.metadata.spi.event.nodecode.NoCodeBeforeSaveArgs; +import com.inspur.edp.metadata.rtcustomization.api.CustomizationService; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * @author liyz + * @date 2021-9-5 + */ +public class NocodeDesignSchemaChangeListener extends BaseDesignSchemaChangeHandler implements NoCodeServiceEventListener { + @Override + public void fireMetadataBeforeSaveEvent(NoCodeBeforeSaveArgs e) { + FormMetadataContent content = (FormMetadataContent) ((e.getMetadata().getContent() instanceof FormMetadataContent) ? e.getMetadata().getContent() : null); + if (content == null) { + return; + } + this.handleFormSaving(content); + } + + @Override + public void fireMetadataAfterSaveEvent(NoCodeAfterSaveArgs noCodeAfterSaveArgs) { + + } + + @Override + public void fireMetadataBeforeDeleteEvent(NoCodeBeforeDeleteArgs noCodeBeforeDeleteArgs) { + + } + + @Override + public void fireMetadataAfterDeleteEvent(NoCodeAfterDeleteArgs noCodeAfterDeleteArgs) { + + } + + @Override + protected GspMetadata getMetadata(String id) { + CustomizationService customizationService = SpringBeanUtils.getBean(CustomizationService.class); + return customizationService.getMetadata(id); + } + + @Override + protected void saveMetadata(GspMetadata metadata, Object... args) { + NoCodeService nocodeService = SpringBeanUtils.getBean(NoCodeService.class); + nocodeService.saveMetadata(metadata); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/Synchronizer.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/Synchronizer.java new file mode 100644 index 00000000..c877599a --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/synchronization/Synchronizer.java @@ -0,0 +1,335 @@ +package com.inspur.edp.web.designschema.synchronization; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.JSONPath; +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.formserver.viewmodel.collection.ValueHelpConfigCollection; +import com.inspur.edp.formserver.viewmodel.common.ValueHelpConfig; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.designschema.elements.*; +import com.inspur.edp.web.designschema.elements.editor.LookupEdit; +import com.inspur.edp.web.designschema.elements.type.EntityType; +import com.inspur.edp.web.designschema.elements.type.ObjectType; +import com.inspur.edp.web.designschema.utils.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class Synchronizer { + public final GspViewModel synchronize(JsonNode formObject, Schema schema, GspViewModel viewObject) { + // 归集绑定表单变量的帮助。 + HashMap lookupConfigsFromVariables = this.gallaryLookupConfigs(formObject); + // 如果ViewObject上无帮助定义,初始化帮助定义集合。 + if (viewObject.getValueHelpConfigs() == null) { + viewObject.setValueHelpConfigs(new ValueHelpConfigCollection()); + } + // 创建表单帮助定义字典。 + HashMap latestValueHelpConfigs = new HashMap<>(); + + // 由绑定表单变量的帮助创建帮助配置对象。 + for (LookupConfig lookupConfig : lookupConfigsFromVariables.values()) { + if (!latestValueHelpConfigs.containsKey(lookupConfig.getUri())) { + ValueHelpConfig tempVar = new ValueHelpConfig(); + tempVar.setElementId(lookupConfig.getUri()); + tempVar.setHelperId(lookupConfig.getLookupId()); + tempVar.setFilterExpression(lookupConfig.getCondition()); + latestValueHelpConfigs.put(lookupConfig.getUri(), tempVar); + } + } + // 带移除的已有帮助配置对象集合。 + ArrayList valueHelpConfigsToRemove = new ArrayList<>(); + // 遍历ViewObject中已有的帮助配置对象,同步已添加数据,识别待删除数据。 + for (ValueHelpConfig valueHelpConfig : viewObject.getValueHelpConfigs()) { + if (latestValueHelpConfigs.containsKey(valueHelpConfig.getElementId())) { + ValueHelpConfig latestValueHelpConfig = latestValueHelpConfigs.get(valueHelpConfig.getElementId()); + valueHelpConfig.setHelperId(latestValueHelpConfig.getHelperId()); + valueHelpConfig.setFilterExpression(latestValueHelpConfig.getFilterExpression()); + latestValueHelpConfigs.remove(valueHelpConfig.getElementId()); + } else { + valueHelpConfigsToRemove.add(valueHelpConfig); + } + } + // 在ViewObject中移除待删除的帮助配置对象。 + for (ValueHelpConfig valueHelpConfig : valueHelpConfigsToRemove) { + viewObject.getValueHelpConfigs().remove(valueHelpConfig); + } + // 向ViewObject中添加新增的帮助配置对象。 + for (ValueHelpConfig lookupConfig : latestValueHelpConfigs.values()) { + viewObject.getValueHelpConfigs().add(lookupConfig); + } + + return viewObject; + } + + private void gallaryLookupConfigsFromEntity(Entity entity, HashMap lookupConfigs) { + this.gallaryLookupConfigsFromEntityList(entity.getType().getFields(), lookupConfigs); + + for (Entity e : entity.getType().getEntities()) { + this.gallaryLookupConfigsFromEntity(e, lookupConfigs); + } + } + + private void gallaryLookupConfigsFromEntityList(List fields, HashMap lookupConfigs) { + for (Field field : fields) { + if (field instanceof SimpleField) { + SimpleField simpleField = (SimpleField) field; + if (simpleField.getEditor() instanceof LookupEdit) { + LookupEdit lookupEditor = (LookupEdit) simpleField.getEditor(); + LookupConfig tempVar = new LookupConfig(); + tempVar.setUri(String.join("/", lookupEditor.getDataSource().getUri().split("\\."))); + tempVar.setLookupId(lookupEditor.getHelpId()); + lookupConfigs.put(lookupEditor.getDataSource().getUri(), tempVar); + } + } else if (field instanceof ComplexField) { + ComplexField complexField = (ComplexField) field; + if (complexField.getType() instanceof EntityType) { + EntityType entityType = (EntityType) complexField.getType(); + this.gallaryLookupConfigsFromEntityList(entityType.getFields(), lookupConfigs); + } else if (complexField.getType() instanceof ObjectType) { + ObjectType objectType = (ObjectType) complexField.getType(); + this.gallaryLookupConfigsFromEntityList(objectType.getFields(), lookupConfigs); + } + } + } + } + + + private HashMap gallaryLookupConfigs(JsonNode formObject) { + HashMap lookupConfigs = new HashMap<>(); + + JsonNode jsonNodeModule = formObject.get("module"); + + JsonNode components = jsonNodeModule.get("components"); + if (components != null) { + + List lookupJsonObjects = new ArrayList<>(); + rescureGetLookup((JSONArray) JSONPath.extract(components.toString(), "$..contents"), lookupJsonObjects); + + + //JsonNode lookupsInField = components.get("$..fields[?(@.editor.type=='LookupEdit')].editor"); + List lookupsInField = new ArrayList<>(); + rescureGetLookupEditor((JSONArray) JSONPath.extract(components.toString(), "$..fields"), lookupsInField); + + List lookupsInColumns = new ArrayList<>(); + rescureGetLookupEditor((JSONArray) JSONPath.extract(components.toString(), "$..columns"), lookupsInColumns); + + //JsonNode lookupsInFilterBar = components.get("$..fieldConfigs[?(@.control.controltype=='help')].control"); + List lookupsInFilterBar = new ArrayList<>(); + rescureGetLookupControl((JSONArray) JSONPath.extract(components.toString(), "$..fieldConfigs"), lookupsInFilterBar); + + + //JsonNode popupLookupsInFilterBar = components.get("$..fieldConfigs[?(@.control.controltype=='combolist-help')].control"); + List popupLookupsInFilterBar = new ArrayList<>(); + rescureGetComboListHelpControl((JSONArray) JSONPath.extract(components.toString(), "$..fieldConfigs"), popupLookupsInFilterBar); + + //JsonNode lookupsInCompactFilterBar = components.get("$..filterList[?(@.control.controltype=='help')].control"); + List lookupsInCompactFilterBar = new ArrayList<>(); + rescureGetHelpControl((JSONArray) JSONPath.extract(components.toString(), "$..filterList"), lookupsInCompactFilterBar); + + if (lookupJsonObjects != null) { + lookupJsonObjects.forEach((lookupConfig) -> this.appendLookupConfigs(lookupConfigs, lookupConfig)); + } + + if(lookupsInColumns!=null){ + lookupsInColumns.forEach((lookupConfig) -> this.appendLookupConfigs(lookupConfigs, lookupConfig)); + } + + if (lookupsInField != null) { + lookupsInField.forEach((lookupConfig) -> this.appendLookupConfigs(lookupConfigs, lookupConfig)); + } + + if (lookupsInFilterBar != null) { + lookupsInFilterBar.forEach((lookupConfig) -> this.appendLookupConfigsByFilterBar(lookupConfigs, lookupConfig)); + } + + if (popupLookupsInFilterBar != null) { + popupLookupsInFilterBar.forEach((lookupConfig) -> this.appendLookupConfigsByFilterBar(lookupConfigs, lookupConfig)); + } + + if (lookupsInCompactFilterBar != null) { + lookupsInCompactFilterBar.forEach((lookupConfig) -> this.appendLookupConfigsByFilterBar(lookupConfigs, lookupConfig)); + } + + } + return lookupConfigs; + } + + private void rescureGetHelpControl(JSONArray jsonArray, List jsonObjectList) { + if (jsonArray == null || jsonArray.size() == 0) { + return; + } + + jsonArray.forEach((item) -> { + if (item instanceof JSONArray) { + JSONArray itemJsonArray = (JSONArray) item; + rescureGetHelpControl(itemJsonArray, jsonObjectList); + } else if (item instanceof JSONObject) { + JSONObject jsonObjectItem = (JSONObject) item; + if (jsonObjectItem.get("control") != null) { + JSONObject editorJsonObject = (JSONObject) jsonObjectItem.get("control"); + if (editorJsonObject != null && "help".equals(editorJsonObject.get("controltype").toString())) { + jsonObjectList.add(editorJsonObject); + } + } + if (jsonObjectItem.get("filterList") instanceof JSONArray) { + JSONArray contentsJsonArray = (JSONArray) jsonObjectItem.get("filterList"); + rescureGetHelpControl(contentsJsonArray, jsonObjectList); + } + } + }); + } + + private void rescureGetComboListHelpControl(JSONArray jsonArray, List jsonObjectList) { + if (jsonArray == null || jsonArray.size() == 0) { + return; + } + + jsonArray.forEach((item) -> { + if (item instanceof JSONArray) { + JSONArray itemJsonArray = (JSONArray) item; + rescureGetComboListHelpControl(itemJsonArray, jsonObjectList); + } else if (item instanceof JSONObject) { + JSONObject jsonObjectItem = (JSONObject) item; + if (jsonObjectItem.get("control") != null) { + JSONObject editorJsonObject = (JSONObject) jsonObjectItem.get("control"); + if (editorJsonObject != null && "combolist-help".equals(editorJsonObject.get("controltype").toString())) { + jsonObjectList.add(editorJsonObject); + } + } + if (jsonObjectItem.get("fieldConfigs") instanceof JSONArray) { + JSONArray contentsJsonArray = (JSONArray) jsonObjectItem.get("fieldConfigs"); + rescureGetComboListHelpControl(contentsJsonArray, jsonObjectList); + } + } + }); + } + + private void rescureGetLookupControl(JSONArray jsonArray, List jsonObjectList) { + if (jsonArray == null || jsonArray.size() == 0) { + return; + } + + jsonArray.forEach((item) -> { + if (item instanceof JSONArray) { + JSONArray itemJsonArray = (JSONArray) item; + rescureGetLookupControl(itemJsonArray, jsonObjectList); + } else if (item instanceof JSONObject) { + JSONObject jsonObjectItem = (JSONObject) item; + if (jsonObjectItem.get("control") != null) { + JSONObject editorJsonObject = (JSONObject) jsonObjectItem.get("control"); + if (editorJsonObject != null && "help".equals(editorJsonObject.get("controltype").toString())) { + jsonObjectList.add(editorJsonObject); + } + } + if (jsonObjectItem.get("fieldConfigs") instanceof JSONArray) { + JSONArray contentsJsonArray = (JSONArray) jsonObjectItem.get("fieldConfigs"); + rescureGetLookupControl(contentsJsonArray, jsonObjectList); + } + } + }); + } + + private void rescureGetLookupEditor(JSONArray jsonArray, List jsonObjectList) { + if (jsonArray == null || jsonArray.size() == 0) { + return; + } + + jsonArray.forEach((item) -> { + if (item instanceof JSONArray) { + JSONArray itemJsonArray = (JSONArray) item; + rescureGetLookupEditor(itemJsonArray, jsonObjectList); + } else if (item instanceof JSONObject) { + JSONObject jsonObjectItem = (JSONObject) item; + if (jsonObjectItem.get("editor") != null) { + JSONObject editorJsonObject = (JSONObject) jsonObjectItem.get("editor"); + if (editorJsonObject != null && editorJsonObject.containsKey("type") && this.isLookupEdit(StringUtils.getSpecialValue(editorJsonObject.get("type")))) { + jsonObjectList.add(editorJsonObject); + } + } + if (jsonObjectItem.get("fields") instanceof JSONArray) { + JSONArray contentsJsonArray = (JSONArray) jsonObjectItem.get("fields"); + rescureGetLookupEditor(contentsJsonArray, jsonObjectList); + } + } + }); + } + + private void rescureGetLookup(JSONArray jsonArray, List jsonObjectList) { + if (jsonArray == null || jsonArray.size() == 0) { + return; + } + + jsonArray.forEach((item) -> { + if (item instanceof JSONArray) { + JSONArray itemJsonArray = (JSONArray) item; + rescureGetLookup(itemJsonArray, jsonObjectList); + } else if (item instanceof JSONObject) { + JSONObject jsonObjectItem = (JSONObject) item; + if (this.isLookupEdit(StringUtils.getSpecialValue(jsonObjectItem.get("type")))) { + jsonObjectList.add(jsonObjectItem); + } + if (jsonObjectItem.get("contents") instanceof JSONArray) { + JSONArray contentsJsonArray = (JSONArray) jsonObjectItem.get("contents"); + rescureGetLookup(contentsJsonArray, jsonObjectList); + } + } + }); + } + + private void appendLookupConfigs(HashMap lookupConfigs, JSONObject lookupJsonObject) { + if (lookupJsonObject == null) { + return; + } + JsonNode lookup = SerializeUtility.getInstance().readTree(lookupJsonObject.toJSONString()); + + // 如果获取到帮助id为空那么返回 + if (lookup.get("helpId") == null) { + return; + } + + String helpId = StringUtils.getSpecialValue(lookup.get("helpId")); + + JsonNode lookupDataSource = lookup.get("dataSource"); + String uri = null; + if (lookupDataSource != null) { + uri = StringUtils.getSpecialValue(lookup.get("dataSource").get("uri")); + } + if (!StringUtility.isNullOrEmpty(helpId) && !StringUtility.isNullOrEmpty(uri)) { + if (!lookupConfigs.containsKey(uri)) { + LookupConfig tempVar = new LookupConfig(); + tempVar.setUri(String.join("/", uri.split("[.]", -1))); + tempVar.setLookupId(helpId); + lookupConfigs.put(uri, tempVar); + } + } + } + + private void appendLookupConfigsByFilterBar(HashMap lookupConfigs, JSONObject lookup) { + if (lookup == null) { + return; + } + + String helpId = StringUtils.getSpecialValue(lookup.get("helpId")); + String uri = StringUtils.getSpecialValue(lookup.get("uri")); + if (!StringUtility.isNullOrEmpty(helpId) && !StringUtility.isNullOrEmpty(uri)) { + if (!lookupConfigs.containsKey(uri)) { + LookupConfig tempVar = new LookupConfig(); + tempVar.setUri(String.join("/", uri.split("[.]", -1))); + tempVar.setLookupId(helpId); + lookupConfigs.put(uri, tempVar); + } + } + } + + /** + * 判断是否为帮助控件 + */ + private boolean isLookupEdit(String editorType) { + return editorType.equals("LookupEdit") || editorType.equals("PersonnelSelector") || editorType.equals("OrganizationSelector"); + } + +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtension.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtension.java new file mode 100644 index 00000000..1fa0c7fc --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtension.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.designschema.udtextensiondef; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.udt.designtime.api.extension.BaseUdtExtension; +import lombok.Data; + +import java.util.HashMap; + +/** + * @author liyz + * @date 2021/7/27 + */ +@Data +public class FormUdtExtension extends BaseUdtExtension { + + private String controlBindingFieldId; + private String controlType; + private LookupConfig lookupConfig; + + @Data + public class LookupConfig { + private String helpId; + private String idField; + private String valueField; + private String textField; + private String displayType; + private String displayName; + private HashMap mapFields; + @JsonInclude(JsonInclude.Include.NON_NULL) + private JsonNode options; + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionDeserializer.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionDeserializer.java new file mode 100644 index 00000000..0083a082 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionDeserializer.java @@ -0,0 +1,107 @@ +package com.inspur.edp.web.designschema.udtextensiondef; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inspur.edp.cef.designtime.api.json.SerializerUtils; +import com.inspur.edp.udt.designtime.api.extension.BaseUdtExtensionDeserializer; + +import java.io.IOException; +import java.util.HashMap; + +/** + * @author liyz + * @date 2021/7/27 + */ +public class FormUdtExtensionDeserializer extends BaseUdtExtensionDeserializer { + @Override + public FormUdtExtension deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) { + FormUdtExtension formUdtExtension = new FormUdtExtension(); + SerializerUtils.readStartObject(jsonParser); + while (jsonParser.getCurrentToken() == JsonToken.FIELD_NAME) { + String propertyName = SerializerUtils.readPropertyName(jsonParser); + switch (propertyName) { + case "controlBindingFieldId": + formUdtExtension.setControlBindingFieldId(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "controlType": + formUdtExtension.setControlType(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "lookupConfig": + readLookupConfig(formUdtExtension, jsonParser, deserializationContext); + break; + default: + SerializerUtils.readNullObject(jsonParser); + break; + } + } + + SerializerUtils.readEndObject(jsonParser); + return formUdtExtension; + } + + private void readLookupConfig(FormUdtExtension extension, JsonParser jsonParser, DeserializationContext deserializationContext) { + SerializerUtils.readStartObject(jsonParser); + + FormUdtExtension.LookupConfig lookupConfig = extension.new LookupConfig(); + extension.setLookupConfig(lookupConfig); + while (jsonParser.getCurrentToken() == JsonToken.FIELD_NAME) { + String propertyName = SerializerUtils.readPropertyName(jsonParser); + switch (propertyName) { + case "helpId": + lookupConfig.setHelpId(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "idField": + lookupConfig.setIdField(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "valueField": + lookupConfig.setValueField(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "textField": + lookupConfig.setTextField(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "displayType": + lookupConfig.setDisplayType(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "displayName": + lookupConfig.setDisplayName(SerializerUtils.readPropertyValue_String(jsonParser)); + break; + case "mapFields": + readMapFields(lookupConfig, jsonParser, deserializationContext); + break; + case "options": + // 大坑,readPropertyValue_Object没有让游标往下走,当前token为空。 + // lookupConfig.setOptions(SerializerUtils.readPropertyValue_Object(JsonNode.class, jsonParser)); + try { + lookupConfig.setOptions((new ObjectMapper()).readValue(jsonParser, JsonNode.class)); + jsonParser.nextToken(); // 游标往下走 + } catch (IOException e) { + e.printStackTrace(); + } + // readOptions(lookupConfig, jsonParser, deserializationContext); + break; + default: + SerializerUtils.readNullObject(jsonParser); + break; + } + } + + SerializerUtils.readEndObject(jsonParser); + } + + private void readMapFields(FormUdtExtension.LookupConfig lookupConfig, JsonParser jsonParser, DeserializationContext deserializationContext) { + HashMap mapFields = new HashMap<>(); + lookupConfig.setMapFields(mapFields); + + SerializerUtils.readStartObject(jsonParser); + while (jsonParser.getCurrentToken() == JsonToken.FIELD_NAME) { + String mapKey = SerializerUtils.readPropertyName(jsonParser); + String mapValue = SerializerUtils.readPropertyValue_String(jsonParser); + mapFields.put(mapKey, mapValue); + } + + SerializerUtils.readEndObject(jsonParser); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionSerializer.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionSerializer.java new file mode 100644 index 00000000..cbf8c32f --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/udtextensiondef/FormUdtExtensionSerializer.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.designschema.udtextensiondef; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.inspur.edp.udt.designtime.api.extension.BaseUdtExtensionSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; + +import java.io.IOException; + +/** + * @author liyz + * @date 2021/7/27 + */ +public class FormUdtExtensionSerializer extends BaseUdtExtensionSerializer { + @Override + public void serialize(FormUdtExtension formUdtExtension, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + ObjectMapper mapper = SerializeUtility.getInstance().getDefaultObjectMapper(); + mapper.writeValue(jsonGenerator, formUdtExtension); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/utils/StringUtils.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/utils/StringUtils.java new file mode 100644 index 00000000..46fb03bc --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/utils/StringUtils.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.designschema.utils; + +import com.fasterxml.jackson.databind.node.TextNode; + +/** + * @author noah + */ +public final class StringUtils { + + + /** + * 根据具体类型获取对应的参数值 + * @param source + * @return + */ + public static String getSpecialValue(Object source) { + if(source==null){ + return ""; + } + if (source instanceof String) { + return (String) source; + } + if (source instanceof TextNode) { + return ((TextNode) source).asText(); + } + + return source.toString(); + } +} diff --git a/web-designschema/src/main/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImpl.java b/web-designschema/src/main/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImpl.java new file mode 100644 index 00000000..dbec1151 --- /dev/null +++ b/web-designschema/src/main/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImpl.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.designschema.webservice; + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.designschema.api.webservice.DesignSchemaWebService; +import com.inspur.edp.web.designschema.elements.Schema; +import com.inspur.edp.web.designschema.generator.SchemaBuilder; + +import java.util.Arrays; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/15 + */ +public class DesignSchemaWebServiceImpl implements DesignSchemaWebService { + @Override + public String CreateDesignSchema(JSONObject content) { + try { + String scene = ""; + boolean isRuntime = false; + JSONObject viewObject = content; + + String viewObjectKey = "viewObject"; + if (content.get(viewObjectKey) != null) { + // vo dto 又包了一层,放在viewObject属性下,为了传递额外的参数 + viewObject = content.getJSONObject(viewObjectKey); + String sceneKey = "scene"; + if (content.containsKey(sceneKey)) { + scene = content.getString(sceneKey); + } + String isRuntimeKey = "isRuntime"; + if (content.containsKey(isRuntimeKey)) { + isRuntime = content.getBoolean(isRuntimeKey); + } + } + + String viewObjectContent = SerializeUtility.getInstance().serialize(viewObject); + GspViewModel vm = SerializeUtility.getInstance().deserialize(viewObjectContent, GspViewModel.class); + + SchemaBuilder schemaBuilder = new SchemaBuilder(); + + Schema schema = schemaBuilder.buildWithScene(vm, scene, isRuntime); + + return SerializeUtility.getInstance().valueToJson(schema, PropertyNamingStrategy.LOWER_CAMEL_CASE).toString(); + } catch (Exception ex) { + System.out.println(ex.getMessage() + Arrays.toString(ex.getStackTrace())); + } + return ""; + } + + @Override + public String CreateDesignSchemaByScene(JSONObject content) { + return null; + } + +} + diff --git a/web-designschema/src/main/resources/META-INF/spring.factories b/web-designschema/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..d6d9b656 --- /dev/null +++ b/web-designschema/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.designschema.config.DesignSchemaConfiguration diff --git a/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListenerTest.java b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListenerTest.java new file mode 100644 index 00000000..e4bc3251 --- /dev/null +++ b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/DesignSchemaChangeListenerTest.java @@ -0,0 +1,27 @@ +package java.com.inspur.edp.web.designschema.synchronization; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.designschema.synchronization.DesignSchemaChangeListener; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import org.junit.jupiter.api.Test; + +class DesignSchemaChangeListenerTest { + + @Test + void fireMetadataSavingEvent() { + String json = FileUtility.readAsString("D:\\InspurCode\\N转J之后代码\\tag2103\\web\\web-designschema\\src\\main\\test\\java\\com\\inspur\\edp\\web\\designschema\\synchronization\\help.json"); + DesignSchemaChangeListener changeListener = new DesignSchemaChangeListener(); + MetadataEventArgs eventArgs = new MetadataEventArgs(); + GspMetadata metadata = new GspMetadata(); + FormMetadataContent metadataContent = new FormMetadataContent(); + metadataContent.setContents(SerializeUtility.getInstance().readTree(json)); + + metadata.setContent(metadataContent); + eventArgs.setMetadata(metadata); + + changeListener.fireMetadataSavingEvent(eventArgs); + } +} diff --git a/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/help.json b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/help.json new file mode 100644 index 00000000..3fb22828 --- /dev/null +++ b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/synchronization/help.json @@ -0,0 +1,3563 @@ +{ + "module": { + "id": "DefectInspectPlanCards", + "code": "DefectInspectPlanCards", + "name": "缺陷检查计划卡片", + "caption": "缺陷检查计划卡片", + "type": "Module", + "creator": "wang-xh", + "creationDate": "2021-04-02T07:16:36.661Z", + "updateVersion": "191104", + "showTitle": true, + "bootstrap": "card-template", + "schemas": [ + { + "extendProperties": { + "enableStdTimeFormat": false + }, + "id": "c96ba332-7315-464c-b17b-3456b8f4fd43", + "code": "DefectInspectPlanCards_frm", + "name": "缺陷检查计划卡片_frm", + "sourceUri": "api/ea/ric/v1.0/DefectInspectPlanCards_frm", + "sourceType": "vo", + "entities": [ + { + "id": "927bbca2-2dfa-4101-9116-03fd27078d72", + "code": "DefectInspectPlan", + "name": "缺陷检查计划", + "label": "defectInspectPlans", + "type": { + "name": "DefectInspectPlan", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "4496d6b8-99ec-49fa-8ec2-f92442e69110", + "originalId": "4496d6b8-99ec-49fa-8ec2-f92442e69110", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "2a281b1d-99d5-4990-bd3c-de5e0dd2aa0d", + "originalId": "2a281b1d-99d5-4990-bd3c-de5e0dd2aa0d", + "code": "Version", + "name": "Version", + "label": "version", + "bindingField": "version", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "Version", + "bindingPath": "version", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f3e36f62-5932-453c-8f92-715219081be3", + "originalId": "f3e36f62-5932-453c-8f92-715219081be3", + "code": "PlanNumber", + "name": "计划编号", + "label": "planNumber", + "bindingField": "planNumber", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 60 + }, + "editor": { + "$type": "TextBox" + }, + "path": "PlanNumber", + "bindingPath": "planNumber", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "7f260ebc-2575-48e7-b5d6-37c0087c9e84", + "originalId": "7f260ebc-2575-48e7-b5d6-37c0087c9e84", + "code": "PlanName", + "name": "计划名称", + "label": "planName", + "bindingField": "planName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 150 + }, + "editor": { + "$type": "TextBox" + }, + "path": "PlanName", + "bindingPath": "planName", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6de2b305-f5ab-4b38-9e08-6dfad5dbe78d", + "originalId": "6de2b305-f5ab-4b38-9e08-6dfad5dbe78d", + "code": "ObjectiveDescription", + "name": "目标描述", + "label": "objectiveDescription", + "bindingField": "objectiveDescription", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ObjectiveDescription", + "bindingPath": "objectiveDescription", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "076d6d83-1121-439b-be1c-e928e15e5033", + "originalId": "076d6d83-1121-439b-be1c-e928e15e5033", + "code": "StartData", + "name": "计划开始日期", + "label": "startData", + "bindingField": "startData", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "StartData", + "bindingPath": "startData", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "38d38d0a-98e7-4de5-a62f-435264fdc54f", + "originalId": "38d38d0a-98e7-4de5-a62f-435264fdc54f", + "code": "EndDate", + "name": "计划结束日期", + "label": "endDate", + "bindingField": "endDate", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "EndDate", + "bindingPath": "endDate", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "7cae1fbd-4d08-4966-8d15-c44dbc0950ac", + "originalId": "7cae1fbd-4d08-4966-8d15-c44dbc0950ac", + "code": "State", + "name": "状态", + "label": "state", + "bindingField": "state", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "VoucherPreparation", + "name": "制单" + }, + { + "value": "Rejected", + "name": "审批不通过" + }, + { + "value": "Submit", + "name": "提交审批" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "State", + "bindingPath": "state", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6c08447a-07e7-413c-899f-e9eef6a1e988", + "originalId": "6c08447a-07e7-413c-899f-e9eef6a1e988", + "code": "CreateMan", + "name": "创建人", + "label": "createMan", + "bindingField": "createMan", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CreateMan", + "bindingPath": "createMan", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0959aaaa-dee1-4b10-963c-cc04baf7c8fe", + "originalId": "0959aaaa-dee1-4b10-963c-cc04baf7c8fe", + "code": "CreateData", + "name": "创建日期", + "label": "createData", + "bindingField": "createData", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "CreateData", + "bindingPath": "createData", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "e2c6c573-e87b-40ad-b174-b1a0eb38676f", + "originalId": "e2c6c573-e87b-40ad-b174-b1a0eb38676f", + "code": "BIllStatus", + "name": "单据状态", + "label": "bIllStatus", + "bindingField": "bIllStatus", + "type": { + "$type": "ObjectType", + "name": "BillStateE2c6", + "fields": [ + { + "$type": "SimpleField", + "id": "e2c6c573-0101-468f-ae3f-40c76c0f06b0", + "originalId": "a0b19650-0101-468f-ae3f-40c76c0f06b0", + "code": "BillState", + "name": "状态", + "label": "billState", + "bindingField": "bIllStatus_BillState", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "Billing", + "name": "制单" + }, + { + "value": "SubmitApproval", + "name": "提交审批" + }, + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "ApprovalNotPassed", + "name": "审批不通过" + }, + { + "value": "Abort", + "name": "流程终止" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "BIllStatus.BillState", + "bindingPath": "bIllStatus.billState", + "multiLanguage": false + } + ], + "displayName": "状态" + }, + "path": "BIllStatus", + "bindingPath": "bIllStatus" + }, + { + "$type": "ComplexField", + "id": "63743754-b1a4-4b15-a113-4ef4e6dd64e3", + "originalId": "63743754-b1a4-4b15-a113-4ef4e6dd64e3", + "code": "InstanceID", + "name": "流程实例", + "label": "instanceID", + "bindingField": "instanceID", + "type": { + "$type": "ObjectType", + "name": "ProcessInstance6374", + "fields": [ + { + "$type": "SimpleField", + "id": "63743754-ad8f-4da3-a430-c8a7f2162135", + "originalId": "2e1beb7d-ad8f-4da3-a430-c8a7f2162135", + "code": "ProcessInstance", + "name": "流程实例", + "label": "processInstance", + "bindingField": "instanceID_ProcessInstance", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "InstanceID.ProcessInstance", + "bindingPath": "instanceID.processInstance", + "multiLanguage": false + } + ], + "displayName": "流程实例" + }, + "path": "InstanceID", + "bindingPath": "instanceID" + }, + { + "$type": "ComplexField", + "id": "0c631515-cf50-42ea-809e-3285431e470d", + "originalId": "0c631515-cf50-42ea-809e-3285431e470d", + "code": "CreateInfo", + "name": "创建信息", + "label": "createInfo", + "bindingField": "createInfo", + "type": { + "$type": "ObjectType", + "name": "AdministrativeInfo0c63", + "fields": [ + { + "$type": "SimpleField", + "id": "0c631515-cbd0-415b-b9b5-2dd85c02e3d8", + "originalId": "06b8f722-cbd0-415b-b9b5-2dd85c02e3d8", + "code": "CreatedBy", + "name": "创建人", + "label": "createdBy", + "bindingField": "createInfo_CreatedBy", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 256 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CreateInfo.CreatedBy", + "bindingPath": "createInfo.createdBy", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0c631515-1961-459e-8e08-c613ea144d1c", + "originalId": "c4b07f76-1961-459e-8e08-c613ea144d1c", + "code": "CreatedOn", + "name": "创建时间", + "label": "createdOn", + "bindingField": "createInfo_CreatedOn", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "CreateInfo.CreatedOn", + "bindingPath": "createInfo.createdOn", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0c631515-db7d-4441-a911-2d11ca7e8a44", + "originalId": "980fa808-db7d-4441-a911-2d11ca7e8a44", + "code": "LastChangedBy", + "name": "最后修改人", + "label": "lastChangedBy", + "bindingField": "createInfo_LastChangedBy", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 256 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CreateInfo.LastChangedBy", + "bindingPath": "createInfo.lastChangedBy", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0c631515-495b-4f29-a8fa-30644dd72fe6", + "originalId": "fde64ec2-495b-4f29-a8fa-30644dd72fe6", + "code": "LastChangedOn", + "name": "最后修改时间", + "label": "lastChangedOn", + "bindingField": "createInfo_LastChangedOn", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "CreateInfo.LastChangedOn", + "bindingPath": "createInfo.lastChangedOn", + "multiLanguage": false + } + ], + "displayName": "更新信息" + }, + "path": "CreateInfo", + "bindingPath": "createInfo" + }, + { + "$type": "SimpleField", + "id": "3ea7194f-0d19-4a3c-96a2-083752aab75d", + "originalId": "3ea7194f-0d19-4a3c-96a2-083752aab75d", + "code": "CompanyId", + "name": "单位ID", + "label": "companyId", + "bindingField": "companyId", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CompanyId", + "bindingPath": "companyId", + "multiLanguage": false + } + ], + "entities": [ + { + "id": "5166a23e-8921-4e6b-b2c2-4102a23f7aab", + "code": "InspectScope", + "name": "检查范围", + "label": "inspectScopes", + "type": { + "name": "InspectScope", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "ed23b354-07a7-470f-9ba1-6e8a990f193f", + "originalId": "ed23b354-07a7-470f-9ba1-6e8a990f193f", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "ad70961b-e06f-46b8-93e0-3fcf106371ba", + "originalId": "ad70961b-e06f-46b8-93e0-3fcf106371ba", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "228b5658-0a3e-45c8-a9ac-aed325f681a1", + "originalId": "228b5658-0a3e-45c8-a9ac-aed325f681a1", + "code": "SerialNumber", + "name": "序号", + "label": "serialNumber", + "bindingField": "serialNumber", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SerialNumber", + "bindingPath": "serialNumber", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "e613bae2-d5d9-4acb-87e7-312782edef66", + "originalId": "e613bae2-d5d9-4acb-87e7-312782edef66", + "code": "Company", + "name": "单位", + "label": "company", + "bindingField": "company", + "type": { + "$type": "EntityType", + "name": "AdminOrganizationCa1f", + "primary": "company", + "fields": [ + { + "$type": "SimpleField", + "id": "ca1f2a71-e5d8-461e-bd87-57e8b33a29eb", + "originalId": "ca1f2a71-e5d8-461e-bd87-57e8b33a29eb", + "code": "Company", + "name": "单位", + "label": "company", + "bindingField": "company", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Company.Company", + "bindingPath": "company.company", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "8d92bbd1-d8d2-4d21-8158-40777d7e763f", + "originalId": "8d92bbd1-d8d2-4d21-8158-40777d7e763f", + "code": "ID", + "name": "ID", + "label": "company_ID", + "bindingField": "company_Company_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Company.Company_ID", + "bindingPath": "company.company_ID", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "93f9ca89-d93b-43b6-aea7-35677166041e", + "originalId": "93f9ca89-d93b-43b6-aea7-35677166041e", + "code": "Code", + "name": "编码", + "label": "company_Code", + "bindingField": "company_Company_Code", + "type": { + "$type": "ObjectType", + "name": "DFCode93f9", + "fields": [ + { + "$type": "SimpleField", + "id": "93f9ca89-b374-4feb-bd57-6614cb990d33", + "originalId": "42e99ef8-b374-4feb-bd57-6614cb990d33", + "code": "DFCode", + "name": "基础数据编码", + "label": "dfCode", + "bindingField": "company_Company_Code_DFCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Company.Company_Code.DFCode", + "bindingPath": "company.company_Code.dfCode", + "multiLanguage": false + } + ], + "displayName": "基础数据编码" + }, + "path": "Company.Company_Code", + "bindingPath": "company.company_Code" + }, + { + "$type": "ComplexField", + "id": "b12c1c48-ea8f-4fc5-bc7f-afef76c36622", + "originalId": "b12c1c48-ea8f-4fc5-bc7f-afef76c36622", + "code": "Name", + "name": "名称", + "label": "company_Name", + "bindingField": "company_Company_Name", + "type": { + "$type": "ObjectType", + "name": "DFNameB12c", + "fields": [ + { + "$type": "SimpleField", + "id": "b12c1c48-091e-4455-b15b-93017ae54fcf", + "originalId": "fb950cb7-091e-4455-b15b-93017ae54fcf", + "code": "DFName", + "name": "基础数据名称", + "label": "dfName", + "bindingField": "company_Company_Name_DFName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Company.Company_Name.DFName", + "bindingPath": "company.company_Name.dfName", + "multiLanguage": false + } + ], + "displayName": "基础数据名称" + }, + "path": "Company.Company_Name", + "bindingPath": "company.company_Name" + } + ], + "entities": [], + "displayName": "行政组织" + }, + "path": "Company", + "bindingPath": "company" + }, + { + "$type": "ComplexField", + "id": "7060a717-cb5e-4f18-aea7-9e091028d39b", + "originalId": "7060a717-cb5e-4f18-aea7-9e091028d39b", + "code": "Department", + "name": "部门", + "label": "department", + "bindingField": "department", + "type": { + "$type": "EntityType", + "name": "AdminOrganization5e0f", + "primary": "department", + "fields": [ + { + "$type": "SimpleField", + "id": "5e0f993a-fc6c-4673-825c-91196292aef8", + "originalId": "5e0f993a-fc6c-4673-825c-91196292aef8", + "code": "Department", + "name": "部门", + "label": "department", + "bindingField": "department", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Department.Department", + "bindingPath": "department.department", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "3b534aae-e864-4a08-b713-f0b0876d5d3a", + "originalId": "3b534aae-e864-4a08-b713-f0b0876d5d3a", + "code": "ID", + "name": "ID", + "label": "department_ID", + "bindingField": "department_Department_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Department.Department_ID", + "bindingPath": "department.department_ID", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "227815f8-50d2-4676-8e04-3d15b05ae15f", + "originalId": "227815f8-50d2-4676-8e04-3d15b05ae15f", + "code": "Code", + "name": "编码", + "label": "department_Code", + "bindingField": "department_Department_Code", + "type": { + "$type": "ObjectType", + "name": "DFCode2278", + "fields": [ + { + "$type": "SimpleField", + "id": "227815f8-b374-4feb-bd57-6614cb990d33", + "originalId": "42e99ef8-b374-4feb-bd57-6614cb990d33", + "code": "DFCode", + "name": "基础数据编码", + "label": "dfCode", + "bindingField": "department_Department_Code_DFCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Department.Department_Code.DFCode", + "bindingPath": "department.department_Code.dfCode", + "multiLanguage": false + } + ], + "displayName": "基础数据编码" + }, + "path": "Department.Department_Code", + "bindingPath": "department.department_Code" + }, + { + "$type": "ComplexField", + "id": "9af292a2-f1d7-4c85-a476-359eae538b37", + "originalId": "9af292a2-f1d7-4c85-a476-359eae538b37", + "code": "Name", + "name": "名称", + "label": "department_Name", + "bindingField": "department_Department_Name", + "type": { + "$type": "ObjectType", + "name": "DFName9af2", + "fields": [ + { + "$type": "SimpleField", + "id": "9af292a2-091e-4455-b15b-93017ae54fcf", + "originalId": "fb950cb7-091e-4455-b15b-93017ae54fcf", + "code": "DFName", + "name": "基础数据名称", + "label": "dfName", + "bindingField": "department_Department_Name_DFName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Department.Department_Name.DFName", + "bindingPath": "department.department_Name.dfName", + "multiLanguage": false + } + ], + "displayName": "基础数据名称" + }, + "path": "Department.Department_Name", + "bindingPath": "department.department_Name" + } + ], + "entities": [], + "displayName": "行政组织" + }, + "path": "Department", + "bindingPath": "department" + } + ], + "entities": [], + "displayName": "检查范围" + } + }, + { + "id": "753d47f9-ddd4-494c-8218-adeaa3e2bfab", + "code": "DefectChecklist", + "name": "缺陷检查列表", + "label": "defectChecklists", + "type": { + "name": "DefectChecklist", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "a8583dc8-962c-4b1a-9652-7fc5fa1cde19", + "originalId": "a8583dc8-962c-4b1a-9652-7fc5fa1cde19", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "031739aa-054d-4b85-8cde-77b664739f23", + "originalId": "031739aa-054d-4b85-8cde-77b664739f23", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "43cba79f-e64b-43b5-b0b2-8f313e0a3082", + "originalId": "43cba79f-e64b-43b5-b0b2-8f313e0a3082", + "code": "SerialNumber", + "name": "序号", + "label": "serialNumber", + "bindingField": "serialNumber", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SerialNumber", + "bindingPath": "serialNumber", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "27e8f422-a6e9-48db-9594-58b72221fbf5", + "originalId": "27e8f422-a6e9-48db-9594-58b72221fbf5", + "code": "ControlCategory", + "name": "管控类别", + "label": "controlCategory", + "bindingField": "controlCategory", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ControlCategory", + "bindingPath": "controlCategory", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "79ed7452-31c4-4b66-bba8-633b9244b48f", + "originalId": "79ed7452-31c4-4b66-bba8-633b9244b48f", + "code": "ControlStandard", + "name": "管控有效标准", + "label": "controlStandard", + "bindingField": "controlStandard", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ControlStandard", + "bindingPath": "controlStandard", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "027d3b02-a1fc-4c89-8bc5-d741dff5a854", + "originalId": "027d3b02-a1fc-4c89-8bc5-d741dff5a854", + "code": "ControlMode", + "name": "管控方式", + "label": "controlMode", + "bindingField": "controlMode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ControlMode", + "bindingPath": "controlMode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "190c49c5-b3c8-4954-9645-92b17217cc34", + "originalId": "190c49c5-b3c8-4954-9645-92b17217cc34", + "code": "SystemDocuments", + "name": "涉及相关制度文件", + "label": "systemDocuments", + "bindingField": "systemDocuments", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SystemDocuments", + "bindingPath": "systemDocuments", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "缺陷检查列表" + } + } + ], + "displayName": "缺陷检查计划" + } + } + ], + "variables": [], + "eapiId": "51fd04d3-bedc-4d9d-a5fc-312d66c23a1b" + } + ], + "states": [], + "contents": [], + "stateMachines": [ + { + "id": "DefectInspectPlanCards_state_machine", + "name": "缺陷检查计划卡片状态机", + "uri": "bdae219a-98ec-473c-b133-87b7683ffd00" + } + ], + "viewmodels": [ + { + "id": "root-viewmodel", + "code": "root-viewmodel", + "name": "缺陷检查计划", + "fields": [], + "stateMachine": "DefectInspectPlanCards_state_machine", + "serviceRefs": [], + "commands": [ + { + "id": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "code": "Load1", + "name": "加载", + "params": [ + { + "name": "action", + "shownName": "初始动作", + "value": "{UISTATE~/root-component/action}", + "description": null + } + ], + "handlerName": "Load", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "code": "LoadAndAdd1", + "name": "加载并新增", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "LoadAndAdd", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "code": "LoadAndView1", + "name": "加载并查看", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "LoadAndView", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "code": "LoadAndEdit1", + "name": "加载并编辑", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "LoadAndEdit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f90aadfa-988c-4da5-a5db-1416c3333794", + "code": "Add1", + "name": "新增数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "Add", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "code": "Edit1", + "name": "编辑数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "Edit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "31b814db-01e4-407d-8fad-0f08dbb01999", + "code": "Save1", + "name": "保存数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Save", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "code": "Cancel1", + "name": "取消变更", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Cancel", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "code": "Close1", + "name": "关闭", + "params": [ + { + "name": "url", + "shownName": "上级Url", + "value": "", + "description": null + }, + { + "name": "params", + "shownName": "路由参数", + "value": "", + "description": null + } + ], + "handlerName": "Close", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c8504c24-33e8-487a-91ce-2218b803fe01", + "code": "ChangeItem1", + "name": "ChangeItem", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "prev", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "code": "ChangeItem2", + "name": "ChangeItem2", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "next", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "enableUnifiedSession": false + }, + { + "id": "basic-form-viewmodel", + "code": "basic-form-viewmodel", + "name": "缺陷检查计划", + "fields": [ + { + "type": "Form", + "id": "f3e36f62-5932-453c-8f92-715219081be3", + "fieldName": "planNumber", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "7f260ebc-2575-48e7-b5d6-37c0087c9e84", + "fieldName": "planName", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "6de2b305-f5ab-4b38-9e08-6dfad5dbe78d", + "fieldName": "objectiveDescription", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "076d6d83-1121-439b-be1c-e928e15e5033", + "fieldName": "startData", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "name": "开始日期", + "require": true + } + }, + { + "type": "Form", + "id": "38d38d0a-98e7-4de5-a62f-435264fdc54f", + "fieldName": "endDate", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "name": "结束日期", + "require": true + } + }, + { + "type": "Form", + "id": "e2c6c573-0101-468f-ae3f-40c76c0f06b0", + "fieldName": "bIllStatus_BillState", + "groupId": null, + "groupName": null, + "updateOn": "change", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "0c631515-cbd0-415b-b9b5-2dd85c02e3d8", + "fieldName": "createInfo_CreatedBy", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "0c631515-1961-459e-8e08-c613ea144d1c", + "fieldName": "createInfo_CreatedOn", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + } + ], + "serviceRefs": [], + "commands": [], + "states": [], + "bindTo": "/", + "parent": "root-viewmodel", + "enableValidation": true + }, + { + "id": "inspectscope-component-viewmodel", + "code": "inspectscope-component-viewmodel", + "name": "检查范围", + "fields": [ + { + "type": "Form", + "id": "228b5658-0a3e-45c8-a9ac-aed325f681a1", + "fieldName": "serialNumber", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "b12c1c48-091e-4455-b15b-93017ae54fcf", + "fieldName": "company_Company_Name_DFName", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "name": "单位" + } + }, + { + "type": "Form", + "id": "9af292a2-091e-4455-b15b-93017ae54fcf", + "fieldName": "department_Department_Name_DFName", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "name": "部门" + } + }, + { + "type": "Form", + "id": "5e0f993a-fc6c-4673-825c-91196292aef8", + "fieldName": "department", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "dataSource": { + "uri": "InspectScope.department", + "displayName": "部门帮助", + "idField": "id", + "type": "ViewObject" + }, + "valueField": "code", + "textField": "name", + "displayType": "NavTreeList", + "mapFields": "", + "helpId": "1c6796c6-578f-4576-b57f-24c29aa12514" + } + } + } + ], + "states": [], + "bindTo": "/inspectScopes", + "parent": "root-viewmodel", + "commands": [ + { + "id": "4cb0446e-6ea2-415e-abe1-5476b1ee63b8", + "code": "inspectscopeAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "bfb97a1d-5265-4fa6-8289-4251f8ab8b05", + "code": "inspectscopeRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/inspectscope-component/inspectScopes/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "b38a8273-3c6d-4c29-a565-035c87d63f10", + "code": "inspectscopecomponentviewmodelBeforeMultiSelectHelpOpen1", + "name": "多选帮助批量赋值帮助前事件1", + "params": [], + "handlerName": "BeforeMultiSelectHelpOpen", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "507f9c90-21ad-44bb-8535-5511e105042e", + "code": "inspectscopecomponentviewmodelAfterMultiSelectHelpClose1", + "name": "多选帮助批量赋值帮助后事件1", + "params": [ + { + "name": "frameId", + "shownName": "grid所在frame", + "value": "inspectscope-component", + "description": "grid所在frame" + }, + { + "name": "mapFields", + "shownName": "帮助字段映射", + "value": "{\"id\":\"department.department\", \"code\":\"department.department_Code.dfCode\", \"name\":\"department.department_Name.dfName\", \"ownerID\":\"company.company\", \"ownerName\":\"company.company_Name.dfName\"}", + "description": "帮助字段映射" + } + ], + "handlerName": "AfterMultiSelectHelpClose", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c7b944f0-bec7-4763-b7a9-a1c1a4763cb5", + "code": "inspectscopecomponentviewmodelOpenHiddenHelp1", + "name": "弹出帮助1", + "params": [ + { + "name": "helpId", + "shownName": "帮助Id", + "value": "depthelpId", + "description": "帮助Id" + } + ], + "handlerName": "OpenHiddenHelp", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": true, + "pagination": { + "enable": false + } + }, + { + "id": "defectchecklist-component-viewmodel", + "code": "defectchecklist-component-viewmodel", + "name": "缺陷检查列表", + "fields": [ + { + "type": "Form", + "id": "43cba79f-e64b-43b5-b0b2-8f313e0a3082", + "fieldName": "serialNumber", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "27e8f422-a6e9-48db-9594-58b72221fbf5", + "fieldName": "controlCategory", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "79ed7452-31c4-4b66-bba8-633b9244b48f", + "fieldName": "controlStandard", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "027d3b02-a1fc-4c89-8bc5-d741dff5a854", + "fieldName": "controlMode", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "190c49c5-b3c8-4954-9645-92b17217cc34", + "fieldName": "systemDocuments", + "groupId": null, + "groupName": null, + "updateOn": "blur" + } + ], + "states": [], + "bindTo": "/defectChecklists", + "parent": "root-viewmodel", + "commands": [ + { + "id": "ae4fa7c5-9071-4489-a211-9f25916d62cf", + "code": "defectchecklistAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + }, + { + "id": "f9de797b-56cc-4814-a5d0-cea3ffeabefa", + "code": "defectchecklistRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/defectchecklist-component/defectChecklists/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": true, + "pagination": { + "enable": false + } + } + ], + "components": [ + { + "id": "root-component", + "type": "Component", + "viewModel": "root-viewmodel", + "componentType": "Frame", + "onInit": "Load1", + "contents": [ + { + "id": "root-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-page f-page-card f-page-is-mainsubcard" + }, + "size": null, + "contents": [ + { + "id": "page-header", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header" + }, + "size": null, + "contents": [ + { + "id": "header-nav", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header-base" + }, + "size": null, + "contents": [ + { + "id": "header-title-container", + "type": "ContentContainer", + "appearance": { + "class": "f-title" + }, + "size": null, + "contents": [ + { + "id": "page-header-title", + "type": "HtmlTemplate", + "html": "

缺陷检查计划卡片

" + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + }, + { + "id": "page-header-toolbar", + "type": "ToolBar", + "appearance": { + "class": "col-7 f-toolbar" + }, + "size": null, + "items": [ + { + "id": "button-add", + "type": "ToolBarItem", + "text": "新增", + "appearance": { + "class": "btn-primary" + }, + "disable": "!viewModel.stateMachine['canAdd']", + "visible": true, + "click": "Add1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-edit", + "type": "ToolBarItem", + "text": "编辑", + "appearance": null, + "disable": "!viewModel.stateMachine['canEdit']", + "visible": true, + "click": "Edit1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-save", + "type": "ToolBarItem", + "text": "保存", + "appearance": null, + "disable": "!viewModel.stateMachine['canSave']", + "visible": true, + "click": "Save1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-cancel", + "type": "ToolBarItem", + "text": "取消", + "appearance": null, + "disable": "!viewModel.stateMachine['canCancel']", + "visible": true, + "click": "Cancel1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-close", + "type": "ToolBarItem", + "text": "关闭", + "appearance": null, + "disable": false, + "visible": true, + "click": "Close1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + } + ], + "visible": true + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + }, + { + "id": "main-container", + "type": "ContentContainer", + "appearance": { + "class": "f-page-main" + }, + "size": null, + "contents": [ + { + "id": "basic-form-component-ref", + "type": "ComponentRef", + "component": "basic-form-component", + "visible": true + }, + { + "id": "detail-container", + "type": "ContentContainer", + "appearance": { + "class": "f-struct-wrapper" + }, + "size": null, + "contents": [ + { + "id": "detail-section", + "type": "Section", + "appearance": { + "class": "f-section-tabs f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": false, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "detail-tab", + "type": "Tab", + "controlSource": "Farris", + "appearance": { + "class": "f-component-tabs f-tabs-has-grid" + }, + "selected": "inspectscope-tab-page", + "size": null, + "position": "top", + "contents": [ + { + "id": "inspectscope-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "检查范围", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "inspectscope-component-ref", + "type": "ComponentRef", + "component": "inspectscope-component", + "visible": true + } + ], + "toolbar": { + "id": "inspectscope-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "inspectscopeAddButton", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-secondary f-btn-ml" + }, + "visible": true, + "click": "root-viewmodel.inspectscope-component-viewmodel.inspectscopecomponentviewmodelOpenHiddenHelp1" + }, + { + "id": "inspectscopeRemoveButton", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-secondary f-btn-ml" + }, + "visible": true, + "click": "root-viewmodel.inspectscope-component-viewmodel.inspectscopeRemoveItem1" + } + ] + }, + "visible": true + }, + { + "id": "defectchecklist-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "缺陷检查列表", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "defectchecklist-component-ref", + "type": "ComponentRef", + "component": "defectchecklist-component", + "visible": true + } + ], + "toolbar": { + "id": "defectchecklist-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "defectchecklistAddButton", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-secondary f-btn-ml" + }, + "visible": true, + "click": "root-viewmodel.defectchecklist-component-viewmodel.defectchecklistAddItem1" + }, + { + "id": "defectchecklistRemoveButton", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-secondary f-btn-ml" + }, + "visible": true, + "click": "root-viewmodel.defectchecklist-component-viewmodel.defectchecklistRemoveItem1" + } + ] + }, + "visible": true + } + ], + "tabChange": null, + "tabRemove": null, + "contentFill": false, + "autoTitleWidth": false, + "titleWidth": 0, + "visible": true + } + ], + "isScrollSpyItem": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "basic-form-component", + "type": "Component", + "viewModel": "basic-form-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "basic-form-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "基本信息", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "basic-form-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "size": null, + "contents": [ + { + "id": "planNumber_f3e36f62_is1n", + "type": "TextBox", + "titleSourceType": "static", + "title": "计划编号", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "planNumber", + "field": "f3e36f62-5932-453c-8f92-715219081be3" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 60, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "planNumber", + "span": 1, + "enableTips": true + }, + { + "id": "planName_7f260ebc_dlj0", + "type": "TextBox", + "titleSourceType": "static", + "title": "计划名称", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "planName", + "field": "7f260ebc-2575-48e7-b5d6-37c0087c9e84" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 150, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "planName", + "span": 1, + "enableTips": true + }, + { + "id": "objectiveDescription_6de2b305_yikf", + "type": "TextBox", + "titleSourceType": "static", + "title": "目标描述", + "appearance": { + "class": "{\"class\":\"col-12 col-md-12 col-xl-12 col-el-12 farris-group-auto col-6\"}" + }, + "size": null, + "binding": { + "type": "Form", + "path": "objectiveDescription", + "field": "6de2b305-f5ab-4b38-9e08-6dfad5dbe78d" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 1000, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "objectiveDescription", + "span": 1, + "enableTips": true + }, + { + "id": "startData_076d6d83_m3ab", + "type": "DateBox", + "titleSourceType": "static", + "title": "开始日期", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "startData", + "field": "076d6d83-1121-439b-be1c-e928e15e5033" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "startData", + "span": 1, + "localization": false + }, + { + "id": "endDate_38d38d0a_s0yl", + "type": "DateBox", + "titleSourceType": "static", + "title": "结束日期", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "endDate", + "field": "38d38d0a-98e7-4de5-a62f-435264fdc54f" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "endDate", + "span": 1, + "localization": false + }, + { + "id": "createInfo_CreatedBy_0c631515_v26g", + "type": "TextBox", + "titleSourceType": "static", + "title": "创建人", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "createInfo_CreatedBy", + "field": "0c631515-cbd0-415b-b9b5-2dd85c02e3d8" + }, + "readonly": true, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 256, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "createInfo.createdBy", + "span": 1, + "enableTips": true + }, + { + "id": "createInfo_CreatedOn_0c631515_u5u9", + "type": "DateBox", + "titleSourceType": "static", + "title": "创建时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "createInfo_CreatedOn", + "field": "0c631515-1961-459e-8e08-c613ea144d1c" + }, + "readonly": true, + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "createInfo.createdOn", + "span": 1, + "localization": false + }, + { + "id": "bIllStatus_BillState_e2c6c573_2coq", + "type": "EnumField", + "titleSourceType": "static", + "title": "状态", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-6 col-el-6 farris-group-auto" + }, + "size": null, + "binding": { + "type": "Form", + "path": "bIllStatus_BillState", + "field": "e2c6c573-0101-468f-ae3f-40c76c0f06b0" + }, + "placeHolder": "", + "readonly": true, + "require": false, + "disable": false, + "enumData": [ + { + "value": "Billing", + "name": "制单" + }, + { + "value": "SubmitApproval", + "name": "提交审批" + }, + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "ApprovalNotPassed", + "name": "审批不通过" + }, + { + "value": "Abort", + "name": "流程终止" + } + ], + "holdPlace": false, + "isTextArea": true, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": false, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "enableCancelSelected": false, + "beforeShow": null, + "beforeHide": null, + "dataSourceType": "static", + "path": "bIllStatus.billState", + "span": 1, + "viewType": "text", + "noSearch": false + } + ], + "controlsInline": true, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "inspectscope-component", + "type": "Component", + "viewModel": "inspectscope-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "inspectscope-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "size": null, + "contents": [ + { + "id": "HiddenContainer-form", + "type": "HiddenContainer", + "appearance": { + "class": "d-flex flex-wrap flex-fill" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "depthelpId", + "type": "LookupEdit", + "title": "name", + "appearance": { + "class": "col-12" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "department", + "field": "5e0f993a-fc6c-4673-825c-91196292aef8", + "fullPath": "Department.Department" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "InspectScope.department", + "displayName": "部门帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "NavTreeList", + "multiSelect": true, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "", + "lookupPicking": "inspectscopecomponentviewmodelBeforeMultiSelectHelpOpen1", + "lookupPicked": "inspectscopecomponentviewmodelAfterMultiSelectHelpClose1", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "clear": null, + "helpId": "1c6796c6-578f-4576-b57f-24c29aa12514", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "loadTreeDataType": "default", + "isTextArea": null, + "holdPlace": false, + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "tabindex": 1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableClear": true, + "enableCascade": false, + "CascadeStatus": "default", + "cascadeStatus": "enable", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "path": "department.department", + "noSearch": false, + "onlySelectLeaf": "default" + } + ], + "controlsInline": false, + "visible": true + }, + { + "id": "dataGrid_inspectscope", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "inspectScopes", + "fields": [ + { + "id": "serialNumber_228b5658_5wdx", + "type": "GridField", + "controlSource": "Farris", + "caption": "序号", + "captionTemplate": null, + "dataField": "serialNumber", + "dataType": "string", + "binding": { + "type": "Form", + "path": "serialNumber", + "field": "228b5658-0a3e-45c8-a9ac-aed325f681a1" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "serialNumber_228b5658_g8cj", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "serialNumber", + "field": "228b5658-0a3e-45c8-a9ac-aed325f681a1" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "serialNumber", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "serialNumber", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "department_Department_Name_DFName_9af292a2_fi30", + "type": "GridField", + "controlSource": "Farris", + "caption": "部门", + "captionTemplate": null, + "dataField": "department.department_Name.dfName", + "dataType": "string", + "binding": { + "type": "Form", + "path": "department_Department_Name_DFName", + "field": "9af292a2-091e-4455-b15b-93017ae54fcf" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "department_Department_Name_DFName_9af292a2_2d5d", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "department_Department_Name_DFName", + "field": "9af292a2-091e-4455-b15b-93017ae54fcf" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 1000, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "department.department_Name.dfName", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "department.department_Name.dfName", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "company_Company_Name_DFName_b12c1c48_i3b1", + "type": "GridField", + "controlSource": "Farris", + "caption": "单位", + "captionTemplate": null, + "dataField": "company.company_Name.dfName", + "dataType": "string", + "binding": { + "type": "Form", + "path": "company_Company_Name_DFName", + "field": "b12c1c48-091e-4455-b15b-93017ae54fcf" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "company_Company_Name_DFName_b12c1c48_i19v", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "company_Company_Name_DFName", + "field": "b12c1c48-091e-4455-b15b-93017ae54fcf" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 1000, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "company.company_Name.dfName", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "company.company_Name.dfName", + "readonly": false, + "visible": true, + "localization": false + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "pagination": true, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageList": false, + "identifyField": null, + "multiSelect": null, + "showCheckbox": false, + "showAllCheckbox": false, + "checkOnSelect": false, + "selectOnCheck": false, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "showGroupColumn": true, + "groupFormatter": null, + "groupStyler": null, + "groupFooter": false, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "fitColumns": true, + "autoFitColumns": false, + "multiSort": false, + "showBorder": false, + "striped": true, + "onSelectionChange": "", + "styler": "", + "showLineNumber": false, + "appendRow": "inspectscopeAddItem1", + "pageChange": null, + "disableRow": null, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "beforeUnCheck": null, + "dblClickRow": null, + "virtualized": false, + "showFooter": false, + "footerTemplate": "", + "footerDataFrom": "client", + "footerDataCommand": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": false, + "useControlPanel": false, + "autoHeight": false, + "rowClick": null, + "showSelectedList": false, + "selectedItemFormatter": null, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "visible": true, + "checkedChange": null, + "beforeEdit": null, + "mergeCell": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "showPageSize": false, + "draggable": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + }, + { + "id": "defectchecklist-component", + "type": "Component", + "viewModel": "defectchecklist-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "defectchecklist-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "size": null, + "contents": [ + { + "id": "dataGrid_defectchecklist", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "defectChecklists", + "fields": [ + { + "id": "serialNumber_43cba79f_oojo", + "type": "GridField", + "controlSource": "Farris", + "caption": "序号", + "captionTemplate": null, + "dataField": "serialNumber", + "dataType": "string", + "binding": { + "type": "Form", + "path": "serialNumber", + "field": "43cba79f-e64b-43b5-b0b2-8f313e0a3082" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "serialNumber_43cba79f_68ln", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "serialNumber", + "field": "43cba79f-e64b-43b5-b0b2-8f313e0a3082" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "serialNumber", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "serialNumber", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "controlCategory_27e8f422_w6da", + "type": "GridField", + "controlSource": "Farris", + "caption": "管控类别", + "captionTemplate": null, + "dataField": "controlCategory", + "dataType": "string", + "binding": { + "type": "Form", + "path": "controlCategory", + "field": "27e8f422-a6e9-48db-9594-58b72221fbf5" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "controlCategory_27e8f422_vtkp", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "controlCategory", + "field": "27e8f422-a6e9-48db-9594-58b72221fbf5" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "controlCategory", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "controlCategory", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "controlStandard_79ed7452_ks3r", + "type": "GridField", + "controlSource": "Farris", + "caption": "管控有效标准", + "captionTemplate": null, + "dataField": "controlStandard", + "dataType": "string", + "binding": { + "type": "Form", + "path": "controlStandard", + "field": "79ed7452-31c4-4b66-bba8-633b9244b48f" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "controlStandard_79ed7452_ootc", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "controlStandard", + "field": "79ed7452-31c4-4b66-bba8-633b9244b48f" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "controlStandard", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "controlStandard", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "controlMode_027d3b02_sfc9", + "type": "GridField", + "controlSource": "Farris", + "caption": "管控方式", + "captionTemplate": null, + "dataField": "controlMode", + "dataType": "string", + "binding": { + "type": "Form", + "path": "controlMode", + "field": "027d3b02-a1fc-4c89-8bc5-d741dff5a854" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "controlMode_027d3b02_84jz", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "controlMode", + "field": "027d3b02-a1fc-4c89-8bc5-d741dff5a854" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "controlMode", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "controlMode", + "readonly": false, + "visible": true, + "localization": false + }, + { + "id": "systemDocuments_190c49c5_wbmy", + "type": "GridField", + "controlSource": "Farris", + "caption": "涉及相关制度文件", + "captionTemplate": null, + "dataField": "systemDocuments", + "dataType": "string", + "binding": { + "type": "Form", + "path": "systemDocuments", + "field": "190c49c5-b3c8-4954-9645-92b17217cc34" + }, + "enumData": null, + "appearance": null, + "size": { + "width": 120 + }, + "displayTemplate": null, + "editor": { + "id": "systemDocuments_190c49c5_ik1o", + "type": "TextBox", + "titleSourceType": "static", + "title": "文本", + "appearance": null, + "size": null, + "binding": { + "type": "Form", + "path": "systemDocuments", + "field": "190c49c5-b3c8-4954-9645-92b17217cc34" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "systemDocuments", + "enableTips": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "enableFilter": false, + "headerStyler": "", + "path": "systemDocuments", + "readonly": false, + "visible": true, + "localization": false + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "pagination": true, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageList": false, + "identifyField": null, + "multiSelect": null, + "showCheckbox": false, + "showAllCheckbox": false, + "checkOnSelect": false, + "selectOnCheck": false, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "showGroupColumn": true, + "groupFormatter": null, + "groupStyler": null, + "groupFooter": false, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "fitColumns": true, + "autoFitColumns": false, + "multiSort": false, + "showBorder": false, + "striped": true, + "onSelectionChange": "", + "styler": "", + "showLineNumber": false, + "appendRow": "defectchecklistAddItem1", + "pageChange": null, + "disableRow": null, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "beforeUnCheck": null, + "dblClickRow": null, + "virtualized": false, + "showFooter": false, + "footerTemplate": "", + "footerDataFrom": "client", + "footerDataCommand": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": false, + "useControlPanel": false, + "autoHeight": false, + "rowClick": null, + "showSelectedList": false, + "selectedItemFormatter": null, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "visible": true, + "checkedChange": null, + "beforeEdit": null, + "mergeCell": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "showPageSize": false, + "draggable": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + } + ], + "webcmds": [ + { + "id": "8172a979-2c80-4637-ace7-b13074d3f393", + "path": "/projects/packages/Inspur.GS.Gsp.Web.WebCmp/webcmd", + "name": "CardController.webcmd", + "refedHandlers": [ + { + "host": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "handler": "Load" + }, + { + "host": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "handler": "LoadAndAdd" + }, + { + "host": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "handler": "LoadAndView" + }, + { + "host": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "handler": "LoadAndEdit" + }, + { + "host": "f90aadfa-988c-4da5-a5db-1416c3333794", + "handler": "Add" + }, + { + "host": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "handler": "Edit" + }, + { + "host": "31b814db-01e4-407d-8fad-0f08dbb01999", + "handler": "Save" + }, + { + "host": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "handler": "Cancel" + }, + { + "host": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "handler": "Close" + }, + { + "host": "c8504c24-33e8-487a-91ce-2218b803fe01", + "handler": "ChangeItem" + }, + { + "host": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "handler": "ChangeItem" + }, + { + "host": "4cb0446e-6ea2-415e-abe1-5476b1ee63b8", + "handler": "AddItem" + }, + { + "host": "bfb97a1d-5265-4fa6-8289-4251f8ab8b05", + "handler": "RemoveItem" + }, + { + "host": "ae4fa7c5-9071-4489-a211-9f25916d62cf", + "handler": "AddItem" + }, + { + "host": "f9de797b-56cc-4814-a5d0-cea3ffeabefa", + "handler": "RemoveItem" + }, + { + "host": "b38a8273-3c6d-4c29-a565-035c87d63f10", + "handler": "BeforeMultiSelectHelpOpen" + }, + { + "host": "507f9c90-21ad-44bb-8535-5511e105042e", + "handler": "AfterMultiSelectHelpClose" + }, + { + "host": "c7b944f0-bec7-4763-b7a9-a1c1a4763cb5", + "handler": "OpenHiddenHelp" + } + ] + } + ], + "serviceRefs": [], + "projectName": "bo-definsplanfront", + "templateId": "card-template" + }, + "options": { + "enableTextArea": true + } +} \ No newline at end of file diff --git a/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImplTest.java b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImplTest.java new file mode 100644 index 00000000..8961064d --- /dev/null +++ b/web-designschema/src/main/test/java/com/inspur/edp/web/designschema/webservice/DesignSchemaWebServiceImplTest.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.designschema.webservice; + +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.designschema.elements.Schema; +import com.inspur.edp.web.designschema.generator.SchemaBuilder; +import com.inspur.edp.web.formmetadata.metadata.module.Module; +import org.junit.jupiter.api.Test; + +class DesignSchemaWebServiceImplTest { + + @Test + void createDesignSchema() { + String fileContent = FileUtility.readAsString("D:\\InspurCode\\N转J之后代码\\web\\web-designschema\\src\\main\\test\\java\\com\\inspur\\edp\\web\\designschema\\webservice\\mmm.json"); + + Module mm= SerializeUtility.getInstance().deserialize(fileContent, Module.class); + String sss=SerializeUtility.getInstance().serialize(mm.getSchemas().get(0)); + GspViewModel vm = SerializeUtility.getInstance().deserialize(sss, GspViewModel.class); + + SchemaBuilder schemaBuilder = new SchemaBuilder(); + + Schema schema = schemaBuilder.buildWithScene(vm, ""); + } +} \ No newline at end of file diff --git a/web-form-jitengine/pom.xml b/web-form-jitengine/pom.xml new file mode 100644 index 00000000..2b621ddd --- /dev/null +++ b/web-form-jitengine/pom.xml @@ -0,0 +1,45 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-jitengine-formmetadata + + + com.inspur.edp + web-tsfile-api + + + com.inspur.edp + web-sourcecode-metadata + + + com.inspur.edp + web-npmpackage-core + + + org.junit.jupiter + junit-jupiter-api + + + com.inspur.edp + web-jitengine-frontendproject-api + + + + + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/JITEngineManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/JITEngineManager.java new file mode 100644 index 00000000..645b9308 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/JITEngineManager.java @@ -0,0 +1,733 @@ +package com.inspur.edp.web.jitengine; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.*; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.environment.checker.ExecuteEnvironmentChecker; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.*; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.service.FormMetataService; +import com.inspur.edp.web.frontendproject.entity.FrontendProjectGenerateParameter; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataItem; +import com.inspur.edp.web.jitengine.babelgrnerate.GenerateForBabel; +import com.inspur.edp.web.jitengine.dynamicform.DynamicFormModuleOperation; +import com.inspur.edp.web.jitengine.expressions.ExpressionFormGenerator; +import com.inspur.edp.web.jitengine.expressions.ExpressionManifest; +import com.inspur.edp.web.jitengine.expressions.ModuleFormExpressions; +import com.inspur.edp.web.jitengine.expressions.utility.ExpressionUtility; +import com.inspur.edp.web.jitengine.i18nresource.GenerateResourceManager; +import com.inspur.edp.web.jitengine.i18nresource.GeneratedI18nResourceList; +import com.inspur.edp.web.jitengine.metadataanalysis.*; +import com.inspur.edp.web.jitengine.metadataanalysis.form.FormComponentParser; +import com.inspur.edp.web.jitengine.metadatamodel.app.form.AnalysisExternalComponentResult; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitBuildParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.core.npminstall.NodeModulesPathGenerator; +import com.inspur.edp.web.npmpackage.core.npminstall.NpmInstallManager; +import com.inspur.edp.web.npmpackage.core.npminstall.PackageJsonPathGenerator; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingManager; +import org.apache.commons.lang3.SystemUtils; + +import java.io.File; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * JIT Engine 管理 + * + * @author noah + */ +public class JITEngineManager { + + + public static void generateFrontendProjectForBabel(String currentProjectPath) { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + if (!FileUtility.isAbsolute(devRootPath)) { + devRootPath = FileUtility.getAbsolutePathHead(devRootPath) + devRootPath; + } + + GenerateForBabel.generateFrontendProjectForBabel(currentProjectPath, devRootPath); + } + + /** + * @param currentBuildPath + */ + public static String buildFrontendProjectWithRuntime(String currentBuildPath, boolean isUpgradeTool, JitBuildParameter buildParameter) { + + String commandArgs = ""; + boolean useBabel = getRuntimeWebBuildNoah(isUpgradeTool); + if (useBabel) { + String runtimeBuildRootPath = getRuntimeBuildRoot(isUpgradeTool); + String buildAppjs = "@farris/farris-babel/app.js"; + + // 获取对应的nodejs命令 + String nodeCommand = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Node, isUpgradeTool); + + String nodeBuild = nodeCommand + buildAppjs + " --paths=" + runtimeBuildRootPath + " --workspacepath=" + currentBuildPath; + if (!OperatingSystemUtility.isLinux()) { + commandArgs += "cd " + runtimeBuildRootPath; + commandArgs += " && " + nodeBuild; + commandArgs += " && exit"; + } else { + commandArgs += "cd " + runtimeBuildRootPath; + commandArgs += " && " + nodeBuild; + } + } else { + // npm在线安装执行 + try { + NpmPackageResponse packageResponse = NpmInstallManager.npmInstallWithDefault(isUpgradeTool, true, false); + if (!packageResponse.isSuccess()) { + LoggerUtility.logToBrowser(packageResponse.getErrorMessage(), LoggerLevelEnum.Info); + } + } catch (Exception ex) { + LoggerUtility.logToBrowser(ex.getMessage() + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Info); + } + + //判断是否存在node_modules 文件夹 避免由于忘放置而导致得问题 + //if (!buildParameter.isMobileApp() && !buildParameter.isMobileApprove() && !buildParameter.isBabelCompile() && + // 针对升级工具 不执行在线安装 + if (!buildParameter.isMobileApprove() && !buildParameter.isBabelCompile() && + !buildParameter.isInUpgradeTool() && !FileUtility.exists(buildParameter.getBuildNodeModulePath())) { + String errorMessage = "编译依赖node_modules未部署,请先部署。部署路径为:" + buildParameter.getBuildNodeModulePath(); + LoggerUtility.log(errorMessage, LoggerLevelEnum.Error); + return errorMessage; + } + + /// 不考虑npm使用安装盘的情况 + ExecuteEnvironmentChecker.beforeCompile(); + + String ngCommand = NodejsFunctionUtility.getNgCommandInServer(isUpgradeTool); + if (!OperatingSystemUtility.isLinux()) { + commandArgs += "cd " + currentBuildPath; + commandArgs += " && " + "npm run build "; + commandArgs += " && exit"; + } else { + commandArgs += "cd " + currentBuildPath; + commandArgs += " && " + "npm run build"; + commandArgs += " && exit "; + } + } + + + return CommandLineUtility.runCommand(commandArgs); + } + + + public static void generateFrontendProject(String projectPath, String refNodeModulesBasePath, TerminalType terminalType) { + FrontendProjectGenerateParameter generateParameter = new FrontendProjectGenerateParameter(); + generateParameter.setProjectPath(projectPath); + generateFrontendProject(generateParameter, refNodeModulesBasePath, terminalType); + } + + /** + * 生成前端工程,目前仅支持生成 Angular 工程 + */ + public static void generateFrontendProject(FrontendProjectGenerateParameter generateParameter, String refNodeModulesBasePath, TerminalType terminalType) { + if (StringUtility.isNullOrEmpty(generateParameter.getProjectPath())) { + return; + } + + boolean isJieXiForm = generateParameter != null && generateParameter.isForceUseJieXi(); + + String currentProjectPath = generateParameter.getProjectPath(); + String currentProjectName = GspProjectUtil.getProjectName(currentProjectPath); + + GspProject gspProject = GspProjectUtil.getGspProject(currentProjectPath); + if (!FileUtility.isAbsolute(currentProjectPath)) { + // 开发根路径 + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + if (!currentProjectPath.startsWith(devRootPath)) { + currentProjectPath = FileUtility.combine(devRootPath, currentProjectPath); + } + if (!FileUtility.isAbsolute(currentProjectPath)) { + currentProjectPath = FileUtility.getAbsolutePathHead(currentProjectPath) + currentProjectPath; + } + } + + LoggerUtility.logToBrowser("编译工程路径为:" + currentProjectPath, LoggerLevelEnum.Info); + + String serviceUnitPath = gspProject.getSuDeploymentPath(); + + String formType = terminalType.toString().toLowerCase(); + String frameworkType = ""; + switch (terminalType) { + case PC: + frameworkType = FrontendFrameworkType.Angular.toString().toLowerCase(); + break; + case MOBILE: + frameworkType = FrontendFrameworkType.Vue.toString().toLowerCase(); + break; + default: + throw new GSPException("Web_GenerateFrontendProject", "暂不支持的终端类型:" + terminalType + "。请联系管理员处理。"); + } + String formJsonAbsolutePath = java.nio.file.Paths.get(currentProjectPath).resolve(getProjectFormRelativeResolvePath(terminalType, isJieXiForm)).toString(); + String formPublishAbsolutePath = java.nio.file.Paths.get(currentProjectPath).resolve(getProjectFormRelativeGeneratePath(terminalType, isJieXiForm)).toString(); + formPublishAbsolutePath = formPublishAbsolutePath.replace("\\", "/"); + ProjectCompileContext projectCompileContext = new ProjectCompileContext(currentProjectName, + getRefNodeModulesPath(refNodeModulesBasePath, terminalType), + formType, frameworkType, + formJsonAbsolutePath, + formPublishAbsolutePath, java.nio.file.Paths.get(currentProjectPath).resolve("eapi").toString(), serviceUnitPath, ExecuteEnvironment.Design); + + // 设置是否解析表单 + projectCompileContext.setJieXiForm(isJieXiForm); + compileProject(projectCompileContext); + } + + private static String getRefNodeModulesPath(String refNodeModulesBasePath, TerminalType terminalType) { + boolean enableMobileBuildWithNpmInstalled = NpmSettingManager.getNpmSetting(false).getSettingConfig().isEnableMobileBuild(); + refNodeModulesBasePath = refNodeModulesBasePath.replace("\\", "/"); + + String refNodeModulesPath = ""; + + switch (terminalType) { + case PC: + refNodeModulesPath = java.nio.file.Paths.get(refNodeModulesBasePath).resolve("node_modules").toString(); + break; + case MOBILE: + if (enableMobileBuildWithNpmInstalled) { + refNodeModulesPath = java.nio.file.Paths.get(refNodeModulesBasePath).resolve("node_modules").toString(); + } else { + refNodeModulesPath = FileUtility.combine(refNodeModulesBasePath, "node_modules"); + } + break; + default: + throw new GSPException("WEB_GetRefNodeModulesPath", "暂不支持的终端类型:" + terminalType + "。请联系管理员处理。"); + } + + return refNodeModulesPath; + } + + /** + * 获取工程中表单的相对解析路径 + * TODO:迁移到公共方法 + * + * @param terminalType + * @return + */ + public static String getProjectFormRelativeResolvePath(TerminalType terminalType, boolean isJieXiForm) { + String projectFormRelativeResolvePath = ""; + switch (terminalType) { + case PC: + if (isJieXiForm) { + projectFormRelativeResolvePath = FrontendProjectConstant.PROJECT_PC_RELATIVE_RESOLVE_Dynamic_PATH; + } else { + projectFormRelativeResolvePath = FrontendProjectConstant.PROJECT_PC_RELATIVE_RESOLVE_PATH; + } + break; + case MOBILE: + projectFormRelativeResolvePath = FrontendProjectConstant.PROJECT_MOBILE_RELATIVE_RESOLVE_PATH; + break; + default: + throw new GSPException("Web_GetProjectFormRelativeResolvePath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return projectFormRelativeResolvePath; + } + + /** + * 获取工程中表单的相对生成路径 + * TODO:迁移到公共方法 + * + * @param terminalType + * @return + */ + private static String getProjectFormRelativeGeneratePath(TerminalType terminalType, boolean isJieXiForm) { + String projectFormRelativeGeneratePath = ""; + switch (terminalType) { + case PC: + if (isJieXiForm) { + projectFormRelativeGeneratePath = FrontendProjectConstant.PROJECT_PC_RELATIVE_GENERATE_Dynamic_PATH; + } else { + projectFormRelativeGeneratePath = FrontendProjectConstant.PROJECT_PC_RELATIVE_GENERATE_PATH; + } + break; + case MOBILE: + projectFormRelativeGeneratePath = FrontendProjectConstant.PROJECT_MOBILE_RELATIVE_GENERATE_PATH; + break; + default: + throw new GSPException("Web_GetProjectFormRelativeGeneratePath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return projectFormRelativeGeneratePath; + } + + /** + * 前端框架类型 + */ + private enum FrontendFrameworkType { + Angular, + Vue, + React; + + public static final int SIZE = java.lang.Integer.SIZE; + + public int getValue() { + return this.ordinal(); + } + + public static FrontendFrameworkType forValue(int value) { + return values()[value]; + } + } + + /** + * 解析表单元数据 + * + * @return + */ + public static void ResolveFormMetadata(ResolveFormMetadataItem resolveFormMetadataItem, String baseFormPath, String projectPath, String targetStorageBasePath, String formServiceBasePath, HashMap projectCmpList, + GeneratedI18nResourceList i18nResourceList, GeneratedI18nResourceList zhI18nResourceList, GeneratedI18nResourceList zhCHTI18nResourceList, + ExpressionManifest expressionManifest, String i18nResourceKeyPrefix, String executeEnvironment, boolean isUpdradeTool) { + FormAnalysis formAnalysis = new FormAnalysis(ExecuteEnvironment.Design, false); + + // Resolve Form + TupleTwo resolveFormResult = formAnalysis.resolveForm(resolveFormMetadataItem.getGspMetadata().getHeader().getFileName(), resolveFormMetadataItem.getGspMetadata().getRelativePath(), targetStorageBasePath, projectPath); + + FormDOM json = resolveFormResult.getItem1(); + String strRelativePath = resolveFormResult.getItem2(); + + // 设置表单元数据的是否解析标识 + resolveFormMetadataItem.setFormDynamicTag(json.getOptions().isEnableFormJieXi()); + + // 设置表达式 manifest.json 文件的code及其对应的文件名 + expressionManifest.setFormModuleCode(json.getModule().getCode()); + expressionManifest.setManifestJsonPath(ExpressionUtility.getExpressionManifestJsonPath(json.getModule().getCode())); + + // 如果是单个表单解析预览 那么保存表单元数据内容 + if (resolveFormMetadataItem.getCalculateIsDynamicForm()) { + DynamicFormModuleOperation.saveForMetadataJs(json, targetStorageBasePath, json.getModule().getCode()); + } + + // 拷贝package.json 文件到当前目录 + if (!resolveFormMetadataItem.getCalculateIsDynamicForm()) { + copyPackageJson(targetStorageBasePath, isUpdradeTool); + } + ResolveFormMetadataWithVisualDom(resolveFormMetadataItem, baseFormPath, json, targetStorageBasePath, strRelativePath, formServiceBasePath, projectPath, projectCmpList, targetStorageBasePath, + i18nResourceList, zhI18nResourceList, zhCHTI18nResourceList, expressionManifest, null, i18nResourceKeyPrefix, executeEnvironment, isUpdradeTool, null); + } + + private static void copyPackageJson(String webDevPath, boolean isUpdradeTool) { + String packageJsonInServerPath = PackageJsonPathGenerator.generate(isUpdradeTool, false); + File packageJsonFile = new File(packageJsonInServerPath); + if (packageJsonFile.exists()) { + // 拷贝至目标文件目录 + String projectWebDevPackageJsonPath = FileUtility.combine(webDevPath, "package.json"); + FileUtility.copyFile(packageJsonInServerPath, projectWebDevPackageJsonPath, true); + } + } + + private static void ResolveFormMetadataWithVisualDom(ResolveFormMetadataItem resolveFormMetadataItem, String baseFormPath, FormDOM formDom, String targetStorageBasePath, String relativePath, + String formServiceBasePath, String projectPath, HashMap projectCmpList, + String webDevPath, GeneratedI18nResourceList i18nResourceList, GeneratedI18nResourceList zhI18nResourceList, GeneratedI18nResourceList zhCHTI18nResourceList, + ExpressionManifest expressionManifest, + String containerId, + String i18nResourceKeyPrefix, + String executeEnvironment, boolean isUpdradeTool, HashMap externalComponentItem) { + String formMetadataName = resolveFormMetadataItem.getGspMetadata().getHeader().getFileName(); + + + // 解析表单时 只解析表单元数据和对应命令元数据 不再解析其他类型元数据 + if (!resolveFormMetadataItem.getCalculateIsDynamicForm()) { + // Resolve Form Internal Route + FormComponentParser.getInstance().ExtractComponent(formDom, formMetadataName, targetStorageBasePath, webDevPath); + + // Resolve StateMachine + StateMachineAnalysis.resolveStateMachine(formDom, formMetadataName, targetStorageBasePath, webDevPath, projectPath, ExecuteEnvironment.Design, false); + } + + // Resolve Command + // 增加是否解析表单参数 如果为解析表单 那么不再生成对应的command.json 文件 + CommandsAnalysis commandsAnalysis = new CommandsAnalysis(ExecuteEnvironment.Design, false, !resolveFormMetadataItem.getCalculateIsDynamicForm()); + commandsAnalysis.resolveCommand(formDom, formMetadataName, targetStorageBasePath, projectCmpList, webDevPath, null); + + if (!resolveFormMetadataItem.getCalculateIsDynamicForm()) { + // Resolve Eapi + EapiAnalysis eapiAnalysis = new EapiAnalysis(ExecuteEnvironment.Design, false); + eapiAnalysis.resolveEapi(formDom, formMetadataName, targetStorageBasePath, projectPath, webDevPath); + } + + // Resolve Command Service + CommandServiceAnalysis.resolveCommandService(formDom, relativePath, formServiceBasePath, targetStorageBasePath, resolveFormMetadataItem); + + // 构造对应的国际化资源项 + GenerateResourceManager.generateI18nResource(resolveFormMetadataItem.getGspMetadata(), baseFormPath, i18nResourceList, relativePath, i18nResourceKeyPrefix, I18nResourceConstant.En); + + // 构建繁体中文 + GenerateResourceManager.generateI18nResource(resolveFormMetadataItem.getGspMetadata(), baseFormPath, zhCHTI18nResourceList, relativePath, i18nResourceKeyPrefix, I18nResourceConstant.ZH_CHT); + + ///获取表单对应的表达式 + ModuleFormExpressions moduleFormExpressions = ExpressionFormGenerator.generate(formDom, containerId, externalComponentItem); + // 仅仅在包含表达式时才进行添加 + if (moduleFormExpressions != null && moduleFormExpressions.getExpressions() != null && moduleFormExpressions.getExpressions().size() > 0) { + expressionManifest.getExpressions().add(moduleFormExpressions); + } + + if (!resolveFormMetadataItem.getCalculateIsDynamicForm()) { + + // 解析组合表单 + resolveExternalDependencyMetadata(resolveFormMetadataItem.getGspMetadata(), baseFormPath, formDom, targetStorageBasePath, zhI18nResourceList, relativePath, i18nResourceKeyPrefix); + + // 递归解析 如果存在子组件 那么需要递归执行子组件 + executeExternalComponent(formDom, baseFormPath, targetStorageBasePath, formServiceBasePath, projectPath, projectCmpList, webDevPath, + i18nResourceList, zhI18nResourceList, zhCHTI18nResourceList, expressionManifest, i18nResourceKeyPrefix, executeEnvironment, isUpdradeTool); + } + } + + /** + * 处理扩展组件 + */ + private static void executeExternalComponent(FormDOM json, String baseFormPath, String targetStorageBasePath, String formServicePath, String projectPath, + HashMap projectCmpList, String webdevpath, + GeneratedI18nResourceList i18nResourceList, GeneratedI18nResourceList zhI18nResourceList, GeneratedI18nResourceList zhCHTI18nResourceList, + ExpressionManifest expressionManifest, + String i18nResourceKeyPrefix, String executeEnvironment, boolean isUpdradeTool) { + if (json != null && json.getModule() != null && json.getModule().getExternalComponents() != null && json.getModule().getExternalComponents().size() > 0) { + for (HashMap item : json.getModule().getExternalComponents()) { + String strI18nResourcePrefix = i18nResourceKeyPrefix; + FormAnalysis formAnalysis = new FormAnalysis(executeEnvironment, isUpdradeTool); + + AnalysisExternalComponentResult externalVisualDom; + try { + externalVisualDom = formAnalysis.analysisExternalComponent(targetStorageBasePath, json.getModule().getCode(), item, webdevpath); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + // 如果获取不到对应的表单元数据。针对的是弹窗Url 情况 + if (externalVisualDom != null && externalVisualDom.getJson() != null) { + // 如果是独立加载表单 那么不再继续执行后续的组合表单文件生成 + if (externalVisualDom.isUseIsolateJs()) { + return; + } + + String externalFormBasePath = FileUtility.combine(targetStorageBasePath, json.getModule().getCode().toLowerCase(), externalVisualDom.getExternalComponentPath()); + /// 表单service文件路径 + String externalFormServicePath = FileUtility.combine(formServicePath, json.getModule().getCode().toLowerCase(), "externalcomponents", externalVisualDom.getExternalComponentPath()); + GspMetadata formMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(externalVisualDom.getExternalComponentUri(), executeEnvironment, isUpdradeTool); + + String[] params = {externalVisualDom.getExternalComponentPath(), externalVisualDom.getJson().getModule().getCode()}; + strI18nResourcePrefix = GenerateResourceManager.generateKeyPrefix(strI18nResourcePrefix, params).toLowerCase(); + + String strContainerId = getExternalContainerId(item); + + ResolveFormMetadataItem resolveFormMetadataItem = new ResolveFormMetadataItem(); + resolveFormMetadataItem.setGspMetadata(formMetadata); + ResolveFormMetadataWithVisualDom(resolveFormMetadataItem, baseFormPath, externalVisualDom.getJson(), + externalFormBasePath, + externalVisualDom.getRelativePath(), externalFormServicePath, projectPath, + projectCmpList, webdevpath, i18nResourceList, zhI18nResourceList, + zhCHTI18nResourceList, expressionManifest, strContainerId, strI18nResourcePrefix, executeEnvironment, isUpdradeTool, + item); + + } + } + } + } + + private static String getExternalContainerId(HashMap item) { + String externalComponentId = item.get("id").toString(); + String externalComponentType = item.get("type").toString(); + String containerId = item.get("containerId").toString(); + String strContainerId; + if ("ModalContainer".equals(externalComponentType)) { + strContainerId = !StringUtility.isNullOrEmpty(containerId) ? containerId : externalComponentId; + } else { + strContainerId = externalComponentId; + } + + return strContainerId; + } + + + /** + * 解析表单元数据依赖的外部元数据,如资源元数据 + */ + private static void resolveExternalDependencyMetadata(GspMetadata formMetadata, String baseFormPath, FormDOM json, String targetStorageBasePath, GeneratedI18nResourceList zhResourceList, String baseRelativePath, String i18nResourcePrefix) { + + List resourceList = FormMetataService.getFormResourceWithMetaData(formMetadata, I18nResourceConstant.ZH_CHS, baseFormPath); + if (resourceList != null && resourceList.size() > 0) { + resourceList.forEach((item) -> + { + I18nResourceItemCollection resourceItemCollection = item.getStringResources(); + if (resourceItemCollection == null || resourceItemCollection.size() == 0) { + return; + } + + // 根据资源项构建生成结构 + StringBuilder resouceItemsStringBuilder = new StringBuilder(); + resouceItemsStringBuilder.append("{"); + for (int i = 0; i < resourceItemCollection.size(); i++) { + I18nResourceItem resourceItem = resourceItemCollection.get(i); + StringBuilder resouceItemStringBuilder = new StringBuilder(); + String id = resourceItem.getKey(); + + String updatedId = id.substring(id.lastIndexOf(".") + 1); // 解析ID + String value = resourceItem.getValue(); + String comment = resourceItem.getComment(); + resouceItemStringBuilder.append("\"").append(updatedId).append("\": {").append("\r\n"); + resouceItemStringBuilder.append(" \"name\": " + "\"").append(value).append("\",").append("\r\n"); + for (String s : Arrays.asList(" \"comment\": " + "\"" + comment + "\"" + "\r\n", "}")) { + resouceItemStringBuilder.append(s); + } + + zhResourceList.add(GenerateResourceManager.generateResourceId(updatedId, i18nResourcePrefix), value); + + if (i != resourceItemCollection.size() - 1) { + resouceItemStringBuilder.append(","); + } + resouceItemStringBuilder.append("\r\n"); + + resouceItemsStringBuilder.append(resouceItemStringBuilder); + } + resouceItemsStringBuilder.append("}"); + + // 将生成的结构持久化到磁盘 + FileUtility.writeFile(targetStorageBasePath, String.format("%1$s.resource.json", formMetadata.getHeader().getFileName().toLowerCase()), resouceItemsStringBuilder.toString()); + }); + + } + } + + public static void compileProject(ProjectCompileContext projectCompileContext) { + // 编译前执行install install的是全局离线包 + NpmInstallBeforeGenerate.beforeCompileExecuteWithNpmInstall(projectCompileContext, projectCompileContext.executeEnvironment.equals(ExecuteEnvironment.Runtime), true); + + // 暂时不考虑jit-engine 放置于安装盘的情况 采用外部的 + ExecuteEnvironmentChecker.beforeGenerate(); + + // 获取jit命令执行参数 + String jitCommand = NodejsFunctionUtility.getJitCommandInServer(projectCompileContext.executeEnvironment.equals(ExecuteEnvironment.UpgradeTool)); + String args = jitCommand;// "jit"; + args += " --projectName=" + projectCompileContext.getProjectName(); + args += " --projectRoute=" + projectCompileContext.getProjectRoute(); + args += " --linkedNodeModules=" + projectCompileContext.getNodeModulesAbsolutePath(); + args += " --formType=" + projectCompileContext.getFormType(); + args += " --frameworkType=" + projectCompileContext.getFrameworkType(); + args += " --mp=" + projectCompileContext.getFormJsonAbsolutePath(); + args += " --pp=" + projectCompileContext.getFormPublishAbsolutePath(); + args += " --eapiPath=" + projectCompileContext.getEapiAbsolutePath(); + args += " --uilib=" + projectCompileContext.getUserInterfaceLibrary(); + args += " --ngVersion=" + projectCompileContext.getAngularVersion(); + args += " --isEnableDynamicForm=true "; + + // 运行时定制当前不使用资源文件内容 增加参数控制 切换至res时,需要将该参数去除 + if (projectCompileContext.executeEnvironment.equals(ExecuteEnvironment.Runtime)) { + args += " --useI18nResource=false "; + if (!StringUtility.isNullOrEmpty(projectCompileContext.extraFormPath)) { + // 如果维度 信息不为空,那么增加维度信息传参 + args += " --runTimeDimPath=" + projectCompileContext.extraFormPath; + } + args += " --isRuntime=true "; + if (projectCompileContext.isGenerateViewModel()) { + args += " --isGenerateViewModel=true"; + } + } + + args += " --serviceUnitPath=" + projectCompileContext.getServiceUnitPath(); + if (projectCompileContext.getIsMobileApprove()) { + args += " --isMobileApprove=" + projectCompileContext.getIsMobileApprove(); + args += " --mobileApproveFormCode=" + projectCompileContext.getMobileApproveFormCode(); + } + + if (projectCompileContext.isDeleteSourceCodeBeforeGenerate()) { + args += " --deleteSourceCodeBeforeGenerate=" + projectCompileContext.isDeleteSourceCodeBeforeGenerate(); + } + + CommandLineUtility.runCommand(args); + } + + + public static void buildFrontendProject(String targetProjectPath, String executeEnvironment, TerminalType terminalType) { + // 标识运行环境 是为运行时定制 或设计时 + boolean isRuntime = executeEnvironment.equals(ExecuteEnvironment.Runtime); + NpmInstallBeforeGenerate.beforeCompileExecuteWithNpmInstall(executeEnvironment, isRuntime, false); + + // 检测node_modules 是否进行了部署 + checkNodeModuleDeployed(isRuntime); + + // 转换路径 + targetProjectPath = FileUtility.getPlatformIndependentPath(targetProjectPath); + + + String currentBuildPath = getProjectBuildPath(targetProjectPath, terminalType); + System.out.println("Build Path is:" + currentBuildPath); + + String ngCommand = NodejsFunctionUtility.getNgCommandInServer(false); + + /// 不考虑npm使用安装盘的情况 + ExecuteEnvironmentChecker.beforeCompile(); + + String[] command = new String[1]; + if (SystemUtils.IS_OS_WINDOWS) { + command = new String[4]; + // 盘符独立打开 + command[0] = FileUtility.getAbsolutePathHead(targetProjectPath); + command[1] = "cd " + currentBuildPath; + command[2] = "npm run build"; + command[3] = "exit"; + } else if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC_OSX) { + command = new String[3]; + command[0] = "cd " + currentBuildPath; + command[1] = "npm run build"; + command[2] = "exit"; + } + + // 如果目标路径不存在 那么无需执行编译 + if (!FileUtility.exists(currentBuildPath)) { + LoggerUtility.log("build path is not exists,so engine will not be to build this path,the path is " + currentBuildPath, LoggerLevelEnum.Info); + return; + } + + if (terminalType == TerminalType.MOBILE) { + // 针对移动工程编译 因为涉及到移动和PC node_modules的合并,如果移动的node_modules 未合并过来,那么进行友好的提示 + // 当前采取策略,读取当前软链接中的node_modules 判断里面是否包含移动固有的包 + checkHasMobileRelyNodeModule(currentBuildPath); + } + + CommandLineUtility.runCommand(command); + } + + /** + * 检测node_modules 是否进行部署 + * + * @param isRuntime + */ + private static void checkNodeModuleDeployed(boolean isRuntime) { + // 获取待执行安装的node_modules 路径 + NpmInstallParameter npmInstallParameter = new NpmInstallParameter(); + // 获取待执行安装的node_modules 路径 + String currentWorkPath = FileUtility.getCurrentWorkPath(false); + + npmInstallParameter.setExecuteEnvironment(isRuntime ? ExecuteEnvironmentEnum.Runtime : ExecuteEnvironmentEnum.Design); + + String parentNode_ModulesPath = NodeModulesPathGenerator.generatePackageJsonPath(npmInstallParameter, currentWorkPath); + + String currentNodeModulesPath = FileUtility.combine(parentNode_ModulesPath, "node_modules"); + if (!FileUtility.exists(currentNodeModulesPath)) { + String errorMessage = "编译依赖node_modules未部署,请先部署。部署路径为:" + currentNodeModulesPath + "或开启Npm在线安装(需要网络连接)。请参考:Npm在线安装。"; + throw new RuntimeException(errorMessage); + } + } + + /** + * 检测是否包含移动编译必须的npm包 + * + * @param currentBuildPath + */ + private static void checkHasMobileRelyNodeModule(String currentBuildPath) { + String node_modulesPath = FileUtility.combine(currentBuildPath, "node_modules"); + File node_modulesFile = new File(node_modulesPath); + if (node_modulesFile.exists()) { + // 获取移动对应的必须包 + File mobileSpecialCli = new File(FileUtility.combine(node_modulesPath, "@farris", "mobile-cli")); + if (!mobileSpecialCli.exists()) { + // 如果移动npm包不存在 那么进行提示 + String tipInfo = "当前node_modules不包含移动npm包,请使用Npm在线安装或更新最新node_modules离线包。请注意:移动表单编译不再使用mobile目录下的node_modules,使用工程目录下node_modules。"; + LoggerUtility.log(tipInfo, LoggerLevelEnum.Info); + throw new RuntimeException(tipInfo); + } + } + } + + + /** + * 不同类型代码存放路径 + * + * @param projectPath + * @param terminalType + * @return + */ + private static String getProjectBuildPath(String projectPath, TerminalType terminalType) { + String projectBuildPath = ""; + switch (terminalType) { + case PC: + projectBuildPath = FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH); + break; + case MOBILE: + projectBuildPath = FileUtility.combine(projectPath, FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_MOBILE_GENERATE_PATH); + break; + default: + throw new GSPException("WEB_GetProjectBuildPath", "暂不支持的终端类型:" + terminalType + "。请联系管理员处理。"); + } + + return projectBuildPath; + } + + public static void buildFrontendProjectForBabel(String targetProjectPath) { + if (StringUtility.isNullOrEmpty(targetProjectPath)) { + return; + } + + // 转换路径 + targetProjectPath = FileUtility.getPlatformIndependentPath(targetProjectPath); + + // 获取build目录 + String currentBuildPath = targetProjectPath + FileUtility.getPlatformIndependentPath("/src" + "/" + FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_BABEL); + + // 获取buildfast目录 + String serverInstanceRootPath = FileUtility.getCurrentWorkPath(false); + + String serverInstanceNewRootPath = FileUtility.combine(serverInstanceRootPath, "web"); + String buildFastPath = serverInstanceNewRootPath + FileUtility.getPlatformIndependentPath("/runtime/buildfast"); + + String[] command = new String[1]; + + StringBuilder sb = new StringBuilder("node @farris/farris-babel/app.js --paths="); + // 执行node命令的目录,/web/runtime/buildfast + sb.append(buildFastPath); + sb.append(" --workspacepath="); + // app所在目录 + sb.append(currentBuildPath); + if (SystemUtils.IS_OS_WINDOWS) { + command = new String[4]; + // buildfast目录在运行环境所在盘符,而不是projects文件所在盘符。 + command[0] = FileUtility.getAbsolutePathHead(serverInstanceRootPath); + command[1] = "cd " + buildFastPath; + command[2] = sb.toString(); + command[3] = "exit"; + } else if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC_OSX) { + command = new String[3]; + // buildfast目录在运行环境所在盘符,而不是projects文件所在盘符。 + command[0] = "cd " + buildFastPath; + command[1] = sb.toString(); + command[2] = "exit"; + } + + CommandLineUtility.runCommand(command); + } + + /** + * 获取运行时编译路径 + * + * @return + */ + private static String getRuntimeBuildRoot(boolean isUpdradeTool) { + String _localServerPath = FileUtility.getPlatformIndependentPath(FileUtility.getCurrentWorkPath(isUpdradeTool)); + return _localServerPath + "/web/runtime/buildfast"; + } + + /** + * 获取运行时编译路径 + * + * @return + */ + public static boolean getRuntimeWebBuildNoah(boolean isUpdradeTool) { + String _localServerPath = FileUtility.getPlatformIndependentPath(FileUtility.getCurrentWorkPath(isUpdradeTool)); + String noahJsonPath = _localServerPath + "/web/runtime/noah.json"; + return FileUtility.exists(noahJsonPath); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/NpmInstallBeforeGenerate.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/NpmInstallBeforeGenerate.java new file mode 100644 index 00000000..c60d8260 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/NpmInstallBeforeGenerate.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.jitengine; + +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.core.npminstall.NpmInstallManager; + +public class NpmInstallBeforeGenerate { + public static void beforeCompileExecuteWithNpmInstall(ProjectCompileContext projectCompileContext, boolean isRuntime, boolean isGlobal) { + beforeCompileExecuteWithNpmInstall(projectCompileContext.executeEnvironment, isRuntime, isGlobal); + } + + public static void beforeCompileExecuteWithNpmInstall(String executeEnvironment, boolean isRuntime, boolean isGlobal) { + NpmPackageResponse packageResponse = null; + if (isGlobal) { + packageResponse = NpmInstallManager.npmInstallWithDefault(executeEnvironment.equals(ExecuteEnvironment.UpgradeTool), false, true); + } else { + packageResponse = NpmInstallManager.npmInstallWithDefault(executeEnvironment.equals(ExecuteEnvironment.UpgradeTool), isRuntime, isGlobal); + } + + if (packageResponse != null && !packageResponse.isSuccess()) { + throw new RuntimeException(packageResponse.getErrorMessage()); + } + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/ProjectCompileContext.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/ProjectCompileContext.java new file mode 100644 index 00000000..a4d7888d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/ProjectCompileContext.java @@ -0,0 +1,220 @@ +package com.inspur.edp.web.jitengine; + +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +public class ProjectCompileContext { + + private boolean generateViewModel; + + public boolean isGenerateViewModel() { + return generateViewModel; + } + + public void setGenerateViewModel(boolean generateViewModel) { + this.generateViewModel = generateViewModel; + } + + private String projectName; + + public String getProjectName() { + return this.projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + private String projectRoute; + + public String getProjectRoute() { + return this.projectRoute; + } + + public void setProjectRoute(String projectRoute) { + this.projectRoute = projectRoute; + } + + private String nodeModulesAbsolutePath; + + private boolean isJieXiForm = false; + + public boolean isJieXiForm() { + return isJieXiForm; + } + + public void setJieXiForm(boolean jieXiForm) { + isJieXiForm = jieXiForm; + } + + public String getNodeModulesAbsolutePath() { + return this.nodeModulesAbsolutePath; + } + + public void setNodeModulesAbsolutePath(String nodeModulesAbsolutePath) { + this.nodeModulesAbsolutePath = nodeModulesAbsolutePath; + } + + private boolean isMobileApprove = false; + + public boolean getIsMobileApprove() { + return isMobileApprove; + } + + public void setIsMobileApprove(boolean mobileApprove) { + isMobileApprove = mobileApprove; + } + + + private String mobileApproveFormCode; + + + public String getMobileApproveFormCode() { + return mobileApproveFormCode; + } + + public void setMobileApproveFormCode(String mobileApproveFormCode) { + this.mobileApproveFormCode = mobileApproveFormCode; + } + + /** + * 表单生成的json文件路径 + */ + private String formJsonAbsolutePath; + + public String getFormJsonAbsolutePath() { + return this.formJsonAbsolutePath; + } + + public void setFormJsonAbsolutePath(String formJsonAbsolutePath) { + this.formJsonAbsolutePath = formJsonAbsolutePath; + } + + /** + * 工程发布路径 + */ + private String formPublishAbsolutePath; + + public String getFormPublishAbsolutePath() { + return this.formPublishAbsolutePath; + } + + public void setFormPublishAbsolutePath(String formPublishAbsolutePath) { + this.formPublishAbsolutePath = formPublishAbsolutePath; + } + + private String eapiAbsolutePath; + + public String getEapiAbsolutePath() { + return this.eapiAbsolutePath; + } + + public void setEapiAbsolutePath(String eapiAbsolutePath) { + this.eapiAbsolutePath = eapiAbsolutePath; + } + + public String getAngularVersion() { + return "ng7"; + } + + public String getUserInterfaceLibrary() { + return "kendo"; + } + + private FormDOM json = null; + + public FormDOM getFormDom() { + return this.json; + } + + public void setFormDom(FormDOM formDom) { + this.json = formDom; + } + + public String executeEnvironment = ExecuteEnvironment.Design; + + + /** + * 微服务单元路径 + */ + private String serviceUnitPath; + + public String getServiceUnitPath() { + return this.serviceUnitPath; + } + + public void setServiceUnitPath(String serviceUnitPath) { + this.serviceUnitPath = serviceUnitPath; + } + + /** + * 运行时定制维度信息 + */ + public String extraFormPath = ""; + + private boolean deleteSourceCodeBeforeGenerate = false; + + /** + * 设置生成前删除源文件目录 + * + * @return + */ + public boolean isDeleteSourceCodeBeforeGenerate() { + return deleteSourceCodeBeforeGenerate; + } + + /** + * 设置生成前删除源文件目录 + * + * @param deleteSourceCodeBeforeGenerate + */ + public void setDeleteSourceCodeBeforeGenerate(boolean deleteSourceCodeBeforeGenerate) { + this.deleteSourceCodeBeforeGenerate = deleteSourceCodeBeforeGenerate; + } + + private String formType = "pc"; + private String frameworkType = "angular"; + private String frameworkVersion = "7.0.0"; + + public String getFormType() { + return formType; + } + + public void setFormType(String formType) { + this.formType = formType; + } + + public String getFrameworkType() { + return frameworkType; + } + + public void setFrameworkType(String frameworkType) { + this.frameworkType = frameworkType; + } + + public String getFrameworkVersion() { + return frameworkVersion; + } + + public void setFrameworkVersion(String frameworkVersion) { + this.frameworkVersion = frameworkVersion; + } + + public ProjectCompileContext(String projectName, String refNodeModulesPath, + String formType, String frameworkType, + String formJsonAbsolutePath, + String formPublishAbsolutePath, String eapiAbsolutePath, String serviceUnitPath, String executeEnvironment) { + this.projectName = projectName; + this.projectRoute = projectName + JITEngineConstants.ProjectRouteFileExtension; + this.nodeModulesAbsolutePath = refNodeModulesPath; + this.formType = formType; + this.frameworkType = frameworkType; + + this.formJsonAbsolutePath = formJsonAbsolutePath; + this.formPublishAbsolutePath = formPublishAbsolutePath; + this.eapiAbsolutePath = eapiAbsolutePath; + this.serviceUnitPath = serviceUnitPath; + this.executeEnvironment = executeEnvironment; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/babelgrnerate/GenerateForBabel.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/babelgrnerate/GenerateForBabel.java new file mode 100644 index 00000000..cae6f07b --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/babelgrnerate/GenerateForBabel.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.jitengine.babelgrnerate; + +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.jitengine.NpmInstallBeforeGenerate; +import com.inspur.edp.web.jitengine.ProjectCompileContext; + +public class GenerateForBabel { + public static void generateFrontendProjectForBabel(String currentProjectPath, String refNodeModulesBasePath) { + if (StringUtility.isNullOrEmpty(currentProjectPath)) { + return; + } + + String currentProjectName = GspProjectUtil.getProjectName(currentProjectPath); + + if (!FileUtility.isAbsolute(currentProjectPath)) { + currentProjectPath = FileUtility.getAbsolutePathHead(currentProjectPath) + currentProjectPath; + } + + GspProject gspProject = GspProjectUtil.getGspProject(currentProjectPath); + String serviceUnitPath = gspProject.getSuDeploymentPath(); + + String formPublishAbsolutePath = currentProjectPath + "/src" + "/"+ FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_BABEL; + + ProjectCompileContext projectCompileContext = new ProjectCompileContext(currentProjectName, java.nio.file.Paths.get(refNodeModulesBasePath).resolve("node_modules").toString(), "pc", "angular", + currentProjectPath + "/src" + "/webdev", formPublishAbsolutePath, + currentProjectPath + "/eapi", serviceUnitPath, ExecuteEnvironment.Design); + + generateProjectForBabel(projectCompileContext); + + } + + private static void generateProjectForBabel(ProjectCompileContext projectCompileContext) { + // 编译前执行install install的是全局离线包 + NpmInstallBeforeGenerate.beforeCompileExecuteWithNpmInstall(projectCompileContext, false, true); + + // 获取jit命令执行参数 + String jitCommand = NodejsFunctionUtility.getJitCommandInServer(projectCompileContext.executeEnvironment.equals(ExecuteEnvironment.UpgradeTool)); + String args = jitCommand;// "jit"; + args += String.format(" --projectName=%1$sforbabel", projectCompileContext.getProjectName()); + args += String.format(" --projectRoute=%1$s", projectCompileContext.getProjectRoute()); + args += String.format(" --linkedNodeModules=%1$s", projectCompileContext.getNodeModulesAbsolutePath()); + args += String.format(" --formType=%1$s", projectCompileContext.getFormType()); + args += String.format(" --frameworkType=%1$s", projectCompileContext.getFrameworkType()); + // 表单生成的json文件路径 + args += String.format(" --mp=%1$s", projectCompileContext.getFormJsonAbsolutePath()); + // 工程发布路径 + args += String.format(" --pp=%1$s", projectCompileContext.getFormPublishAbsolutePath()); + // eapi路径 + args += String.format(" --eapiPath=%1$s", projectCompileContext.getEapiAbsolutePath()); + args += String.format(" --serviceUnitPath=%1$s", projectCompileContext.getServiceUnitPath()); + args += " --isRuntime=true"; + args += " --isBabelCompile=true"; + //args += $" --isGenerateViewModel=false"; + + String[] command = {args}; + CommandLineUtility.runCommand(command); + } + + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/constant/JitConstant.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/constant/JitConstant.java new file mode 100644 index 00000000..b3534542 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/constant/JitConstant.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.jitengine.constant; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/14 + */ +public class JitConstant { + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormMetaFileNameGenerator.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormMetaFileNameGenerator.java new file mode 100644 index 00000000..c5a306ac --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormMetaFileNameGenerator.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.jitengine.dynamicform; + +/** + * @Title: DynamicFormMetaFileNameGenerator + * @Description: com.inspur.edp.web.frontendproject.formdynamic 保存的metadata.js文件的名称构造 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/12 17:38 + */ +public class DynamicFormMetaFileNameGenerator { + /** + * 构造对应的解析表单metadata文件名称 + * @param formCode + * @return + */ + public static String generateMetaFileName(String formCode) { + return String.format("%s.metadata.js", formCode.toLowerCase()); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormModuleOperation.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormModuleOperation.java new file mode 100644 index 00000000..7387295f --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/dynamicform/DynamicFormModuleOperation.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.jitengine.dynamicform; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +/** + * @Title: DynamicFormModuleOperation + * @Description: com.inspur.edp.web.frontendproject.formdynamic 解析表单针对表单dom得操作 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/12 17:36 + */ +public class DynamicFormModuleOperation { + /** + * 解析表单保存metadata.js文件 + * + * @param formDOM + * @param targetBasePath + * @param formCode + */ + public static void saveForMetadataJs(FormDOM formDOM, String targetBasePath, String formCode) { + String metadataJsFileName = DynamicFormMetaFileNameGenerator.generateMetaFileName(formCode); + String targetMetadataJsFilePath = FileUtility.combine(targetBasePath, metadataJsFileName); + FileUtility.writeFile(targetMetadataJsFilePath, SerializeUtility.getInstance().serialize(formDOM)); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/DesignExpressionValue.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/DesignExpressionValue.java new file mode 100644 index 00000000..30df0d36 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/DesignExpressionValue.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.jitengine.expressions; + +/** + * 设计时表达式值对应实体结构 + * @author guozhiqi + */ +public class DesignExpressionValue { + private String expr; + private String sexpr; + + public String getExpr() { + return expr; + } + + public void setExpr(String expr) { + this.expr = expr; + } + + public String getSexpr() { + return sexpr; + } + + public void setSexpr(String sexpr) { + this.sexpr = sexpr; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldExpression.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldExpression.java new file mode 100644 index 00000000..2f9128ef --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldExpression.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ExpressionFormFieldExpression { + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private String type; + + @JsonProperty("value") + private String value; + + /** + * 提示消息 + */ + @JsonProperty("message") + private String message; + /** + * 消息类型 + */ + @JsonProperty("messageType") + private String messageType; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldJsonEntity.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldJsonEntity.java new file mode 100644 index 00000000..f2f6706b --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormFieldJsonEntity.java @@ -0,0 +1,69 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ExpressionFormFieldJsonEntity { + + @JsonProperty("path") + private String path; + + @JsonProperty("ns") + private String ns; + + @JsonProperty("type") + private String type; + + @JsonProperty("expressions") + private List expressions; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public void setPath(String bindTo, String path) { + this.path = "/" + bindTo + "/" + path; + } + + public String getNs() { + return ns; + } + + public void setNs(String ns) { + this.ns = ns; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public List getExpressions() { + if(this.expressions==null){ + this.expressions=new ArrayList<>(); + } + return expressions; + } + + public void setExpressions(List expressions) { + this.expressions = expressions; + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGenerator.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGenerator.java new file mode 100644 index 00000000..6a7ccbab --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGenerator.java @@ -0,0 +1,97 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.expressions.utility.ExpressionUtility; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ExpressionFormGenerator { + public static ModuleFormExpressions generate(FormDOM formDom, String containerId, HashMap externalComponentItem) { + ModuleFormExpressions moduleFormExpressions = new ModuleFormExpressions(); + moduleFormExpressions.setFormModuleCode(formDom.getModule().getCode()); + + if (externalComponentItem != null) { + String externalComponentCode = externalComponentItem.get("code") == null ? "" : externalComponentItem.get("code").toString(); + String nameSpace = ExpressionUtility.getNameSpace(externalComponentItem.get("id").toString(), externalComponentCode.toLowerCase()); + // 转换为小写形式 + moduleFormExpressions.setNameSpace(nameSpace); + } else { + moduleFormExpressions.setNameSpace(""); + } + + + // 获取组合表单设定的containerId + //var externalComponentUniqueID = parentExternalComponent.containerId ? parentExternalComponent.containerId : parentExternalComponent.id; + // 临时设定uniqueId为空 + moduleFormExpressions.setFormExpressionJsonPath(ExpressionUtility.getExpressionFormJsonPath(containerId, formDom.getModule().getCode())); + + // 获取表单中定义的表达式 + List> expressionsJson = formDom.getModule().getExpressions(); + + // 如果表达式为空 或表达式未定义 那么不再进行后续处理 + if (expressionsJson == null || expressionsJson.isEmpty()) { + return moduleFormExpressions; + } + String strExpressionJson = SerializeUtility.getInstance().serialize(expressionsJson, false); + List expressionFieldItemList = new ArrayList<>(); + expressionFieldItemList = SerializeUtility.getInstance().deserialize(strExpressionJson, new com.fasterxml.jackson.core.type.TypeReference>() { + }); + + ArrayList> entities = (ArrayList>) formDom.getModule().getSchemas().get(0).get("entities"); + String mainEntityName = (String) entities.get(0).get("code"); + + for (ModuleFormExpressionFieldItem item : expressionFieldItemList) { + List fieldExpressionList = item.getExpression(); + + if (fieldExpressionList.size() == 0) { + continue; + } + ModuleFormExpressionFieldItem moduleFormExpressionFieldItem = new ModuleFormExpressionFieldItem(); + moduleFormExpressionFieldItem.setFieldId(item.getFieldId()); + moduleFormExpressionFieldItem.setSourceType("Field"); + FieldInfo fieldInfo = ExpressionUtility.getFieldInfoById(item.getFieldId(), formDom); + if (fieldInfo != null && fieldInfo.getSchemaFields() != null) { + HashMap fieldInfoSchemaFields = (HashMap) fieldInfo.getSchemaFields(); + if (!fieldInfoSchemaFields.isEmpty()) { + String bindTo = fieldInfo.getBindTo(); + moduleFormExpressionFieldItem.setFieldCode(fieldInfoSchemaFields.get("code").toString()); + moduleFormExpressionFieldItem.setFieldLabel(fieldInfo.getRefElementLabelPath()); + moduleFormExpressionFieldItem.setBindTo(bindTo); + + if (fieldExpressionList != null && fieldExpressionList.size() > 0) { + for (ModuleExpressionStatement fieldExpressionItem : fieldExpressionList) { + String fieldExpressionType = fieldExpressionItem.getType(); + String expressionValue = fieldExpressionItem.getValue(); + + ModuleExpressionStatement moduleExpressionStatement = new ModuleExpressionStatement(); + + moduleExpressionStatement.setValue(expressionValue); + moduleExpressionStatement.setType(fieldExpressionType); + + moduleExpressionStatement.setMessage(fieldExpressionItem.getMessage()); + moduleExpressionStatement.setMessageType(fieldExpressionItem.getMessageType()); + moduleExpressionStatement.setId(fieldExpressionItem.getId()); + + + moduleFormExpressionFieldItem.getExpression().add(moduleExpressionStatement); + } + // 追加 + moduleFormExpressions.getExpressions().add(moduleFormExpressionFieldItem); + } + } + } + + } + + return moduleFormExpressions; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormJsonEntity.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormJsonEntity.java new file mode 100644 index 00000000..09c53d62 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormJsonEntity.java @@ -0,0 +1,40 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ExpressionFormJsonEntity { + @JsonProperty("path") + private String path; + + public List formFieldJsonEntities; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getFormFieldJsonEntities() { + if (this.formFieldJsonEntities == null) { + this.formFieldJsonEntities = new ArrayList<>(); + } + return formFieldJsonEntities; + } + + public void setFormFieldJsonEntities(List formFieldJsonEntities) { + this.formFieldJsonEntities = formFieldJsonEntities; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifest.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifest.java new file mode 100644 index 00000000..b1f94b1c --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifest.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.jitengine.expressions; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +/// +/// 关联的表达式清单 +/// 包含组合表单 +/// +public class ExpressionManifest { + /// + /// 清单文件对应的文件路径 + /// + public String manifestJsonPath; + + /// + /// 清单文件关联的主表单code + /// + public String formModuleCode; + + /// + /// 清单文件中包含的表单表达式集合 + /// + public List expressions; + + public String getManifestJsonPath() { + return manifestJsonPath; + } + + public void setManifestJsonPath(String manifestJsonPath) { + this.manifestJsonPath = manifestJsonPath; + } + + public String getFormModuleCode() { + return formModuleCode; + } + + public void setFormModuleCode(String formModuleCode) { + this.formModuleCode = formModuleCode; + } + + public List getExpressions() { + if (this.expressions == null) { + this.expressions = new ArrayList<>(); + } + return expressions; + } + + public void setExpressions(List expressions) { + this.expressions = expressions; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonEntity.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonEntity.java new file mode 100644 index 00000000..2ebb3b2c --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonEntity.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +/// +/// 表达式清单json +/// +@Data +public class ExpressionManifestJsonEntity { + + @JsonProperty("expressions") + private List expressions; + + public List getExpressions() { + if (this.expressions == null) { + this.expressions = new ArrayList<>(); + } + return expressions; + } + + public void setExpressions(List expressions) { + this.expressions = expressions; + } +} + + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonItemEntity.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonItemEntity.java new file mode 100644 index 00000000..c680998d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestJsonItemEntity.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ExpressionManifestJsonItemEntity +{ + + @JsonProperty("path") + private String path; + + @JsonProperty("ns") + private String ns; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getNs() { + return ns; + } + + public void setNs(String ns) { + this.ns = ns; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestManager.java new file mode 100644 index 00000000..8ea27cf9 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ExpressionManifestManager.java @@ -0,0 +1,109 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/25 + */ +public class ExpressionManifestManager { + + /** + * 表单表达式json文件写入 + * + * @param expressionManifest + * @param basePath + * @param isSingleDynamicForm + */ + public static void writeExpressionJson(ExpressionManifest expressionManifest, String basePath, boolean isSingleDynamicForm) { + + String expressionManifestJsonPath = Paths.get(basePath, "expressions", expressionManifest.getFormModuleCode().toLowerCase(), "expressions").toString(); + if (isSingleDynamicForm) { + expressionManifestJsonPath = Paths.get(basePath, "expressions").toString(); + } + java.io.File directoryInfo = new java.io.File(expressionManifestJsonPath); + if (directoryInfo.exists()) { + directoryInfo.delete(); + } + + ExpressionManifestJsonEntity expressionManifestJsonEntity = new ExpressionManifestJsonEntity(); + + if (expressionManifest != null && expressionManifest.getExpressions().size() > 0) { + + // 所有关联表单的表达式 + List expressionFormJsonEntities = new ArrayList<>(); + + expressionManifest.getExpressions().forEach((item) -> + { + ExpressionManifestJsonItemEntity expressionManifestJsonItemEntity = new ExpressionManifestJsonItemEntity(); + expressionManifestJsonItemEntity.setNs(item.getNameSpace()); + expressionManifestJsonItemEntity.setPath("./" + item.getFormExpressionJsonPath()); + expressionManifestJsonEntity.getExpressions().add(expressionManifestJsonItemEntity); + + ExpressionFormJsonEntity expressionFormJsonEntity = new ExpressionFormJsonEntity(); + expressionFormJsonEntity.setPath(item.getFormExpressionJsonPath()); + item.getExpressions().forEach((expressionItem) -> { + ExpressionFormFieldJsonEntity expressionFormFieldJsonEntity = new ExpressionFormFieldJsonEntity(); + expressionFormFieldJsonEntity.setNs(item.getNameSpace()); + + if (!StringUtility.isNullOrEmpty(expressionItem.getBindTo()) && !expressionItem.getBindTo().equals("/")) { + expressionFormFieldJsonEntity.setPath(expressionItem.getBindTo(), expressionItem.getFieldLabel()); + } else { + expressionFormFieldJsonEntity.setPath(expressionItem.getFieldLabel()); + } + + expressionFormFieldJsonEntity.setType(expressionItem.getSourceType()); + + expressionItem.getExpression().forEach((expressionStatementItem) -> { + + ExpressionFormFieldExpression expressionFormFieldExpression = new ExpressionFormFieldExpression(); + expressionFormFieldExpression.setType(expressionStatementItem.getType()); + + expressionFormFieldExpression.setMessage(expressionStatementItem.getMessage()); + expressionFormFieldExpression.setMessageType(expressionStatementItem.getMessageType()); + expressionFormFieldExpression.setId(expressionStatementItem.getId()); + // + if (expressionStatementItem.getValue() != null || expressionStatementItem.getValue().length() > 0) { + DesignExpressionValue designExpressionValue = SerializeUtility.getInstance().deserialize(expressionStatementItem.getValue(), DesignExpressionValue.class); + if (designExpressionValue != null) { + expressionFormFieldExpression.setValue(designExpressionValue.getExpr()); + } else { + expressionFormFieldExpression.setValue(""); + } + } else { + expressionFormFieldExpression.setValue(""); + } + // 构造依赖 + //expressionFormFieldExpression.Deps + expressionFormFieldJsonEntity.getExpressions().add(expressionFormFieldExpression); + }); + + + expressionFormJsonEntity.getFormFieldJsonEntities().add(expressionFormFieldJsonEntity); + }); + + expressionFormJsonEntities.add(expressionFormJsonEntity); + }); + + // 写入具体的表单文件 + String finalExpressionManifestJsonPath = expressionManifestJsonPath; + expressionFormJsonEntities.forEach((expressionFormJsonEntityItem) -> { + String strFormExpression = SerializeUtility.getInstance().serialize(expressionFormJsonEntityItem.getFormFieldJsonEntities(), false); + FileUtility.writeFile(finalExpressionManifestJsonPath, expressionFormJsonEntityItem.getPath(), strFormExpression); + }); + } + String strExpressionManifestJsonEntity = SerializeUtility.getInstance().serialize(expressionManifestJsonEntity, false); + // 写入表单 表达式清单文件 + FileUtility.writeFile(expressionManifestJsonPath, expressionManifest.getManifestJsonPath(), strExpressionManifestJsonEntity); + + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/FieldInfo.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/FieldInfo.java new file mode 100644 index 00000000..0b2fd0ab --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/FieldInfo.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.jitengine.expressions; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class FieldInfo { + private Object schemaFields; + private ModuleSchemaEntities relatedEntity; + private String bindTo; + private String refElementLabelPath; + + public Object getSchemaFields() { + return schemaFields; + } + + public void setSchemaFields(Object schemaFields) { + this.schemaFields = schemaFields; + } + + public ModuleSchemaEntities getRelatedEntity() { + return relatedEntity; + } + + public void setRelatedEntity(ModuleSchemaEntities relatedEntity) { + this.relatedEntity = relatedEntity; + } + + public String getBindTo() { + return bindTo; + } + + public void setBindTo(String bindTo) { + this.bindTo = bindTo; + } + + public String getRefElementLabelPath() { + return refElementLabelPath; + } + + public void setRefElementLabelPath(String refElementLabelPath) { + this.refElementLabelPath = refElementLabelPath; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleExpressionStatement.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleExpressionStatement.java new file mode 100644 index 00000000..157d12bc --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleExpressionStatement.java @@ -0,0 +1,66 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * description:表达式语句 + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ModuleExpressionStatement { + @JsonProperty("id") + private String id; + + @JsonProperty("type") + private String type; + + @JsonProperty("value") + private String value; + /** + * 提示消息 + */ + @JsonProperty("message") + private String message; + /** + * 消息类型 + */ + @JsonProperty("messageType") + private String messageType; + + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionFieldItem.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionFieldItem.java new file mode 100644 index 00000000..f5498c5d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionFieldItem.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * description:表单表达式对应的字段定义 + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ModuleFormExpressionFieldItem extends ModuleFormExpressionItem { + @JsonProperty("fieldId") + private String fieldId; + + @JsonProperty("fieldCode") + private String fieldCode; + + @JsonProperty("fieldLabel") + private String fieldLabel; + + @JsonProperty("bindTo") + private String bindTo; + + public String getFieldId() { + return fieldId; + } + + public void setFieldId(String fieldId) { + this.fieldId = fieldId; + } + + public String getFieldCode() { + return fieldCode; + } + + public void setFieldCode(String fieldCode) { + this.fieldCode = fieldCode; + } + + public String getFieldLabel() { + return fieldLabel; + } + + public void setFieldLabel(String fieldLabel) { + this.fieldLabel = fieldLabel; + } + + public String getBindTo() { + return bindTo; + } + + public void setBindTo(String bindTo) { + this.bindTo = bindTo; + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionItem.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionItem.java new file mode 100644 index 00000000..8aaa248a --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressionItem.java @@ -0,0 +1,41 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +@Data +public class ModuleFormExpressionItem { + @JsonProperty("sourceType") + private String sourceType = "Field"; + + @JsonProperty("expression") + private List expression; + + public String getSourceType() { + return sourceType; + } + + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + public List getExpression() { + if(this.expression==null){ + this.expression=new ArrayList<>(); + } + return expression; + } + + public void setExpression(List expressions) { + this.expression = expressions; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressions.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressions.java new file mode 100644 index 00000000..1303bc13 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleFormExpressions.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.jitengine.expressions; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ModuleFormExpressions { + private String formModuleCode; + private String nameSpace; + private String formExpressionJsonPath; + private List expressions; + + public String getFormModuleCode() { + return formModuleCode; + } + + public void setFormModuleCode(String formModuleCode) { + this.formModuleCode = formModuleCode; + } + + public String getNameSpace() { + return nameSpace; + } + + public void setNameSpace(String nameSpace) { + this.nameSpace = nameSpace; + } + + public String getFormExpressionJsonPath() { + return formExpressionJsonPath; + } + + public void setFormExpressionJsonPath(String formExpressionJsonPath) { + this.formExpressionJsonPath = formExpressionJsonPath; + } + + public List getExpressions() { + if (this.expressions == null) { + this.expressions = new ArrayList<>(); + } + return expressions; + } + + public void setExpressions(List expressions) { + this.expressions = expressions; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntities.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntities.java new file mode 100644 index 00000000..b68c3866 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntities.java @@ -0,0 +1,56 @@ +package com.inspur.edp.web.jitengine.expressions; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ModuleSchemaEntities { + private String id; + private String code; + private String name; + private String label; + private ModuleSchemaEntityType type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public ModuleSchemaEntityType getType() { + return type; + } + + public void setType(ModuleSchemaEntityType type) { + this.type = type; + } +} + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntityType.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntityType.java new file mode 100644 index 00000000..bae430be --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/ModuleSchemaEntityType.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.jitengine.expressions; + +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ModuleSchemaEntityType { + private String name; + + private String primary; + + private List> fields; + + private List entities; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } + + public List> getFields() { + return fields; + } + + public void setFields(List> fields) { + this.fields = fields; + } + + public List getEntities() { + return entities; + } + + public void setEntities(List entities) { + this.entities = entities; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/DefaultFunctionExpressionParser.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/DefaultFunctionExpressionParser.java new file mode 100644 index 00000000..a3ac477c --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/DefaultFunctionExpressionParser.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.jitengine.expressions.parser; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +/// +/// 表达式 defaultFunction 解析 +/// 将defaultFunction替换成为ctx +/// +public class DefaultFunctionExpressionParser { + private final Pattern regex; + + public DefaultFunctionExpressionParser() { + regex = Pattern.compile("DefaultFunction.[^\n(]+",Pattern.COMMENTS); + } + + /// + /// defaultfunction 的正则匹配 及参数替换操作 + /// + /// + /// + public String Parse(String source) { + String parsedResult = source; + Matcher defaultFunctionMatches = regex.matcher(source); + + while (defaultFunctionMatches.find()) { + String matchedValue = defaultFunctionMatches.group(); + String[] chainedMethods = matchedValue.split("\\."); + if (chainedMethods.length > 1) { + String matchedMethod = chainedMethods[1]; + // 如果为固定方法名 进行替换 + if ("GetContextParameter".equals(matchedMethod)) { + matchedMethod = "getState"; + } + String lowerMethod = FirstToLower(matchedMethod); + String target = "ctx." + lowerMethod; + parsedResult = parsedResult.replace(matchedValue, target); + } + } + return parsedResult; + } + + /// + /// 首字母小写 + /// + /// + /// + public String FirstToLower(String source) { + if (StringUtility.isNullOrEmpty(source)) { + return ""; + } + return source.substring(0, 1).toLowerCase() + source.substring(1); + } + + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/EntityExpressionParser.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/EntityExpressionParser.java new file mode 100644 index 00000000..fbbef602 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/EntityExpressionParser.java @@ -0,0 +1,114 @@ +package com.inspur.edp.web.jitengine.expressions.parser; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +/// +/// 表达式实体解析 +/// +public class EntityExpressionParser { + /// + /// 表达式实体解析 + /// + /// + /// + /// + public String Parse(String source, String entityName) { + String parsedResult = source; + // 解析表达式中对应的entity匹配 + Matcher matchedEntityExpression = ExpressionSourceEntityMatch(source, entityName); + + while (matchedEntityExpression.find()) { + /// 表达式实体entity具体项匹配 + String matchedExpressionValue = matchedEntityExpression.group(); + String result = ExpressionSourceItemMatch(entityName, matchedExpressionValue); + if (!StringUtility.isNullOrEmpty(result)) { + parsedResult = parsedResult.replace(matchedExpressionValue, result); + } + } + + return parsedResult; + } + + + /// + /// 表达式匹配 + /// + /// + /// + /// + private static String ExpressionSourceItemMatch(String entityName, String matchedExpressionValue) { + String result = matchedExpressionValue; + Matcher matchedItemExpression = ExpressionSourceItemRegex(entityName, matchedExpressionValue); + if (matchedItemExpression.find()) { + String matchedItemExpressionValue = matchedItemExpression.group(); + if (!StringUtility.isNullOrEmpty(matchedItemExpressionValue) && + !StringUtility.isNullOrEmpty(matchedItemExpressionValue)) { + String replacedMatchedValue = matchedItemExpressionValue + .replace(entityName, "ENTITY~") + .replace(".", "/") + .replace("'", "") + .replace("\"", ""); + if (!((replacedMatchedValue.startsWith("\"") && replacedMatchedValue.endsWith("\"")) || + (replacedMatchedValue.startsWith("'") && replacedMatchedValue.endsWith("\"")))) { + replacedMatchedValue = "'{" + replacedMatchedValue + "}'"; + } + + result = result.replace(matchedItemExpressionValue, replacedMatchedValue); + + // 括号替换 + result = replaceKuoHao(result); + + } + + } + return result; + } + + private static Matcher ExpressionSourceItemRegex(String entityName, String matchedExpressionValue) { + String strPattern = "[\\'\\\"]?\\s*" + entityName + "[\\.\\[\\]a-zA-Z0-9_]+\\s*[\\'\\\"]?"; + Pattern regexItem = Pattern.compile(strPattern, Pattern.COMMENTS); + return regexItem.matcher(matchedExpressionValue); + } + + /// + /// 针对输入的数据源进行正则匹配 + /// 匹配实体参数 + /// + /// + /// + /// + /// + public static Matcher ExpressionSourceEntityMatch(String source, String entityName) { + String strPattern = "ctx\\.[^\n\\(]+\\(\\s*\"?\\s*" + entityName + "[\\.\\[\\]a-zA-Z0-9_]+\\s*\"?\\s*\\)?"; + Pattern regex = Pattern.compile(strPattern, Pattern.COMMENTS); + return regex.matcher(source); + } + + public static String replaceKuoHao(String source) { + if (StringUtility.isNullOrEmpty(source)) { + return source; + } + String result = source; + Matcher kuoHaoMatched = expressionKuoHaoReplace(source); + while (kuoHaoMatched.find()) { + String matchedValue = kuoHaoMatched.group(); + result = result.replace(matchedValue, ""); + } + return result; + } + + public static Matcher expressionKuoHaoReplace(String source) { + String strPattern = "\\[\\d*\\]"; + Pattern regex = Pattern.compile(strPattern, Pattern.COMMENTS); + return regex.matcher(source); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/ExpressionParserManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/ExpressionParserManager.java new file mode 100644 index 00000000..26cc1bf4 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/ExpressionParserManager.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.jitengine.expressions.parser; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ExpressionParserManager { + public static String Parse(String source, String entityName) { + DefaultFunctionExpressionParser defaultFunctionExpressionParser = new DefaultFunctionExpressionParser(); + String defaultFunctionExpressionParseResult = defaultFunctionExpressionParser.Parse(source); + + EntityExpressionParser entityExpressionParser = new EntityExpressionParser(); + String entityExpressionParseResult = entityExpressionParser.Parse(defaultFunctionExpressionParseResult, entityName); + + FieldsExpressionParser fieldsExpressionParser = new FieldsExpressionParser(); + String fieldExpressionParseResult = fieldsExpressionParser.Parse(entityExpressionParseResult, entityName); + if (!StringUtility.isNullOrEmpty(fieldExpressionParseResult)) { + + // 判断是否包含return + if (!checkHasReturn(fieldExpressionParseResult)) { + fieldExpressionParseResult = "(ctx)=>{return " + fieldExpressionParseResult + "}"; + } else { + fieldExpressionParseResult = "(ctx)=>{" + fieldExpressionParseResult + "}"; + } + + } + return fieldExpressionParseResult; + } + + /** + * 判断是否包含return + * + * @param source + * @return + */ + public static boolean checkHasReturn(String source) { + String strPattern = "([\\s\\r\\n{;}]+return)|(^return)\\s+"; + Pattern pattern = Pattern.compile(strPattern,Pattern.COMMENTS); + Matcher matcher = pattern.matcher(source); + return matcher.find(); + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/FieldsExpressionParser.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/FieldsExpressionParser.java new file mode 100644 index 00000000..f8176147 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/parser/FieldsExpressionParser.java @@ -0,0 +1,69 @@ +package com.inspur.edp.web.jitengine.expressions.parser; + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +/// +/// 表达式包含字段参数匹配 +/// +public class FieldsExpressionParser { + public String Parse(String source, String entityName) { + // 替换条件、case、普通实体及属性 + String parsedResult = source; + Matcher matchedFieldsExpressions = MatchEntityFieldExpression(source, entityName); + + while (matchedFieldsExpressions.find()) { + String matchedFieldsExpressionItemValue = matchedFieldsExpressions.group(); + + Matcher matchedFieldRegex = MatchFieldExpression(entityName, matchedFieldsExpressionItemValue); + if (matchedFieldRegex.find()) { + String matchFieldRegexValue = matchedFieldRegex.group(); + // ENTITY~/a + String result = matchFieldRegexValue.replace(entityName, "ENTITY~").replace(".", "/"); + + // 进行括号参数替换 + result=EntityExpressionParser.replaceKuoHao(result); + result = "ctx.getField('{" + result + "}')"; + + + + String b = matchedFieldsExpressionItemValue. + replace("\"", "").replace("'", "").replace(matchFieldRegexValue, result); + + // 截取首次出现的地方 + int firstIndex = parsedResult.indexOf(matchedFieldsExpressionItemValue); + + if (firstIndex >= 0) { + StringBuilder sb = new StringBuilder(parsedResult); + parsedResult = sb.replace(firstIndex, firstIndex + matchedFieldsExpressionItemValue.length(), b).toString(); + } + } + } + + return parsedResult; + } + + private static Matcher MatchFieldExpression(String entityName, String matchedFieldsExpressionItemValue) { + Pattern fieldRegex = Pattern.compile(entityName + "[\\.\\[\\]a-zA-Z0-9_]+", Pattern.COMMENTS); + return fieldRegex.matcher(matchedFieldsExpressionItemValue); + } + + /// + /// 表达式中包含字段参数匹配 + /// + /// + /// + /// + private static Matcher MatchEntityFieldExpression(String source, String entityName) { + String strPattern = "\\(?\\s*\\\"?\\s*" + entityName + "[\\.\\[\\]a-zA-Z0-9_]+\\s*\\\"?\\s*\\)?"; + Pattern regex = Pattern.compile(strPattern, Pattern.COMMENTS); + return regex.matcher(source); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/ExpressionUtility.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/ExpressionUtility.java new file mode 100644 index 00000000..562e1c71 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/ExpressionUtility.java @@ -0,0 +1,220 @@ +package com.inspur.edp.web.jitengine.expressions.utility; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.expressions.ModuleSchemaEntities; +import com.inspur.edp.web.jitengine.expressions.ModuleSchemaEntityType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * description: 表达式定义utility + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class ExpressionUtility { + + /// + /// 构造表达式对应的清单文件名称 + /// + /// + /// + public static String getExpressionManifestJsonPath(String moduleCode) { + return "form.manifest.json"; + } + + /// + /// 获取表单对应的表达式文件名称 + /// + /// + /// + /// + public static String getExpressionFormJsonPath(String uniqueID, String moduleCode) { + String jsonPath = ""; + if (!StringUtility.isNullOrEmpty(uniqueID)) { + jsonPath = jsonPath + uniqueID.toLowerCase() + "-"; + } + if (!StringUtility.isNullOrEmpty(moduleCode)) { + jsonPath = jsonPath + moduleCode.toLowerCase(); + } + jsonPath = jsonPath + ".expression.json"; + return jsonPath; + } + + /// + /// 构造表单对应的namespace + /// + /// + /// + /// + public static String getNameSpace(String externalComponentCode, String moduleCode) { + String strNameSpace = ""; + if (!StringUtility.isNullOrEmpty(externalComponentCode)) { + strNameSpace += externalComponentCode + "_"; + } + if (!StringUtility.isNullOrEmpty(moduleCode)) { + strNameSpace += moduleCode; + } + return strNameSpace; + } + + + public static com.inspur.edp.web.jitengine.expressions.FieldInfo getFieldInfoById(String fieldId, FormDOM formDom) { + if (formDom == null || formDom.getModule() == null || formDom.getModule().getSchemas() == null || formDom.getModule().getSchemas().size() == 0 || + formDom.getModule().getviewmodels() == null || formDom.getModule().getviewmodels().size() == 0) { + return null; + } + com.inspur.edp.web.jitengine.expressions.FieldInfo fieldInfo = null; + String serializedModuleEntities = SerializeUtility.getInstance().serialize(formDom.getModule().getSchemas().get(0).get("entities"), false); + List temp = new ArrayList<>(); + List schemaEntities = SerializeUtility.getInstance().deserialize(serializedModuleEntities, new TypeReference>() { + }); + if (schemaEntities == null || schemaEntities.size() == 0) { + return null; + } + + for (HashMap viewModel : formDom.getModule().getviewmodels()) { + if ("/".equals(viewModel.get("bindTo").toString()) && (!viewModel.containsKey("parent") || viewModel.get("parent") == null)) { + + } else { + String originalBindTo = viewModel.get("bindTo").toString(); + int splitIndex = originalBindTo.indexOf("/"); + if (splitIndex == 0) { + originalBindTo = originalBindTo.substring(splitIndex + 1); + } + TableFieldsInfo tableFieldsInfo = getTableFieldsByBindTo(schemaEntities, viewModel.get("bindTo").toString(), originalBindTo); + + if (tableFieldsInfo != null && tableFieldsInfo.getFields() != null && tableFieldsInfo.getFields().size() > 0) { + + FieldByIDAndVMIDResult result = getFieldByIDAndVMID(tableFieldsInfo, fieldId, ""); + if (result != null && result.getSchemaField() != null) { + fieldInfo = new com.inspur.edp.web.jitengine.expressions.FieldInfo(); + fieldInfo.setSchemaFields(result.getSchemaField()); + fieldInfo.setRelatedEntity(tableFieldsInfo.getRelatedEntity()); + fieldInfo.setBindTo(tableFieldsInfo.getBindTo()); + fieldInfo.setRefElementLabelPath(result.getRefElementLabelPath()); + return fieldInfo; + } + } + } + } + + return fieldInfo; + } + + private static TableFieldsInfo getTableFieldsByBindTo(List entities, String bindTo, String originalBindTo) { + String initBindTo = bindTo; + TableFieldsInfo tableFieldsInfo = new TableFieldsInfo(); + List> tableFields = new ArrayList<>(); + if (entities == null || entities.size() == 0) { + tableFieldsInfo.setFields(tableFields); + tableFieldsInfo.setBindTo(originalBindTo); + return tableFieldsInfo; + } + int splitIndex = bindTo.indexOf("/"); + if (splitIndex > -1) { + bindTo = bindTo.substring(splitIndex + 1); + } + String finalBindTo = bindTo; + for (ModuleSchemaEntities entity : entities) { + ModuleSchemaEntityType entityType = entity.getType(); + if (entityType == null) { + tableFieldsInfo.setFields(tableFields); + tableFieldsInfo.setRelatedEntity(entity); + tableFieldsInfo.setBindTo(originalBindTo); + return tableFieldsInfo; + } + if ("".equals(finalBindTo) || finalBindTo.equals(entity.getCode()) || finalBindTo.equals(entity.getLabel())) { + tableFieldsInfo.setFields(entityType.getFields()); + tableFieldsInfo.setRelatedEntity(entity); + tableFieldsInfo.setBindTo(originalBindTo); + return tableFieldsInfo; + } + List entityObj = entityType.getEntities(); + + if (entityObj != null && entityObj.size() > 0) { + TableFieldsInfo tableFieldsInfoByBindTo = ExpressionUtility.getTableFieldsByBindTo(entityObj, finalBindTo, originalBindTo); + if (tableFieldsInfoByBindTo != null && tableFieldsInfoByBindTo.getFields() != null) { + tableFieldsInfo.setFields(tableFieldsInfoByBindTo.getFields()); + tableFieldsInfo.setRelatedEntity(tableFieldsInfoByBindTo.getRelatedEntity()); + tableFieldsInfo.setBindTo(originalBindTo); + return tableFieldsInfoByBindTo; + } + } + } + return tableFieldsInfo; + } + + private static FieldByIDAndVMIDResult getFieldByIDAndVMID(TableFieldsInfo tableFieldsInfo, String id, String refElementLabelPath) { + return rescureGetFieldByIDAndVMID(tableFieldsInfo, id, refElementLabelPath); + } + + private static FieldByIDAndVMIDResult rescureGetFieldByIDAndVMID(TableFieldsInfo tableFieldsInfo, String id, String refElementLabelPath) { + Object element = new HashMap(); + boolean isRefElement = false; + if (StringUtility.isNullOrEmpty(refElementLabelPath)) { + refElementLabelPath = ""; + } + + String parentLabel = !StringUtility.isNullOrEmpty(refElementLabelPath) ? refElementLabelPath + "/" : ""; + for (HashMap field : tableFieldsInfo.getFields()) { + if (field.get("id").equals(id)) { + element = field; + refElementLabelPath = parentLabel + field.get("label"); + isRefElement = !StringUtility.isNullOrEmpty(parentLabel); + break; + } else { + // 关联字段/UDT字段 + if (field.containsKey("type") && field.get("type") != null) { + HashMap fieldTypeMap = (HashMap) field.get("type"); + if (fieldTypeMap.containsKey("fields") && fieldTypeMap.get("fields") != null) { + + TableFieldsInfo udtTableFieldInfo = new TableFieldsInfo(); + udtTableFieldInfo.setFields((List>) fieldTypeMap.get("fields")); + udtTableFieldInfo.setRelatedEntity(tableFieldsInfo.getRelatedEntity()); + + FieldByIDAndVMIDResult childResult = rescureGetFieldByIDAndVMID(udtTableFieldInfo, id, parentLabel + (field.get("label").toString())); + if (childResult != null && childResult.getSchemaField() != null && (childResult.getSchemaField() instanceof HashMap)) { + HashMap temper = (HashMap) childResult.getSchemaField(); + if (temper != null && !temper.isEmpty()) { + element = childResult.getSchemaField(); + refElementLabelPath = childResult.getRefElementLabelPath(); + isRefElement = childResult.isRefElement(); + break; + } + } + } + + } + } + } + + // 如果未获取到字段信息 + if (element == null || (!(element instanceof HashMap))) { + return null; + } + HashMap hashMapElement = (HashMap) element; + if (hashMapElement == null || hashMapElement.isEmpty()) { + return null; + } + + FieldByIDAndVMIDResult fieldByIDAndVMIDResult = new FieldByIDAndVMIDResult(); + fieldByIDAndVMIDResult.setRefElement(isRefElement); + fieldByIDAndVMIDResult.setRefElementLabelPath(refElementLabelPath); + fieldByIDAndVMIDResult.setSchemaField(element); + fieldByIDAndVMIDResult.setRelatedEntity(tableFieldsInfo.getRelatedEntity()); + + return fieldByIDAndVMIDResult; + } + +} + + + + + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/FieldByIDAndVMIDResult.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/FieldByIDAndVMIDResult.java new file mode 100644 index 00000000..65409db5 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/FieldByIDAndVMIDResult.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.jitengine.expressions.utility; + +import com.inspur.edp.web.jitengine.expressions.ModuleSchemaEntities; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +class FieldByIDAndVMIDResult { + private Object schemaField; + + private boolean isRefElement; + + private String refElementLabelPath; + + private ModuleSchemaEntities relatedEntity; + + public Object getSchemaField() { + return schemaField; + } + + public void setSchemaField(Object schemaField) { + this.schemaField = schemaField; + } + + public boolean isRefElement() { + return isRefElement; + } + + public void setRefElement(boolean refElement) { + isRefElement = refElement; + } + + public String getRefElementLabelPath() { + return refElementLabelPath; + } + + public void setRefElementLabelPath(String refElementLabelPath) { + this.refElementLabelPath = refElementLabelPath; + } + + public ModuleSchemaEntities getRelatedEntity() { + return relatedEntity; + } + + public void setRelatedEntity(ModuleSchemaEntities relatedEntity) { + this.relatedEntity = relatedEntity; + } +} + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/TableFieldsInfo.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/TableFieldsInfo.java new file mode 100644 index 00000000..907b5192 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/expressions/utility/TableFieldsInfo.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.jitengine.expressions.utility; + +import com.inspur.edp.web.jitengine.expressions.ModuleSchemaEntities; + +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/07 + */ +public class TableFieldsInfo { + private List> fields; + + private ModuleSchemaEntities relatedEntity; + + private String bindTo; + + public List> getFields() { + return fields; + } + + public void setFields(List> fields) { + this.fields = fields; + } + + public ModuleSchemaEntities getRelatedEntity() { + return relatedEntity; + } + + public void setRelatedEntity(ModuleSchemaEntities relatedEntity) { + this.relatedEntity = relatedEntity; + } + + public String getBindTo() { + return bindTo; + } + + public void setBindTo(String bindTo) { + this.bindTo = bindTo; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GenerateResourceManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GenerateResourceManager.java new file mode 100644 index 00000000..9e15b509 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GenerateResourceManager.java @@ -0,0 +1,223 @@ +package com.inspur.edp.web.jitengine.i18nresource; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.I18nResource; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.service.FormMetataService; + +import java.util.Arrays; +import java.util.List; + +/** + * 资源项管理 + */ +public class GenerateResourceManager { + /** + * 生成资源项id + * + * @param id + * @param prefix + * @return + */ + public static String generateResourceId(String id, String prefix) { + if (StringUtility.isNullOrEmpty(prefix)) { + return id; + } + return prefix.toLowerCase() + "_" + id; + } + + + public static void generateEnI18nResource(GspMetadata metadata, String baseFormPath, + GeneratedI18nResourceList i18nResourceList, + String baseFormRelativePath, + String keyPrefix) { + generateI18nResource(metadata, baseFormPath, i18nResourceList, baseFormRelativePath, keyPrefix, "en"); + } + + /** + * 生成对应的资源列表 + * + * @param metadata + * @param i18nResourceList + * @param keyPrefix key前缀 + * @param language + */ + public static void generateI18nResource(GspMetadata metadata, String baseFormPath, + GeneratedI18nResourceList i18nResourceList, + String baseFormRelativePath, + String keyPrefix, + String language) { + try { + List resourceList = FormMetataService.getFormResourceWithMetaData(metadata, language, baseFormPath); + + if (resourceList != null && !resourceList.isEmpty()) { + if (!StringUtility.isBlank(keyPrefix)) { + keyPrefix = keyPrefix + "_"; + } + for (I18nResource item : resourceList) { + if (item.getStringResources() != null && item.getStringResources().size() > 0) { + for (int i = 0; i <= item.getStringResources().size() - 1; i++) { + I18nResourceItem stringResourceItem = item.getStringResources().get(i); + if (stringResourceItem != null && !StringUtility.isNullOrEmpty(stringResourceItem.getKey())) { + if (stringResourceItem.getKey().contains(".")) { + i18nResourceList.add(keyPrefix + stringResourceItem.getKey().substring(stringResourceItem.getKey().lastIndexOf(".") + 1), stringResourceItem.getValue()); + } else { + i18nResourceList.add(keyPrefix + stringResourceItem.getKey(), stringResourceItem.getValue()); + } + } + } + } + } + } + } catch (Exception ex) { + //排除掉找不到对应的资源文件的异常 + if (ex.getMessage() != null && !ex.getMessage().contains("Can't Find Metadata")) { + LoggerUtility.log(ex.getMessage(), LoggerLevelEnum.Info); + } else { + ex.printStackTrace(); + throw ex; + } + } + } + + + /** + * 生成前端国际化资源文件 + * 针对组合表单 递归生成对应的i18n文件 + * + * @param i18nResourceList + * @param languageJsonPath + */ + public static void generateZhI18nJsonFile(GeneratedI18nResourceList i18nResourceList, + String languageJsonPath, String fileName) { + try { + String languageJsonFilePath = ""; + + languageJsonFilePath = FileUtility.combine(languageJsonPath, fileName); + + + if (FileUtility.exists(languageJsonPath)) { + FileUtility.deleteFile(languageJsonFilePath); + } + + if (i18nResourceList != null && i18nResourceList.getResourceList() != null && i18nResourceList.getResourceList().size() > 0) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + + for (int i = 0; i < i18nResourceList.getResourceList().size(); i++) { + GeneratedI8nResource item = i18nResourceList.getResourceList().get(i); + sb.append("\"" + item.getKey() + "\":" + "{\"name\":\"" + (StringUtility.isNullOrEmpty(item.getValue()) ? "" : item.getValue()) + "\"}"); + if (i < i18nResourceList.getResourceList().size() - 1) { + sb.append(","); + } + } + sb.append("}"); + + if (!FileUtility.exists(languageJsonPath)) { + FileUtility.createDirectory(languageJsonPath); + } + FileUtility.updateFile(languageJsonFilePath, sb.toString()); + } + + + } catch (Exception ex) { + //排除掉找不到对应的资源文件的异常 + if (ex.getMessage() != null && !ex.getMessage().contains("Can't Find Metadata")) { + LoggerUtility.log(ex.getMessage() + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Info); + } else { + LoggerUtility.log(ex.getMessage() + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Error); + throw ex; + } + } + } + + + public static void generateI18nJsonFile(GeneratedI18nResourceList i18nResourceList, String languageJsonPath, String fileName) { + generateI18nJsonFile(i18nResourceList, languageJsonPath, fileName, "en"); + } + + + /** + * 生成前端国际化资源文件 + * 针对组合表单 递归生成对应的i18n文件 + * + * @param i18nResourceList + * @param languageJsonPath + * @param language + */ + public static void generateI18nJsonFile(GeneratedI18nResourceList i18nResourceList, + String languageJsonPath, String fileName, String language) { + try { + String languageJsonFilePath = ""; + if (StringUtility.isNullOrEmpty(fileName)) { + fileName = language + ".json"; + } + languageJsonFilePath = FileUtility.combine(languageJsonPath, fileName); + + + if (FileUtility.exists(languageJsonFilePath)) { + FileUtility.deleteFile(languageJsonFilePath); + } + + if (i18nResourceList != null && !i18nResourceList.getResourceList().isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + + for (int i = 0; i < i18nResourceList.getResourceList().size(); i++) { + GeneratedI8nResource item = i18nResourceList.getResourceList().get(i); + sb.append("\"" + item.getKey() + "\":\"" + (StringUtility.isNullOrEmpty(item.getValue()) ? "" : item.getValue()) + "\""); + if (i < i18nResourceList.getResourceList().size() - 1) { + sb.append(","); + } + } + sb.append("}"); + + if (!FileUtility.exists(languageJsonPath)) { + FileUtility.createDirectory(languageJsonPath); + } + FileUtility.updateFile(languageJsonFilePath, sb.toString()); + } + + + } catch (Exception ex) { + //排除掉找不到对应的资源文件的异常 + if (ex.getMessage() != null && !ex.getMessage().contains("Can't Find Metadata")) { + LoggerUtility.log(ex.getMessage() + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Info); + } else { + LoggerUtility.log(ex.getMessage() + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Error); + } + } + } + + + /** + * 生成资源项前缀 + * + * @param source + * @param paramaters + * @return + */ + public static String generateKeyPrefix(String source, String... paramaters) { + if (paramaters == null || paramaters.length == 0) { + return source; + } + String generatedParameter = ""; + for (int i = 0; i < paramaters.length; i++) { + if (i == 0) { + generatedParameter = paramaters[0]; + } else { + generatedParameter = generatedParameter + "_" + paramaters[i]; + } + } + + if (StringUtility.isNullOrEmpty(source)) { + return generatedParameter; + } else { + return source + "_" + generatedParameter; + } + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI18nResourceList.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI18nResourceList.java new file mode 100644 index 00000000..f22a61be --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI18nResourceList.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.jitengine.i18nresource; + +import java.util.ArrayList; + +/** + 生成的资源项集合 +*/ +public class GeneratedI18nResourceList +{ + /** + 生成的资源项列表集合 + */ + private final ArrayList resourceList = new ArrayList<>(); + + public final ArrayList getResourceList() + { + return resourceList; + } + + /** + 增加资源项 + + @param key + @param value + */ + public final void add(String key, String value) + { + GeneratedI8nResource generatedI8nResourceItem = new GeneratedI8nResource(); + generatedI8nResourceItem.setKey(key); + generatedI8nResourceItem.setValue(value); + this.getResourceList().add(generatedI8nResourceItem); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI8nResource.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI8nResource.java new file mode 100644 index 00000000..ddcdc4a8 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/GeneratedI8nResource.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.jitengine.i18nresource; + +/** + 生成的i18n资源 +*/ +public class GeneratedI8nResource +{ + /** + 生成资源项key + */ + private String key; + public final String getKey() + { + return key; + } + public final void setKey(String value) + { + key = value; + } + + /** + 生成资源项value + */ + private String value; + public final String getValue() + { + return value; + } + public final void setValue(String value) + { + this.value = value; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/I18nResourceLanguage.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/I18nResourceLanguage.java new file mode 100644 index 00000000..5ff7f9fc --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/i18nresource/I18nResourceLanguage.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.jitengine.i18nresource; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/05 + */ +public class I18nResourceLanguage { + public static String ZHCN = "zh-CN"; + + public static String EN = "en"; + + public static String ZHCHT = "zh-CHT"; +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandServiceAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandServiceAnalysis.java new file mode 100644 index 00000000..fc964f5e --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandServiceAnalysis.java @@ -0,0 +1,143 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodeJsCommandResult; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataItem; +import com.inspur.edp.web.jitengine.metadatamanager.CommandServiceManager; +import org.apache.commons.io.FilenameUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 命令服务解析 + * + * @author noah + */ +public class CommandServiceAnalysis { + public static void resolveCommandService(FormDOM json, String path, String targetFormServiceBasePath, String targetStorageBasePath, ResolveFormMetadataItem resolveFormMetadataItem) { + if (json != null && json.getModule() != null && json.getModule().getServiceRefs() != null && json.getModule().getServiceRefs().size() > 0) { + String code = json.getModule().getCode(); + + String destDirectory = FileUtility.combine(targetFormServiceBasePath, code.toLowerCase(), "services"); + String directory = destDirectory.replace("/", FileUtility.DIRECTORY_SEPARATOR_CHAR).replace("\\", FileUtility.DIRECTORY_SEPARATOR_CHAR); + + HashMap serviceFileList = new HashMap<>(); + for (HashMap o : json.getModule().getServiceRefs()) { + if ("0".equals(o.get("isCommon").toString())) { + + String fileName = o.get("path").toString().substring(o.get("path").toString().lastIndexOf("/") + 1); + String contents = CommandServiceManager.getTypescriptFileContent(path, "", o, ExecuteEnvironment.Design, false); + if (StringUtility.isNullOrEmpty(contents)) { + return; + } + + boolean isPathExists = FileUtility.exists(destDirectory); + if (!isPathExists) { + FileUtility.createDirectory(destDirectory); + } + + FileUtility.writeFile(directory, fileName.toLowerCase(), contents); + + serviceFileList.put(fileName.toLowerCase(), directory); + } + } + + if (resolveFormMetadataItem.getCalculateIsDynamicForm()) { + // 进行自定义service的解析编译 + buildCustomService(json, directory, serviceFileList, resolveFormMetadataItem); + + // 拷贝对应生成物 + String sourceBuildPath = FileUtility.combine(directory, "dist-rollup"); + if (FileUtility.exists(sourceBuildPath)) { + String customJsDeployToFormFolder = FileUtility.combine(targetStorageBasePath, "dynamicjs"); + if (FileUtility.exists(customJsDeployToFormFolder)) { + FileUtility.forceDelete(customJsDeployToFormFolder); + } + // 将dist-rollup 拷贝 + FileUtility.copyFolder(sourceBuildPath, customJsDeployToFormFolder); + } + + } + } + } + + /** + * 自定义service的解析编译 + * + * @param json + * @param directory + * @param serviceFileList + * @param resolveFormMetadataItem + */ + private static void buildCustomService(FormDOM json, String directory, HashMap serviceFileList, ResolveFormMetadataItem resolveFormMetadataItem) { + StringBuilder sbIndexContent = new StringBuilder(); + boolean hasWriteTsConfigJsonFile = false; + boolean isJieXiForm = resolveFormMetadataItem.getCalculateIsDynamicForm(); + for (Map.Entry item : serviceFileList.entrySet()) { + if (!hasWriteTsConfigJsonFile && isJieXiForm) { + String tsConfigJsonContent = TsBuildConfigJsonGenerator.getTsConfigJsonContent(); + FileUtility.writeFile((String) item.getValue(), "tsconfig.json", tsConfigJsonContent); + hasWriteTsConfigJsonFile = true; + } + // 如果是解析型 + if (isJieXiForm) { + // 执行rollup打包 + String fileNameWithoutExtension = FilenameUtils.getBaseName((String) item.getKey()); + sbIndexContent.append("export * from './").append(fileNameWithoutExtension).append("';"); + } + } + + // 执行tsc + if (isJieXiForm && !serviceFileList.isEmpty()) { + // 写入index.ts 文件 + // 暂时屏蔽打包为单一文件的形式 + // FileUtility.writeFile(directory, "index.ts", sbIndexContent.toString()); + + NodeJsCommandResult tscCommandResult = NodejsFunctionUtility.getTscCommandInServer(false); + // "npx"; + String args = "cd " + directory + " && " + tscCommandResult.getNodeJsCommand(); + + args += " --build tsconfig.json "; + String tscBuildResult = CommandLineUtility.runCommand(args); + if (!StringUtility.isNullOrEmpty(tscBuildResult)) { + LoggerUtility.logToBrowser(tscBuildResult, LoggerLevelEnum.Info); + } + + //String fileNameWithoutExtension = FilenameUtils.getBaseName((String) item.getKey()); + String rollupPath = FileUtility.combine(directory, "dist-tsc"); + + NodeJsCommandResult rollupCommandResult = NodejsFunctionUtility.getRollupCommandInServer(false); + // 对每个js文件进行打包 + for (Map.Entry item : serviceFileList.entrySet()) { + String fileNameWithoutExtension = FilenameUtils.getBaseName((String) item.getKey()); + String rollupCommand = "cd " + rollupPath + " && " + rollupCommandResult.getNodeJsCommand(); + rollupCommand += " -f system "; + rollupCommand += "-i " + fileNameWithoutExtension + ".js "; + rollupCommand += "-o ../dist-rollup/" + fileNameWithoutExtension + ".js"; + String rollupBuildResult = CommandLineUtility.runCommand(rollupCommand); + if (!StringUtility.isNullOrEmpty(rollupBuildResult)) { + LoggerUtility.logToBrowser(rollupBuildResult, LoggerLevelEnum.Info); + } + } + // 暂时屏蔽打包 使用分散的脚本 + if (false && FileUtility.exists(FileUtility.combine(rollupPath, "index.js"))) { + String rollupCommand = "cd " + rollupPath + " && " + rollupCommandResult.getNodeJsCommand(); + rollupCommand += " -f system "; + rollupCommand += "-i " + "index.js "; + rollupCommand += "-o ../dist-rollup/" + "custom.service.js"; + String rollupBuildResult = CommandLineUtility.runCommand(rollupCommand); + if (!StringUtility.isNullOrEmpty(rollupBuildResult)) { + LoggerUtility.logToBrowser(rollupBuildResult, LoggerLevelEnum.Info); + } + } + } + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandsAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandsAnalysis.java new file mode 100644 index 00000000..3b6ee750 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/CommandsAnalysis.java @@ -0,0 +1,262 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.command.component.metadata.*; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.CommandsMetadataManager; +import com.inspur.edp.web.jitengine.metadatamanager.ComponentMetadataManager; + +import java.util.*; + +/** + * 命令解析 + * + * @author noah + */ + +public class CommandsAnalysis { + private String executeEnvironment = ExecuteEnvironment.Design; + private boolean isUpdradeTool = false; + // 是否生成command.json 文件 + private boolean createCommandJsonFile = true; + + public CommandsAnalysis(String executeEnvironment, boolean isUpdradeTool) { + this.executeEnvironment = executeEnvironment; + this.isUpdradeTool = isUpdradeTool; + } + + public CommandsAnalysis(String executeEnvironment, boolean isUpdradeTool, boolean createCommandJsonFile) { + this.executeEnvironment = executeEnvironment; + this.isUpdradeTool = isUpdradeTool; + this.createCommandJsonFile = createCommandJsonFile; + } + + + public void resolveCommand(FormDOM json, String formMetadataName, String targetStoragePath, + HashMap projectCmpList, + String webDevPath, String fileName) { + HashMap cmpList = new HashMap<>(8); + CommandsMetadataManager cmdManager = new CommandsMetadataManager(this.executeEnvironment, this.isUpdradeTool); + ComponentMetadataManager componentMetadataManager = new ComponentMetadataManager(this.executeEnvironment, this.isUpdradeTool); + StringBuilder sbCommands = new StringBuilder(); + sbCommands.append("{"); + if (json.getModule() != null && json.getModule().getWebcmds() != null && json.getModule().getWebcmds().size() > 0) { + sbCommands.append("\"commands\":{"); + int index = 0; + WebCommandsMetadata metadata; + String cmdId; + for (HashMap c : json.getModule().getWebcmds()) { + if (index > 0) { + sbCommands.append(","); + } + cmdId = c.get("id").toString(); + metadata = cmdManager.getWebCommands(cmdId); + analysisComponentMetadata(metadata, cmpList, null, componentMetadataManager, projectCmpList); + + try { + analysisServiceRef(json, cmpList); + } catch (Exception e) { + e.printStackTrace(); + return; + } + + sbCommands.append("\"").append(cmdId).append("\":"); + sbCommands.append(cmdManager.serialize(metadata)); + index += 1; + } + sbCommands.append("}"); + + if (cmpList.size() > 0) { + sbCommands.append(",\"serviceList\":["); + index = 0; + + Iterator iter = cmpList.entrySet().iterator(); + while (iter.hasNext()) { + HashMap.Entry entry = (HashMap.Entry) iter.next(); + if (index > 0) { + sbCommands.append(","); + } + sbCommands.append(SerializeUtility.getInstance().serialize(entry.getValue(), false)); + index += 1; + } + sbCommands.append("]"); + } + } + sbCommands.append("}"); + + if (StringUtility.isNullOrEmpty(fileName)) { + fileName = json.getModule().getCode().toLowerCase(); + } + if (this.createCommandJsonFile) { + cmdManager.saveMetadataFile(targetStoragePath, formMetadataName.toLowerCase() + ".command.json", sbCommands.toString()); + } + + } + + private void analysisComponentMetadata(WebCommandsMetadata metadata, HashMap cmpList, + List items, ComponentMetadataManager cmpManager, + HashMap projectCmpList) { + if (items == null || items.size() == 0) { + if (metadata.getCommands() != null && metadata.getCommands().size() > 0) { + for (WebCommand webCommandItem : metadata.getCommands()) { + try { + analysisComponentCommandItemList(webCommandItem.getItems(), cmpList, cmpManager, projectCmpList); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } else { + for (BranchCommandItem branchCommandItem : items) { + try { + analysisComponentCommandItemList(branchCommandItem.getItems(), cmpList, cmpManager, projectCmpList); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + /// + /// 解析commandItem + /// + /// + /// + /// + private void analysisComponentCommandItemList(List commandItemList, HashMap cmpList, + ComponentMetadataManager cmpManager, HashMap projectCmpList) throws Exception { + if (commandItemList != null && commandItemList.size() > 0) { + if (cmpManager == null) { + cmpManager = new ComponentMetadataManager(this.executeEnvironment, this.isUpdradeTool); + } + WebComponentMetadata cmpMetadata = null; + for (CommandItem item : commandItemList) { + switch (item.getItemType()) { + case MethodRefer: + if (!cmpList.containsKey(((CmpMethodRefering) item).getComponentId())) { + if (!projectCmpList.containsKey(((CmpMethodRefering) item).getComponentId())) { + try { + cmpMetadata = cmpManager.getComponentMetadata(((CmpMethodRefering) item).getComponentId()); + if (cmpMetadata == null) { + throw new Exception("标识为'" + ((CmpMethodRefering) item).getComponentId() + "'的服务构件为null。"); + } + LoggerUtility.logToBrowser("Get WebCommands By Id:" + cmpMetadata.getId(), LoggerLevelEnum.Info, false); + cmpList.put(cmpMetadata.getId(), cmpMetadata); + projectCmpList.put(cmpMetadata.getId(), cmpMetadata); + } catch (Exception ex) { + throw new Exception("获取command元数据" + ((CmpMethodRefering) item).getComponentId() + "失败", ex); + } + } else { + cmpMetadata = projectCmpList.get(((CmpMethodRefering) item).getComponentId()); + cmpList.put(cmpMetadata.getId(), cmpMetadata); + } + } + break; + case BranchCollection: + analysisComponentMetadata(null, cmpList, ((BranchCollectionCommandItem) item).getItems(), cmpManager, projectCmpList); + break; + default: + break; + + } + } + } + } + + private void analysisServiceRef(FormDOM json, HashMap cmpList) throws Exception { + if (cmpList != null && cmpList.size() > 0) { + + Iterator iter = cmpList.entrySet().iterator(); + while (iter.hasNext()) { + HashMap.Entry entry = (HashMap.Entry) iter.next(); + + if (json.getModule().getServiceRefs() == null) { + json.getModule().setServiceRefs(new ArrayList<>()); + } + + HashMap serviceRef = new HashMap<>(); + WebComponentMetadata component = (WebComponentMetadata) entry.getValue(); + if (component == null) { + throw new RuntimeException("不存在标识为'" + entry.getKey() + "'的服务构件"); + } + + if (!hasServiceReference(json.getModule().getServiceRefs(), component)) { + serviceRef.put("cmpId", component.getId()); + serviceRef.put("name", component.getClassName()); + String path = component.getSource(); + if (path == null || path.isEmpty()) { + path = getTSFileName(component.getId()); + component.setSource(path); + } + serviceRef.put("path", path); + + serviceRef.put("isCommon", component.isCommon() ? "1" : "0"); + serviceRef.put("alias", component.getClassName() + "1"); + + json.getModule().getServiceRefs().add(serviceRef); + } + } + } + } + + private boolean hasServiceReference(List> serviceReferenceList, WebComponentMetadata component) throws Exception { + boolean flag = false; + for (HashMap serviceRef : serviceReferenceList) { + if (serviceRef.containsKey("name") && serviceRef.containsKey("path")) { + if (serviceRef.get("name") == null) { + throw new Exception("标识为'{" + serviceRef.get("cmpId") + "'的服务构件name属性不允许为null。"); + } + + if (serviceRef.get("path") == null) { + throw new Exception("标识为'" + serviceRef.get("cmpId") + "'的服务构件path属性不允许为null。"); + } + + if (serviceRef.get("name").toString().equals(component.getClassName()) && + serviceRef.get("path") == component.getSource()) { + flag = true; + break; + } + } + } + return flag; + } + + /** + * 获取ts文件路径和名称 + */ + private String getTSFileName(String cmpId) throws Exception { + // 最理想的方式:路径来自webcmp构件路径,名称来自path(即元数据的Source属性) + // 先用webcmp的文件名构造,后续可以考虑调整 + if (cmpId == null || cmpId.isEmpty()) { + throw new Exception("获取ts文件名出错,对应的web构件id不能为空。"); + } + + CommandsMetadataManager manager = new CommandsMetadataManager(this.executeEnvironment, this.isUpdradeTool); + GspMetadata metadata = manager.getMetadata(cmpId); + + if (metadata == null) { + throw new RuntimeException("load command metatdata is null,commandId is " + cmpId); + } + + String path = metadata.getRelativePath(); + String cmpFileName = metadata.getHeader().getFileName(); + // 后缀为.webcmp + int suffixIndex = cmpFileName.lastIndexOf(".webcmp"); + String fileName; + if (suffixIndex > 0 && suffixIndex + 7 == cmpFileName.length()) { + fileName = cmpFileName.substring(0, suffixIndex); + } else if (cmpFileName.contains(metadata.getHeader().getCode())) { + fileName = cmpFileName; + } else { + throw new Exception("获取ts文件名出错,web构件上获取的文件名不对。"); + } + + return path + "/" + fileName + ".ts"; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/EapiAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/EapiAnalysis.java new file mode 100644 index 00000000..e5fcbeab --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/EapiAnalysis.java @@ -0,0 +1,71 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.EapiMetadataManager; + +import java.util.HashMap; +import java.util.List; + +/** + * Eapi解析 + * + * @author noah + */ + +public class EapiAnalysis { + + private String executeEnvironment = ExecuteEnvironment.Design; + private boolean isUpdradeTool = false; + + public EapiAnalysis(String executeEnvironment, boolean isUpdradeTool) { + this.executeEnvironment = executeEnvironment; + this.isUpdradeTool = isUpdradeTool; + } + + + /** + * 解析表单代码引用的eapi + * + * @param json 表单代码 + * @param targetStoragePath 解析后eapi存储路径 + * @param projectPath 工程路径 + * @param webDevPath webdev目录所在路径 + */ + public void resolveEapi(FormDOM json, String formMetadataName, String targetStoragePath, String projectPath, + String webDevPath) { + if (json == null || json.getModule() == null || json.getModule().getCode() == null + || StringUtility.isNullOrEmpty(targetStoragePath) + || json.getModule().getSchemas() == null || json.getModule().getSchemas().size() == 0) { + return; + } + StringBuilder eapis = new StringBuilder(); + eapis.append("["); + int index = 0; + // VO-EAPI(vo和eapi是一对一的关系) + List> schemas = json.getModule().getSchemas(); + EapiMetadataManager eapiMetadataManager = new EapiMetadataManager(this.executeEnvironment, this.isUpdradeTool); + for (HashMap item : schemas) { + if (index > 0) { + eapis.append(","); + } + //获取对应的EapiID 如果可以读取到 + String strEapiID = item.containsKey("eapiId") ? item.get("eapiId").toString() : ""; + // 如果获取到EapiID 抛出对应的异常,主要目的是因为eapi的结构调整 + if (!StringUtility.isNullOrEmpty(strEapiID)) { + IMetadataContent eapiMetadataContent = eapiMetadataManager.getEapiMetadataContent(strEapiID); + String eapiJson = eapiMetadataManager.serialize(eapiMetadataContent, PropertyNamingStrategy.UPPER_CAMEL_CASE); + eapis.append(eapiJson); + + index += 1; + } + } + eapis.append("]"); + eapiMetadataManager.saveMetadataFile(targetStoragePath, + formMetadataName.toLowerCase() + ".eapi.json", eapis.toString()); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/FormAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/FormAnalysis.java new file mode 100644 index 00000000..b077f9b6 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/FormAnalysis.java @@ -0,0 +1,103 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.common.utility.TupleTwo; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.FormMetadataManager; +import com.inspur.edp.web.jitengine.metadatamodel.app.form.AnalysisExternalComponentResult; + +import java.util.HashMap; + +/** + * 表单数据解析 + * + * @author noah + */ +public class FormAnalysis { + // 设定执行环境 + private String executeEnvironment = ExecuteEnvironment.Design; + private boolean isUpdradeTool = false; + + public FormAnalysis(String executeEnvironment, boolean isUpdradeTool) { + this.executeEnvironment = executeEnvironment; + this.isUpdradeTool = isUpdradeTool; + } + + /** + * 解析表单元数据 + */ + public TupleTwo resolveForm(String formMetadataFileName, String formMetadataFilePath, String destStoragePath, String projectPath) { + // Get Visual Dom + FormMetadataManager formMetadataManager = new FormMetadataManager(this.executeEnvironment, this.isUpdradeTool); + String formDom = formMetadataManager.getVisualDom(formMetadataFileName, formMetadataFilePath); + + // 反序列化表单元数据 + FormDOM json = SerializeUtility.getInstance().deserialize(formDom, FormDOM.class); + + if (!json.getOptions().isEnableFormJieXi()) { + formMetadataManager.saveMetadataFile(destStoragePath, formMetadataFileName.toLowerCase() + ".json", formDom); + } + + return new TupleTwo<>(json, formMetadataManager.getRelativePath()); + } + + /// + /// 分析扩展组件 + /// + /// + public AnalysisExternalComponentResult analysisExternalComponent(String frmJsonSavePath, + String parentModuleCode, + HashMap externalComponent, String webDevPath) { + FormDOM json = null; + Object objUri = null; + String externalComponentUri = ""; + Object objCode = null; + String externalComponentCode = ""; + Object objExternalComponentContainerId = null; + String externalComponentContainerId = ""; + String externalComponentPath = ""; + FormMetadataManager formMetadataManager = new FormMetadataManager(this.executeEnvironment, this.isUpdradeTool); + //TODO: 验证TryGetValue在java中语义实现 + objUri = externalComponent.get("uri"); + externalComponentUri = objUri != null ? objUri.toString() : ""; + objCode = externalComponent.get("code"); + externalComponentCode = objCode != null ? objCode.toString() : ""; + if (externalComponent.containsKey("containerId")) { + objExternalComponentContainerId = externalComponent.get("containerId"); + externalComponentContainerId = objExternalComponentContainerId.toString(); + } + + boolean useIsolateJs = externalComponent.get("useIsolateJs") != null && (boolean) externalComponent.get("useIsolateJs"); + + if (!useIsolateJs && !StringUtility.isNullOrEmpty(externalComponentUri)) { + // 获取组合表单的元数据信息 + String formMetaDataStr = formMetadataManager.getVisualDom(externalComponentUri); + json = SerializeUtility.getInstance().deserialize(formMetaDataStr, FormDOM.class); + + if (!StringUtility.isNullOrEmpty(formMetaDataStr)) { + externalComponentPath = !StringUtility.isNullOrEmpty(externalComponentContainerId) ? externalComponentContainerId : externalComponentCode; + externalComponentPath = externalComponentPath.toLowerCase(); + // 保存独立组件frmJson文件 + if (!StringUtility.isNullOrEmpty(frmJsonSavePath)) { + + formMetadataManager.saveMetadataFile(FileUtility.combine(frmJsonSavePath, parentModuleCode.toLowerCase(), + externalComponentPath), externalComponentCode.toLowerCase() + ".frm.json", formMetaDataStr); + + } else { + throw new RuntimeException("暂时无法处理frmJsonSavePath为空场景,请咨询开发人员该功能完成情况"); + } + } + } + AnalysisExternalComponentResult externalComponentResult = new AnalysisExternalComponentResult(); + externalComponentResult.setJson(json); + externalComponentResult.setExternalComponentPath(externalComponentPath); + externalComponentResult.setRelativePath(formMetadataManager.getRelativePath()); + externalComponentResult.setExternalComponentUri(externalComponentUri); + externalComponentResult.setUseIsolateJs(useIsolateJs); + + return externalComponentResult; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/StateMachineAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/StateMachineAnalysis.java new file mode 100644 index 00000000..c3a2577b --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/StateMachineAnalysis.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.StateMachineMetadataManager; + +import java.util.HashMap; + +/** + * 状态机的解析 + */ +public class StateMachineAnalysis { + /** + * 解析状态机元数据 + */ + public static void resolveStateMachine(FormDOM json, String metaDataFileName, String targetStoragePath, String webDevPath, + String projectPath, String executeEnvironment, + boolean isUpdradeTool) { + // Get StateMachine Metadata, and Save StateMachine + if (json.getModule() != null && json.getModule().getStateMachines() != null && json.getModule().getStateMachines().size() > 0) { + StateMachineMetadataManager smManager = new StateMachineMetadataManager(executeEnvironment, isUpdradeTool); + StringBuilder stateMachines = new StringBuilder(); + stateMachines.append("{"); + int index = 0; + for (HashMap o : json.getModule().getStateMachines()) { + if (index > 0) { + stateMachines.append(","); + } + String uri = o.get("uri").toString(); + Object obj = smManager.getStateMachine(uri); + String sm_json = smManager.serialize((IMetadataContent) obj); + String idStr = o.get("id").toString(); + stateMachines.append("\"").append(idStr).append("\":"); + stateMachines.append(sm_json); + index += 1; + } + stateMachines.append("}"); + + // Save StateMachine + smManager.saveMetadataFile(targetStoragePath, String.format("%1$s.sm.json", metaDataFileName.toLowerCase()), stateMachines.toString()); + } + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/TsBuildConfigJsonGenerator.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/TsBuildConfigJsonGenerator.java new file mode 100644 index 00000000..94672d15 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/TsBuildConfigJsonGenerator.java @@ -0,0 +1,56 @@ +package com.inspur.edp.web.jitengine.metadataanalysis; + +public class TsBuildConfigJsonGenerator { + /** + * ts编译配置文件 + */ + private static final String tsConfigJsonContent = "{\n" + + " \"compileOnSave\": false,\n" + + " \"compilerOptions\": {\n" + + " \"baseUrl\": \"./\",\n" + + " \"outDir\": \"./dist-tsc\",\n" + + " \"rootDir\": \"./\",\n" + + " \"sourceMap\": false,\n" + + " \"declaration\": false,\n" + + " \"module\": \"es2015\",\n" + + " \"moduleResolution\": \"node\",\n" + + " \"emitDecoratorMetadata\": true,\n" + + " \"experimentalDecorators\": true,\n" + + " \"importHelpers\": true,\n" + + " \"noImplicitAny\": false,\n" + + " \"noStrictGenericChecks\": true,\n" + + " \"noUnusedLocals\": false,\n" + + " \"noEmitOnError\": true,\n" + + " \"suppressExcessPropertyErrors\": true,\n" + + " \"skipDefaultLibCheck\": true,\n" + + " \"skipLibCheck\": true,\n" + + " \"noEmitHelpers\": true,\n" + + " \"diagnostics\": false,\n" + + " \"traceResolution\": false,\n" + + " \"removeComments\": false,\n" + + " \"target\": \"es5\",\n" + + " \"typeRoots\": [\n" + + " \"node_modules/@types\"\n" + + " ],\n" + + " \"lib\": [\n" + + " \"es2018\",\n" + + " \"dom\"\n" + + " ],\n" + + " \"paths\": {}\n" + + " },\n" + + " \"angularCompilerOptions\": {\n" + + " \"strictInjectionParameters\": false,\n" + + " \"trace\": false,\n" + + " \"preserveWhitespaces\": false,\n" + + " \"fullTemplateTypeCheck\": false,\n" + + " \"disableTypeScriptVersionCheck\": true,\n" + + " \"skipMetadataEmit\": true,\n" + + " \"skipTemplateCodegen\": false,\n" + + " \"annotationsAs\": \"decorators\"\n" + + " }\n" + + "}"; + + public static String getTsConfigJsonContent() { + return tsConfigJsonContent; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/form/FormComponentParser.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/form/FormComponentParser.java new file mode 100644 index 00000000..cfd9aeda --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataanalysis/form/FormComponentParser.java @@ -0,0 +1,109 @@ +package com.inspur.edp.web.jitengine.metadataanalysis.form; + +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 表单组件解析器 + * @author noah + */ +public class FormComponentParser { + private FormComponentParser() { + + } + + private static final FormComponentParser formComponentParser = new FormComponentParser(); + + public static FormComponentParser getInstance() { + return formComponentParser; + } + + /** + * 提取组件信息 + */ + public final void ExtractComponent(FormDOM json, String metadataFileName, String targetStoragePath, String webDevPath) { + if (json == null || json.getModule() == null || json.getModule().getComponents() == null || json.getModule().getComponents().size() <= 0) { + return; + } + String serilizedPageCollectionStr = SerilizePageCollection(json.getModule().getComponents()); + if (StringUtility.isNullOrEmpty(serilizedPageCollectionStr)) { + return; + } + + String internalRoutes = "{" + + serilizedPageCollectionStr + + "}"; + + FileUtility.writeFile(targetStoragePath, String.format("%1$s%2s", metadataFileName.toLowerCase(), JITEngineConstants.ProjectRouteFileExtension), internalRoutes); + } + + private String SerilizePageCollection(ArrayList> componentCollection) { + if (componentCollection == null || componentCollection.size() <= 0) { + return null; + } + + StringBuilder pages = new StringBuilder(); + pages.append("\"pages\":"); + pages.append("["); + + int index = 0; + for (HashMap component : componentCollection) { + if (component.containsKey("route")) { + if (index > 0) { + pages.append(","); + } + pages.append(SerializeUtility.getInstance().serialize(component.get("route"),false)); + index++; + } + } + + pages.append("]"); + return pages.toString(); + } + + ///// + ///// 将Route对象序列化成json串 + ///// TODO:找到将Dictionary转换成实体类的方法并统一替换 + ///// + ///// + ///// + //private static string serilizeRouteObject(Dictionary routeObject) + //{ + // StringBuilder routeStringBuilder = new StringBuilder(); + // routeStringBuilder.Append("{"); + // if (routeObject.ContainsKey("id")) + // { + // routeStringBuilder.Append("\"id\":" + "\"" + routeObject["id"] + "\"" + ","); + // } + + // if (routeObject.ContainsKey("uri")) + // { + // routeStringBuilder.Append("\"uri\":" + "\"" + routeObject["uri"] + "\"" + ","); + // } + + // if (routeObject.ContainsKey("name")) + // { + // routeStringBuilder.Append("\"name\":" + "\"" + routeObject["name"] + "\""); + // } + + // // TODO: 列表还需单独处理 + // //routeObject["params"] + + // routeStringBuilder.Append("}"); + + // return routeStringBuilder.ToString(); + //} + + //private Dictionary ConvertToDictionaryObject(object targetObject) + //{ + // string json = JsonConvert.SerializeObject(targetObject); + // Dictionary convertedObject = JsonConvert.DeserializeObject>(json); + // return convertedObject; + //} +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/BaseMetaDataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/BaseMetaDataManager.java new file mode 100644 index 00000000..253a429f --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/BaseMetaDataManager.java @@ -0,0 +1,75 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; + +/** + * 基础元数据manager + * + * @author noah + */ +public class BaseMetaDataManager { + + /** + * 设定必须获取当前的运行环境 + * + * @param executeEnvironment + */ + public BaseMetaDataManager(String executeEnvironment, boolean isUpdradeTool) { + this.setExecuteEnvironment(executeEnvironment); + this.isUpdradeTool = isUpdradeTool; + } + + private boolean isUpdradeTool = false; + + private String relativePath = ""; + + public String getRelativePath() { + return this.relativePath; + } + + // 运行环境 运行时或设计时 + private String executeEnvironment = ExecuteEnvironment.Design; + + public String getExecuteEnvironment() { + return this.executeEnvironment; + } + + public void setExecuteEnvironment(String value) { + this.executeEnvironment = value; + } + + public GspMetadata getMetadata(String metaDataID) { + GspMetadata metadata = MetadataUtility.getInstance().getMetadataWithEnvironment(metaDataID, this.executeEnvironment, this.isUpdradeTool); + if (metadata != null) { + relativePath = metadata.getRelativePath(); + } + return metadata; + } + + public GspMetadata getMetadata(String metaDataFileName, String metaDataFilePath) { + GspMetadata metadata = MetadataUtility.getInstance().getMetadata(metaDataFileName, metaDataFilePath); + if (metadata != null) { + relativePath = metadata.getRelativePath(); + } + return metadata; + } + + public String serialize(IMetadataContent obj) { + return SerializeUtility.getInstance().serialize(obj,false); + } + + public String serialize(IMetadataContent obj, PropertyNamingStrategy namingStrategy) { + return SerializeUtility.getInstance().serialize(obj, namingStrategy,false); + } + + public void saveMetadataFile(String path, String fileName, String contents) { + FileUtility.writeFile(path, fileName, contents); + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandExtendProperty.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandExtendProperty.java new file mode 100644 index 00000000..abf8c5b7 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandExtendProperty.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +/** + * 命令扩展 + * @author noah + */ +public class CommandExtendProperty { + private String sourceCode; + + public final String getSourceCode() { + return sourceCode; + } + + public final void setsourceCode(String value) { + sourceCode = value; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandServiceManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandServiceManager.java new file mode 100644 index 00000000..1d35841b --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandServiceManager.java @@ -0,0 +1,69 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.tsfile.api.service.TsFileService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; + +/** + * 命令manager + * + * @author noah + */ +@Slf4j +public class CommandServiceManager { + private CommandServiceManager() { + } + + /** + * 从ts文件内容或ts所在构件元数据中读取文件内容 + * + * @param sourcePath + * @param serviceRef + * @return + */ + public static String getTypescriptFileContent(String sourcePath, String devRootPath, HashMap serviceRef, String executeEnvironment, boolean isUpdradeTool) { + try { + String refCmpId = serviceRef.get("cmpId").toString(); + // 仅在设计时进行文件读取 + if (executeEnvironment.equals(ExecuteEnvironment.Design)) { + try { + TsFileService fileService = SpringBeanUtils.getBean(TsFileService.class); + return fileService.loadTsFileContentByWebCmp(sourcePath, refCmpId); + } catch (Exception ex) { + LoggerUtility.log("command ts file read failed,use cmp metadata! the cmpid is " + refCmpId, LoggerLevelEnum.Info); + } + } + + return getTsSourceFromMetaData(refCmpId, executeEnvironment, isUpdradeTool); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /// + /// 从元数据中读取ts内容 适用于跨工程引用表单的情况 + /// + /// + /// + private static String getTsSourceFromMetaData(String cmpId, String executeEnvironment, boolean isUpdradeTool) { + GspMetadata gspMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(cmpId, executeEnvironment, isUpdradeTool); + if (gspMetadata != null && !StringUtility.isNullOrEmpty(gspMetadata.getExtendProperty())) { + CommandExtendProperty commandExtendProperty = SerializeUtility.getInstance().deserialize(gspMetadata.getExtendProperty(), CommandExtendProperty.class); + if (commandExtendProperty != null) { + return commandExtendProperty.getSourceCode(); + } + } + return ""; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandsMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandsMetadataManager.java new file mode 100644 index 00000000..496bb031 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/CommandsMetadataManager.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.command.component.metadata.WebCommandsMetadata; + +/** + * 命令元数据manager + * + * @author noah + */ +public class CommandsMetadataManager extends BaseMetaDataManager { + public CommandsMetadataManager(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + public WebCommandsMetadata getWebCommands(String id) { + GspMetadata webCommandMetadata = getMetadata(id); + if (webCommandMetadata == null) { + throw new RuntimeException("load webCommand metadata is null,the commandId is " + id); + } + return (WebCommandsMetadata) webCommandMetadata.getContent(); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/ComponentMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/ComponentMetadataManager.java new file mode 100644 index 00000000..194cc92d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/ComponentMetadataManager.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * 构件元数据manager + * + * @author noah + */ +public class ComponentMetadataManager extends BaseMetaDataManager { + public ComponentMetadataManager(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + public WebComponentMetadata getComponentMetadata(String id) { + GspMetadata webComponentMetadata = getMetadata(id); + if (webComponentMetadata == null) { + throw new RuntimeException("load webComponent metadata is null,the metaDataId is " + id); + } + return (WebComponentMetadata) webComponentMetadata.getContent(); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/EapiMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/EapiMetadataManager.java new file mode 100644 index 00000000..1dbafe15 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/EapiMetadataManager.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * Eapi 元数据管理器 + * @author noah + */ +public class EapiMetadataManager extends BaseMetaDataManager { + public EapiMetadataManager(String executeEnvironment,boolean isUpdradeTool) { + super(executeEnvironment,isUpdradeTool); + } + + /** + * 获取eapi元数据内容 + * + * @return + */ + public IMetadataContent getEapiMetadataContent(String eapiMetadataId) { + GspMetadata eapiMetadata=getMetadata(eapiMetadataId); + if(eapiMetadata==null){ + throw new RuntimeException("load eapi metadata is null,the metaDataId is " + eapiMetadataId); + } + return getMetadata(eapiMetadataId).getContent(); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/FormMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/FormMetadataManager.java new file mode 100644 index 00000000..4f9f730d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/FormMetadataManager.java @@ -0,0 +1,53 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +/** + * 表单元数据管理 + */ +public class FormMetadataManager extends BaseMetaDataManager { + public FormMetadataManager(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + /** + * 获取可视化的DOM + */ + public String getVisualDom(String metaDataFileName, String metaDataFilePath) { + GspMetadata metadata = getMetadata(metaDataFileName, metaDataFilePath); + return ((FormMetadataContent) metadata.getContent()).getContents().toString(); + } + + + /** + * 根据元数据id获取表单元数据 + * + * @param metaDataId + * @return + */ + private GspMetadata getFormMetaData(String metaDataId) { + GspMetadata metadata = getMetadata(metaDataId); + if (metadata == null) { + throw new RuntimeException("load form metadata is null,the metaDataId is " + metaDataId); + } + return metadata; + } + + /** + * 根据元数据ID获取元数据信息 + */ + public String getVisualDom(String metadataID) { + GspMetadata metadata = this.getFormMetaData(metadataID); + return ((FormMetadataContent) metadata.getContent()).getContents().toString(); + } + + /** + * 根据元数据ID获取元数据信息 + */ + public MetadataHeader getVisulDomHeader(String metaDataID) { + GspMetadata metadata = this.getMetadata(metaDataID); + return metadata.getHeader(); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/StateMachineMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/StateMachineMetadataManager.java new file mode 100644 index 00000000..8bf96f2d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/StateMachineMetadataManager.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.jitengine.metadatamanager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +public class StateMachineMetadataManager extends BaseMetaDataManager { + public StateMachineMetadataManager(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } + + public Object getStateMachine(String id) { + GspMetadata stateMachineMetaData = getMetadata(id); + if (stateMachineMetaData == null) { + throw new RuntimeException("load statemachine metadata is null,the metaDataId is " + id); + } + return stateMachineMetaData.getContent(); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/app/AppMetadataManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/app/AppMetadataManager.java new file mode 100644 index 00000000..8167c694 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamanager/app/AppMetadataManager.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.jitengine.metadatamanager.app; + +import com.inspur.edp.web.jitengine.metadatamanager.BaseMetaDataManager; + +/** + * appmetadataManager + * @author noah + */ +public class AppMetadataManager extends BaseMetaDataManager { + + /** + * 设定必须获取当前的运行环境 + * + * @param executeEnvironment + * @param isUpdradeTool + */ + public AppMetadataManager(String executeEnvironment, boolean isUpdradeTool) { + super(executeEnvironment, isUpdradeTool); + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/AppConfig.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/AppConfig.java new file mode 100644 index 00000000..0137717d --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/AppConfig.java @@ -0,0 +1,40 @@ +package com.inspur.edp.web.jitengine.metadatamodel.app; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * appconfig 实体信息 + * @author noah + */ +public class AppConfig { + private HashMap project; + + public final HashMap getproject() { + return project; + } + + public final void setproject(HashMap value) { + project = value; + } + + private ArrayList> pages; + + public final ArrayList> getpages() { + return pages; + } + + public final void setpages(ArrayList> value) { + pages = value; + } + + private String entry; + + public final String getentry() { + return entry; + } + + public final void setentry(String value) { + entry = value; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/form/AnalysisExternalComponentResult.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/form/AnalysisExternalComponentResult.java new file mode 100644 index 00000000..71e07338 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadatamodel/app/form/AnalysisExternalComponentResult.java @@ -0,0 +1,62 @@ +package com.inspur.edp.web.jitengine.metadatamodel.app.form; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/14 + */ +public class AnalysisExternalComponentResult { + private FormDOM json; + private String externalComponentPath; + private String relativePath; + private String externalComponentUri; + private boolean useIsolateJs = false; + + public FormDOM getJson() { + return json; + } + + public void setJson(FormDOM json) { + this.json = json; + } + + public String getExternalComponentPath() { + // 如果扩展表单路径以数字开头 那么增加默认的f参数值 + if (StringUtility.isStartWithNumber(this.externalComponentPath)) { + return "f" + this.externalComponentPath; + } + return externalComponentPath; + } + + public void setExternalComponentPath(String externalComponentPath) { + this.externalComponentPath = externalComponentPath; + } + + public String getRelativePath() { + return relativePath; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + + public String getExternalComponentUri() { + return externalComponentUri; + } + + public void setExternalComponentUri(String externalComponentUri) { + this.externalComponentUri = externalComponentUri; + } + + public boolean isUseIsolateJs() { + return useIsolateJs; + } + + public void setUseIsolateJs(boolean useIsolateJs) { + this.useIsolateJs = useIsolateJs; + } +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataparser/commandservice/CommandServiceAnalysis.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataparser/commandservice/CommandServiceAnalysis.java new file mode 100644 index 00000000..e1c15cd7 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/metadataparser/commandservice/CommandServiceAnalysis.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.jitengine.metadataparser.commandservice; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.CommandServiceManager; + +import java.util.HashMap; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/14 + */ +public class CommandServiceAnalysis { + public static void resolveCommandService(FormDOM json, String path, String targetStoragePath, + String webDevPath, String executeEnvironment, boolean isUpdradeTool) { + + if (json != null && json.getModule() != null && json.getModule().getServiceRefs() != null + && json.getModule().getServiceRefs().size() > 0) { + String code = json.getModule().getCode(); + for (HashMap serviceRefsObject : json.getModule().getServiceRefs()) { + if (serviceRefsObject.get("isCommon").toString().equals("0")) { + String fileName = serviceRefsObject.get("path").toString().substring(serviceRefsObject.get("path").toString().lastIndexOf("/") + 1); + + String contents = CommandServiceManager.getTypescriptFileContent(path, webDevPath, serviceRefsObject, executeEnvironment,isUpdradeTool); + if (StringUtility.isNullOrEmpty(contents)) { + return; + } + String destDirectory = FileUtility.combine(targetStoragePath, code.toLowerCase(), "services"); + boolean isPathExists = FileUtility.exists(destDirectory); + if (!isPathExists) { + FileUtility.createDirectory(destDirectory); + } + + FileUtility.writeFile(destDirectory, fileName.toLowerCase(), contents); + + } + } + } + } +} + diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormManager.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormManager.java new file mode 100644 index 00000000..b332626a --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormManager.java @@ -0,0 +1,124 @@ +package com.inspur.edp.web.jitengine.sourcecode; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; + +import java.util.ArrayList; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/03/05 + */ +public class SourceCodeInFormManager { + /** + * 从元数据内容中获取对应的自定义代码引用关系 + * @param formRefList + * @param strFormMetadataContent + */ + public static void getSourceCodeWithFormMetadataContent(List formRefList, String strFormMetadataContent) { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = null; + try { + // 获取表单元数据中对自定义web构件的引用 + JsonNode contentNode = mapper.readTree(strFormMetadataContent).get("Contents"); + + if (contentNode.textValue() != null) { + jsonNode = mapper.readTree(contentNode.textValue()).get("module").get("sourceCodeRef"); + } else { + jsonNode = mapper.readTree(contentNode.toString()).get("module").get("sourceCodeRef"); + } + + if (jsonNode != null) { + jsonNode.forEach(node -> { + SourceCodeInFormRef sourceCodeInFormRef = getSourceCodeInFormRef(node); + if (sourceCodeInFormRef != null) { + formRefList.add(sourceCodeInFormRef); + } + }); + } + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + + /** + * 根据表单引用关系获取对应的自定义web构件 + * + * @param sourceCodeInFormRefList + * @return + */ + public static List getSourceCodeMetadataEntities(List sourceCodeInFormRefList, boolean isUpdradeTool) { + List sourceCodeMetadataEntityList = new ArrayList<>(); + if (sourceCodeInFormRefList != null && sourceCodeInFormRefList.size() > 0) { + sourceCodeInFormRefList.forEach((formRef) -> { + String formRefSourceCodeMetadataId = formRef.getId(); + SourceCodeMetadataEntity sourceCodeMetadataEntity = getSourceCodeMetadataWithId(formRefSourceCodeMetadataId, isUpdradeTool); + if (sourceCodeMetadataEntity != null) { + sourceCodeMetadataEntityList.add(sourceCodeMetadataEntity); + } + }); + } + return sourceCodeMetadataEntityList; + } + + /** + * 根据元数据id获取对应的元数据内容 + * + * @param sourceCodeMetadataId + * @return + */ + public static SourceCodeMetadataEntity getSourceCodeMetadataWithId(String sourceCodeMetadataId, boolean isUpdradeTool) { + if (!StringUtility.isNullOrEmpty(sourceCodeMetadataId)) { + GspMetadata gspMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(sourceCodeMetadataId, ExecuteEnvironment.Runtime, isUpdradeTool); + if (gspMetadata != null) { + IMetadataContent metadataContent = gspMetadata.getContent(); + SourceCodeMetadataEntity metadataEntity = SerializeUtility.getInstance().deserialize(SerializeUtility.getInstance().serialize(metadataContent,false), SourceCodeMetadataEntity.class); + System.out.println("获取元数据成功" + metadataEntity == null ? "为空" : "不为空"); + return metadataEntity; + } else { + System.out.println("根据元数据id获取元数据为空,对应元数据id为" + sourceCodeMetadataId); + } + } + + return null; + } + + /** + * 从dom结构中获取表单引用关系 + * + * @param node + * @return + */ + private static SourceCodeInFormRef getSourceCodeInFormRef(JsonNode node) { + JsonNode jsonNodeId = node.get("id"); + String strSourceCodeMetadataId = jsonNodeId != null ? jsonNodeId.textValue() : ""; + + JsonNode jsonNodeCode = node.get("code"); + String strSourceCodeMetadataCode = jsonNodeCode != null ? jsonNodeCode.textValue() : ""; + + JsonNode jsonNodeName = node.get("name"); + String strSourceCodeMetadataName = jsonNodeName != null ? jsonNodeName.textValue() : ""; + + SourceCodeInFormRef sourceCodeInFormRef = new SourceCodeInFormRef(); + sourceCodeInFormRef.setId(strSourceCodeMetadataId); + sourceCodeInFormRef.setCode(strSourceCodeMetadataCode); + sourceCodeInFormRef.setName(strSourceCodeMetadataName); + // 如果自定义web构件id为空 + if (StringUtility.isNullOrEmpty(strSourceCodeMetadataId)) { + return null; + } + return sourceCodeInFormRef; + } + +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormRef.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormRef.java new file mode 100644 index 00000000..cfa58bad --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/sourcecode/SourceCodeInFormRef.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.jitengine.sourcecode; + +/** + * description: + * + * @author Noah Guo + * @date 2021/03/05 + */ +public class SourceCodeInFormRef { + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * 自定义web构件id + */ + private String id; + /** + * 自定义web构件编码 code + */ + private String code; + /** + * 自定义web构件名称 name + */ + private String name; +} diff --git a/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/utility/PathUtility.java b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/utility/PathUtility.java new file mode 100644 index 00000000..734f9016 --- /dev/null +++ b/web-form-jitengine/src/main/java/com/inspur/edp/web/jitengine/utility/PathUtility.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.jitengine.utility; + + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * TODO n转j + */ +public class PathUtility +{ + public static String DIRECTORY_SEPARATOR_CHAR = FileUtility.DIRECTORY_SEPARATOR_CHAR; + + //public static String DOM_FILE_PATH = java.nio.file.Paths.get(GspServiceUnitPathService.GetPath("main")).resolve("web/webdev/").toString().Replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + public static String DOM_FILE_PATH = ""; + //public static String WEB_COMPILE_SERVER = java.nio.file.Paths.get(GspServiceUnitPathService.GetPath("main")).resolve("web/webidedebug/").toString().Replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + public static String WEB_COMPILE_SERVER = ""; + //public static String WEB_DEGUG_SERVER_ROUTE_CONFIG = java.nio.file.Paths.get(GspServiceUnitPathService.GetPath("main")).resolve("web/webidedebug/src/assets/").toString().Replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + public static String WEB_DEGUG_SERVER_ROUTE_CONFIG =""; + + @Deprecated + public static String getProjectTemplatePath() + { + return ""; + } + + public static String getAppDebugPath(String projectName) + { + return ""; + //return java.nio.file.Paths.get(GspServiceUnitPathService.GetPath("main")).resolve("web/webidedebug/package/" + projectName).toString().Replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + } + + public static String getPublishPath(String projectName) + { + return ""; + //return FileUtility.combine(GspServiceUnitPathService.GetPath("main"), "web/webidedebug/package", projectName, "src/app/modules/", projectName).Replace("/", DIRECTORY_SEPARATOR_CHAR).Replace("\\", DIRECTORY_SEPARATOR_CHAR); + } + + public static String getModuleCompileInfo(String projectName) + { + return ""; + //return FileUtility.combine(GspServiceUnitPathService.GetPath("main"), "web/webidedebug/package", projectName, "src/assets").replace("/", DIRECTORY_SEPARATOR_CHAR).replace("\\", DIRECTORY_SEPARATOR_CHAR); + } +} diff --git a/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGeneratorTest.java b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGeneratorTest.java new file mode 100644 index 00000000..3c31d3b5 --- /dev/null +++ b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/ExpressionFormGeneratorTest.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.jitengine.expressions; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +class ExpressionFormGeneratorTest { + + + @Test + void testGenerate() { + String fileContent = FileUtility.readAsString("D:\\InspurCode\\N转J之后代码\\tag2103\\web\\web-form-jitengine\\src\\test\\java\\com\\inspur\\edp\\web\\jitengine\\expressions\\expensemrgtxflcjt.frm.json"); + FormDOM formDOM = SerializeUtility.getInstance().deserialize(fileContent, FormDOM.class); + ModuleFormExpressions expressions = ExpressionFormGenerator.generate(formDOM, "", null); + + ExpressionManifest expressionManifest = new ExpressionManifest(); + + + List eeeeeee = new ArrayList<>(); + eeeeeee.add(expressions); + + expressionManifest.setExpressions(eeeeeee); + expressionManifest.setFormModuleCode("ddddddd"); + expressionManifest.setManifestJsonPath("c:/dddd.json"); + ExpressionManifestManager.writeExpressionJson(expressionManifest, "c:/dddd", false); + + } + + +} diff --git a/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/SystemVariableTest.java b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/SystemVariableTest.java new file mode 100644 index 00000000..7116bdfa --- /dev/null +++ b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/SystemVariableTest.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.jitengine.expressions; + +import org.junit.Test; + +/** + * @Title: SystemVariableTest + * @Description: com.inspur.edp.web.jitengine.expressions + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/29 9:24 + */ + +public class SystemVariableTest { + @Test + public void tes() { + System.getenv().forEach((key, value) -> System.out.println("key:" + key + " value:" + value)); + + System.out.println(); + + System.getProperties().forEach((key, value) -> System.out.println("key:" + key + " value:" + value)); + + } +} diff --git a/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/bxd003.frm.json b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/bxd003.frm.json new file mode 100644 index 00000000..c69dc33a --- /dev/null +++ b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/bxd003.frm.json @@ -0,0 +1,10384 @@ +{ + "module": { + "id": "frmclbxd001", + "code": "frmclbxd001", + "name": "差旅费报销单001", + "caption": "差旅费报销单001", + "type": "Module", + "creator": "wang-xh", + "creationDate": "2020-01-19T00:55:53.947Z", + "updateVersion": "191104", + "sourceCodeRef": [ + { + "id": "9c1357dc-ccff-4f6e-b0ef-0a127a821458", + "path": "", + "name": "" + } + ], + "showTitle": true, + "bootstrap": "card-template", + "states": [], + "contents": [], + "ctrlLangs": { + "ch": { + "form_djbh": "报销单编号", + "form_tbsj": "填报时间", + "form_bxrY_BXRY_Name": "报销人名称", + "form_zy": "报账说明", + "form_zdr": "制单人", + "form_bxje": "报销金额", + "form_bhsje": "不含税金额", + "form_dwbH_DWBH_OrgName": "单位名称", + "roclmx-tab-page": "差旅明细", + "dataGrid_roclmx_norecord": "暂无数据", + "gridField_5386c292-27c0-45ca-aa54-4badd26b7f9d_cfcS_CFCS_OrgName": "出发城市", + "gridField_fe4b4e56-96ff-4194-ac5b-2044be8b836a_cfsj": "出发时间", + "gridField_258048fb-a7d5-4859-a237-d0fc50465537_ddcS_DDCS_OrgName": "到达城市", + "gridField_96d83e67-5106-45f8-9f7e-1d6d69a0d51b_ddsj": "到达时间", + "gridField_75039c1b-800f-426b-991d-7035659c2a31_transportation": "交通工具", + "gridField_141d0f1b-175d-4a05-8546-1aab4dfa5fad_carnumber": "车次", + "gridField_741227f0-87f2-43db-a951-8cf96dafad6b_fjzs": "附件张数", + "gridField_b334b8d4-aa6a-4f50-97dc-297a0e4981dd_jtgjf": "交通工具费", + "gridField_b57cc8e1-7d55-4c2b-8cfb-4369f5a717f3_qtfy": "其他费用", + "gridField_9e6b8e1a-f0f6-4b81-9f35-c3ccf42ee3ec_zsfje": "住宿费金额", + "gridField_d81581b0-2fac-4df4-96e8-47226271bae5_zsfzpse": "住宿费专票税额", + "gridField_3486f51d-d708-4bc1-ac44-74d183cdcf63_ccts": "出差天数", + "gridField_c69e0186-aa02-4daf-bdcc-3d6de193ac18_bzbz": "补助标准", + "gridField_82f2bd8d-e103-45d5-a515-49fc5b02f084_mxbxje": "报销金额", + "gridField_45bac14b-de82-4d77-82fc-faeb3d44c1be_bz": "详细说明", + "gridField_e8b798c4-1fd9-4a6c-b129-e9489a5a0539_cwtzje": "财务调整金额", + "gridField_8cbdd664-cd6d-4377-b063-cca9b5cf106b_cwtzyy": "财务调整原因", + "rofkmx-tab-page": "付款明细", + "dataGrid_rofkmx_norecord": "暂无数据", + "gridField_007b6390-fdc7-4579-9e8a-e587a6487677_skfhm_skfhm_name": "银行账号名称", + "gridField_d7bf734b-3f00-4ced-932d-73f38a6bdd6d_fkhb": "付款货币", + "gridField_bf9b1463-418f-4a28-a309-a7c493819ce4_fkje": "付款金额", + "gridField_fdf6a560-ef6b-4850-8d92-4581111ea9e0_fkfs": "付款方式", + "gridField_52aa8a40-6f29-44cd-a297-a711b85417aa_yhfl": "银行分类", + "gridField_e049f868-a8f3-49c1-919b-602fade76b3b_skzh": "收款账号", + "gridField_1ce0b835-c3f9-4d83-a370-2bfbbec2af8d_khh": "开户行", + "rospjl-tab-page": "审批记录", + "dataGrid_rospjl_norecord": "暂无数据", + "gridField_b65be3a6-feb5-42f8-810f-8ca22f502512_spR_SPR_Name": "名称", + "gridField_1f117e30-a8e0-4232-8cf8-e6f00db2560b_spsj": "审批时间", + "gridField_85f5869b-1bdb-443f-808d-d52f2979d9ee_spyj": "审批意见", + "button-add": "新增", + "button-edit": "编辑", + "button-save": "保存", + "button-cancel": "取消", + "button-close": "关闭", + "gridField_092ee414-9b6f-43f8-9639-311432dc5a1b_cfcS_CFCS_OrgName": "出发城市", + "gridField_574554dc-9605-4a77-9bf6-ca8e95395c69_cfsj": "出发时间", + "gridField_6dbbe9c2-5a68-4d13-810d-160a04a7a463_ddcS_DDCS_OrgName": "到达城市", + "gridField_91d71207-5a50-4442-90fa-a7140731b50c_ddsj": "到达时间", + "gridField_575ed208-6ed0-4179-85b7-89824e7eccae_transportation": "交通工具", + "gridField_1e00ede8-d335-436d-bba0-fd0cea39234b_carnumber": "车次", + "gridField_1f20fde2-4938-4fb3-9c9b-b446faaccc1f_fjzs": "附件张数", + "gridField_3beb91d4-44ad-4189-90bb-d6fcdfda5559_jtgjf": "交通工具费", + "gridField_5ac85821-b1c8-466e-9fa6-cdb2a44117be_qtfy": "其他费用", + "gridField_d591ed4a-e8db-4120-9c9b-70a4e2e64413_zsfje": "住宿费金额", + "gridField_da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c_zsfzpse": "住宿费专票税额", + "gridField_df3ae210-5c7d-4f5a-9067-f584792834ee_ccts": "出差天数", + "gridField_595b5a9d-4103-4cc4-b6d4-9610d741c6a6_bzbz": "补助标准", + "gridField_a734eba7-eb12-4b4b-967b-5aaad25bfbd9_mxbxje": "报销金额", + "gridField_a5129114-0bca-4664-8b24-8272c554be40_bz": "详细说明", + "gridField_c2297d15-9021-4a7c-b8bf-fe4ce44fd25b_cwtzje": "财务调整金额", + "gridField_ef6b2547-b3bc-4885-9f2f-7ad8b7daa923_cwtzyy": "财务调整原因", + "gridField_619fd9ba-a0f2-4577-ad26-589e479e6f0b_skfhm_skfhm_name": "银行账号名称", + "gridField_39d0f0d8-fa39-475a-9ef0-1743a3692655_fkhb": "付款货币", + "gridField_fc8c0fe2-60be-4ddf-b76f-6cc119246ec6_fkje": "付款金额", + "gridField_47bb1f77-4ca0-4d98-aa9a-092d70dac2bb_fkfs": "付款方式", + "gridField_83673651-4c82-4f9f-a83d-6c6383e46eb1_yhfl": "银行分类", + "gridField_aabf51f9-d4d9-450a-bdc0-63756cfa1cdc_skzh": "收款账号", + "gridField_5a962507-c861-4819-8c62-9f8b54d40724_khh": "开户行", + "gridField_d0111e70-abe4-4361-89ed-228f71153ef6_spR_SPR_Name": "审批人", + "gridField_e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6_spsj": "审批时间", + "gridField_946380b5-3734-4173-95fd-b3b53731c37c_spyj": "审批意见" + }, + "zh-CHS": {}, + "en": {} + }, + "projectName": "bo-demojroclffront1", + "templateId": "card-template", + "schemas": [ + { + "id": "c0ad1cd5-0bd1-48d9-950f-f541376ade9f", + "code": "bxD003", + "name": "同步测试-三级-私有", + "sourceUri": "api/demojsales/demojmarket/v1.0/bxd003/72e9c946-e90d-4187-bbaf-4e9369a38cb1/339e2fc2-8d44-4820-b0f7-de945cd8a4e6", + "sourceType": "vo", + "entities": [ + { + "id": "131065f4-51dd-48fb-b823-64748f126d98", + "code": "roCLDJ", + "name": "J版差旅费表头", + "label": "roCLDJs", + "type": { + "name": "roCLDJ", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "ffa12d66-ad95-48e8-8915-e467ca2a59de", + "originalId": "ffa12d66-ad95-48e8-8915-e467ca2a59de", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "e2e5373e-90d3-45b9-b46e-bbd402cf1066", + "originalId": "e2e5373e-90d3-45b9-b46e-bbd402cf1066", + "code": "Version", + "name": "Version", + "label": "version", + "bindingField": "version", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "Version", + "bindingPath": "version", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "818f2272-f372-4afa-8c71-6328c0fc00b4", + "originalId": "818f2272-f372-4afa-8c71-6328c0fc00b4", + "code": "DJBH", + "name": "报销单编号", + "label": "djbh", + "bindingField": "djbh", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 80 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DJBH", + "bindingPath": "djbh", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "458dc0b4-fff0-4868-8e34-be3df68ab55e", + "originalId": "458dc0b4-fff0-4868-8e34-be3df68ab55e", + "code": "TBSJ", + "name": "填报时间", + "label": "tbsj", + "bindingField": "tbsj", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期/时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "TBSJ", + "bindingPath": "tbsj", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "4f223a80-d7a9-4ba6-9bc1-3fbb35f140a6", + "originalId": "4f223a80-d7a9-4ba6-9bc1-3fbb35f140a6", + "code": "BXRY", + "name": "报销人员", + "label": "bxry", + "bindingField": "bxry", + "type": { + "$type": "EntityType", + "name": "DemoJPerson4a17", + "primary": "bxry", + "fields": [ + { + "$type": "SimpleField", + "id": "4a175623-7371-42d9-864f-9e03c38793cd", + "originalId": "4a175623-7371-42d9-864f-9e03c38793cd", + "code": "BXRY", + "name": "报销人员", + "label": "bxry", + "bindingField": "bxry", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BXRY", + "bindingPath": "bxry", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c8f93ae2-3ba6-4378-ab86-0743b576845a", + "originalId": "c8f93ae2-3ba6-4378-ab86-0743b576845a", + "code": "ID", + "name": "ID", + "label": "bxrY_ID", + "bindingField": "bxrY_BXRY_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BXRY.BXRY_ID", + "bindingPath": "bxry.bxrY_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1cac6aa7-01f1-4440-b7bf-64ac81d8af61", + "originalId": "1cac6aa7-01f1-4440-b7bf-64ac81d8af61", + "code": "Code", + "name": "编号", + "label": "bxrY_Code", + "bindingField": "bxrY_BXRY_Code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BXRY.BXRY_Code", + "bindingPath": "bxry.bxrY_Code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d17cd77e-7c0a-42cb-9a09-687b5677f7ac", + "originalId": "d17cd77e-7c0a-42cb-9a09-687b5677f7ac", + "code": "Name", + "name": "名称", + "label": "bxrY_Name", + "bindingField": "bxrY_BXRY_Name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BXRY.BXRY_Name", + "bindingPath": "bxry.bxrY_Name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "DemoJPerson" + }, + "path": "BXRY", + "bindingPath": "bxry" + }, + { + "$type": "SimpleField", + "id": "b94def87-1de5-45ea-8ddd-291224f1e5e1", + "originalId": "b94def87-1de5-45ea-8ddd-291224f1e5e1", + "code": "ZY", + "name": "报账说明", + "label": "zy", + "bindingField": "zy", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ZY", + "bindingPath": "zy", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6ae80bb6-8083-44d7-8897-256d5c677773", + "originalId": "6ae80bb6-8083-44d7-8897-256d5c677773", + "code": "ZDR", + "name": "制单人", + "label": "zdr", + "bindingField": "zdr", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ZDR", + "bindingPath": "zdr", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "b020b1e1-5dcd-4a44-a1c8-50fcba92f278", + "originalId": "b020b1e1-5dcd-4a44-a1c8-50fcba92f278", + "code": "STATE", + "name": "状态", + "label": "state", + "bindingField": "state", + "type": { + "$type": "ObjectType", + "name": "BillStateB020", + "fields": [ + { + "$type": "SimpleField", + "id": "b020b1e1-0101-468f-ae3f-40c76c0f06b0", + "originalId": "a0b19650-0101-468f-ae3f-40c76c0f06b0", + "code": "BillState", + "name": "状态", + "label": "billState", + "bindingField": "statE_BillState", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "Billing", + "name": "制单" + }, + { + "value": "SubmitApproval", + "name": "提交审批" + }, + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "ApprovalNotPassed", + "name": "审批不通过" + }, + { + "value": "Abort", + "name": "流程终止" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "STATE.BillState", + "bindingPath": "state.billState", + "multiLanguage": false + } + ], + "displayName": "状态" + }, + "path": "STATE", + "bindingPath": "state" + }, + { + "$type": "SimpleField", + "id": "e3e99d10-9543-4bd1-82e4-533caf21668a", + "originalId": "e3e99d10-9543-4bd1-82e4-533caf21668a", + "code": "BXJE", + "name": "报销金额", + "label": "bxje", + "bindingField": "bxje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BXJE", + "bindingPath": "bxje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "cdb96871-0307-4659-8aa9-2f1921b6b103", + "originalId": "cdb96871-0307-4659-8aa9-2f1921b6b103", + "code": "BHSJE", + "name": "不含税金额", + "label": "bhsje", + "bindingField": "bhsje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BHSJE", + "bindingPath": "bhsje", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "8862cc4a-8c87-4b7f-872c-99777cc59b72", + "originalId": "8862cc4a-8c87-4b7f-872c-99777cc59b72", + "code": "DWBH", + "name": "单位编号", + "label": "dwbh", + "bindingField": "dwbh", + "type": { + "$type": "EntityType", + "name": "DemoJmarke079d", + "primary": "dwbh", + "fields": [ + { + "$type": "SimpleField", + "id": "079d69f9-174d-428d-a3e7-eaf72a6d655b", + "originalId": "079d69f9-174d-428d-a3e7-eaf72a6d655b", + "code": "DWBH", + "name": "单位编号", + "label": "dwbh", + "bindingField": "dwbh", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DWBH", + "bindingPath": "dwbh", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "b566058e-dba3-4d4d-b1bd-3bea8adbf321", + "originalId": "b566058e-dba3-4d4d-b1bd-3bea8adbf321", + "code": "ID", + "name": "ID", + "label": "dwbH_ID", + "bindingField": "dwbH_DWBH_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DWBH.DWBH_ID", + "bindingPath": "dwbh.dwbH_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "31a7e4eb-ebb4-4a5f-a4e5-6e83a58da966", + "originalId": "31a7e4eb-ebb4-4a5f-a4e5-6e83a58da966", + "code": "OrgCode", + "name": "组织编号", + "label": "dwbH_OrgCode", + "bindingField": "dwbH_DWBH_OrgCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 30 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DWBH.DWBH_OrgCode", + "bindingPath": "dwbh.dwbH_OrgCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "616b9a60-2a0d-4953-8875-606906def113", + "originalId": "616b9a60-2a0d-4953-8875-606906def113", + "code": "OrgName", + "name": "名称", + "label": "dwbH_OrgName", + "bindingField": "dwbH_DWBH_OrgName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 60 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DWBH.DWBH_OrgName", + "bindingPath": "dwbh.dwbH_OrgName", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "DemoJmarke" + }, + "path": "DWBH", + "bindingPath": "dwbh" + }, + { + "$type": "SimpleField", + "id": "0d01d25b-d4fa-42ba-a628-b9bce6cc4e7d", + "originalId": "0d01d25b-d4fa-42ba-a628-b9bce6cc4e7d", + "code": "BZ1", + "name": "备用1", + "label": "bZ1", + "bindingField": "bZ1", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BZ1", + "bindingPath": "bZ1", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9c2134b8-122e-4ca3-96bb-ab665d7f93d0", + "originalId": "9c2134b8-122e-4ca3-96bb-ab665d7f93d0", + "code": "BZ2", + "name": "备用2", + "label": "bZ2", + "bindingField": "bZ2", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BZ2", + "bindingPath": "bZ2", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f9577ac7-1820-49f6-bd24-61e0b75f72f8", + "originalId": "f9577ac7-1820-49f6-bd24-61e0b75f72f8", + "code": "BZ3", + "name": "备用3", + "label": "bZ3", + "bindingField": "bZ3", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期/时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "BZ3", + "bindingPath": "bZ3", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1fce9f14-a607-48a6-a59f-3389edbe7c38", + "originalId": "1fce9f14-a607-48a6-a59f-3389edbe7c38", + "code": "BZ4", + "name": "备用4", + "label": "bZ4", + "bindingField": "bZ4", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ4", + "bindingPath": "bZ4", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "ca768b04-4a98-43cf-b58c-f336e2371994", + "originalId": "ca768b04-4a98-43cf-b58c-f336e2371994", + "code": "BZ5", + "name": "备用5", + "label": "bZ5", + "bindingField": "bZ5", + "type": { + "$type": "EntityType", + "name": "JDttype1304", + "primary": "bZ5", + "fields": [ + { + "$type": "SimpleField", + "id": "13046dcf-2ac1-447d-9eb3-ab9c0c4aae42", + "originalId": "13046dcf-2ac1-447d-9eb3-ab9c0c4aae42", + "code": "BZ5", + "name": "备用5", + "label": "bZ5", + "bindingField": "bZ5", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ5", + "bindingPath": "bZ5", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "5dfe033c-c942-45ca-a935-83fa11eb2019", + "originalId": "5dfe033c-c942-45ca-a935-83fa11eb2019", + "code": "ID", + "name": "ID", + "label": "bZ5_ID", + "bindingField": "bZ5_BZ5_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ5.BZ5_ID", + "bindingPath": "bZ5.bZ5_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "180f1a2e-e7c9-43c1-b297-052735bffdee", + "originalId": "180f1a2e-e7c9-43c1-b297-052735bffdee", + "code": "name", + "name": "单据类型名称", + "label": "bZ5_name", + "bindingField": "bZ5_BZ5_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ5.BZ5_name", + "bindingPath": "bZ5.bZ5_name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "J版报销单类型" + }, + "path": "BZ5", + "bindingPath": "bZ5" + }, + { + "$type": "SimpleField", + "id": "3dce8efa-593e-448b-8a08-37ad041d6c2d", + "originalId": "3dce8efa-593e-448b-8a08-37ad041d6c2d", + "code": "BZ6", + "name": "备用6", + "label": "bZ6", + "bindingField": "bZ6", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ6", + "bindingPath": "bZ6", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "a0b42ee4-c9e6-4a54-9c2f-c3b9a08f9945", + "originalId": "a0b42ee4-c9e6-4a54-9c2f-c3b9a08f9945", + "code": "lcslid", + "name": "流程实例id", + "label": "lcslid", + "bindingField": "lcslid", + "type": { + "$type": "ObjectType", + "name": "ProcessInstanceA0b4", + "fields": [ + { + "$type": "SimpleField", + "id": "a0b42ee4-ad8f-4da3-a430-c8a7f2162135", + "originalId": "2e1beb7d-ad8f-4da3-a430-c8a7f2162135", + "code": "ProcessInstance", + "name": "流程实例", + "label": "processInstance", + "bindingField": "lcslid_ProcessInstance", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "lcslid.ProcessInstance", + "bindingPath": "lcslid.processInstance", + "multiLanguage": false + } + ], + "displayName": "流程实例" + }, + "path": "lcslid", + "bindingPath": "lcslid" + }, + { + "$type": "ComplexField", + "id": "cadc1e08-dfb2-4a6a-b40f-c7ead6103f2c", + "originalId": "cadc1e08-dfb2-4a6a-b40f-c7ead6103f2c", + "code": "BZ8", + "name": "UDT嵌套", + "label": "bZ8", + "bindingField": "bZ8", + "type": { + "$type": "ObjectType", + "name": "JDemoUDT02CadC", + "fields": [ + { + "$type": "ComplexField", + "id": "cadc1e08-ac99-48a7-a1e5-8311d9572996", + "originalId": "27222fcf-ac99-48a7-a1e5-8311d9572996", + "code": "JDemoUDT02", + "name": "J版单值UDT关联", + "label": "jDemoUDT02", + "bindingField": "bZ8_JDemoUDT02", + "type": { + "$type": "EntityType", + "name": "JKHHXXCadC", + "primary": "jDemoUDT02", + "fields": [ + { + "$type": "SimpleField", + "id": "cadc1e08-2a4b-49ae-99f6-1e76b2fc0a48", + "originalId": "3dbf0c12-2a4b-49ae-99f6-1e76b2fc0a48", + "code": "JDemoUDT02", + "name": "J版单值UDT关联", + "label": "jDemoUDT02", + "bindingField": "bZ8_JDemoUDT02", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ8.JDemoUDT02", + "bindingPath": "bZ8.jDemoUDT02", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "cadc1e08-7684-45e9-90cf-0b01e7a03957", + "originalId": "c948a4fd-7684-45e9-90cf-0b01e7a03957", + "code": "name", + "name": "单据类型名称", + "label": "jDemoUDT02_LHHUDT_JDemoUDT3_name", + "bindingField": "bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ8.JDemoUDT02.JDemoUDT02_LHHUDT_JDemoUDT3_name", + "bindingPath": "bZ8.jDemoUDT02.jDemoUDT02_LHHUDT_JDemoUDT3_name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "J版开户行信息" + }, + "path": "BZ8.JDemoUDT02", + "bindingPath": "bZ8.jDemoUDT02" + } + ], + "displayName": "J版单值UDT关联" + }, + "path": "BZ8", + "bindingPath": "bZ8" + }, + { + "$type": "ComplexField", + "id": "d9ee0e39-12e2-4512-95f0-2028f9be89d8", + "originalId": "d9ee0e39-12e2-4512-95f0-2028f9be89d8", + "code": "BZ7", + "name": "UDT字段测试", + "label": "bZ7", + "bindingField": "bZ7", + "type": { + "$type": "ObjectType", + "name": "JDemoUDT01D9ee", + "fields": [ + { + "$type": "SimpleField", + "id": "d9ee0e39-771f-4be9-b0aa-98156e62b2e0", + "originalId": "433ec470-771f-4be9-b0aa-98156e62b2e0", + "code": "code", + "name": "人员编号", + "label": "code", + "bindingField": "bZ7_code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ7.code", + "bindingPath": "bZ7.code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-7ade-4cc2-8579-0a419b53fd1e", + "originalId": "ee68d29c-7ade-4cc2-8579-0a419b53fd1e", + "code": "name", + "name": "人员名称", + "label": "name", + "bindingField": "bZ7_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ7.name", + "bindingPath": "bZ7.name", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-bce5-4e64-a9e3-739795c64027", + "originalId": "585ec3c5-bce5-4e64-a9e3-739795c64027", + "code": "email", + "name": "邮箱", + "label": "email", + "bindingField": "bZ7_email", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ7.email", + "bindingPath": "bZ7.email", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-73f4-4cdd-b24b-e73c1e7b85ea", + "originalId": "ff2d0b14-73f4-4cdd-b24b-e73c1e7b85ea", + "code": "phone", + "name": "手机号", + "label": "phone", + "bindingField": "bZ7_phone", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BZ7.phone", + "bindingPath": "bZ7.phone", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-c087-4cbc-8e0a-7ba031d9b9c7", + "originalId": "b236ce6d-c087-4cbc-8e0a-7ba031d9b9c7", + "code": "cratetime", + "name": "计划付款时间", + "label": "cratetime", + "bindingField": "bZ7_cratetime", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "BZ7.cratetime", + "bindingPath": "bZ7.cratetime", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-d5ae-46e2-8632-f5073868baa1", + "originalId": "5b4a44d5-d5ae-46e2-8632-f5073868baa1", + "code": "endtime", + "name": "实际付款日期", + "label": "endtime", + "bindingField": "bZ7_endtime", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期/时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "BZ7.endtime", + "bindingPath": "bZ7.endtime", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-bb19-4e12-a42a-b457dd8b2287", + "originalId": "d4acc864-bb19-4e12-a42a-b457dd8b2287", + "code": "fdje", + "name": "浮动金额", + "label": "fdje", + "bindingField": "bZ7_fdje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 3 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BZ7.fdje", + "bindingPath": "bZ7.fdje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d9ee0e39-9baa-46e7-863c-aad9cc72f3c5", + "originalId": "2cde8813-9baa-46e7-863c-aad9cc72f3c5", + "code": "markudt", + "name": "付款备注信息", + "label": "markudt", + "bindingField": "bZ7_markudt", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "BZ7.markudt", + "bindingPath": "bZ7.markudt", + "multiLanguage": false + } + ], + "displayName": "JDemoUDT01" + }, + "path": "BZ7", + "bindingPath": "bZ7" + }, + { + "$type": "SimpleField", + "id": "f972ab8c-c68f-4bf3-b39b-4b5386ce861c", + "originalId": "f972ab8c-c68f-4bf3-b39b-4b5386ce861c", + "code": "BZ9", + "name": "备注9", + "label": "bZ9", + "bindingField": "bZ9", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BZ9", + "bindingPath": "bZ9", + "multiLanguage": false + }, + { + "id": "ac71778f-eea0-4f15-9d11-4bb75fdb8586", + "originalId": "ac71778f-eea0-4f15-9d11-4bb75fdb8586", + "code": "code01", + "name": "扩展文本01", + "label": "ext_code01_Lv9", + "bindingField": "ext_code01_Lv9", + "bindingPath": "ext_code01_Lv9", + "path": "ext_code01_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "c342d6e5-5932-40e6-9ac3-35319b3ef0c0", + "originalId": "c342d6e5-5932-40e6-9ac3-35319b3ef0c0", + "code": "code02", + "name": "扩展备注02", + "label": "ext_code02_Lv9", + "bindingField": "ext_code02_Lv9", + "bindingPath": "ext_code02_Lv9", + "path": "ext_code02_Lv9", + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "6b04013d-9232-4f7a-9913-38767c32f25c", + "originalId": "6b04013d-9232-4f7a-9913-38767c32f25c", + "code": "code03", + "name": "扩展整数03", + "label": "ext_code03_Lv9", + "bindingField": "ext_code03_Lv9", + "bindingPath": "ext_code03_Lv9", + "path": "ext_code03_Lv9", + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0, + "elementType": "Integer" + }, + "editor": { + "$type": "NumericBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "bb0c83bc-3bce-415a-87ea-c4d4ef93d81e", + "originalId": "bb0c83bc-3bce-415a-87ea-c4d4ef93d81e", + "code": "code04", + "name": "扩展浮点04", + "label": "ext_code04_Lv9", + "bindingField": "ext_code04_Lv9", + "bindingPath": "ext_code04_Lv9", + "path": "ext_code04_Lv9", + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2, + "elementType": "Decimal" + }, + "editor": { + "$type": "NumericBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "945c039c-2156-4bdb-bf3f-fe1675b3b031", + "originalId": "945c039c-2156-4bdb-bf3f-fe1675b3b031", + "code": "code201", + "name": "二级文本01", + "label": "ext_code201_Lv9", + "bindingField": "ext_code201_Lv9", + "bindingPath": "ext_code201_Lv9", + "path": "ext_code201_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "6bad8059-f969-47e1-ad8f-210af8936ede", + "originalId": "6bad8059-f969-47e1-ad8f-210af8936ede", + "code": "code202", + "name": "二级文本02", + "label": "ext_code202_Lv9", + "bindingField": "ext_code202_Lv9", + "bindingPath": "ext_code202_Lv9", + "path": "ext_code202_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "1bef012d-9b72-4a15-af6e-06bd30218992", + "originalId": "1bef012d-9b72-4a15-af6e-06bd30218992", + "code": "code203", + "name": "二级文本03", + "label": "ext_code203_Lv9", + "bindingField": "ext_code203_Lv9", + "bindingPath": "ext_code203_Lv9", + "path": "ext_code203_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "cfaccd90-77ac-4ea1-b18c-1420716fa92e", + "originalId": "cfaccd90-77ac-4ea1-b18c-1420716fa92e", + "code": "code05", + "name": "扩展帮助05", + "label": "ext_code05_Lv9", + "bindingField": "ext_code05_Lv9", + "bindingPath": "ext_code05_Lv9", + "path": "ext_code05_Lv9", + "$type": "ComplexField", + "type": { + "$type": "EntityType", + "name": "JROPersonBTBZ29ea", + "primary": "ext_code05_Lv9", + "fields": [ + { + "id": "29ea6d2e-4285-4418-857b-ad241846120d", + "originalId": "29ea6d2e-4285-4418-857b-ad241846120d", + "code": "code05", + "name": "扩展帮助05", + "label": "ext_code05_Lv9", + "bindingField": "ext_code05_Lv9", + "bindingPath": "ext_code05_Lv9", + "path": "ext_code05_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "$type": "SimpleField", + "id": "cff02548-b67d-4491-9294-314343a91bb4", + "originalId": "7e02c43a-1c6d-4e28-8ca3-dd72a519ecaa", + "code": "lbcode", + "name": "种类编号", + "label": "ext_code05_Lv9_lbcode", + "bindingField": "ext_code05_Lv9_ext_code05_Lv9_lbcode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ext_code05_Lv9.ext_code05_Lv9_lbcode", + "bindingPath": "ext_code05_Lv9.ext_code05_Lv9_lbcode" + }, + { + "$type": "SimpleField", + "id": "bd222971-43f8-4b94-9d6d-90aea913a9de", + "originalId": "4ab93af7-1078-4d0c-8aa7-2582340646c3", + "code": "lcname", + "name": "种类名称", + "label": "ext_code05_Lv9_lcname", + "bindingField": "ext_code05_Lv9_ext_code05_Lv9_lcname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLDJ.ext_code05_Lv9_ext_code05_Lv9_lcname", + "displayName": "J版人员类别帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "lcname", + "valueField": "lbcode", + "displayType": "List", + "helpId": "44abb8c8-193a-4773-984d-b8cb8c7a8691", + "mapFields": "{\"lbcode\":\"ext_code05_Lv9.ext_code05_Lv9_lbcode\",\"lcname\":\"ext_code05_Lv9.ext_code05_Lv9_lcname\",\"id\":\"ext_code05_Lv9.ext_code05_Lv9\"}", + "conditions": [] + }, + "path": "ext_code05_Lv9.ext_code05_Lv9_lcname", + "bindingPath": "ext_code05_Lv9.ext_code05_Lv9_lcname" + } + ], + "entities": [], + "displayName": "JROPersonBTBZ", + "extendProperty": { + "beId": "1b4da331-1122-4528-a6fd-ba355b1aabef", + "voId": "ffff2f57-914c-4400-bfca-ce3f41d50e64" + } + } + }, + { + "id": "7d37a0c5-6898-4e0e-b5ea-47dd39271735", + "originalId": "7d37a0c5-6898-4e0e-b5ea-47dd39271735", + "code": "code06", + "name": "扩展整数枚举06", + "label": "ext_code06_Lv9", + "bindingField": "ext_code06_Lv9", + "bindingPath": "ext_code06_Lv9", + "path": "ext_code06_Lv9", + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0, + "elementType": "Integer" + }, + "enumValues": [ + { + "value": "1", + "name": "VIP" + }, + { + "value": "2", + "name": "普通" + }, + { + "value": "3", + "name": "黑名单" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "e4b6e2d9-4f1b-41a1-aa90-7e490afb6c2d", + "originalId": "e4b6e2d9-4f1b-41a1-aa90-7e490afb6c2d", + "code": "code301", + "name": "三级文本01", + "label": "ext_code301_Lv9", + "bindingField": "ext_code301_Lv9", + "bindingPath": "ext_code301_Lv9", + "path": "ext_code301_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + } + ], + "entities": [ + { + "id": "29d057f6-b919-4e72-ae34-1f4d24611e49", + "code": "roCLMX", + "name": "差旅明细", + "label": "roCLMXs", + "type": { + "name": "roCLMX", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "ec52ea25-013e-45c8-9931-323503605a72", + "originalId": "ec52ea25-013e-45c8-9931-323503605a72", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9fbcf854-b734-4164-a9ef-8e2b11d511af", + "originalId": "9fbcf854-b734-4164-a9ef-8e2b11d511af", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "eaa63a95-11b0-4dae-a973-a7cfbf221d09", + "originalId": "eaa63a95-11b0-4dae-a973-a7cfbf221d09", + "code": "CFCS", + "name": "出发城市", + "label": "cfcs", + "bindingField": "cfcs", + "type": { + "$type": "EntityType", + "name": "DemoJmarke35e9", + "primary": "cfcs", + "fields": [ + { + "$type": "SimpleField", + "id": "35e91e09-cbc7-408e-bf4a-82a39c10d289", + "originalId": "35e91e09-cbc7-408e-bf4a-82a39c10d289", + "code": "CFCS", + "name": "出发城市", + "label": "cfcs", + "bindingField": "cfcs", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CFCS", + "bindingPath": "cfcs", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f1cce7e7-9b50-49dd-b74b-ccea4a76adf8", + "originalId": "f1cce7e7-9b50-49dd-b74b-ccea4a76adf8", + "code": "ID", + "name": "ID", + "label": "cfcS_ID", + "bindingField": "cfcS_CFCS_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CFCS.CFCS_ID", + "bindingPath": "cfcs.cfcS_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "b3a104db-527f-4532-9ec9-1466d6d99c74", + "originalId": "b3a104db-527f-4532-9ec9-1466d6d99c74", + "code": "OrgCode", + "name": "组织编号", + "label": "cfcS_OrgCode", + "bindingField": "cfcS_CFCS_OrgCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 30 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CFCS.CFCS_OrgCode", + "bindingPath": "cfcs.cfcS_OrgCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "092ee414-9b6f-43f8-9639-311432dc5a1b", + "originalId": "092ee414-9b6f-43f8-9639-311432dc5a1b", + "code": "OrgName", + "name": "名称", + "label": "cfcS_OrgName", + "bindingField": "cfcS_CFCS_OrgName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 60 + }, + "editor": { + "$type": "TextBox" + }, + "path": "CFCS.CFCS_OrgName", + "bindingPath": "cfcs.cfcS_OrgName", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "DemoJmarke" + }, + "path": "CFCS", + "bindingPath": "cfcs" + }, + { + "$type": "SimpleField", + "id": "574554dc-9605-4a77-9bf6-ca8e95395c69", + "originalId": "574554dc-9605-4a77-9bf6-ca8e95395c69", + "code": "CFSJ", + "name": "出发时间", + "label": "cfsj", + "bindingField": "cfsj", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "CFSJ", + "bindingPath": "cfsj", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "4e7d55f3-9064-461f-b767-b7570384e05b", + "originalId": "4e7d55f3-9064-461f-b767-b7570384e05b", + "code": "DDCS", + "name": "到达城市", + "label": "ddcs", + "bindingField": "ddcs", + "type": { + "$type": "EntityType", + "name": "DemoJmarke6d96", + "primary": "ddcs", + "fields": [ + { + "$type": "SimpleField", + "id": "6d968522-5058-4447-bae9-43d17df9c816", + "originalId": "6d968522-5058-4447-bae9-43d17df9c816", + "code": "DDCS", + "name": "到达城市", + "label": "ddcs", + "bindingField": "ddcs", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DDCS", + "bindingPath": "ddcs", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "a20ea351-4704-4611-a10c-a4e28ffecfa2", + "originalId": "a20ea351-4704-4611-a10c-a4e28ffecfa2", + "code": "ID", + "name": "ID", + "label": "ddcS_ID", + "bindingField": "ddcS_DDCS_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DDCS.DDCS_ID", + "bindingPath": "ddcs.ddcS_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "a509e794-a928-4a33-8447-19567d2dba6c", + "originalId": "a509e794-a928-4a33-8447-19567d2dba6c", + "code": "OrgCode", + "name": "组织编号", + "label": "ddcS_OrgCode", + "bindingField": "ddcS_DDCS_OrgCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 30 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DDCS.DDCS_OrgCode", + "bindingPath": "ddcs.ddcS_OrgCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6dbbe9c2-5a68-4d13-810d-160a04a7a463", + "originalId": "6dbbe9c2-5a68-4d13-810d-160a04a7a463", + "code": "OrgName", + "name": "名称", + "label": "ddcS_OrgName", + "bindingField": "ddcS_DDCS_OrgName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 60 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DDCS.DDCS_OrgName", + "bindingPath": "ddcs.ddcS_OrgName", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "DemoJmarke" + }, + "path": "DDCS", + "bindingPath": "ddcs" + }, + { + "$type": "SimpleField", + "id": "91d71207-5a50-4442-90fa-a7140731b50c", + "originalId": "91d71207-5a50-4442-90fa-a7140731b50c", + "code": "DDSJ", + "name": "到达时间", + "label": "ddsj", + "bindingField": "ddsj", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "DDSJ", + "bindingPath": "ddsj", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "575ed208-6ed0-4179-85b7-89824e7eccae", + "originalId": "575ed208-6ed0-4179-85b7-89824e7eccae", + "code": "transportation", + "name": "交通工具", + "label": "transportation", + "bindingField": "transportation", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "Car", + "name": "汽车" + }, + { + "value": "trains", + "name": "火车" + }, + { + "value": "airplane", + "name": "飞机" + }, + { + "value": "others", + "name": "其他" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "transportation", + "bindingPath": "transportation", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1e00ede8-d335-436d-bba0-fd0cea39234b", + "originalId": "1e00ede8-d335-436d-bba0-fd0cea39234b", + "code": "Carnumber", + "name": "车次", + "label": "carnumber", + "bindingField": "carnumber", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Carnumber", + "bindingPath": "carnumber", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1f20fde2-4938-4fb3-9c9b-b446faaccc1f", + "originalId": "1f20fde2-4938-4fb3-9c9b-b446faaccc1f", + "code": "fjzs", + "name": "附件张数", + "label": "fjzs", + "bindingField": "fjzs", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "fjzs", + "bindingPath": "fjzs", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "3beb91d4-44ad-4189-90bb-d6fcdfda5559", + "originalId": "3beb91d4-44ad-4189-90bb-d6fcdfda5559", + "code": "jtgjf", + "name": "交通工具费", + "label": "jtgjf", + "bindingField": "jtgjf", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "jtgjf", + "bindingPath": "jtgjf", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "5ac85821-b1c8-466e-9fa6-cdb2a44117be", + "originalId": "5ac85821-b1c8-466e-9fa6-cdb2a44117be", + "code": "qtfy", + "name": "其他费用", + "label": "qtfy", + "bindingField": "qtfy", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "qtfy", + "bindingPath": "qtfy", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d591ed4a-e8db-4120-9c9b-70a4e2e64413", + "originalId": "d591ed4a-e8db-4120-9c9b-70a4e2e64413", + "code": "zsfje", + "name": "住宿费金额", + "label": "zsfje", + "bindingField": "zsfje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "zsfje", + "bindingPath": "zsfje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c", + "originalId": "da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c", + "code": "zsfzpse", + "name": "住宿费专票税额", + "label": "zsfzpse", + "bindingField": "zsfzpse", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "zsfzpse", + "bindingPath": "zsfzpse", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "df3ae210-5c7d-4f5a-9067-f584792834ee", + "originalId": "df3ae210-5c7d-4f5a-9067-f584792834ee", + "code": "ccts", + "name": "出差天数", + "label": "ccts", + "bindingField": "ccts", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 5, + "precision": 1 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "ccts", + "bindingPath": "ccts", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "595b5a9d-4103-4cc4-b6d4-9610d741c6a6", + "originalId": "595b5a9d-4103-4cc4-b6d4-9610d741c6a6", + "code": "bzbz", + "name": "补助标准", + "label": "bzbz", + "bindingField": "bzbz", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "bzbz", + "bindingPath": "bzbz", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "a734eba7-eb12-4b4b-967b-5aaad25bfbd9", + "originalId": "a734eba7-eb12-4b4b-967b-5aaad25bfbd9", + "code": "mxbxje", + "name": "报销金额", + "label": "mxbxje", + "bindingField": "mxbxje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "mxbxje", + "bindingPath": "mxbxje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "a5129114-0bca-4664-8b24-8272c554be40", + "originalId": "a5129114-0bca-4664-8b24-8272c554be40", + "code": "bz", + "name": "详细说明", + "label": "bz", + "bindingField": "bz", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "bz", + "bindingPath": "bz", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c2297d15-9021-4a7c-b8bf-fe4ce44fd25b", + "originalId": "c2297d15-9021-4a7c-b8bf-fe4ce44fd25b", + "code": "cwtzje", + "name": "财务调整金额", + "label": "cwtzje", + "bindingField": "cwtzje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "cwtzje", + "bindingPath": "cwtzje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "ef6b2547-b3bc-4885-9f2f-7ad8b7daa923", + "originalId": "ef6b2547-b3bc-4885-9f2f-7ad8b7daa923", + "code": "cwtzyy", + "name": "财务调整原因", + "label": "cwtzyy", + "bindingField": "cwtzyy", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "cwtzyy", + "bindingPath": "cwtzyy", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "差旅明细" + } + }, + { + "id": "fc0ce2ff-4694-4f76-ad73-bddbb4e67025", + "code": "roFKMX", + "name": "付款明细", + "label": "roFKMXs", + "type": { + "name": "roFKMX", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "c5e2f440-e6e9-4707-8c3c-c25587b54104", + "originalId": "c5e2f440-e6e9-4707-8c3c-c25587b54104", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "190bc3e8-8047-44c6-b00e-c3a30b2e672a", + "originalId": "190bc3e8-8047-44c6-b00e-c3a30b2e672a", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "86ddcd37-f83d-4512-85d0-6b45b6f15394", + "originalId": "86ddcd37-f83d-4512-85d0-6b45b6f15394", + "code": "skfhm", + "name": "收款方户名", + "label": "skfhm", + "bindingField": "skfhm", + "type": { + "$type": "EntityType", + "name": "JKHHXX327c", + "primary": "skfhm", + "fields": [ + { + "$type": "SimpleField", + "id": "327cdfe2-a6b2-4795-9523-054eb2596dd1", + "originalId": "327cdfe2-a6b2-4795-9523-054eb2596dd1", + "code": "skfhm", + "name": "收款方户名", + "label": "skfhm", + "bindingField": "skfhm", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "skfhm", + "bindingPath": "skfhm", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6580c058-2635-48c6-9bef-a268c9efeee8", + "originalId": "6580c058-2635-48c6-9bef-a268c9efeee8", + "code": "name", + "name": "银行账号名称", + "label": "skfhm_name", + "bindingField": "skfhm_skfhm_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 500 + }, + "editor": { + "$type": "TextBox" + }, + "path": "skfhm.skfhm_name", + "bindingPath": "skfhm.skfhm_name", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "5cd116a6-5562-4080-90c1-49d2ce3021e3", + "originalId": "5cd116a6-5562-4080-90c1-49d2ce3021e3", + "code": "country", + "name": "省分", + "label": "skfhm_inbank_country", + "bindingField": "skfhm_skfhm_inbank_country", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "skfhm.skfhm_inbank_country", + "bindingPath": "skfhm.skfhm_inbank_country", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f28b73f0-0a30-49bc-a553-7bac5a19a92c", + "originalId": "f28b73f0-0a30-49bc-a553-7bac5a19a92c", + "code": "city", + "name": "地区", + "label": "skfhm_inbank_city", + "bindingField": "skfhm_skfhm_inbank_city", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "skfhm.skfhm_inbank_city", + "bindingPath": "skfhm.skfhm_inbank_city", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "J版开户行信息" + }, + "path": "skfhm", + "bindingPath": "skfhm" + }, + { + "$type": "SimpleField", + "id": "39d0f0d8-fa39-475a-9ef0-1743a3692655", + "originalId": "39d0f0d8-fa39-475a-9ef0-1743a3692655", + "code": "fkhb", + "name": "付款货币", + "label": "fkhb", + "bindingField": "fkhb", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1 + }, + "enumValues": [ + { + "value": "RMB", + "name": "人民币" + }, + { + "value": "US", + "name": "美元" + }, + { + "value": "AU", + "name": "澳元" + }, + { + "value": "OT", + "name": "其他" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "fkhb", + "bindingPath": "fkhb", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "fc8c0fe2-60be-4ddf-b76f-6cc119246ec6", + "originalId": "fc8c0fe2-60be-4ddf-b76f-6cc119246ec6", + "code": "fkje", + "name": "付款金额", + "label": "fkje", + "bindingField": "fkje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "fkje", + "bindingPath": "fkje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb", + "originalId": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb", + "code": "fkfs", + "name": "付款方式", + "label": "fkfs", + "bindingField": "fkfs", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1 + }, + "enumValues": [ + { + "value": "W", + "name": "网银" + }, + { + "value": "X", + "name": "现金" + }, + { + "value": "Z", + "name": "支票" + }, + { + "value": "O", + "name": "其他" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "fkfs", + "bindingPath": "fkfs", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "83673651-4c82-4f9f-a83d-6c6383e46eb1", + "originalId": "83673651-4c82-4f9f-a83d-6c6383e46eb1", + "code": "yhfl", + "name": "银行分类", + "label": "yhfl", + "bindingField": "yhfl", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "yhfl", + "bindingPath": "yhfl", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "aabf51f9-d4d9-450a-bdc0-63756cfa1cdc", + "originalId": "aabf51f9-d4d9-450a-bdc0-63756cfa1cdc", + "code": "skzh", + "name": "收款账号", + "label": "skzh", + "bindingField": "skzh", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "skzh", + "bindingPath": "skzh", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "5a962507-c861-4819-8c62-9f8b54d40724", + "originalId": "5a962507-c861-4819-8c62-9f8b54d40724", + "code": "khh", + "name": "开户行", + "label": "khh", + "bindingField": "khh", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "khh", + "bindingPath": "khh", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "58e4ab8a-e9d6-4afc-ba00-375bb10c2ac7", + "originalId": "58e4ab8a-e9d6-4afc-ba00-375bb10c2ac7", + "code": "lhh", + "name": "联行号", + "label": "lhh", + "bindingField": "lhh", + "type": { + "$type": "ObjectType", + "name": "JDemoUDT0158e4", + "fields": [ + { + "$type": "SimpleField", + "id": "58e4ab8a-771f-4be9-b0aa-98156e62b2e0", + "originalId": "433ec470-771f-4be9-b0aa-98156e62b2e0", + "code": "code", + "name": "人员编号", + "label": "code", + "bindingField": "lhh_code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "lhh.code", + "bindingPath": "lhh.code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-7ade-4cc2-8579-0a419b53fd1e", + "originalId": "ee68d29c-7ade-4cc2-8579-0a419b53fd1e", + "code": "name", + "name": "人员名称", + "label": "name", + "bindingField": "lhh_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 200 + }, + "editor": { + "$type": "TextBox" + }, + "path": "lhh.name", + "bindingPath": "lhh.name", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-bce5-4e64-a9e3-739795c64027", + "originalId": "585ec3c5-bce5-4e64-a9e3-739795c64027", + "code": "email", + "name": "邮箱", + "label": "email", + "bindingField": "lhh_email", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "lhh.email", + "bindingPath": "lhh.email", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-73f4-4cdd-b24b-e73c1e7b85ea", + "originalId": "ff2d0b14-73f4-4cdd-b24b-e73c1e7b85ea", + "code": "phone", + "name": "手机号", + "label": "phone", + "bindingField": "lhh_phone", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "lhh.phone", + "bindingPath": "lhh.phone", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-c087-4cbc-8e0a-7ba031d9b9c7", + "originalId": "b236ce6d-c087-4cbc-8e0a-7ba031d9b9c7", + "code": "cratetime", + "name": "计划付款时间", + "label": "cratetime", + "bindingField": "lhh_cratetime", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "lhh.cratetime", + "bindingPath": "lhh.cratetime", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-d5ae-46e2-8632-f5073868baa1", + "originalId": "5b4a44d5-d5ae-46e2-8632-f5073868baa1", + "code": "endtime", + "name": "实际付款日期", + "label": "endtime", + "bindingField": "lhh_endtime", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期/时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "lhh.endtime", + "bindingPath": "lhh.endtime", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-bb19-4e12-a42a-b457dd8b2287", + "originalId": "d4acc864-bb19-4e12-a42a-b457dd8b2287", + "code": "fdje", + "name": "浮动金额", + "label": "fdje", + "bindingField": "lhh_fdje", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 3 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "lhh.fdje", + "bindingPath": "lhh.fdje", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "58e4ab8a-9baa-46e7-863c-aad9cc72f3c5", + "originalId": "2cde8813-9baa-46e7-863c-aad9cc72f3c5", + "code": "markudt", + "name": "付款备注信息", + "label": "markudt", + "bindingField": "lhh_markudt", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "lhh.markudt", + "bindingPath": "lhh.markudt", + "multiLanguage": false + } + ], + "displayName": "JDemoUDT01" + }, + "path": "lhh", + "bindingPath": "lhh" + } + ], + "entities": [], + "displayName": "付款明细" + } + }, + { + "id": "59865ff5-b9d2-4c17-994a-b56e222c3d69", + "code": "roSPJL", + "name": "审批记录", + "label": "roSPJLs", + "type": { + "name": "roSPJL", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "98b8a9b8-8a09-428c-a6bc-c7f57a827f02", + "originalId": "98b8a9b8-8a09-428c-a6bc-c7f57a827f02", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "b3a9dee9-5a27-417a-b0d5-8c18b672b732", + "originalId": "b3a9dee9-5a27-417a-b0d5-8c18b672b732", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "faab32ab-5eb1-4ce7-8876-79f3d4598ceb", + "originalId": "faab32ab-5eb1-4ce7-8876-79f3d4598ceb", + "code": "SPR", + "name": "审批人", + "label": "spr", + "bindingField": "spr", + "type": { + "$type": "EntityType", + "name": "DemoJPersonC1fa", + "primary": "spr", + "fields": [ + { + "$type": "SimpleField", + "id": "c1fa4793-80d9-49e4-b9c4-8358504556a1", + "originalId": "c1fa4793-80d9-49e4-b9c4-8358504556a1", + "code": "SPR", + "name": "审批人", + "label": "spr", + "bindingField": "spr", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SPR", + "bindingPath": "spr", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9078b2c0-6c91-4f51-b4cb-dadaf4da6e99", + "originalId": "9078b2c0-6c91-4f51-b4cb-dadaf4da6e99", + "code": "ID", + "name": "ID", + "label": "spR_ID", + "bindingField": "spR_SPR_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SPR.SPR_ID", + "bindingPath": "spr.spR_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0a0585ac-38ae-4496-bbd3-fd3dcc280558", + "originalId": "0a0585ac-38ae-4496-bbd3-fd3dcc280558", + "code": "Code", + "name": "编号", + "label": "spR_Code", + "bindingField": "spR_SPR_Code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SPR.SPR_Code", + "bindingPath": "spr.spR_Code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d0111e70-abe4-4361-89ed-228f71153ef6", + "originalId": "d0111e70-abe4-4361-89ed-228f71153ef6", + "code": "Name", + "name": "名称", + "label": "spR_Name", + "bindingField": "spR_SPR_Name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SPR.SPR_Name", + "bindingPath": "spr.spR_Name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "DemoJPerson" + }, + "path": "SPR", + "bindingPath": "spr" + }, + { + "$type": "SimpleField", + "id": "e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6", + "originalId": "e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6", + "code": "spsj", + "name": "审批时间", + "label": "spsj", + "bindingField": "spsj", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "spsj", + "bindingPath": "spsj", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "946380b5-3734-4173-95fd-b3b53731c37c", + "originalId": "946380b5-3734-4173-95fd-b3b53731c37c", + "code": "spyj", + "name": "审批意见", + "label": "spyj", + "bindingField": "spyj", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "spyj", + "bindingPath": "spyj", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "0f417e87-0d95-4ef4-b60b-29067c4a2006", + "originalId": "0f417e87-0d95-4ef4-b60b-29067c4a2006", + "code": "bz1", + "name": "备注1", + "label": "bz1", + "bindingField": "bz1", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "bz1", + "bindingPath": "bz1", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "审批记录" + } + } + ], + "displayName": "J版差旅费表头" + } + } + ], + "variables": [], + "eapiId": "d964d109-7c1a-443f-9d20-d442a9bdf303" + } + ], + "stateMachines": [ + { + "id": "bxD003_state_machine", + "name": "同步测试-三级-私有状态机", + "uri": "24004b25-c5ea-4118-b59e-b83ad11aa318" + } + ], + "viewmodels": [ + { + "id": "root-viewmodel", + "code": "root-viewmodel", + "name": "J版差旅费表头", + "fields": [], + "stateMachine": "bxD003_state_machine", + "serviceRefs": [], + "commands": [ + { + "id": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "code": "Load1", + "name": "加载", + "params": [ + { + "name": "action", + "shownName": "初始动作", + "value": "{UISTATE~/root-component/action}", + "description": null + } + ], + "handlerName": "Load", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "code": "LoadAndAdd1", + "name": "加载并新增", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "LoadAndAdd", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "code": "LoadAndView1", + "name": "加载并查看", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "LoadAndView", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "code": "LoadAndEdit1", + "name": "加载并编辑", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "LoadAndEdit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f90aadfa-988c-4da5-a5db-1416c3333794", + "code": "Add1", + "name": "新增数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "Add", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "code": "Edit1", + "name": "编辑数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "Edit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "31b814db-01e4-407d-8fad-0f08dbb01999", + "code": "Save1", + "name": "保存数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Save", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "code": "Cancel1", + "name": "取消变更", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Cancel", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "code": "Close1", + "name": "关闭", + "params": [ + { + "name": "url", + "shownName": "上级Url", + "value": "", + "description": null + }, + { + "name": "params", + "shownName": "路由参数", + "value": "", + "description": null + } + ], + "handlerName": "Close", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c8504c24-33e8-487a-91ce-2218b803fe01", + "code": "ChangeItem1", + "name": "ChangeItem", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "prev", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "code": "ChangeItem2", + "name": "ChangeItem2", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "next", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4e9f36c0-bf8f-40cc-8b64-c5b2ddab44a9", + "code": "submitApproveWithState1", + "name": "提交审批(带状态)", + "params": [ + { + "name": "bizInstId", + "shownName": "业务单据ID", + "value": "{DATA~/basic-form-component/id}", + "description": null + }, + { + "name": "transitState", + "shownName": "状态迁移", + "value": "", + "description": null + } + ], + "handlerName": "submitApproveWithState", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "5860e99d-d975-4674-9140-b226596cf7b3", + "code": "cancelApproveWithState1", + "name": "取消提交审批(带状态)", + "params": [ + { + "name": "bizInstId", + "shownName": "业务单据ID", + "value": "{DATA~/basic-form-component/id}", + "description": null + }, + { + "name": "transitState", + "shownName": "状态迁移", + "value": "", + "description": null + } + ], + "handlerName": "cancelApproveWithState", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "46fa7d6a-40f3-4efc-be55-67550500e63f", + "code": "rootviewmodelyxs0011", + "name": "yxs0011", + "params": [ + { + "name": "a_rowData", + "shownName": "a_rowData", + "value": "夏老师你好", + "description": null + } + ], + "handlerName": "yxs001", + "cmpId": "8400adee-9863-4c48-9918-aa4c30421593", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "enableUnifiedSession": false, + "pagination": { + "enable": false + } + }, + { + "id": "basic-form-viewmodel", + "code": "basic-form-viewmodel", + "name": "J版差旅费表头", + "fields": [ + { + "type": "Form", + "id": "818f2272-f372-4afa-8c71-6328c0fc00b4", + "fieldName": "djbh", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "报销单私有A", + "require": false + } + }, + { + "type": "Form", + "id": "458dc0b4-fff0-4868-8e34-be3df68ab55e", + "fieldName": "tbsj", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "填报时间C" + } + }, + { + "type": "Form", + "id": "d17cd77e-7c0a-42cb-9a09-687b5677f7ac", + "fieldName": "bxrY_BXRY_Name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": null, + "updateOn": "blur", + "fieldSchema": { + "name": "报销人名称", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLDJ.bxrY_BXRY_Name", + "displayName": "J版人员帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "code", + "valueField": "name", + "displayType": "List", + "helpId": "76774958-8e91-406e-812c-981ba9ef2726", + "mapFields": "{'id':'bxry.bxry','name':'bxry.bxrY_Name','code':'bxry.bxrY_ID'}" + } + } + }, + { + "type": "Form", + "id": "b94def87-1de5-45ea-8ddd-291224f1e5e1", + "fieldName": "zy", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "require": true, + "name": "报账说明A" + } + }, + { + "type": "Form", + "id": "6ae80bb6-8083-44d7-8897-256d5c677773", + "fieldName": "zdr", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "e3e99d10-9543-4bd1-82e4-533caf21668a", + "fieldName": "bxje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "cdb96871-0307-4659-8aa9-2f1921b6b103", + "fieldName": "bhsje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "616b9a60-2a0d-4953-8875-606906def113", + "fieldName": "dwbH_DWBH_OrgName", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "单位名称", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLDJ.dwbH_DWBH_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgCode", + "valueField": "orgName", + "displayType": "TreeList", + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "mapFields": "{'id':'dwbh.dwbh','orgName':'dwbh.dwbH_OrgName','orgCode':'dwbh.dwbH_ID'}" + } + } + }, + { + "type": "Form", + "id": "d9ee0e39-73f4-4cdd-b24b-e73c1e7b85ea", + "fieldName": "bZ7_phone", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "d9ee0e39-c087-4cbc-8e0a-7ba031d9b9c7", + "fieldName": "bZ7_cratetime", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "cadc1e08-7684-45e9-90cf-0b01e7a03957", + "fieldName": "bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "UDT嵌套UDT", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLDJ.bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name", + "displayName": "J版银行账号信息01", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "helpId": "2dddc2bd-75e3-43df-ae99-e22beea01fba", + "mapFields": "{'id':'bZ8.jDemoUDT02.jDemoUDT02','lhhudt.jDemoUDT3.jDemoUDT3_name':'bZ8.jDemoUDT02.jDemoUDT02_LHHUDT_JDemoUDT3_name'}" + } + } + }, + { + "type": "Form", + "id": "180f1a2e-e7c9-43c1-b297-052735bffdee", + "fieldName": "bZ5_BZ5_name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLDJ.bZ5_BZ5_name", + "displayName": "J版单据类型帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "helpId": "67bb1e7a-74de-449d-a156-135c9246b38d", + "mapFields": "{'id':'bZ5.bZ5','name':'bZ5.bZ5_name'}" + } + } + }, + { + "type": "Form", + "id": "d9ee0e39-bb19-4e12-a42a-b457dd8b2287", + "fieldName": "bZ7_fdje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "ac71778f-eea0-4f15-9d11-4bb75fdb8586", + "fieldName": "ext_code01_Lv9", + "groupId": "ddf784df-4e63-4f08-b300-0cc08c213c06", + "groupName": "一级分组-01", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "c342d6e5-5932-40e6-9ac3-35319b3ef0c0", + "fieldName": "ext_code02_Lv9", + "groupId": "ddf784df-4e63-4f08-b300-0cc08c213c06", + "groupName": "一级分组-01", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "6b04013d-9232-4f7a-9913-38767c32f25c", + "fieldName": "ext_code03_Lv9", + "groupId": "ddf784df-4e63-4f08-b300-0cc08c213c06", + "groupName": "一级分组-01", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "bb0c83bc-3bce-415a-87ea-c4d4ef93d81e", + "fieldName": "ext_code04_Lv9", + "groupId": "6e981ca8-329c-405a-9f1c-04a9e98d5e5f", + "groupName": "二级分组-02", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "945c039c-2156-4bdb-bf3f-fe1675b3b031", + "fieldName": "ext_code201_Lv9", + "groupId": "01638918-2c32-4564-8819-11c21da6104f", + "groupName": "二级分组-01", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "6bad8059-f969-47e1-ad8f-210af8936ede", + "fieldName": "ext_code202_Lv9", + "groupId": "01638918-2c32-4564-8819-11c21da6104f", + "groupName": "二级分组-01", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "1bef012d-9b72-4a15-af6e-06bd30218992", + "fieldName": "ext_code203_Lv9", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "7d37a0c5-6898-4e0e-b5ea-47dd39271735", + "fieldName": "ext_code06_Lv9", + "groupId": "6e981ca8-329c-405a-9f1c-04a9e98d5e5f", + "groupName": "二级分组-02", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "bd222971-43f8-4b94-9d6d-90aea913a9de", + "fieldName": "ext_code05_Lv9_ext_code05_Lv9_lcname", + "groupId": "2d135270-d3d3-4edb-9ef3-a12fc692318b", + "groupName": "一级分组-02", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "e4b6e2d9-4f1b-41a1-aa90-7e490afb6c2d", + "fieldName": "ext_code301_Lv9", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "serviceRefs": [], + "commands": [ + { + "id": "b44d7015-c83f-4c40-94b4-d72ec44f0b0b", + "code": "bxrhelpafter01b44d", + "name": "报销人帮助后事件b44d", + "params": [], + "handlerName": "bxrhelpafter01", + "cmpId": "c0b8cf1c-66d6-477c-bcb5-23f31bd0811b", + "shortcut": {}, + "extensions": [] + }, + { + "id": "b94aa188-52cf-49d8-8e41-56ecf253f074", + "code": "basicformviewmodelBeforeMultiSelectHelpOpen1", + "name": "多选帮助批量赋值帮助前事件1", + "params": [ + { + "name": "frameId", + "shownName": "grid所在frame", + "value": "rofkmx-component", + "description": "grid所在frame" + }, + { + "name": "associatedField", + "shownName": "列表关联字段", + "value": "skfhm", + "description": "列表关联字段" + } + ], + "handlerName": "BeforeMultiSelectHelpOpen", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "fd63bb21-95cc-4c68-b478-ecc76cef6bcd", + "code": "basicformviewmodelAfterMultiSelectHelpClose1", + "name": "多选帮助批量赋值帮助后事件1", + "params": [ + { + "name": "frameId", + "shownName": "grid所在frame", + "value": "rofkmx-component", + "description": "grid所在frame" + }, + { + "name": "mapFields", + "shownName": "帮助字段映射", + "value": "{ \t\"id\": \"skfhm.skfhm\", \t\"code\": \"skzh\", \t\"name\": \"skfhm.skfhm_name\", \t\"inbank.inbank_khhqc\": \"khh\", \t\"inbank.inbank_address\": \"email\" }", + "description": "帮助字段映射" + }, + { + "name": "associatedField", + "shownName": "关联字段", + "value": "skfhm", + "description": "关联字段" + } + ], + "handlerName": "AfterMultiSelectHelpClose", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "04b131d0-6434-4be7-9201-c1d6c0f5bada", + "code": "basicformviewmodelOpenHiddenHelp1", + "name": "弹出帮助1", + "params": [ + { + "name": "helpId", + "shownName": "帮助Id", + "value": "help_yhzhxx", + "description": "帮助Id" + } + ], + "handlerName": "OpenHiddenHelp", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "parent": "root-viewmodel", + "pagination": { + "enable": false + }, + "enableValidation": false + }, + { + "id": "roclmx-component-viewmodel", + "code": "roclmx-component-viewmodel", + "name": "差旅明细", + "fields": [ + { + "type": "Form", + "id": "092ee414-9b6f-43f8-9639-311432dc5a1b", + "fieldName": "cfcS_CFCS_OrgName", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "出发城市", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLMX.cfcS_CFCS_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgName", + "valueField": "orgCode", + "displayType": "TreeList", + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "mapFields": "{'id':'cfcs.cfcs','orgName':'cfcs.cfcS_OrgName','orgCode':'cfcs.cfcS_ID'}" + }, + "type": { + "length": 60 + } + } + }, + { + "type": "Form", + "id": "574554dc-9605-4a77-9bf6-ca8e95395c69", + "fieldName": "cfsj", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "6dbbe9c2-5a68-4d13-810d-160a04a7a463", + "fieldName": "ddcS_DDCS_OrgName", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "到达城市", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roCLMX.ddcS_DDCS_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgName", + "valueField": "orgCode", + "displayType": "TreeList", + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "mapFields": "{'id':'ddcs.ddcs','orgName':'ddcs.ddcS_OrgName','orgCode':'ddcs.ddcS_ID'}" + } + } + }, + { + "type": "Form", + "id": "91d71207-5a50-4442-90fa-a7140731b50c", + "fieldName": "ddsj", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "575ed208-6ed0-4179-85b7-89824e7eccae", + "fieldName": "transportation", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "1e00ede8-d335-436d-bba0-fd0cea39234b", + "fieldName": "carnumber", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "1f20fde2-4938-4fb3-9c9b-b446faaccc1f", + "fieldName": "fjzs", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "3beb91d4-44ad-4189-90bb-d6fcdfda5559", + "fieldName": "jtgjf", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "Jdemosumje19f92", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "5ac85821-b1c8-466e-9fa6-cdb2a44117be", + "fieldName": "qtfy", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "Jdemosumje19f92", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "d591ed4a-e8db-4120-9c9b-70a4e2e64413", + "fieldName": "zsfje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "Jdemosumje19f92", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c", + "fieldName": "zsfzpse", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "df3ae210-5c7d-4f5a-9067-f584792834ee", + "fieldName": "ccts", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "Jdemosumje19f92", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "595b5a9d-4103-4cc4-b6d4-9610d741c6a6", + "fieldName": "bzbz", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "Jdemosumje19f92", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "a734eba7-eb12-4b4b-967b-5aaad25bfbd9", + "fieldName": "mxbxje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "a5129114-0bca-4664-8b24-8272c554be40", + "fieldName": "bz", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "行程摘要" + } + }, + { + "type": "Form", + "id": "c2297d15-9021-4a7c-b8bf-fe4ce44fd25b", + "fieldName": "cwtzje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "ef6b2547-b3bc-4885-9f2f-7ad8b7daa923", + "fieldName": "cwtzyy", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "states": [], + "bindTo": "/roCLMXs", + "parent": "root-viewmodel", + "commands": [ + { + "id": "007858dc-b0a2-41a0-b9f2-19519cce1eb5", + "code": "roclmxAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "2945376a-52a5-48d6-8910-66b17620fb5e", + "code": "roclmxRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/roclmx-component/roCLMXs/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "9f920ac6-953b-4295-85da-0dd4f4a91bd2", + "code": "Jdemosumje19f92", + "name": "明细报销金额自动计算19f92", + "params": [], + "handlerName": "Jdemosumje1", + "cmpId": "c0b8cf1c-66d6-477c-bcb5-23f31bd0811b", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4a500d59-394d-43ff-8cec-77b62ee2c0e5", + "code": "copyRow4a50", + "name": "复制行4a50", + "params": [ + { + "name": "frameId", + "shownName": "grid所在frame的frameId", + "value": "roclmx-component", + "description": "grid所在frame的frameId" + }, + { + "name": "ignoreFields", + "shownName": "复制时忽略的字段,逗号分隔", + "value": "", + "description": "复制时忽略的字段,逗号分隔" + } + ], + "handlerName": "copyRow", + "cmpId": "43f68561-eae4-4495-b318-d629615523f8", + "shortcut": {}, + "extensions": [] + } + ], + "serviceRefs": [], + "pagination": { + "enable": false + }, + "enableValidation": true + }, + { + "id": "rofkmx-component-viewmodel", + "code": "rofkmx-component-viewmodel", + "name": "付款明细", + "fields": [ + { + "type": "Form", + "id": "39d0f0d8-fa39-475a-9ef0-1743a3692655", + "fieldName": "fkhb", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "fc8c0fe2-60be-4ddf-b76f-6cc119246ec6", + "fieldName": "fkje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb", + "fieldName": "fkfs", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "83673651-4c82-4f9f-a83d-6c6383e46eb1", + "fieldName": "yhfl", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "aabf51f9-d4d9-450a-bdc0-63756cfa1cdc", + "fieldName": "skzh", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "5a962507-c861-4819-8c62-9f8b54d40724", + "fieldName": "khh", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "readonly": true + } + }, + { + "type": "Form", + "id": "6580c058-2635-48c6-9bef-a268c9efeee8", + "fieldName": "skfhm_skfhm_name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "roFKMX.skfhm_skfhm_name", + "displayName": "J版银行账号信息01", + "idField": "id", + "type": "ViewObject" + }, + "textField": "code", + "valueField": "name", + "displayType": "List", + "helpId": "2dddc2bd-75e3-43df-ae99-e22beea01fba", + "mapFields": "{'name':'skfhm.skfhm_name','inbank.inbank_khhqc':'khh','code':'skzh','id':'skfhm.skfhm'}" + } + } + }, + { + "type": "Form", + "id": "58e4ab8a-771f-4be9-b0aa-98156e62b2e0", + "fieldName": "lhh_code", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-7ade-4cc2-8579-0a419b53fd1e", + "fieldName": "lhh_name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-bce5-4e64-a9e3-739795c64027", + "fieldName": "lhh_email", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-73f4-4cdd-b24b-e73c1e7b85ea", + "fieldName": "lhh_phone", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-c087-4cbc-8e0a-7ba031d9b9c7", + "fieldName": "lhh_cratetime", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-d5ae-46e2-8632-f5073868baa1", + "fieldName": "lhh_endtime", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-bb19-4e12-a42a-b457dd8b2287", + "fieldName": "lhh_fdje", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "58e4ab8a-9baa-46e7-863c-aad9cc72f3c5", + "fieldName": "lhh_markudt", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "states": [], + "bindTo": "/roFKMXs", + "parent": "root-viewmodel", + "commands": [ + { + "id": "f00fbcf3-33c6-4eaf-a3d2-a66494cc2a69", + "code": "rofkmxAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + }, + { + "id": "f30e6c38-1db0-403c-9d09-3583bba0a7cf", + "code": "rofkmxRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/rofkmx-component/roFKMXs/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": false + }, + { + "id": "rospjl-component-viewmodel", + "code": "rospjl-component-viewmodel", + "name": "审批记录", + "fields": [ + { + "type": "Form", + "id": "d0111e70-abe4-4361-89ed-228f71153ef6", + "fieldName": "spR_SPR_Name", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "审批人" + } + }, + { + "type": "Form", + "id": "e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6", + "fieldName": "spsj", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "946380b5-3734-4173-95fd-b3b53731c37c", + "fieldName": "spyj", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "states": [], + "bindTo": "/roSPJLs", + "parent": "root-viewmodel", + "commands": [ + { + "id": "38f0f818-9d6e-456b-8fec-8df59b57a34d", + "code": "rospjlAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + }, + { + "id": "8a2767e3-939b-4c08-8eab-39711d1b1807", + "code": "rospjlRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/rospjl-component/roSPJLs/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": false + } + ], + "components": [ + { + "id": "root-component", + "type": "Component", + "viewModel": "root-viewmodel", + "componentType": "Frame", + "onInit": "Load1", + "contents": [ + { + "id": "root-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-page f-page-card f-page-is-mainsubcard" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-nav", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header-base" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-title-container", + "type": "ContentContainer", + "appearance": { + "class": "f-title" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header-title", + "type": "HtmlTemplate", + "html": "\r\n

三级-私有A

\r\n
\r\n\t\r\n
" + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + }, + { + "id": "page-header-toolbar", + "type": "ToolBar", + "appearance": { + "class": "col-7 f-toolbar" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "items": [ + { + "id": "toolBarItem_4006", + "type": "ToolBarItem", + "appearance": null, + "disable": false, + "text": "运行时外部ts方法测试", + "visible": true, + "click": "rootviewmodelyxs0011", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-add", + "type": "ToolBarItem", + "text": "新增", + "appearance": { + "class": "btn-primary" + }, + "disable": "!viewModel.stateMachine['canAdd']", + "visible": true, + "click": "Add1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-edit", + "type": "ToolBarItem", + "text": "编辑", + "appearance": null, + "disable": "!viewModel.stateMachine['canEdit']", + "visible": true, + "click": "Edit1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-save", + "type": "ToolBarItem", + "text": "保存", + "appearance": null, + "disable": "!viewModel.stateMachine['canSave']", + "visible": true, + "click": "Save1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_8960", + "type": "ToolBarItem", + "appearance": null, + "disable": false, + "text": "提交审批", + "visible": true, + "click": "submitApproveWithState1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-cancel", + "type": "ToolBarItem", + "text": "取消", + "appearance": null, + "disable": "!viewModel.stateMachine['canCancel']", + "visible": true, + "click": "Cancel1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-close", + "type": "ToolBarItem", + "text": "关闭", + "appearance": null, + "disable": false, + "visible": true, + "click": "Close1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + } + ], + "visible": true + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + }, + { + "id": "main-container", + "type": "ContentContainer", + "appearance": { + "class": "f-page-main" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "basic-form-component-ref", + "type": "ComponentRef", + "component": "basic-form-component", + "visible": true + }, + { + "id": "detail-container", + "type": "ContentContainer", + "appearance": { + "class": "f-struct-wrapper" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "detail-section", + "type": "Section", + "appearance": { + "class": "f-section-tabs f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": true, + "expanded": true, + "enableMaximize": true, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": false, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "detail-tab", + "type": "Tab", + "controlSource": "Farris", + "appearance": { + "class": "f-component-tabs f-tabs-has-grid" + }, + "selected": "roclmx-tab-page", + "size": null, + "position": "top", + "contents": [ + { + "id": "roclmx-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "差旅明细", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "roclmx-component-ref", + "type": "ComponentRef", + "component": "roclmx-component", + "visible": true + } + ], + "toolbar": { + "id": "roclmx-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "roclmx-button-add", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.roclmx-component-viewmodel.roclmxAddItem1" + }, + { + "id": "roclmx-button-remove", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.roclmx-component-viewmodel.roclmxRemoveItem1" + }, + { + "id": "tabToolbarItem_3530", + "type": "TabToolbarItem", + "title": "复制当前选中行", + "disable": false, + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.roclmx-component-viewmodel.copyRow4a50" + } + ] + }, + "visible": true + }, + { + "id": "rofkmx-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "付款明细", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "rofkmx-component-ref", + "type": "ComponentRef", + "component": "rofkmx-component", + "visible": true + } + ], + "toolbar": { + "id": "rofkmx-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "tabToolbarItem_1544", + "type": "TabToolbarItem", + "title": "收款银行账号多选映射", + "disable": false, + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.basic-form-viewmodel.basicformviewmodelOpenHiddenHelp1" + }, + { + "id": "rofkmx-button-add", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.rofkmx-component-viewmodel.rofkmxAddItem1" + }, + { + "id": "rofkmx-button-remove", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.rofkmx-component-viewmodel.rofkmxRemoveItem1" + } + ] + }, + "visible": true + }, + { + "id": "rospjl-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "审批记录", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "rospjl-component-ref", + "type": "ComponentRef", + "component": "rospjl-component", + "visible": true + } + ], + "toolbar": { + "id": "rospjl-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "rospjl-button-add", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.rospjl-component-viewmodel.rospjlAddItem1" + }, + { + "id": "rospjl-button-remove", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.rospjl-component-viewmodel.rospjlRemoveItem1" + } + ] + }, + "visible": true + } + ], + "tabChange": null, + "tabRemove": null, + "contentFill": true, + "autoTitleWidth": false, + "visible": true + } + ], + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "afterViewInit": "", + "visible": true + }, + { + "id": "basic-form-component", + "type": "Component", + "viewModel": "basic-form-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "basic-form-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": true, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "basic-form-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "form_djbh", + "type": "TextBox", + "title": "报销单私有A", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "djbh", + "field": "818f2272-f372-4afa-8c71-6328c0fc00b4" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 80, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "djbh", + "isTextArea": null, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "form_tbsj", + "type": "DateBox", + "title": "填报时间C", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "tbsj", + "field": "458dc0b4-fff0-4868-8e34-be3df68ab55e" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "tbsj", + "isTextArea": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "controlSource": "Kendo", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "form_bxrY_BXRY_Name", + "type": "LookupEdit", + "title": "报销人名称", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bxrY_BXRY_Name", + "field": "d17cd77e-7c0a-42cb-9a09-687b5677f7ac" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLDJ.bxrY_BXRY_Name", + "displayName": "J版人员帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "code", + "valueField": "name", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'bxry.bxry','name':'bxry.bxrY_Name','code':'bxry.bxrY_ID'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": false, + "path": "bxry.bxrY_Name", + "clear": null, + "isTextArea": null, + "helpId": "76774958-8e91-406e-812c-981ba9ef2726", + "lookupStyle": "popup", + "expandLevel": -1, + "isRecordSize": false, + "enableFullTree": false, + "loadTreeDataType": "default", + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "bZ5_BZ5_name_180f1a2e_e7c9_43c1_b297_052735bffdee_48u5", + "type": "LookupEdit", + "title": "单据类型名称", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bZ5_BZ5_name", + "field": "180f1a2e-e7c9-43c1-b297-052735bffdee" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLDJ.bZ5_BZ5_name", + "displayName": "J版单据类型帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'bZ5.bZ5','name':'bZ5.bZ5_name'}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": true, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bZ5.bZ5_name", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "helpId": "67bb1e7a-74de-449d-a156-135c9246b38d", + "cascadeStatus": "enable", + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "form_zy", + "type": "TextBox", + "title": "报账说明A", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "zy", + "field": "b94def87-1de5-45ea-8ddd-291224f1e5e1" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 200, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "zy", + "isTextArea": null, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "form_bxje", + "type": "NumericBox", + "title": "报销金额", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bxje", + "field": "e3e99d10-9543-4bd1-82e4-533caf21668a" + }, + "readonly": true, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "bxje", + "maxLength": 18, + "isTextArea": null, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "form_bhsje", + "type": "NumericBox", + "title": "不含税金额", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bhsje", + "field": "cdb96871-0307-4659-8aa9-2f1921b6b103" + }, + "readonly": true, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "bhsje", + "maxLength": 18, + "isTextArea": null, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "form_dwbH_DWBH_OrgName", + "type": "LookupEdit", + "title": "单位名称", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "dwbH_DWBH_OrgName", + "field": "616b9a60-2a0d-4953-8875-606906def113" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLDJ.dwbH_DWBH_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgCode", + "valueField": "orgName", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'dwbh.dwbh','orgName':'dwbh.dwbH_OrgName','orgCode':'dwbh.dwbH_ID'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": false, + "path": "dwbh.dwbH_OrgName", + "clear": null, + "isTextArea": null, + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "loadTreeDataType": "default", + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "form_zdr", + "type": "TextBox", + "title": "制单人", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "zdr", + "field": "6ae80bb6-8083-44d7-8897-256d5c677773" + }, + "readonly": true, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "zdr", + "isTextArea": null, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name_cadc1e08_7684_45e9_90cf_0b01e7a03957_o07s", + "type": "LookupEdit", + "title": "UDT嵌套UDT", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name", + "field": "cadc1e08-7684-45e9-90cf-0b01e7a03957" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLDJ.bZ8_JDemoUDT02_JDemoUDT02_LHHUDT_JDemoUDT3_name", + "displayName": "J版银行账号信息01", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'bZ8.jDemoUDT02.jDemoUDT02','lhhudt.jDemoUDT3.jDemoUDT3_name':'bZ8.jDemoUDT02.jDemoUDT02_LHHUDT_JDemoUDT3_name'}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bZ8.jDemoUDT02.jDemoUDT02_LHHUDT_JDemoUDT3_name", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "helpId": "2dddc2bd-75e3-43df-ae99-e22beea01fba", + "cascadeStatus": "enable", + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "bZ7_phone_d9ee0e39_73f4_4cdd_b24b_e73c1e7b85ea_9u1q", + "type": "NumericBox", + "title": "手机号", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bZ7_phone", + "field": "d9ee0e39-73f4-4cdd-b24b-e73c1e7b85ea" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": "n0", + "precision": 0, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bZ7.phone", + "maxLength": 0, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "bZ7_cratetime_d9ee0e39_c087_4cbc_8e0a_7ba031d9b9c7_rx6x", + "type": "DateBox", + "title": "计划付款时间", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bZ7_cratetime", + "field": "d9ee0e39-c087-4cbc-8e0a-7ba031d9b9c7" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bZ7.cratetime", + "controlSource": "Kendo", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "bZ7_fdje_d9ee0e39_bb19_4e12_a42a_b457dd8b2287_nuf3", + "type": "NumericBox", + "title": "浮动金额", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-4 col-xl-4 col-el-4 col-md-6 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "bZ7_fdje", + "field": "d9ee0e39-bb19-4e12-a42a-b457dd8b2287" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 3, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 18, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bZ7.fdje", + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "help_yhzhxx", + "type": "LookupEdit", + "title": "银行账号帮助", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Variable", + "path": "skfhm", + "field": "327cdfe2-a6b2-4795-9523-054eb2596dd1" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "detail-form-component-viewmodel.skfhm", + "displayName": "银行账号帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "List", + "multiSelect": true, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "", + "lookupPicking": "basicformviewmodelBeforeMultiSelectHelpOpen1", + "lookupPicked": "basicformviewmodelAfterMultiSelectHelpClose1", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "clear": null, + "helpId": "2dddc2bd-75e3-43df-ae99-e22beea01fba", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "loadTreeDataType": "default", + "isTextArea": null, + "holdPlace": false, + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "span": 3, + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "noSearch": false + }, + { + "id": "ext_code203_Lv9_1bef012d_ti9c", + "type": "TextBox", + "titleSourceType": "static", + "title": "二级文本03", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code203_Lv9", + "field": "1bef012d-9b72-4a15-af6e-06bd30218992", + "fullPath": "ext_code203_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code203_Lv9", + "isRTControl": true, + "span": 0.75 + }, + { + "id": "ext_code301_Lv9_e4b6e2d9_ppfd", + "type": "TextBox", + "titleSourceType": "static", + "title": "三级文本01", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code301_Lv9", + "field": "e4b6e2d9-4f1b-41a1-aa90-7e490afb6c2d", + "fullPath": "ext_code301_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code301_Lv9", + "isRTControl": true + }, + { + "id": "01638918-2c32-4564-8819-11c21da6104f", + "type": "FieldSet", + "title": "二级分组-01", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "ext_code201_Lv9_945c039c_ymws", + "type": "TextBox", + "titleSourceType": "static", + "title": "二级文本01", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code201_Lv9", + "field": "945c039c-2156-4bdb-bf3f-fe1675b3b031", + "fullPath": "ext_code201_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code201_Lv9", + "isRTControl": true, + "span": 0.75 + }, + { + "id": "ext_code202_Lv9_6bad8059_83t9", + "type": "TextBox", + "titleSourceType": "static", + "title": "二级文本02", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code202_Lv9", + "field": "6bad8059-f969-47e1-ad8f-210af8936ede", + "fullPath": "ext_code202_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code202_Lv9", + "isRTControl": true, + "span": 0.75 + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "isRTControl": true, + "span": 3, + "columns": 3, + "draggable": false + }, + { + "id": "ddf784df-4e63-4f08-b300-0cc08c213c06", + "type": "FieldSet", + "title": "一级分组-01", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "ext_code01_Lv9_ac71778f_vgs4", + "type": "TextBox", + "titleSourceType": "static", + "title": "扩展文本01", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code01_Lv9", + "field": "ac71778f-eea0-4f15-9d11-4bb75fdb8586", + "fullPath": "ext_code01_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code01_Lv9", + "isRTControl": true, + "span": 0.75 + }, + { + "id": "ext_code02_Lv9_c342d6e5_tj34", + "type": "MultiTextBox", + "titleSourceType": "static", + "title": "扩展备注02", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code02_Lv9", + "field": "c342d6e5-5932-40e6-9ac3-35319b3ef0c0", + "fullPath": "ext_code02_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 0, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "editType": "default", + "dialogWidth": 500, + "dialogHeight": 400, + "path": "ext_code02_Lv9", + "isRTControl": true, + "span": 0.75 + }, + { + "id": "ext_code03_Lv9_6b04013d_d0el", + "type": "NumericBox", + "titleSourceType": "static", + "title": "扩展整数03", + "controlSource": "Farris", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code03_Lv9", + "field": "6b04013d-9232-4f7a-9913-38767c32f25c", + "fullPath": "ext_code03_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 0, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": false, + "maxLength": 0, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code03_Lv9", + "isRTControl": true, + "span": 0.75, + "precisionSourceType": "static" + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "isRTControl": true, + "span": 3, + "columns": 3, + "draggable": false + }, + { + "id": "6e981ca8-329c-405a-9f1c-04a9e98d5e5f", + "type": "FieldSet", + "title": "二级分组-02", + "appearance": { + "class": "col-12 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "ext_code04_Lv9_bb0c83bc_z052", + "type": "NumericBox", + "titleSourceType": "static", + "title": "扩展浮点04", + "controlSource": "Farris", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code04_Lv9", + "field": "bb0c83bc-3bce-415a-87ea-c4d4ef93d81e", + "fullPath": "ext_code04_Lv9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 2, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": false, + "maxLength": 18, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ext_code04_Lv9", + "isRTControl": true, + "span": 0.75, + "precisionSourceType": "static" + }, + { + "id": "ext_code06_Lv9_7d37a0c5_xiq3", + "type": "EnumField", + "titleSourceType": "static", + "title": "扩展整数枚举06", + "controlSource": "Farris", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code06_Lv9", + "field": "7d37a0c5-6898-4e0e-b5ea-47dd39271735", + "fullPath": "ext_code06_Lv9" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "1", + "name": "VIP" + }, + { + "value": "2", + "name": "普通" + }, + { + "value": "3", + "name": "黑名单" + } + ], + "idField": "value", + "textField": "name", + "holdPlace": false, + "isTextArea": true, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": false, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "enableCancelSelected": false, + "beforeShow": null, + "beforeHide": null, + "dataSourceType": "static", + "viewType": "text", + "path": "ext_code06_Lv9", + "isRTControl": true, + "span": 0.75, + "noSearch": false + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "isRTControl": true, + "draggable": false + }, + { + "id": "2d135270-d3d3-4edb-9ef3-a12fc692318b", + "type": "FieldSet", + "title": "一级分组-02", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "ext_code05_Lv9_ext_code05_Lv9_lcname_bd222971_zq1c", + "type": "LookupEdit", + "titleSourceType": "static", + "title": "种类名称", + "appearance": { + "class": " col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_code05_Lv9_ext_code05_Lv9_lcname", + "field": "bd222971-43f8-4b94-9d6d-90aea913a9de", + "fullPath": "ext_code05_Lv9.ext_code05_Lv9_lcname" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "dataSource": { + "uri": "roCLDJ.ext_code05_Lv9_ext_code05_Lv9_lcname", + "displayName": "J版人员类别帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "lcname", + "valueField": "lbcode", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{\"lbcode\":\"ext_code05_Lv9.ext_code05_Lv9_lbcode\",\"lcname\":\"ext_code05_Lv9.ext_code05_Lv9_lcname\",\"id\":\"ext_code05_Lv9.ext_code05_Lv9\"}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": true, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "isRecordSize": false, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "expandLevel": -1, + "enableCascade": false, + "cascadeStatus": "enable", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "textAlign": "left", + "useExtendInfo": false, + "path": "ext_code05_Lv9.ext_code05_Lv9_lcname", + "helpId": "44abb8c8-193a-4773-984d-b8cb8c7a8691", + "conditions": [], + "isRTControl": true, + "span": 0.75, + "selectFirstInNav": false, + "loadDataWhenOpen": true + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "isRTControl": true, + "span": 3, + "columns": 3, + "draggable": false + } + ], + "controlsInline": false, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 3 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "roclmx-component", + "type": "Component", + "viewModel": "roclmx-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "roclmx-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "dataGrid_roclmx", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "roCLMXs", + "fields": [ + { + "id": "gridField_092ee414-9b6f-43f8-9639-311432dc5a1b_cfcS_CFCS_OrgName", + "type": "GridField", + "caption": "出发城市", + "binding": { + "type": "Form", + "path": "cfcS_CFCS_OrgName", + "field": "092ee414-9b6f-43f8-9639-311432dc5a1b" + }, + "appearance": { + "class": "", + "style": null + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "cfcs.cfcS_OrgName", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_cfcS_CFCS_OrgName", + "type": "LookupEdit", + "title": "出发城市", + "appearance": { + "class": "", + "style": "width:80px" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "cfcS_CFCS_OrgName", + "field": "092ee414-9b6f-43f8-9639-311432dc5a1b" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLMX.cfcS_CFCS_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgName", + "valueField": "orgCode", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'cfcs.cfcs','orgName':'cfcs.cfcS_OrgName','orgCode':'cfcs.cfcS_ID'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": true, + "path": "cfcs.cfcS_OrgName", + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "clear": null, + "loadTreeDataType": "default", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_574554dc-9605-4a77-9bf6-ca8e95395c69_cfsj", + "type": "GridField", + "controlSource": "Farris", + "caption": "出发时间", + "binding": { + "type": "Form", + "path": "cfsj", + "field": "574554dc-9605-4a77-9bf6-ca8e95395c69" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "cfsj", + "dataType": "datetime", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_cfsj", + "type": "DateBox", + "title": "出发时间", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "cfsj", + "field": "574554dc-9605-4a77-9bf6-ca8e95395c69" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "cfsj", + "controlSource": "Farris", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "gridField_6dbbe9c2-5a68-4d13-810d-160a04a7a463_ddcS_DDCS_OrgName", + "type": "GridField", + "caption": "到达城市", + "binding": { + "type": "Form", + "path": "ddcS_DDCS_OrgName", + "field": "6dbbe9c2-5a68-4d13-810d-160a04a7a463" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "ddcs.ddcS_OrgName", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_ddcS_DDCS_OrgName", + "type": "LookupEdit", + "title": "到达城市", + "appearance": { + "class": "", + "style": "width:80px" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "ddcS_DDCS_OrgName", + "field": "6dbbe9c2-5a68-4d13-810d-160a04a7a463" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roCLMX.ddcS_DDCS_OrgName", + "displayName": "J版销售组织树帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "orgName", + "valueField": "orgCode", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'ddcs.ddcs','orgName':'ddcs.ddcS_OrgName','orgCode':'ddcs.ddcS_ID'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": false, + "path": "ddcs.ddcS_OrgName", + "helpId": "ef908c29-27f7-4f92-86dc-8012320b21b6", + "clear": null, + "loadTreeDataType": "default", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_91d71207-5a50-4442-90fa-a7140731b50c_ddsj", + "type": "GridField", + "controlSource": "Farris", + "caption": "到达时间", + "binding": { + "type": "Form", + "path": "ddsj", + "field": "91d71207-5a50-4442-90fa-a7140731b50c" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "ddsj", + "dataType": "datetime", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_ddsj", + "type": "DateBox", + "title": "到达时间", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "ddsj", + "field": "91d71207-5a50-4442-90fa-a7140731b50c" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ddsj", + "controlSource": "Farris", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "gridField_575ed208-6ed0-4179-85b7-89824e7eccae_transportation", + "type": "GridField", + "caption": "交通工具", + "binding": { + "type": "Form", + "path": "transportation", + "field": "575ed208-6ed0-4179-85b7-89824e7eccae" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "transportation", + "dataType": "enum", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_transportation", + "type": "EnumField", + "title": "交通工具", + "binding": { + "type": "Form", + "path": "transportation", + "field": "575ed208-6ed0-4179-85b7-89824e7eccae" + }, + "placeHolder": "", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "enumData": [ + { + "value": "Car", + "name": "汽车" + }, + { + "value": "trains", + "name": "火车" + }, + { + "value": "airplane", + "name": "飞机" + }, + { + "value": "others", + "name": "其他" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "transportation", + "controlSource": "Kendo", + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "noSearch": false + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": [ + { + "value": "Car", + "name": "汽车" + }, + { + "value": "trains", + "name": "火车" + }, + { + "value": "airplane", + "name": "飞机" + }, + { + "value": "others", + "name": "其他" + } + ], + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "idField": "value", + "textField": "name" + }, + { + "id": "gridField_1e00ede8-d335-436d-bba0-fd0cea39234b_carnumber", + "type": "GridField", + "caption": "车次", + "binding": { + "type": "Form", + "path": "carnumber", + "field": "1e00ede8-d335-436d-bba0-fd0cea39234b" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 70 + }, + "dataField": "carnumber", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_carnumber", + "type": "TextBox", + "title": "车次", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "carnumber", + "field": "1e00ede8-d335-436d-bba0-fd0cea39234b" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "carnumber", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "count" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_1f20fde2-4938-4fb3-9c9b-b446faaccc1f_fjzs", + "type": "GridField", + "caption": "附件张数", + "binding": { + "type": "Form", + "path": "fjzs", + "field": "1f20fde2-4938-4fb3-9c9b-b446faaccc1f" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "fjzs", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_fjzs", + "type": "NumericBox", + "title": "附件张数", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "fjzs", + "field": "1f20fde2-4938-4fb3-9c9b-b446faaccc1f" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n0", + "precision": 0, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "fjzs", + "maxLength": 0, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 0, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_3beb91d4-44ad-4189-90bb-d6fcdfda5559_jtgjf", + "type": "GridField", + "caption": "交通工具费", + "binding": { + "type": "Form", + "path": "jtgjf", + "field": "3beb91d4-44ad-4189-90bb-d6fcdfda5559" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 95 + }, + "dataField": "jtgjf", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_jtgjf", + "type": "NumericBox", + "title": "交通工具费", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "jtgjf", + "field": "3beb91d4-44ad-4189-90bb-d6fcdfda5559" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "jtgjf", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_5ac85821-b1c8-466e-9fa6-cdb2a44117be_qtfy", + "type": "GridField", + "caption": "其他费用", + "binding": { + "type": "Form", + "path": "qtfy", + "field": "5ac85821-b1c8-466e-9fa6-cdb2a44117be" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "qtfy", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_qtfy", + "type": "NumericBox", + "title": "其他费用", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "qtfy", + "field": "5ac85821-b1c8-466e-9fa6-cdb2a44117be" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "qtfy", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_d591ed4a-e8db-4120-9c9b-70a4e2e64413_zsfje", + "type": "GridField", + "caption": "住宿费金额", + "binding": { + "type": "Form", + "path": "zsfje", + "field": "d591ed4a-e8db-4120-9c9b-70a4e2e64413" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 95 + }, + "dataField": "zsfje", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_zsfje", + "type": "NumericBox", + "title": "住宿费金额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "zsfje", + "field": "d591ed4a-e8db-4120-9c9b-70a4e2e64413" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "zsfje", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c_zsfzpse", + "type": "GridField", + "caption": "住宿费专票税额", + "binding": { + "type": "Form", + "path": "zsfzpse", + "field": "da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 145 + }, + "dataField": "zsfzpse", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_zsfzpse", + "type": "NumericBox", + "title": "住宿费专票税额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "zsfzpse", + "field": "da99d2ad-0e89-4f21-8cfe-b056cf2d5a6c" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "zsfzpse", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_df3ae210-5c7d-4f5a-9067-f584792834ee_ccts", + "type": "GridField", + "caption": "出差天数", + "binding": { + "type": "Form", + "path": "ccts", + "field": "df3ae210-5c7d-4f5a-9067-f584792834ee" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 80 + }, + "dataField": "ccts", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_ccts", + "type": "NumericBox", + "title": "出差天数", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "ccts", + "field": "df3ae210-5c7d-4f5a-9067-f584792834ee" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n1", + "precision": 1, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "ccts", + "maxLength": 5, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 1, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_595b5a9d-4103-4cc4-b6d4-9610d741c6a6_bzbz", + "type": "GridField", + "caption": "补助标准", + "binding": { + "type": "Form", + "path": "bzbz", + "field": "595b5a9d-4103-4cc4-b6d4-9610d741c6a6" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 90 + }, + "dataField": "bzbz", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_bzbz", + "type": "TextBox", + "title": "补助标准", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bzbz", + "field": "595b5a9d-4103-4cc4-b6d4-9610d741c6a6" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "bzbz", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_a734eba7-eb12-4b4b-967b-5aaad25bfbd9_mxbxje", + "type": "GridField", + "caption": "报销金额", + "binding": { + "type": "Form", + "path": "mxbxje", + "field": "a734eba7-eb12-4b4b-967b-5aaad25bfbd9" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 85 + }, + "dataField": "mxbxje", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_mxbxje", + "type": "NumericBox", + "title": "报销金额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "mxbxje", + "field": "a734eba7-eb12-4b4b-967b-5aaad25bfbd9" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "mxbxje", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "sum", + "formatter": { + "precision": 2, + "thousand": ",", + "prefix": "", + "suffix": "", + "decimal": ".", + "type": "number" + } + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": true, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_a5129114-0bca-4664-8b24-8272c554be40_bz", + "type": "GridField", + "caption": "行程摘要", + "binding": { + "type": "Form", + "path": "bz", + "field": "a5129114-0bca-4664-8b24-8272c554be40" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 180 + }, + "dataField": "bz", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_bz", + "type": "TextBox", + "title": "详细说明", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "bz", + "field": "a5129114-0bca-4664-8b24-8272c554be40" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 200, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "bz", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_c2297d15-9021-4a7c-b8bf-fe4ce44fd25b_cwtzje", + "type": "GridField", + "caption": "财务调整金额", + "binding": { + "type": "Form", + "path": "cwtzje", + "field": "c2297d15-9021-4a7c-b8bf-fe4ce44fd25b" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 110 + }, + "dataField": "cwtzje", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_cwtzje", + "type": "NumericBox", + "title": "财务调整金额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "cwtzje", + "field": "c2297d15-9021-4a7c-b8bf-fe4ce44fd25b" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "cwtzje", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "sum" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_ef6b2547-b3bc-4885-9f2f-7ad8b7daa923_cwtzyy", + "type": "GridField", + "caption": "财务调整原因", + "binding": { + "type": "Form", + "path": "cwtzyy", + "field": "ef6b2547-b3bc-4885-9f2f-7ad8b7daa923" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 180 + }, + "dataField": "cwtzyy", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_cwtzyy", + "type": "TextBox", + "title": "财务调整原因", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "cwtzyy", + "field": "ef6b2547-b3bc-4885-9f2f-7ad8b7daa923" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 200, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "cwtzyy", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": false, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill", + "style": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "identifyField": null, + "multiSelect": null, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "onSelectionChange": "", + "showLineNumber": true, + "appendRow": "roclmxAddItem1", + "pageChange": null, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "disableRow": null, + "checkedChange": null, + "showAllCheckbox": false, + "multiSort": true, + "fitColumns": true, + "striped": true, + "dblClickRow": null, + "showBorder": false, + "beforeEdit": null, + "pagination": true, + "mergeCell": false, + "visible": true, + "virtualized": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "footerDataFrom": "client", + "footerDataCommand": null, + "checkOnSelect": true, + "selectOnCheck": true, + "autoFitColumns": false, + "showGroupColumn": true, + "styler": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": null, + "useControlPanel": false, + "autoHeight": false, + "groupFooter": false, + "beforeUnCheck": null, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageSize": false, + "showFooter": true, + "footerTemplate": "
\r\n 差旅行程数: \r\n {{ctx[0]?.carnumber}} 条\r\n
\r\n 报账金额总计:\r\n\t {{ctx[0]?.mxbxje}}元\r\n \r\n 财务调整后金额共计:\r\n\t {{ctx[0]?.cwtzje}}元\r\n \r\n
", + "draggable": false, + "showSelectedList": false, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + }, + { + "id": "rofkmx-component", + "type": "Component", + "viewModel": "rofkmx-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "rofkmx-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "dataGrid_rofkmx", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "roFKMXs", + "fields": [ + { + "id": "gridField_6580c058-2635-48c6-9bef-a268c9efeee8_skfhm_skfhm_name", + "type": "GridField", + "caption": "银行账号名称", + "binding": { + "type": "Form", + "path": "skfhm_skfhm_name", + "field": "6580c058-2635-48c6-9bef-a268c9efeee8" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "skfhm.skfhm_name", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_skfhm_skfhm_name", + "type": "LookupEdit", + "title": "银行账号名称", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "skfhm_skfhm_name", + "field": "6580c058-2635-48c6-9bef-a268c9efeee8" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "roFKMX.skfhm_skfhm_name", + "displayName": "J版银行账号信息01", + "idField": "id", + "type": "ViewObject" + }, + "textField": "code", + "valueField": "name", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'name':'skfhm.skfhm_name','inbank.inbank_khhqc':'khh','code':'skzh','id':'skfhm.skfhm'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": false, + "path": "skfhm.skfhm_name", + "helpId": "2dddc2bd-75e3-43df-ae99-e22beea01fba", + "clear": null, + "loadTreeDataType": "default", + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_39d0f0d8-fa39-475a-9ef0-1743a3692655_fkhb", + "type": "GridField", + "caption": "付款货币", + "binding": { + "type": "Form", + "path": "fkhb", + "field": "39d0f0d8-fa39-475a-9ef0-1743a3692655" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "fkhb", + "dataType": "enum", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_fkhb", + "type": "EnumField", + "title": "付款货币", + "binding": { + "type": "Form", + "path": "fkhb", + "field": "39d0f0d8-fa39-475a-9ef0-1743a3692655" + }, + "placeHolder": "", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "enumData": [ + { + "value": "RMB", + "name": "人民币" + }, + { + "value": "US", + "name": "美元" + }, + { + "value": "AU", + "name": "澳元" + }, + { + "value": "OT", + "name": "其他" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "fkhb", + "controlSource": "Kendo", + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "noSearch": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": [ + { + "value": "RMB", + "name": "人民币" + }, + { + "value": "US", + "name": "美元" + }, + { + "value": "AU", + "name": "澳元" + }, + { + "value": "OT", + "name": "其他" + } + ], + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "idField": "value", + "textField": "name" + }, + { + "id": "gridField_fc8c0fe2-60be-4ddf-b76f-6cc119246ec6_fkje", + "type": "GridField", + "caption": "付款金额", + "binding": { + "type": "Form", + "path": "fkje", + "field": "fc8c0fe2-60be-4ddf-b76f-6cc119246ec6" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "fkje", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_fkje", + "type": "NumericBox", + "title": "付款金额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "fkje", + "field": "fc8c0fe2-60be-4ddf-b76f-6cc119246ec6" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "fkje", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "number", + "precision": 2, + "thousand": ",", + "decimal": "." + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_47bb1f77-4ca0-4d98-aa9a-092d70dac2bb_fkfs", + "type": "GridField", + "caption": "付款方式", + "binding": { + "type": "Form", + "path": "fkfs", + "field": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "fkfs", + "dataType": "enum", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_fkfs", + "type": "EnumField", + "title": "付款方式", + "binding": { + "type": "Form", + "path": "fkfs", + "field": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb" + }, + "placeHolder": "", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "enumData": [ + { + "value": "W", + "name": "网银" + }, + { + "value": "X", + "name": "现金" + }, + { + "value": "Z", + "name": "支票" + }, + { + "value": "O", + "name": "其他" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "fkfs", + "controlSource": "Kendo", + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "noSearch": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": [ + { + "value": "W", + "name": "网银" + }, + { + "value": "X", + "name": "现金" + }, + { + "value": "Z", + "name": "支票" + }, + { + "value": "O", + "name": "其他" + } + ], + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "idField": "value", + "textField": "name" + }, + { + "id": "gridField_83673651-4c82-4f9f-a83d-6c6383e46eb1_yhfl", + "type": "GridField", + "caption": "银行分类", + "binding": { + "type": "Form", + "path": "yhfl", + "field": "83673651-4c82-4f9f-a83d-6c6383e46eb1" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "yhfl", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_yhfl", + "type": "TextBox", + "title": "银行分类", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "yhfl", + "field": "83673651-4c82-4f9f-a83d-6c6383e46eb1" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "yhfl", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_aabf51f9-d4d9-450a-bdc0-63756cfa1cdc_skzh", + "type": "GridField", + "caption": "收款账号", + "binding": { + "type": "Form", + "path": "skzh", + "field": "aabf51f9-d4d9-450a-bdc0-63756cfa1cdc" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "skzh", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_skzh", + "type": "TextBox", + "title": "收款账号", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "skzh", + "field": "aabf51f9-d4d9-450a-bdc0-63756cfa1cdc" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "skzh", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_5a962507-c861-4819-8c62-9f8b54d40724_khh", + "type": "GridField", + "caption": "开户行", + "binding": { + "type": "Form", + "path": "khh", + "field": "5a962507-c861-4819-8c62-9f8b54d40724" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "khh", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_khh", + "type": "TextBox", + "title": "开户行", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "khh", + "field": "5a962507-c861-4819-8c62-9f8b54d40724" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "khh", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "lhh_code_58e4ab8a_771f_4be9_b0aa_98156e62b2e0_penx", + "type": "GridField", + "controlSource": "Farris", + "caption": "人员编号", + "binding": { + "type": "Form", + "path": "lhh_code", + "field": "58e4ab8a-771f-4be9-b0aa-98156e62b2e0" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.code", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_code_58e4ab8a_771f_4be9_b0aa_98156e62b2e0_hzp4", + "type": "TextBox", + "title": "人员编号", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_code", + "field": "58e4ab8a-771f-4be9-b0aa-98156e62b2e0" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.code" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_name_58e4ab8a_7ade_4cc2_8579_0a419b53fd1e_5lib", + "type": "GridField", + "controlSource": "Farris", + "caption": "人员名称", + "binding": { + "type": "Form", + "path": "lhh_name", + "field": "58e4ab8a-7ade-4cc2-8579-0a419b53fd1e" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.name", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_name_58e4ab8a_7ade_4cc2_8579_0a419b53fd1e_2wxz", + "type": "TextBox", + "title": "人员名称", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_name", + "field": "58e4ab8a-7ade-4cc2-8579-0a419b53fd1e" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 200, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.name" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_email_58e4ab8a_bce5_4e64_a9e3_739795c64027_ruxy", + "type": "GridField", + "controlSource": "Farris", + "caption": "邮箱", + "binding": { + "type": "Form", + "path": "lhh_email", + "field": "58e4ab8a-bce5-4e64-a9e3-739795c64027" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.email", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_email_58e4ab8a_bce5_4e64_a9e3_739795c64027_0vzc", + "type": "TextBox", + "title": "邮箱", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_email", + "field": "58e4ab8a-bce5-4e64-a9e3-739795c64027" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 100, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.email" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_phone_58e4ab8a_73f4_4cdd_b24b_e73c1e7b85ea_u07x", + "type": "GridField", + "controlSource": "Farris", + "caption": "手机号", + "binding": { + "type": "Form", + "path": "lhh_phone", + "field": "58e4ab8a-73f4-4cdd-b24b-e73c1e7b85ea" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.phone", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_phone_58e4ab8a_73f4_4cdd_b24b_e73c1e7b85ea_p3jr", + "type": "NumericBox", + "title": "手机号", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_phone", + "field": "58e4ab8a-73f4-4cdd-b24b-e73c1e7b85ea" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n0", + "precision": 0, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.phone", + "maxLength": 0, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "number", + "precision": 0, + "thousand": ",", + "decimal": "." + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_cratetime_58e4ab8a_c087_4cbc_8e0a_7ba031d9b9c7_q5b9", + "type": "GridField", + "controlSource": "Farris", + "caption": "计划付款时间", + "binding": { + "type": "Form", + "path": "lhh_cratetime", + "field": "58e4ab8a-c087-4cbc-8e0a-7ba031d9b9c7" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.cratetime", + "dataType": "date", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_cratetime_58e4ab8a_c087_4cbc_8e0a_7ba031d9b9c7_lwh4", + "type": "DateBox", + "title": "计划付款时间", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_cratetime", + "field": "58e4ab8a-c087-4cbc-8e0a-7ba031d9b9c7" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.cratetime", + "controlSource": "Farris", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "date", + "dateFormat": "yyyy-MM-dd" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_endtime_58e4ab8a_d5ae_46e2_8632_f5073868baa1_xm4u", + "type": "GridField", + "controlSource": "Farris", + "caption": "实际付款日期", + "binding": { + "type": "Form", + "path": "lhh_endtime", + "field": "58e4ab8a-d5ae-46e2-8632-f5073868baa1" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.endtime", + "dataType": "date", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_endtime_58e4ab8a_d5ae_46e2_8632_f5073868baa1_pw7w", + "type": "DateBox", + "title": "实际付款日期", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_endtime", + "field": "58e4ab8a-d5ae-46e2-8632-f5073868baa1" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.endtime", + "controlSource": "Farris", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "date", + "dateFormat": "yyyy-MM-dd" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_fdje_58e4ab8a_bb19_4e12_a42a_b457dd8b2287_4a5n", + "type": "GridField", + "controlSource": "Farris", + "caption": "浮动金额", + "binding": { + "type": "Form", + "path": "lhh_fdje", + "field": "58e4ab8a-bb19-4e12-a42a-b457dd8b2287" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.fdje", + "dataType": "number", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_fdje_58e4ab8a_bb19_4e12_a42a_b457dd8b2287_8hls", + "type": "NumericBox", + "title": "浮动金额", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_fdje", + "field": "58e4ab8a-bb19-4e12-a42a-b457dd8b2287" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "n3", + "precision": 3, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "spin": null, + "step": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lhh.fdje", + "maxLength": 18, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "number", + "precision": 3, + "thousand": ",", + "decimal": "." + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "lhh_markudt_58e4ab8a_9baa_46e7_863c_aad9cc72f3c5_ojv4", + "type": "GridField", + "controlSource": "Farris", + "caption": "付款备注信息", + "binding": { + "type": "Form", + "path": "lhh_markudt", + "field": "58e4ab8a-9baa-46e7-863c-aad9cc72f3c5" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "lhh.markudt", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "lhh_markudt_58e4ab8a_9baa_46e7_863c_aad9cc72f3c5_qes4", + "type": "MultiTextBox", + "title": "付款备注信息", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "lhh_markudt", + "field": "58e4ab8a-9baa-46e7-863c-aad9cc72f3c5" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 0, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "editType": "default", + "dialogWidth": 500, + "dialogHeight": 400, + "path": "lhh.markudt" + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "identifyField": null, + "multiSelect": null, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "onSelectionChange": "", + "showLineNumber": false, + "appendRow": "rofkmxAddItem1", + "pageChange": null, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "disableRow": null, + "checkedChange": null, + "showAllCheckbox": false, + "multiSort": false, + "dblClickRow": null, + "showBorder": false, + "striped": true, + "beforeEdit": null, + "pagination": true, + "mergeCell": false, + "visible": true, + "virtualized": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "footerDataFrom": "client", + "footerDataCommand": null, + "checkOnSelect": true, + "selectOnCheck": true, + "fitColumns": true, + "autoFitColumns": false, + "showGroupColumn": true, + "styler": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": null, + "useControlPanel": false, + "autoHeight": false, + "groupFooter": false, + "beforeUnCheck": null, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageSize": false, + "draggable": false, + "showSelectedList": false, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + }, + { + "id": "rospjl-component", + "type": "Component", + "viewModel": "rospjl-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "rospjl-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "dataGrid_rospjl", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "roSPJLs", + "fields": [ + { + "id": "gridField_d0111e70-abe4-4361-89ed-228f71153ef6_spR_SPR_Name", + "type": "GridField", + "caption": "审批人", + "binding": { + "type": "Form", + "path": "spR_SPR_Name", + "field": "d0111e70-abe4-4361-89ed-228f71153ef6" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "spr.spR_Name", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_spR_SPR_Name", + "type": "TextBox", + "title": "审批人", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "spR_SPR_Name", + "field": "d0111e70-abe4-4361-89ed-228f71153ef6" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 1000, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "spr.spR_Name", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + }, + { + "id": "gridField_e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6_spsj", + "type": "GridField", + "controlSource": "Farris", + "caption": "审批时间", + "binding": { + "type": "Form", + "path": "spsj", + "field": "e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "spsj", + "dataType": "datetime", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_spsj", + "type": "DateBox", + "title": "审批时间", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "spsj", + "field": "e8b1bbd3-30eb-4dcb-a76b-6d79ed4d78e6" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": "'yyyy-MM-dd'", + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "spsj", + "controlSource": "Farris", + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": null + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null + }, + { + "id": "gridField_946380b5-3734-4173-95fd-b3b53731c37c_spyj", + "type": "GridField", + "caption": "审批意见", + "binding": { + "type": "Form", + "path": "spyj", + "field": "946380b5-3734-4173-95fd-b3b53731c37c" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "spyj", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_spyj", + "type": "TextBox", + "title": "审批意见", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "spyj", + "field": "946380b5-3734-4173-95fd-b3b53731c37c" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 100, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "spyj", + "isPassword": false + }, + "draggable": false, + "frozen": "none", + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "controlSource": "Farris", + "readonly": false, + "visible": true, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "styler": null, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "" + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "identifyField": null, + "multiSelect": null, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "onSelectionChange": "", + "showLineNumber": false, + "appendRow": "rospjlAddItem1", + "pageChange": null, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "disableRow": null, + "checkedChange": null, + "showAllCheckbox": false, + "multiSort": false, + "dblClickRow": null, + "showBorder": false, + "striped": true, + "beforeEdit": null, + "pagination": true, + "mergeCell": false, + "visible": true, + "virtualized": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "footerDataFrom": "client", + "footerDataCommand": null, + "checkOnSelect": true, + "selectOnCheck": true, + "fitColumns": false, + "autoFitColumns": false, + "showGroupColumn": true, + "styler": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": null, + "useControlPanel": false, + "autoHeight": false, + "groupFooter": false, + "beforeUnCheck": null, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageSize": false, + "draggable": false, + "showSelectedList": false, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + } + ], + "webcmds": [ + { + "id": "8172a979-2c80-4637-ace7-b13074d3f393", + "path": "/projects/packages/Inspur.GS.Gsp.Web.WebCmp/webcmd", + "name": "CardController.webcmd", + "refedHandlers": [ + { + "host": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "handler": "Load" + }, + { + "host": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "handler": "LoadAndAdd" + }, + { + "host": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "handler": "LoadAndView" + }, + { + "host": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "handler": "LoadAndEdit" + }, + { + "host": "f90aadfa-988c-4da5-a5db-1416c3333794", + "handler": "Add" + }, + { + "host": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "handler": "Edit" + }, + { + "host": "31b814db-01e4-407d-8fad-0f08dbb01999", + "handler": "Save" + }, + { + "host": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "handler": "Cancel" + }, + { + "host": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "handler": "Close" + }, + { + "host": "c8504c24-33e8-487a-91ce-2218b803fe01", + "handler": "ChangeItem" + }, + { + "host": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "handler": "ChangeItem" + }, + { + "host": "007858dc-b0a2-41a0-b9f2-19519cce1eb5", + "handler": "AddItem" + }, + { + "host": "2945376a-52a5-48d6-8910-66b17620fb5e", + "handler": "RemoveItem" + }, + { + "host": "f00fbcf3-33c6-4eaf-a3d2-a66494cc2a69", + "handler": "AddItem" + }, + { + "host": "f30e6c38-1db0-403c-9d09-3583bba0a7cf", + "handler": "RemoveItem" + }, + { + "host": "38f0f818-9d6e-456b-8fec-8df59b57a34d", + "handler": "AddItem" + }, + { + "host": "8a2767e3-939b-4c08-8eab-39711d1b1807", + "handler": "RemoveItem" + }, + { + "host": "b93baca5-a150-4318-a44b-6c6cd6195da3", + "handler": "BeforeMultiSelectHelpOpen" + }, + { + "host": "bee044f9-2754-4ef3-bbcf-46643ec5d903", + "handler": "AfterMultiSelectHelpClose" + }, + { + "host": "42906fb1-e81f-4039-9fdb-b184e621cb7f", + "handler": "OpenHiddenHelp" + }, + { + "host": "b94aa188-52cf-49d8-8e41-56ecf253f074", + "handler": "BeforeMultiSelectHelpOpen" + }, + { + "host": "fd63bb21-95cc-4c68-b478-ecc76cef6bcd", + "handler": "AfterMultiSelectHelpClose" + }, + { + "host": "04b131d0-6434-4be7-9201-c1d6c0f5bada", + "handler": "OpenHiddenHelp" + } + ] + }, + { + "id": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "path": null, + "name": "ApproveController.webcmd", + "refedHandlers": [ + { + "host": "4e9f36c0-bf8f-40cc-8b64-c5b2ddab44a9", + "handler": "submitApproveWithState" + }, + { + "host": "5860e99d-d975-4674-9140-b226596cf7b3", + "handler": "cancelApproveWithState" + } + ] + }, + { + "id": "c0b8cf1c-66d6-477c-bcb5-23f31bd0811b", + "path": "DemoJSales/DemoJMarket/DemoJROCLF/bo-demojroclffront1/metadata/components", + "name": "frmclbxd001_frm_JDemosumbxje.webcmd", + "refedHandlers": [ + { + "host": "b44d7015-c83f-4c40-94b4-d72ec44f0b0b", + "handler": "bxrhelpafter01" + } + ] + }, + { + "id": "43f68561-eae4-4495-b318-d629615523f8", + "path": null, + "name": "BatchEditCommands.webcmd", + "refedHandlers": [ + { + "host": "4a500d59-394d-43ff-8cec-77b62ee2c0e5", + "handler": "copyRow" + } + ] + }, + { + "id": "8400adee-9863-4c48-9918-aa4c30421593", + "path": "DemoJSales/DemoJMarket/DemoJROCLF/bo-demojroclffront1/metadata/components", + "name": "frmclbxd001_frm_yxstest.webcmd", + "refedHandlers": [ + { + "host": "fd6bf216-550c-4131-9108-e100c2c37003", + "handler": "yxs001" + }, + { + "host": "46fa7d6a-40f3-4efc-be55-67550500e63f", + "handler": "yxs001" + } + ] + }, + { + "id": "3f40288a-d11e-4dbd-89ba-388abf931ca3", + "path": "Gsp/Common/DataIE/bo-dataie/metadata/webcmd", + "name": "DataImportExportCommand.webcmd", + "refedHandlers": [ + { + "host": "60cad103-7cae-49d8-a5ec-eea50e886f5e", + "handler": "DataImport" + }, + { + "host": "afaf43af-6e8a-451b-938f-04d083830148", + "handler": "DataImport" + }, + { + "host": "b33196e3-fdcb-46dc-871b-40381a689a19", + "handler": "DataExport" + }, + { + "host": "4e5e218b-6663-4254-a7da-26ef832b55fc", + "handler": "DataImport" + }, + { + "host": "dbba9a66-5ef5-46cd-9307-26b5c5bee099", + "handler": "DataExport" + }, + { + "host": "f852e645-a92f-4136-88d3-78a44b9bb975", + "handler": "DataImport" + } + ] + } + ], + "serviceRefs": [], + "expressions": [ + { + "fieldId": "818f2272-f372-4afa-8c71-6328c0fc00b4", + "expression": [ + { + "type": "compute", + "value": "{\"expr\":\"return \\\"BXD\\\"+Math.random();\",\"sexpr\":\"\"}" + }, + { + "type": "readonly", + "value": "{\"expr\":\"return true ;\",\"sexpr\":\"\"}" + } + ] + }, + { + "fieldId": "a5129114-0bca-4664-8b24-8272c554be40", + "expression": [ + { + "type": "compute", + "value": "{\"expr\":\"return roCLDJ.djbh;\",\"sexpr\":\"\"}" + } + ] + }, + { + "fieldId": "47bb1f77-4ca0-4d98-aa9a-092d70dac2bb", + "expression": [ + { + "type": "compute", + "value": "{\"expr\":\"if(roCLDJ.roFKMXs[0].fkje > 500)\\r\\n{\\r\\n return \\\"W\\\";\\r\\n}\\r\\nelse\\r\\n{\\r\\n return \\\"X\\\";\\r\\n}\",\"sexpr\":\"\"}" + } + ] + }, + { + "fieldId": "e3e99d10-9543-4bd1-82e4-533caf21668a", + "expression": [ + { + "type": "compute", + "value": "{\"expr\":\"return DefaultFunction.SumByProp(\\\"roCLDJ.roCLMXs\\\",\\\"mxbxje\\\");\",\"sexpr\":\"\"}" + } + ] + } + ] + }, + "options": {} +} \ No newline at end of file diff --git a/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/expensemrgtxflcjt.frm.json b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/expensemrgtxflcjt.frm.json new file mode 100644 index 00000000..b9e4c895 --- /dev/null +++ b/web-form-jitengine/src/test/java/com/inspur/edp/web/jitengine/expressions/expensemrgtxflcjt.frm.json @@ -0,0 +1,4736 @@ +{ + "module": { + "id": "ExpenseMrg", + "code": "ExpenseMrg", + "name": "费用管理", + "caption": "费用管理", + "type": "Module", + "creator": "wang-xh", + "creationDate": "2019-12-18T01:46:45.554Z", + "updateVersion": "191104", + "showTitle": true, + "bootstrap": "card-template", + "states": [], + "contents": [], + "ctrlLangs": { + "ch": { + "form_employeeID_EmployeeID_EmployeeName": "人员名称", + "form_billCode": "单据编号", + "form_billStatus": "审批状态", + "form_billDate": "制单日期", + "form_billType": "报销类型", + "form_billNote": "报销说明", + "expensedetail-tab-page": "费用报销明细", + "dataGrid_expensedetail_norecord": "暂无数据", + "gridField_797b34f9-cafd-4ab7-99fa-35dddc16a81d_billDetailDate": "费用日期", + "gridField_2d6cdb35-e5a7-49e5-8352-5f4cb66416b2_billDetailAmount": "报销金额", + "gridField_8868ef9e-a87d-4413-8aa8-9c9e23fe56fc_invoiceNO": "发票号码", + "gridField_51461960-5be0-44f8-8a6f-0174a969100c_billDetailNote": "费用说明", + "attadetail-tab-page": "附件明细", + "dataGrid_attadetail_norecord": "暂无数据", + "gridField_abb0f176-2648-46f2-b2db-42d6fb252d50_fileName": "附件名称", + "gridField_b9b23cd1-091f-44ec-b3f5-1e438d53ab96_filePath": "附件路径", + "gridField_8d0efbc1-acaf-4d97-8e5b-8443ec5cfbf3_fileSize": "附件大小", + "button-add": "新增", + "button-edit": "编辑", + "button-save": "保存", + "button-cancel": "取消", + "button-close": "关闭", + "form_domainID_DomainID_Name": "组织名称", + "form_projectID_ProjectID_ProjectName": "项目名称", + "4a2225a9-f0c5-4545-806e-9434e2b4649f": "基本信息", + "c11bfc72-9a55-455a-9f13-13bf0146933d": "报账信息", + "7b4ff734-ecfb-49c0-9106-9352165af188": "审批信息", + "5d0ef017-6ee9-4c6a-a374-6555d35a885a": "其他信息", + "44d1f233-2f17-483d-9b78-77c9fc6acbf1": "其他信息", + "6d04f029-6cd0-4608-be8a-37b75c64caf3": "基本信息", + "7d1225d2-b517-4ac2-8a1f-7280fee9cc29": "报账信息", + "9debf1df-10f2-4799-a809-6871176e1657": "新增分组", + "page-header-title": "费用报销", + "cecf9705-a680-4aba-a7ce-610e150fee68": "报账信息", + "form_billStatus_BillState": "审批状态", + "bc6e0cde-c2d8-4f6c-b8d0-1cae716f04f3": "其他信息", + "gridField_839dca6a-1497-4526-86f9-290aab400e0b_fileID_FileName": "附件信息名称", + "toolBarItem_8666": "提交审批", + "toolBarItem_6367": "取消提交审批", + "toolBarItem_6867": "扩展" + }, + "zh-CHS": {}, + "en": {} + }, + "projectName": "bo-expensefront", + "templateId": "card-template", + "schemas": [ + { + "id": "d038bd71-3aaf-49fe-885f-ec900122126a", + "code": "expenseMrgTxfLcjt", + "name": "费用管理_通讯费_浪潮集团", + "sourceUri": "api/fssc/expensemrg/v1.0/expensemrgtxflcjt/64c9e533-d059-4aa3-9b2a-34fcba9c9683/75429c19-934a-737d-33a0-a12cf9ec6fc7", + "sourceType": "vo", + "entities": [ + { + "id": "1f8b1d5d-36f9-454b-a34d-fa3c0ebedc0d", + "code": "Expense", + "name": "费用报销", + "label": "expenses", + "type": { + "name": "Expense", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "6287ff55-9a18-40e7-a0f3-2093764e72d3", + "originalId": "6287ff55-9a18-40e7-a0f3-2093764e72d3", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "49bb55a9-6a09-4ce1-9250-5a280adbe9ff", + "originalId": "49bb55a9-6a09-4ce1-9250-5a280adbe9ff", + "code": "Version", + "name": "Version", + "label": "version", + "bindingField": "version", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "Version", + "bindingPath": "version", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "39c0e547-e05d-46e0-af89-b9884dac86ec", + "originalId": "39c0e547-e05d-46e0-af89-b9884dac86ec", + "code": "EmployeeID", + "name": "报销人员", + "label": "employeeID", + "bindingField": "employeeID", + "type": { + "$type": "EntityType", + "name": "employee6ff5", + "primary": "employeeID", + "fields": [ + { + "$type": "SimpleField", + "id": "6ff552e2-b24a-4bae-a760-6aa6373dae32", + "originalId": "6ff552e2-b24a-4bae-a760-6aa6373dae32", + "code": "EmployeeID", + "name": "报销人员", + "label": "employeeID", + "bindingField": "employeeID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "EmployeeID", + "bindingPath": "employeeID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f0bdfaf2-d8d8-4ac4-89da-68e8f44d289b", + "originalId": "f0bdfaf2-d8d8-4ac4-89da-68e8f44d289b", + "code": "Code", + "name": "编号", + "label": "employeeID_Code", + "bindingField": "employeeID_EmployeeID_Code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 100 + }, + "editor": { + "$type": "TextBox" + }, + "path": "EmployeeID.EmployeeID_Code", + "bindingPath": "employeeID.employeeID_Code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "86314c41-df2e-4ceb-aee5-13e32df7a3c1", + "originalId": "86314c41-df2e-4ceb-aee5-13e32df7a3c1", + "code": "Name", + "name": "名称", + "label": "employeeID_Name", + "bindingField": "employeeID_EmployeeID_Name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "EmployeeID.EmployeeID_Name", + "bindingPath": "employeeID.employeeID_Name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "employee" + }, + "path": "EmployeeID", + "bindingPath": "employeeID" + }, + { + "$type": "ComplexField", + "id": "27957391-970a-4f06-9713-43c09ed0dd16", + "originalId": "27957391-970a-4f06-9713-43c09ed0dd16", + "code": "DomainID", + "name": "所属部门", + "label": "domainID", + "bindingField": "domainID", + "type": { + "$type": "EntityType", + "name": "SysOrgFF30", + "primary": "domainID", + "fields": [ + { + "$type": "SimpleField", + "id": "ff3063b8-91bf-41e9-9d65-d01cfff5ee7b", + "originalId": "ff3063b8-91bf-41e9-9d65-d01cfff5ee7b", + "code": "DomainID", + "name": "所属部门", + "label": "domainID", + "bindingField": "domainID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DomainID", + "bindingPath": "domainID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "13fdd337-8fa8-43e0-adef-fd041f7d1d58", + "originalId": "13fdd337-8fa8-43e0-adef-fd041f7d1d58", + "code": "code", + "name": "编号", + "label": "domainID_code", + "bindingField": "domainID_DomainID_code", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DomainID.DomainID_code", + "bindingPath": "domainID.domainID_code", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "639efad2-d863-45d1-8f4a-9c1294ede3bd", + "originalId": "639efad2-d863-45d1-8f4a-9c1294ede3bd", + "code": "name", + "name": "名称", + "label": "domainID_name", + "bindingField": "domainID_DomainID_name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "DomainID.DomainID_name", + "bindingPath": "domainID.domainID_name", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "系统组织" + }, + "path": "DomainID", + "bindingPath": "domainID" + }, + { + "$type": "SimpleField", + "id": "75b3994d-3311-4809-a4f8-881207bf17cc", + "originalId": "75b3994d-3311-4809-a4f8-881207bf17cc", + "code": "BillType", + "name": "报销类型", + "label": "billType", + "bindingField": "billType", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1 + }, + "enumValues": [ + { + "value": "travel", + "name": "差旅费" + }, + { + "value": "traffic", + "name": "交通费" + }, + { + "value": "communication", + "name": "通讯费" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "BillType", + "bindingPath": "billType", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "05121716-1cef-4754-a8a0-54d53bb40fdb", + "originalId": "05121716-1cef-4754-a8a0-54d53bb40fdb", + "code": "BillStatus", + "name": "审批状态", + "label": "billStatus", + "bindingField": "billStatus", + "type": { + "$type": "ObjectType", + "name": "BillState0512", + "fields": [ + { + "$type": "SimpleField", + "id": "05121716-0101-468f-ae3f-40c76c0f06b0", + "originalId": "a0b19650-0101-468f-ae3f-40c76c0f06b0", + "code": "BillState", + "name": "状态", + "label": "billState", + "bindingField": "billStatus_BillState", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "Billing", + "name": "制单" + }, + { + "value": "SubmitApproval", + "name": "提交审批" + }, + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "ApprovalNotPassed", + "name": "审批不通过" + }, + { + "value": "Abort", + "name": "流程终止" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "BillStatus.BillState", + "bindingPath": "billStatus.billState", + "multiLanguage": false + } + ], + "displayName": "状态" + }, + "path": "BillStatus", + "bindingPath": "billStatus" + }, + { + "$type": "ComplexField", + "id": "0983fe47-bdd7-4fed-9ed3-8eaed1819f04", + "originalId": "0983fe47-bdd7-4fed-9ed3-8eaed1819f04", + "code": "FlowInstance", + "name": "流程实例", + "label": "flowInstance", + "bindingField": "flowInstance", + "type": { + "$type": "ObjectType", + "name": "ProcessInstance0983", + "fields": [ + { + "$type": "SimpleField", + "id": "0983fe47-ad8f-4da3-a430-c8a7f2162135", + "originalId": "2e1beb7d-ad8f-4da3-a430-c8a7f2162135", + "code": "ProcessInstance", + "name": "流程实例", + "label": "processInstance", + "bindingField": "flowInstance_ProcessInstance", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "FlowInstance.ProcessInstance", + "bindingPath": "flowInstance.processInstance", + "multiLanguage": false + } + ], + "displayName": "流程实例" + }, + "path": "FlowInstance", + "bindingPath": "flowInstance" + }, + { + "$type": "SimpleField", + "id": "172bafa9-405a-4d56-8190-b7b61a20cc59", + "originalId": "172bafa9-405a-4d56-8190-b7b61a20cc59", + "code": "BillDate", + "name": "制单日期", + "label": "billDate", + "bindingField": "billDate", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "BillDate", + "bindingPath": "billDate", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "f4d723e3-c65e-4ad2-943f-df9f623d62e6", + "originalId": "f4d723e3-c65e-4ad2-943f-df9f623d62e6", + "code": "SecID", + "name": "密级ID", + "label": "secID", + "bindingField": "secID", + "type": { + "$type": "ObjectType", + "name": "SecurityLevelF4d7$1", + "fields": [ + { + "$type": "ComplexField", + "id": "f4d723e3-e9ed-47e8-b08f-533b28928c5f", + "originalId": "bd050131-e9ed-47e8-b08f-533b28928c5f", + "code": "SecurityLevel", + "name": "SecurityLevel", + "label": "securityLevel", + "bindingField": "secID_SecurityLevel", + "type": { + "$type": "EntityType", + "name": "SecurityLevelF4d7", + "primary": "securityLevel", + "fields": [ + { + "$type": "SimpleField", + "id": "f4d723e3-f426-4c45-8066-c67bdda1b24b", + "originalId": "6ded9d7f-f426-4c45-8066-c67bdda1b24b", + "code": "SecurityLevel", + "name": "SecurityLevel", + "label": "securityLevel", + "bindingField": "secID_SecurityLevel", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SecID.SecurityLevel", + "bindingPath": "secID.securityLevel", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f4d723e3-3046-4434-bbd9-8f0218b979ff", + "originalId": "900981a8-3046-4434-bbd9-8f0218b979ff", + "code": "ID", + "name": "ID", + "label": "securityLevel_ID", + "bindingField": "secID_SecurityLevel_SecurityLevel_ID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SecID.SecurityLevel.SecurityLevel_ID", + "bindingPath": "secID.securityLevel.securityLevel_ID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f4d723e3-51e0-4ed0-bad0-cebb5e60f84d", + "originalId": "48b78824-51e0-4ed0-bad0-cebb5e60f84d", + "code": "Name", + "name": "Name", + "label": "securityLevel_Name", + "bindingField": "secID_SecurityLevel_SecurityLevel_Name", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "SecID.SecurityLevel.SecurityLevel_Name", + "bindingPath": "secID.securityLevel.securityLevel_Name", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f4d723e3-78a5-4352-9e5f-0a924340e1e3", + "originalId": "c2addf2d-78a5-4352-9e5f-0a924340e1e3", + "code": "Seclevel", + "name": "Seclevel", + "label": "secID_Seclevel", + "bindingField": "secID_SecurityLevel_SecID_Seclevel", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "SecID.SecurityLevel.SecID_Seclevel", + "bindingPath": "secID.securityLevel.secID_Seclevel", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "SecurityLevel" + }, + "path": "SecID.SecurityLevel", + "bindingPath": "secID.securityLevel" + } + ], + "displayName": "SecurityLevel" + }, + "path": "SecID", + "bindingPath": "secID" + }, + { + "$type": "ComplexField", + "id": "01365279-59fc-4386-abe9-9fd78782f99e", + "originalId": "01365279-59fc-4386-abe9-9fd78782f99e", + "code": "ProjectID", + "name": "所属项目", + "label": "projectID", + "bindingField": "projectID", + "type": { + "$type": "EntityType", + "name": "ProjectInfoFFd0", + "primary": "projectID", + "fields": [ + { + "$type": "SimpleField", + "id": "ffd097c9-883d-4016-b201-241622b4215e", + "originalId": "ffd097c9-883d-4016-b201-241622b4215e", + "code": "ProjectID", + "name": "所属项目", + "label": "projectID", + "bindingField": "projectID", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ProjectID", + "bindingPath": "projectID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "3795f282-89b1-4f81-8ee5-e8017aead8ed", + "originalId": "3795f282-89b1-4f81-8ee5-e8017aead8ed", + "code": "ProjectCode", + "name": "项目编号", + "label": "projectID_ProjectCode", + "bindingField": "projectID_ProjectID_ProjectCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ProjectID.ProjectID_ProjectCode", + "bindingPath": "projectID.projectID_ProjectCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1678e382-8ac4-492b-8d39-054445cdf06f", + "originalId": "1678e382-8ac4-492b-8d39-054445cdf06f", + "code": "ProjectName", + "name": "项目名称", + "label": "projectID_ProjectName", + "bindingField": "projectID_ProjectID_ProjectName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 512 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ProjectID.ProjectID_ProjectName", + "bindingPath": "projectID.projectID_ProjectName", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "ProjectInfo" + }, + "path": "ProjectID", + "bindingPath": "projectID" + }, + { + "$type": "SimpleField", + "id": "aaa2146f-83f5-4d6d-a970-5e13b19c916f", + "originalId": "aaa2146f-83f5-4d6d-a970-5e13b19c916f", + "code": "BillNote", + "name": "报销说明", + "label": "billNote", + "bindingField": "billNote", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "BillNote", + "bindingPath": "billNote", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "61dd7f98-d370-4708-a4c0-80835634927d", + "originalId": "61dd7f98-d370-4708-a4c0-80835634927d", + "code": "BillCode", + "name": "单据编号", + "label": "billCode", + "bindingField": "billCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "BillCode", + "bindingPath": "billCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "12ba92ef-8b1f-4a3d-8484-ab90bb7bb093", + "originalId": "12ba92ef-8b1f-4a3d-8484-ab90bb7bb093", + "code": "FinishState", + "name": "完成标志", + "label": "finish", + "bindingField": "finish", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "UnFinished", + "name": "未完成" + }, + { + "value": "Finished", + "name": "已完成" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "Finish", + "bindingPath": "finish", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "36078912-77f1-47d1-aa83-df25ec3496ec", + "originalId": "36078912-77f1-47d1-aa83-df25ec3496ec", + "code": "ShareOrg", + "name": "分摊组织", + "label": "shareOrg", + "bindingField": "shareOrg", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ShareOrg", + "bindingPath": "shareOrg", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "bf64eabb-db76-482e-bf3e-598a707cb958", + "originalId": "bf64eabb-db76-482e-bf3e-598a707cb958", + "code": "ShareProject", + "name": "分摊项目", + "label": "shareProject", + "bindingField": "shareProject", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ShareProject", + "bindingPath": "shareProject", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "4c3d12c5-66e4-4e1b-81cb-d8d797d5aa60", + "originalId": "4c3d12c5-66e4-4e1b-81cb-d8d797d5aa60", + "code": "TotalSum", + "name": "报帐金额", + "label": "totalSum", + "bindingField": "totalSum", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BigNumericType", + "name": "BigNumber", + "displayName": "大数字", + "length": 50, + "precision": 20 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "TotalSum", + "bindingPath": "totalSum", + "multiLanguage": false + }, + { + "id": "d1370325-df05-451a-bce0-f4226999f6a2", + "originalId": "d1370325-df05-451a-bce0-f4226999f6a2", + "code": "gyzd", + "name": "公有字段", + "label": "ext_gyzd_Lv9", + "bindingField": "ext_gyzd_Lv9", + "bindingPath": "ext_gyzd_Lv9", + "path": "ext_gyzd_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + }, + { + "id": "d28b2295-c408-4570-acd7-520150acf2c9", + "originalId": "d28b2295-c408-4570-acd7-520150acf2c9", + "code": "bxr", + "name": "报销人", + "label": "ext_bxr_Lv9", + "bindingField": "ext_bxr_Lv9", + "bindingPath": "ext_bxr_Lv9", + "path": "ext_bxr_Lv9", + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "$type": "SimpleField", + "readonly": false, + "require": false, + "multiLanguage": false, + "defaultValue": "" + } + ], + "entities": [ + { + "id": "9dc48b3c-8bd7-470d-ac04-b431d16b2b7d", + "code": "ExpenseDetail", + "name": "费用报销明细", + "label": "expenseDetails", + "type": { + "name": "ExpenseDetail", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "491cd548-4780-4185-a926-6d58003e2a9c", + "originalId": "491cd548-4780-4185-a926-6d58003e2a9c", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f8eeb185-2ce1-4a81-8a8d-7ef6d6344ec4", + "originalId": "f8eeb185-2ce1-4a81-8a8d-7ef6d6344ec4", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "797b34f9-cafd-4ab7-99fa-35dddc16a81d", + "originalId": "797b34f9-cafd-4ab7-99fa-35dddc16a81d", + "code": "BillDetailDate", + "name": "费用日期", + "label": "billDetailDate", + "bindingField": "billDetailDate", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "BillDetailDate", + "bindingPath": "billDetailDate", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "2d6cdb35-e5a7-49e5-8352-5f4cb66416b2", + "originalId": "2d6cdb35-e5a7-49e5-8352-5f4cb66416b2", + "code": "BillDetailAmount", + "name": "报销金额", + "label": "billDetailAmount", + "bindingField": "billDetailAmount", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "BillDetailAmount", + "bindingPath": "billDetailAmount", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "8868ef9e-a87d-4413-8aa8-9c9e23fe56fc", + "originalId": "8868ef9e-a87d-4413-8aa8-9c9e23fe56fc", + "code": "InvoiceNO", + "name": "发票号码", + "label": "invoiceNO", + "bindingField": "invoiceNO", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "InvoiceNO", + "bindingPath": "invoiceNO", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "51461960-5be0-44f8-8a6f-0174a969100c", + "originalId": "51461960-5be0-44f8-8a6f-0174a969100c", + "code": "BillDetailNote", + "name": "费用说明", + "label": "billDetailNote", + "bindingField": "billDetailNote", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "BillDetailNote", + "bindingPath": "billDetailNote", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "费用报销明细" + } + }, + { + "id": "99d87cb2-bc3c-4552-9b74-4b5dade639e3", + "code": "AttaDetail", + "name": "附件明细", + "label": "attaDetails", + "type": { + "name": "AttaDetail", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "7d7b3b0c-3b05-4480-be8e-44aa434989a6", + "originalId": "7d7b3b0c-3b05-4480-be8e-44aa434989a6", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f337c392-5988-4d60-a6c5-408ae1273fc1", + "originalId": "f337c392-5988-4d60-a6c5-408ae1273fc1", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "abb0f176-2648-46f2-b2db-42d6fb252d50", + "originalId": "abb0f176-2648-46f2-b2db-42d6fb252d50", + "code": "FileName", + "name": "附件名称", + "label": "fileName", + "bindingField": "fileName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "FileName", + "bindingPath": "fileName", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "b9b23cd1-091f-44ec-b3f5-1e438d53ab96", + "originalId": "b9b23cd1-091f-44ec-b3f5-1e438d53ab96", + "code": "FilePath", + "name": "附件路径", + "label": "filePath", + "bindingField": "filePath", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 1000 + }, + "editor": { + "$type": "TextBox" + }, + "path": "FilePath", + "bindingPath": "filePath", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "8d0efbc1-acaf-4d97-8e5b-8443ec5cfbf3", + "originalId": "8d0efbc1-acaf-4d97-8e5b-8443ec5cfbf3", + "code": "FileSize", + "name": "附件大小", + "label": "fileSize", + "bindingField": "fileSize", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "FileSize", + "bindingPath": "fileSize", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "839dca6a-befa-4386-8a18-8b5959ba6300", + "originalId": "839dca6a-befa-4386-8a18-8b5959ba6300", + "code": "FileInfo", + "name": "附件信息", + "label": "fileID", + "bindingField": "fileID", + "type": { + "$type": "ObjectType", + "name": "AttachmentInfo839d", + "fields": [ + { + "$type": "SimpleField", + "id": "839dca6a-4fd6-49ff-a18a-f466a068f905", + "originalId": "ff73a947-4fd6-49ff-a18a-f466a068f905", + "code": "AttachmentId", + "name": "附件Id", + "label": "attachmentId", + "bindingField": "fileID_AttachmentId", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "FileID.AttachmentId", + "bindingPath": "fileID.attachmentId", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "839dca6a-1497-4526-86f9-290aab400e0b", + "originalId": "026b07a9-1497-4526-86f9-290aab400e0b", + "code": "FileName", + "name": "附件名称", + "label": "fileName", + "bindingField": "fileID_FileName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 128 + }, + "editor": { + "$type": "TextBox" + }, + "path": "FileID.FileName", + "bindingPath": "fileID.fileName", + "multiLanguage": false + } + ], + "displayName": "附件信息" + }, + "path": "FileID", + "bindingPath": "fileID" + } + ], + "entities": [], + "displayName": "附件明细" + } + } + ], + "displayName": "费用报销" + } + } + ], + "variables": [], + "eapiId": "ad508b92-838e-41cf-bb5c-175fc8173bf4" + } + ], + "stateMachines": [ + { + "id": "expenseMrgTxfLcjt_state_machine", + "name": "费用管理_通讯费_浪潮集团状态机", + "uri": "3743345f-6fc5-42be-a66a-2352933b2b96" + } + ], + "viewmodels": [ + { + "id": "root-viewmodel", + "code": "root-viewmodel", + "name": "费用报销", + "fields": [], + "stateMachine": "expenseMrgTxfLcjt_state_machine", + "serviceRefs": [], + "commands": [ + { + "id": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "code": "Load1", + "name": "加载", + "params": [ + { + "name": "action", + "shownName": "初始动作", + "value": "{UISTATE~/root-component/action}", + "description": null + } + ], + "handlerName": "Load", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "code": "LoadAndAdd1", + "name": "加载并新增", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "LoadAndAdd", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "code": "LoadAndView1", + "name": "加载并查看", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "LoadAndView", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "code": "LoadAndEdit1", + "name": "加载并编辑", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "LoadAndEdit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f90aadfa-988c-4da5-a5db-1416c3333794", + "code": "Add1", + "name": "新增数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "Add", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "code": "Edit1", + "name": "编辑数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "Edit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "31b814db-01e4-407d-8fad-0f08dbb01999", + "code": "Save1", + "name": "保存数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Save", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "code": "Cancel1", + "name": "取消变更", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Cancel", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "code": "Close1", + "name": "关闭", + "params": [ + { + "name": "url", + "shownName": "上级Url", + "value": "", + "description": null + }, + { + "name": "params", + "shownName": "路由参数", + "value": "", + "description": null + } + ], + "handlerName": "Close", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c8504c24-33e8-487a-91ce-2218b803fe01", + "code": "ChangeItem1", + "name": "ChangeItem", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "prev", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "code": "ChangeItem2", + "name": "ChangeItem2", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "next", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "2d57a211-6920-4cc5-9e1e-361d825a3642", + "code": "submitApproveWithState1", + "name": "提交审批(带状态)", + "params": [ + { + "name": "bizInstId", + "shownName": "业务单据ID", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "transitState", + "shownName": "状态迁移", + "value": "", + "description": null + } + ], + "handlerName": "submitApproveWithState", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "722fd986-cf74-45fe-95f4-66ca8cdebebb", + "code": "cancelApproveWithState1", + "name": "取消提交审批(带状态)", + "params": [ + { + "name": "bizInstId", + "shownName": "业务单据ID", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitState", + "shownName": "状态迁移", + "value": "", + "description": null + } + ], + "handlerName": "cancelApproveWithState", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c3c56f45-bd40-4294-8df1-c756eb7efbb1", + "code": "rootviewmodelAddAndInit1", + "name": "新增表单初始值1", + "params": [ + { + "name": "transit_迁移动作", + "shownName": "transit_迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "AddAndInit", + "cmpId": "4d910b64-ab62-4c5f-b775-822f3ff69ac3", + "shortcut": {}, + "extensions": [] + }, + { + "id": "a01473e3-f5b1-4984-a635-2a3bc1daa9b3", + "code": "rootviewmodelsubmitWithBizDefKey1", + "name": "提交审批1", + "params": [ + { + "name": "dataId", + "shownName": "单据id", + "value": "{DATA~/root-component/id}", + "description": "单据id" + }, + { + "name": "bizDefKey", + "shownName": "入口单据id", + "value": "eebe7704-b77a-46ee-a509-319fb4ec3004", + "description": "入口单据id" + }, + { + "name": "action", + "shownName": "迁移动作(可选)", + "value": "", + "description": "迁移动作(可选)" + } + ], + "handlerName": "submitWithBizDefKey", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "b08a9e14-be2b-4941-af12-9230b1eb08d6", + "code": "rootviewmodelcancelSubmitWithDataId1", + "name": "取消提交1", + "params": [ + { + "name": "dataId", + "shownName": "单据id", + "value": "{DATA~/root-component/id}", + "description": "单据id" + }, + { + "name": "bizDefKey", + "shownName": "入口单据id", + "value": "eebe7704-b77a-46ee-a509-319fb4ec3004", + "description": "入口单据id" + }, + { + "name": "action", + "shownName": "迁移动作(可选)", + "value": "", + "description": "迁移动作(可选)" + } + ], + "handlerName": "cancelSubmitWithDataId", + "cmpId": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "shortcut": {}, + "extensions": [] + }, + { + "id": "385d7a39-c401-458c-8c37-3d27863d26ac", + "code": "rootviewmodelqueryComments1", + "name": "查询评论1", + "params": [ + { + "name": "id", + "shownName": "数据Id", + "value": "{UISTATE~/root-component/id}", + "description": "数据Id" + }, + { + "name": "configId", + "shownName": "配置Id", + "value": "expenseInfo", + "description": "配置Id" + } + ], + "handlerName": "queryComments", + "cmpId": "76a6ee73-c068-4834-be8c-ef14e80fe325", + "shortcut": {}, + "extensions": [] + }, + { + "id": "02401a4f-8511-4c08-b3f0-ecca43788888", + "code": "rootviewmodelqueryAtUsers1", + "name": "加载At用户1", + "params": [], + "handlerName": "queryAtUsers", + "cmpId": "76a6ee73-c068-4834-be8c-ef14e80fe325", + "shortcut": {}, + "extensions": [] + }, + { + "id": "9711820d-6aa9-45b6-9f50-e6cd3bfce637", + "code": "rootviewmodeladdComment1", + "name": "提交评论1", + "params": [ + { + "name": "id", + "shownName": "单据编号", + "value": "{UISTATE~/root-component/id}", + "description": "单据编号" + }, + { + "name": "summary", + "shownName": "描述", + "value": "费用报销制单消息", + "description": "描述" + }, + { + "name": "configId", + "shownName": "配置Id", + "value": "expenseInfo", + "description": "配置Id" + } + ], + "handlerName": "addComment", + "cmpId": "76a6ee73-c068-4834-be8c-ef14e80fe325", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3db96cf6-55a9-4765-8731-9ce50c21c1cc", + "code": "rootviewmodelSendFRMSG1", + "name": "SendFRMSG1", + "params": [], + "handlerName": "SendFRMSG", + "cmpId": "fae33747-0b18-4dbb-9027-1ecbc829c271", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "enableUnifiedSession": false, + "pagination": { + "enable": false + } + }, + { + "id": "basic-form-viewmodel", + "code": "basic-form-viewmodel", + "name": "费用报销", + "fields": [ + { + "type": "Form", + "id": "172bafa9-405a-4d56-8190-b7b61a20cc59", + "fieldName": "billDate", + "groupId": "5b5890c0-1064-4789-ae1a-b0dac00a37bc", + "groupName": "订单信息", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "yyyy-MM-dd HH:mm:ss" + }, + "require": true + } + }, + { + "type": "Form", + "id": "aaa2146f-83f5-4d6d-a970-5e13b19c916f", + "fieldName": "billNote", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "MultiTextBox" + }, + "require": true, + "name": "报销说明" + } + }, + { + "type": "Form", + "id": "75b3994d-3311-4809-a4f8-881207bf17cc", + "fieldName": "billType", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "05121716-0101-468f-ae3f-40c76c0f06b0", + "fieldName": "billStatus_BillState", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": { + "name": "审批状态", + "require": true + } + }, + { + "type": "Form", + "id": "61dd7f98-d370-4708-a4c0-80835634927d", + "fieldName": "billCode", + "groupId": "5b5890c0-1064-4789-ae1a-b0dac00a37bc", + "groupName": "订单信息", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "单据编号", + "require": false + } + }, + { + "type": "Form", + "id": "86314c41-df2e-4ceb-aee5-13e32df7a3c1", + "fieldName": "employeeID_EmployeeID_Name", + "groupId": "5b5890c0-1064-4789-ae1a-b0dac00a37bc", + "groupName": "订单信息", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "Expense.employeeID_EmployeeID_EmployeeName", + "displayName": "员工帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "helpId": "915c8506-628b-4500-851a-04a83b432321", + "mapFields": "{'id':'employeeID.employeeID','name':'employeeID.employeeID_Name'}" + }, + "name": "报销人" + } + }, + { + "type": "Form", + "id": "f4d723e3-51e0-4ed0-bad0-cebb5e60f84d", + "fieldName": "secID_SecurityLevel_SecurityLevel_Name", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "单据密级", + "require": true, + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "Expense.secID_SecurityLevel_SecurityLevel_Name", + "displayName": "SecLevelFI", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "List", + "helpId": "11f843ff-93f0-478c-bafd-13c0f732479a", + "mapFields": "{'id':'secID.securityLevel.securityLevel','name':'secID.securityLevel.securityLevel_Name','seclevel':'secID.securityLevel.secID_Seclevel'}" + } + } + }, + { + "type": "Form", + "id": "1678e382-8ac4-492b-8d39-054445cdf06f", + "fieldName": "projectID_ProjectID_ProjectName", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "EnumField" + }, + "require": false, + "name": "费用项目" + } + }, + { + "type": "Form", + "id": "639efad2-d863-45d1-8f4a-9c1294ede3bd", + "fieldName": "domainID_DomainID_name", + "groupId": "5b5890c0-1064-4789-ae1a-b0dac00a37bc", + "groupName": "订单信息", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "所属组织", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "Expense.domainID_DomainID_name", + "displayName": "系统组织帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "TreeList", + "helpId": "b524a702-7323-4d46-998e-5ba0c6abcd49", + "mapFields": "{'id':'domainID.domainID','name':'domainID.domainID_name'}" + }, + "require": true + } + }, + { + "type": "Form", + "id": "12ba92ef-8b1f-4a3d-8484-ab90bb7bb093", + "fieldName": "finish", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "36078912-77f1-47d1-aa83-df25ec3496ec", + "fieldName": "shareOrg", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "Expense.shareOrg", + "displayName": "系统组织帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "TreeList", + "helpId": "b524a702-7323-4d46-998e-5ba0c6abcd49", + "mapFields": "{'name':'shareOrg'}" + } + } + }, + { + "type": "Form", + "id": "bf64eabb-db76-482e-bf3e-598a707cb958", + "fieldName": "shareProject", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "Expense.shareProject", + "displayName": "项目帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "projectName", + "valueField": "projectCode", + "displayType": "List", + "helpId": "c66bd976-7f44-4dfc-b969-18bb6ea923b9", + "mapFields": "" + } + } + }, + { + "type": "Form", + "id": "4c3d12c5-66e4-4e1b-81cb-d8d797d5aa60", + "fieldName": "totalSum", + "groupId": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "groupName": "报销详情", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "d1370325-df05-451a-bce0-f4226999f6a2", + "fieldName": "ext_gyzd_Lv9", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "d28b2295-c408-4570-acd7-520150acf2c9", + "fieldName": "ext_bxr_Lv9", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "serviceRefs": [], + "commands": [ + { + "id": "e3088a43-2e09-47a4-8677-b9d3779cb304", + "code": "Test1", + "name": "Test", + "params": [], + "handlerName": "Test", + "cmpId": "3655a6c9-ca22-44c5-9a94-09871a4db918", + "shortcut": {}, + "extensions": [] + }, + { + "id": "b74974d1-27fa-4d1b-a0b1-87966c199233", + "code": "Caculate1", + "name": "Caculate", + "params": [], + "handlerName": "Caculate", + "cmpId": "02fe2fde-09d6-4087-bc80-0ede61319964", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "parent": "root-viewmodel", + "enableValidation": true, + "pagination": { + "enable": false + } + }, + { + "id": "expensedetail-component-viewmodel", + "code": "expensedetail-component-viewmodel", + "name": "费用报销明细", + "fields": [ + { + "type": "Form", + "id": "797b34f9-cafd-4ab7-99fa-35dddc16a81d", + "fieldName": "billDetailDate", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "yyyy-MM-dd HH:mm:ss" + } + } + }, + { + "type": "Form", + "id": "2d6cdb35-e5a7-49e5-8352-5f4cb66416b2", + "fieldName": "billDetailAmount", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "valueChanged": "Caculate1" + }, + { + "type": "Form", + "id": "8868ef9e-a87d-4413-8aa8-9c9e23fe56fc", + "fieldName": "invoiceNO", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "51461960-5be0-44f8-8a6f-0174a969100c", + "fieldName": "billDetailNote", + "groupId": null, + "groupName": null, + "updateOn": "blur" + } + ], + "states": [], + "bindTo": "/expenseDetails", + "parent": "root-viewmodel", + "commands": [ + { + "id": "b19ae595-c2c1-4e08-9f20-6b1ccb3952d8", + "code": "expensedetailAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "d9f168c0-c5a9-4ff6-814e-009eb8d92cfb", + "code": "expensedetailRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/expensedetail-component/expenseDetails/id}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "17451014-b44b-419d-a7be-88c7a7c163d6", + "code": "Caculate1", + "name": "Caculate", + "params": [], + "handlerName": "Caculate", + "cmpId": "02fe2fde-09d6-4087-bc80-0ede61319964", + "shortcut": {}, + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": false + }, + { + "id": "attadetail-component-viewmodel", + "code": "attadetail-component-viewmodel", + "name": "附件明细", + "fields": [ + { + "type": "Form", + "id": "b9b23cd1-091f-44ec-b3f5-1e438d53ab96", + "fieldName": "filePath", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "839dca6a-1497-4526-86f9-290aab400e0b", + "fieldName": "fileID_FileName", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "附件信息名称" + } + } + ], + "states": [], + "bindTo": "/attaDetails", + "parent": "root-viewmodel", + "commands": [ + { + "id": "04e9a99b-1eef-4c39-a710-da6c8d1624ed", + "code": "attadetailAddItem1", + "name": "新增子表数据", + "params": [], + "handlerName": "AddItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "269d430b-7c9f-4bbf-a838-6386562aefad", + "code": "attadetailRemoveItem1", + "name": "删除子表数据", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{DATA~/attadetail-component/attaDetails/fileID/attachmentId}", + "description": null + } + ], + "handlerName": "RemoveItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3ec7e83a-72fd-495a-ad6a-65814bce3cc4", + "code": "UploadAndBatchAddRows1", + "name": "上传并批量新增行", + "params": [ + { + "name": "attachmentInfoFieldPath", + "shownName": "附件信息字段路径", + "value": "/attaDetails/fileInfo", + "description": "附件信息字段路径" + }, + { + "name": "rootDirId", + "shownName": "根目录id", + "value": "default-root", + "description": "根目录id" + }, + { + "name": "subDirName", + "shownName": "子目录名称", + "value": "{UISTATE~/root-component/id}", + "description": "子目录名称" + }, + { + "name": "fileType", + "shownName": "附件类型(如.txt,.doc)", + "value": "", + "description": "附件类型(如.txt,.doc)" + } + ], + "handlerName": "UploadAndBatchAddRows", + "cmpId": "2eb7bbd1-fabd-4d0f-991d-7242f53225b1", + "shortcut": {}, + "extensions": [] + }, + { + "id": "8301fb5f-fa86-41ce-af41-b581d67e1b8e", + "code": "download1", + "name": "下载附件", + "params": [ + { + "name": "attachmentId", + "shownName": "附件id", + "value": "{DATA~/attadetail-component/attaDetails/fileID/attachmentId}", + "description": "附件id" + }, + { + "name": "rootId", + "shownName": "根目录id", + "value": "default-root", + "description": "根目录id" + } + ], + "handlerName": "download", + "cmpId": "2eb7bbd1-fabd-4d0f-991d-7242f53225b1", + "shortcut": {}, + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": false, + "pagination": { + "enable": false + } + } + ], + "components": [ + { + "id": "root-component", + "type": "Component", + "viewModel": "root-viewmodel", + "componentType": "Frame", + "onInit": "rootviewmodelSendFRMSG1", + "contents": [ + { + "id": "root-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-page f-page-card f-page-is-mainsubcard" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-nav", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header-base" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-title-container", + "type": "ContentContainer", + "appearance": { + "class": "f-title" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header-title", + "type": "HtmlTemplate", + "appearance": { + "class": "f-title-text" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "title": "费用报销", + "binding": null, + "displayTemplate": "", + "html": "\r\n

费用报销单

\r\n
\r\n\t\r\n
" + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + }, + { + "id": "page-header-toolbar", + "type": "ToolBar", + "appearance": { + "class": "col-7 f-toolbar" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "items": [ + { + "id": "button-add", + "type": "ToolBarItem", + "text": "新增", + "appearance": { + "class": "btn-primary" + }, + "disable": "!viewModel.stateMachine['canAdd']", + "visible": true, + "click": "Add1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-edit", + "type": "ToolBarItem", + "text": "编辑", + "appearance": null, + "disable": "!viewModel.stateMachine['canEdit']", + "visible": true, + "click": "Edit1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-save", + "type": "ToolBarItem", + "text": "保存", + "appearance": null, + "disable": "!viewModel.stateMachine['canSave']", + "visible": true, + "click": "Save1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-cancel", + "type": "ToolBarItem", + "text": "取消", + "appearance": null, + "disable": "!viewModel.stateMachine['canCancel']", + "visible": true, + "click": "Cancel1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-close", + "type": "ToolBarItem", + "text": "关闭", + "appearance": null, + "disable": false, + "visible": true, + "click": "Close1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_8666", + "type": "ToolBarItem", + "appearance": null, + "disable": "!viewModel.stateMachine['canAudit']", + "text": "提交审批", + "visible": true, + "click": "rootviewmodelsubmitWithBizDefKey1", + "items": [], + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_6367", + "type": "ToolBarItem", + "appearance": null, + "disable": "!viewModel.stateMachine['canCancelAudit']", + "text": "取消提交审批", + "visible": true, + "click": "rootviewmodelcancelSubmitWithDataId1", + "items": [], + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_6867", + "type": "ToolBarItem", + "appearance": null, + "disable": false, + "text": "扩展", + "visible": false, + "click": "root-viewmodel.basic-form-viewmodel.Test1", + "items": [], + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + } + ], + "visible": true + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + }, + { + "id": "main-container", + "type": "ContentContainer", + "appearance": { + "class": "f-page-main" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "basic-form-component-ref", + "type": "ComponentRef", + "component": "basic-form-component", + "visible": true + }, + { + "id": "detail-container", + "type": "ContentContainer", + "appearance": { + "class": "f-struct-wrapper" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "detail-section", + "type": "Section", + "appearance": { + "class": "f-section-tabs f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "明细信息", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": true, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "detail-tab", + "type": "Tab", + "controlSource": "Farris", + "appearance": { + "class": "f-component-tabs f-tabs-has-grid" + }, + "selected": "expensedetail-tab-page", + "size": null, + "position": "top", + "contents": [ + { + "id": "expensedetail-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "费用报销明细", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "expensedetail-component-ref", + "type": "ComponentRef", + "component": "expensedetail-component", + "visible": true + } + ], + "toolbar": { + "id": "expensedetail-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "expensedetail-button-add", + "type": "TabToolbarItem", + "title": "新增", + "disable": "!viewModel.stateMachine['canAddDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.expensedetail-component-viewmodel.expensedetailAddItem1" + }, + { + "id": "expensedetail-button-remove", + "type": "TabToolbarItem", + "title": "删除", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.expensedetail-component-viewmodel.expensedetailRemoveItem1" + } + ] + }, + "visible": true + }, + { + "id": "attadetail-tab-page", + "type": "TabPage", + "controlSource": "Farris", + "title": "附件明细", + "appearance": null, + "size": null, + "removeable": false, + "headerTemplate": null, + "contents": [ + { + "id": "attadetail-component-ref", + "type": "ComponentRef", + "component": "attadetail-component", + "visible": true + } + ], + "toolbar": { + "id": "attadetail-tab-toolbar", + "type": "TabToolbar", + "position": "inHead", + "contents": [ + { + "id": "tabToolbarItem_4804", + "type": "TabToolbarItem", + "title": "上传附件", + "disable": false, + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.attadetail-component-viewmodel.UploadAndBatchAddRows1" + }, + { + "id": "tabToolbarItem_8469", + "type": "TabToolbarItem", + "title": "下载附件", + "disable": false, + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.attadetail-component-viewmodel.download1" + }, + { + "id": "attadetail-button-remove", + "type": "TabToolbarItem", + "title": "删除附件", + "disable": "!viewModel.stateMachine['canRemoveDetail']", + "appearance": { + "class": "btn btn-link mr-2" + }, + "visible": true, + "click": "root-viewmodel.attadetail-component-viewmodel.attadetailRemoveItem1" + } + ] + }, + "visible": true + } + ], + "tabChange": null, + "tabRemove": null, + "contentFill": false, + "autoTitleWidth": true, + "visible": true, + "draggable": false + } + ], + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + }, + { + "id": "f-struct-wrapper", + "type": "ContentContainer", + "contents": [ + { + "id": "section", + "type": "Section", + "appearance": { + "class": "f-section-in-mainsubcard" + }, + "mainTitle": "评论", + "contents": [ + { + "id": "discussion-editor", + "type": "DiscussionEditor", + "visible": true, + "queryUserCommand": "rootviewmodelqueryAtUsers1", + "addCommentCommand": "rootviewmodeladdComment1" + }, + { + "id": "container", + "type": "ContentContainer", + "appearance": { + "style": "margin-top:20px;" + }, + "contents": [ + { + "id": "discussion-list", + "type": "DiscussionList", + "supportPaging": true, + "visible": true, + "queryCommentsCommand": "rootviewmodelqueryComments1" + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "afterViewInit": "", + "visible": true + }, + { + "id": "basic-form-component", + "type": "Component", + "viewModel": "basic-form-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "basic-form-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "单据信息", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": true, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "basic-form-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "5b5890c0-1064-4789-ae1a-b0dac00a37bc", + "type": "FieldSet", + "title": "订单信息", + "appearance": { + "class": "col-12 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "form_billCode", + "type": "TextBox", + "title": "单据编号", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "billCode", + "field": "61dd7f98-d370-4708-a4c0-80835634927d" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "billCode", + "isTextArea": null, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "titleSourceType": "static", + "enableTips": true + }, + { + "id": "domainID_DomainID_name_639efad2_d863_45d1_8f4a_9c1294ede3bd_yyfj", + "type": "LookupEdit", + "title": "所属组织", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "domainID_DomainID_name", + "field": "639efad2-d863-45d1-8f4a-9c1294ede3bd" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "Expense.domainID_DomainID_name", + "displayName": "系统组织帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'domainID.domainID','name':'domainID.domainID_name'}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": true, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "domainID.domainID_name", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "helpId": "b524a702-7323-4d46-998e-5ba0c6abcd49", + "cascadeStatus": "enable", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "onlySelectLeaf": "default" + }, + { + "id": "form_employeeID_EmployeeID_EmployeeName", + "type": "LookupEdit", + "title": "报销人", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "employeeID_EmployeeID_Name", + "field": "86314c41-df2e-4ceb-aee5-13e32df7a3c1", + "fullPath": "EmployeeID.EmployeeID_Name" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "Expense.employeeID_EmployeeID_EmployeeName", + "displayName": "员工帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "code", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'employeeID.employeeID','name':'employeeID.employeeID_Name'}", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": false, + "editable": false, + "path": "employeeID.employeeID_EmployeeName", + "helpId": "915c8506-628b-4500-851a-04a83b432321", + "clear": null, + "isTextArea": null, + "expandLevel": -1, + "isRecordSize": false, + "lookupStyle": "popup", + "enableFullTree": false, + "loadTreeDataType": "default", + "beforeShow": null, + "beforeHide": null, + "onShown": null, + "onHidden": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableClear": true, + "enableCascade": false, + "cascadeStatus": "enable", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "onlySelectLeaf": "default" + }, + { + "id": "billDate_172bafa9_405a_4d56_8190_b7b61a20cc59_myzp", + "type": "DateBox", + "title": "制单日期", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "billDate", + "field": "172bafa9-405a-4d56-8190-b7b61a20cc59" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "placeHolder": "请选择", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "DatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "isTextArea": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "billDate", + "format": "'yyyy-MM-dd HH:mm:ss'", + "controlSource": "Farris", + "dateRangeDatesDelimiter": "~", + "titleSourceType": "static", + "localization": false + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "draggable": false + }, + { + "id": "e47ca568-35d2-451d-93ba-dd2c1c47f8b6", + "type": "FieldSet", + "title": "报销详情", + "appearance": { + "class": "col-12 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "totalSum_4c3d12c5_66e4_4e1b_81cb_d8d797d5aa60_bs0x", + "type": "NumericBox", + "title": "报帐金额", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "totalSum", + "field": "4c3d12c5-66e4-4e1b-81cb-d8d797d5aa60" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 20, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": true, + "maxLength": 50, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "totalSum", + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "shareOrg_36078912_77f1_47d1_aa83_df25ec3496ec_5ugt", + "type": "LookupEdit", + "title": "分摊组织", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "shareOrg", + "field": "36078912-77f1-47d1-aa83-df25ec3496ec" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "Expense.shareOrg", + "displayName": "系统组织帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "TreeList", + "multiSelect": true, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'name':'shareOrg'}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": true, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "enableCascade": false, + "cascadeStatus": "enable", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "shareOrg", + "expandLevel": -1, + "isRecordSize": false, + "helpId": "b524a702-7323-4d46-998e-5ba0c6abcd49", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "onlySelectLeaf": "default" + }, + { + "id": "form_billType", + "type": "EnumField", + "title": "报销类型", + "binding": { + "type": "Form", + "path": "billType", + "field": "75b3994d-3311-4809-a4f8-881207bf17cc" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "enumData": [ + { + "value": "travel", + "name": "差旅费" + }, + { + "value": "traffic", + "name": "交通费" + }, + { + "value": "communication", + "name": "通讯费" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "billType", + "isTextArea": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "controlSource": "Kendo", + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "form_billStatus_BillState", + "type": "EnumField", + "title": "审批状态", + "binding": { + "type": "Form", + "path": "billStatus_BillState", + "field": "05121716-0101-468f-ae3f-40c76c0f06b0" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "enumData": [ + { + "value": "Billing", + "name": "制单" + }, + { + "value": "SubmitApproval", + "name": "提交审批" + }, + { + "value": "Approved", + "name": "审批通过" + }, + { + "value": "ApprovalNotPassed", + "name": "审批不通过" + }, + { + "value": "Abort", + "name": "流程终止" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "billStatus.billState", + "isTextArea": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "controlSource": "Kendo", + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "finish_12ba92ef_8b1f_4a3d_8484_ab90bb7bb093_wfl9", + "type": "EnumField", + "title": "完成标志", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "finish", + "field": "12ba92ef-8b1f-4a3d-8484-ab90bb7bb093" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "UnFinished", + "name": "未完成" + }, + { + "value": "Finished", + "name": "已完成" + } + ], + "holdPlace": false, + "isTextArea": true, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "finish", + "viewType": "text", + "enableCancelSelected": false, + "dataSourceType": "static", + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "projectID_ProjectID_ProjectName_1678e382_8ac4_492b_8d39_054445cdf06f_2e4w", + "type": "EnumField", + "title": "费用项目", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "projectID_ProjectID_ProjectName", + "field": "1678e382-8ac4-492b-8d39-054445cdf06f" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "holdPlace": false, + "isTextArea": true, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": false, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "enableCancelSelected": false, + "beforeShow": null, + "beforeHide": null, + "dataSourceType": "static", + "viewType": "text", + "path": "projectID.projectID_ProjectName", + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "secID_SecurityLevel_SecurityLevel_Name_f4d723e3_51e0_4ed0_bad0_cebb5e60f84d_dns1", + "type": "LookupEdit", + "title": "单据密级", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "secID_SecurityLevel_SecurityLevel_Name", + "field": "f4d723e3-51e0-4ed0-bad0-cebb5e60f84d" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "Expense.secID_SecurityLevel_SecurityLevel_Name", + "displayName": "SecLevelFI", + "idField": "id", + "type": "ViewObject" + }, + "textField": "name", + "valueField": "id", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'secID.securityLevel.securityLevel','name':'secID.securityLevel.securityLevel_Name','seclevel':'secID.securityLevel.secID_Seclevel'}", + "lookupStyle": "popup", + "holdPlace": false, + "isTextArea": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "secID.securityLevel.securityLevel_Name", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "helpId": "11f843ff-93f0-478c-bafd-13c0f732479a", + "cascadeStatus": "enable", + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "onlySelectLeaf": "default" + }, + { + "id": "shareProject_bf64eabb_db76_482e_bf3e_598a707cb958_su0g", + "type": "LookupEdit", + "title": "分摊项目", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "shareProject", + "field": "bf64eabb-db76-482e-bf3e-598a707cb958" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "Expense.shareProject", + "displayName": "项目帮助", + "idField": "id", + "type": "ViewObject" + }, + "textField": "projectName", + "valueField": "projectCode", + "displayType": "List", + "multiSelect": true, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "", + "lookupStyle": "combolist", + "holdPlace": false, + "isTextArea": true, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "enableCascade": false, + "cascadeStatus": "enable", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "shareProject", + "helpId": "c66bd976-7f44-4dfc-b969-18bb6ea923b9", + "expandLevel": -1, + "isRecordSize": false, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true, + "onlySelectLeaf": "default" + }, + { + "id": "form_billNote", + "type": "MultiTextBox", + "title": "报销说明", + "appearance": { + "class": "col-12 farris-group-auto" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "billNote", + "field": "aaa2146f-83f5-4d6d-a970-5e13b19c916f" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 0, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "billNote", + "isTextArea": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "titleSourceType": "static" + }, + { + "id": "ext_gyzd_Lv9_d1370325_df05_451a_bce0_f4226999f6a2_ttep", + "type": "TextBox", + "titleSourceType": "static", + "title": "公有字段", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_gyzd_Lv9", + "field": "d1370325-df05-451a-bce0-f4226999f6a2" + }, + "readonly": false, + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": 0, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableTips": true, + "path": "ext_gyzd_Lv9", + "isRTControl": true + }, + { + "id": "ext_bxr_Lv9_d28b2295_c408_4570_acd7_520150acf2c9_yx1y", + "type": "TextBox", + "titleSourceType": "static", + "title": "报销人", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ext_bxr_Lv9", + "field": "d28b2295-c408-4570-acd7-520150acf2c9" + }, + "readonly": false, + "require": false, + "disable": false, + "placeHolder": "", + "maxLength": 36, + "holdPlace": false, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": 0, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "enableTips": true, + "path": "ext_bxr_Lv9", + "isRTControl": true + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "draggable": false + } + ], + "controlsInline": false, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "expensedetail-component", + "type": "Component", + "viewModel": "expensedetail-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "expensedetail-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "dataGrid_expensedetail", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "expenseDetails", + "fields": [ + { + "id": "gridField_797b34f9-cafd-4ab7-99fa-35dddc16a81d_billDetailDate", + "type": "GridField", + "controlSource": "Farris", + "caption": "费用日期", + "binding": { + "type": "Form", + "path": "billDetailDate", + "field": "797b34f9-cafd-4ab7-99fa-35dddc16a81d" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": { + "width": 120 + }, + "dataField": "billDetailDate", + "dataType": "datetime", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "billDetailDate_797b34f9_cafd_4ab7_99fa_35dddc16a81d_qxrn", + "type": "DateBox", + "title": "费用日期", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "billDetailDate", + "field": "797b34f9-cafd-4ab7-99fa-35dddc16a81d" + }, + "require": false, + "disable": false, + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "placeHolder": "请选择", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "DatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "isTextArea": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "billDetailDate", + "format": "yyyy-MM-dd HH:mm:ss", + "controlSource": "Farris", + "dateRangeDatesDelimiter": "~", + "localization": false + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "textAlign": "left", + "hAlign": "left", + "vAlign": "middle", + "formatter": { + "type": "none" + }, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "visible": true, + "enableFilter": false, + "headerStyler": "", + "readonly": false, + "styler": null, + "localization": false + }, + { + "id": "gridField_2d6cdb35-e5a7-49e5-8352-5f4cb66416b2_billDetailAmount", + "type": "GridField", + "controlSource": "Farris", + "caption": "报销金额", + "captionTemplate": null, + "dataField": "billDetailAmount", + "dataType": "number", + "binding": { + "type": "Form", + "path": "billDetailAmount", + "field": "2d6cdb35-e5a7-49e5-8352-5f4cb66416b2" + }, + "enumData": null, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "displayTemplate": null, + "editor": { + "id": "gridFieldEditor_billDetailAmount", + "type": "NumericBox", + "title": "数值框", + "binding": { + "type": "Form", + "path": "billDetailAmount", + "field": "2d6cdb35-e5a7-49e5-8352-5f4cb66416b2" + }, + "placeHolder": "", + "require": false, + "disable": false, + "format": "n2", + "precision": 2, + "validation": null, + "value": null, + "maxValue": null, + "minValue": null, + "maxLength": 18, + "spin": null, + "step": 1, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "controlSource": "Kendo", + "formatter": null, + "parser": null, + "useThousands": true, + "textAlign": "left", + "canNull": true, + "bigNumber": false, + "precisionSourceType": "static" + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "path": "billDetailAmount", + "precision": 2, + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "visible": true, + "readonly": false, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "localization": false + }, + { + "id": "gridField_8868ef9e-a87d-4413-8aa8-9c9e23fe56fc_invoiceNO", + "type": "GridField", + "controlSource": "Farris", + "caption": "发票号码", + "captionTemplate": null, + "dataField": "invoiceNO", + "dataType": "string", + "binding": { + "type": "Form", + "path": "invoiceNO", + "field": "8868ef9e-a87d-4413-8aa8-9c9e23fe56fc" + }, + "enumData": null, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "displayTemplate": null, + "editor": { + "id": "gridFieldEditor_invoiceNO", + "type": "TextBox", + "title": "文本", + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "invoiceNO", + "field": "8868ef9e-a87d-4413-8aa8-9c9e23fe56fc" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isPassword": false, + "enableTips": true + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "path": "invoiceNO", + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "visible": true, + "readonly": false, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "localization": false + }, + { + "id": "gridField_51461960-5be0-44f8-8a6f-0174a969100c_billDetailNote", + "type": "GridField", + "controlSource": "Farris", + "caption": "费用说明", + "captionTemplate": null, + "dataField": "billDetailNote", + "dataType": "string", + "binding": { + "type": "Form", + "path": "billDetailNote", + "field": "51461960-5be0-44f8-8a6f-0174a969100c" + }, + "enumData": null, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "displayTemplate": null, + "editor": { + "id": "gridFieldEditor_billDetailNote", + "type": "MultiTextBox", + "title": "多行文本框", + "binding": { + "type": "Form", + "path": "billDetailNote", + "field": "51461960-5be0-44f8-8a6f-0174a969100c" + }, + "placeHolder": "", + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "maxLength": 0, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "editType": "default", + "dialogWidth": 500, + "dialogHeight": 400 + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "path": "billDetailNote", + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "visible": true, + "readonly": false, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "localization": false + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "identifyField": null, + "multiSelect": false, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "onSelectionChange": "", + "showLineNumber": false, + "appendRow": "expensedetailAddItem1", + "pageChange": null, + "fitColumns": true, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "disableRow": null, + "checkedChange": null, + "showAllCheckbox": false, + "multiSort": false, + "dblClickRow": null, + "showBorder": false, + "pagination": true, + "striped": true, + "beforeEdit": null, + "mergeCell": false, + "visible": true, + "virtualized": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "footerDataFrom": "client", + "footerDataCommand": null, + "checkOnSelect": true, + "selectOnCheck": true, + "autoFitColumns": false, + "showGroupColumn": true, + "styler": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": null, + "useControlPanel": false, + "autoHeight": false, + "groupFooter": false, + "beforeUnCheck": null, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageSize": false, + "draggable": false, + "showSelectedList": false, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + }, + { + "id": "attadetail-component", + "type": "Component", + "viewModel": "attadetail-component-viewmodel", + "appearance": { + "class": "f-struct-is-subgrid" + }, + "contents": [ + { + "id": "attadetail-component-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-grid-is-sub f-utils-flex-column" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "dataGrid_attadetail", + "type": "DataGrid", + "controlSource": "Farris", + "dataSource": "attaDetails", + "fields": [ + { + "id": "gridField_839dca6a-1497-4526-86f9-290aab400e0b_fileID_FileName", + "type": "GridField", + "caption": "附件信息名称", + "binding": { + "type": "Form", + "path": "fileID_FileName", + "field": "839dca6a-1497-4526-86f9-290aab400e0b" + }, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "dataField": "fileID.fileName", + "dataType": "string", + "displayTemplate": null, + "captionTemplate": null, + "editor": { + "id": "gridFieldEditor_fileID_FileName", + "type": "TextBox", + "title": "附件信息名称", + "appearance": { + "class": "" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "fileID_FileName", + "field": "839dca6a-1497-4526-86f9-290aab400e0b" + }, + "readonly": false, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 128, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "path": "fileID.fileName" + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "format": "", + "enumData": null, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "multiLanguage": false + }, + { + "id": "gridField_b9b23cd1-091f-44ec-b3f5-1e438d53ab96_filePath", + "type": "GridField", + "controlSource": "Farris", + "caption": "附件路径", + "captionTemplate": null, + "dataField": "filePath", + "dataType": "string", + "binding": { + "type": "Form", + "path": "filePath", + "field": "b9b23cd1-091f-44ec-b3f5-1e438d53ab96" + }, + "enumData": null, + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "displayTemplate": null, + "editor": { + "id": "gridFieldEditor_filePath", + "type": "TextBox", + "title": "文本", + "appearance": null, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "binding": { + "type": "Form", + "path": "filePath", + "field": "b9b23cd1-091f-44ec-b3f5-1e438d53ab96" + }, + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 1000, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isPassword": false, + "enableTips": true + }, + "draggable": false, + "frozen": false, + "sortable": true, + "sortOrder": null, + "resizeable": true, + "aggregate": { + "type": "none" + }, + "groupAggregate": { + "type": "none" + }, + "styler": "", + "colTemplate": "", + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "path": "filePath", + "textAlign": "left", + "hAlign": "left", + "formatter": { + "type": "none" + }, + "visible": true, + "readonly": false, + "showTips": false, + "tipContent": null, + "multiLanguage": false, + "vAlign": "middle", + "enableFilter": false, + "headerStyler": "", + "localization": false + } + ], + "appearance": { + "class": "f-component-grid f-utils-fill" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "disable": false, + "focusedItem": null, + "focusedIndex": null, + "identifyField": null, + "multiSelect": false, + "selectable": null, + "itemTemplate": null, + "toolBar": null, + "summary": null, + "groupable": false, + "group": null, + "editable": "viewModel.stateMachine['editable']", + "fieldEditable": true, + "onSelectionChange": "", + "showLineNumber": false, + "appendRow": "attadetailAddItem1", + "pageChange": null, + "fitColumns": true, + "beforeSelect": null, + "beforeUnSelect": null, + "beforeCheck": null, + "disableRow": null, + "checkedChange": null, + "showAllCheckbox": false, + "multiSort": false, + "dblClickRow": null, + "showBorder": false, + "pagination": true, + "striped": true, + "beforeEdit": null, + "mergeCell": false, + "visible": true, + "virtualized": false, + "nowrap": true, + "remoteSort": false, + "columnSorted": null, + "footerDataFrom": "client", + "footerDataCommand": null, + "checkOnSelect": true, + "selectOnCheck": true, + "autoFitColumns": false, + "showGroupColumn": true, + "styler": null, + "enableFilterRow": false, + "remoteFilter": false, + "showFilterBar": null, + "useControlPanel": false, + "autoHeight": false, + "groupFooter": false, + "beforeUnCheck": null, + "lockPagination": "viewModel.stateMachine&&viewModel.stateMachine['editable']", + "showPageSize": false, + "draggable": false, + "showSelectedList": false, + "lineNumberWidth": 36, + "enableMorePageSelect": false, + "footerHeight": 29, + "headerWrap": false, + "emptyDataHeight": 240, + "rowHeight": 30 + } + ], + "isScrollspyContainer": false, + "visible": true, + "draggable": false + } + ], + "componentType": "dataGrid", + "onInit": "", + "afterViewInit": "" + } + ], + "webcmds": [ + { + "id": "8172a979-2c80-4637-ace7-b13074d3f393", + "path": "/projects/packages/Inspur.GS.Gsp.Web.WebCmp/webcmd", + "name": "CardController.webcmd", + "refedHandlers": [ + { + "host": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "handler": "Load" + }, + { + "host": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "handler": "LoadAndAdd" + }, + { + "host": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "handler": "LoadAndView" + }, + { + "host": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "handler": "LoadAndEdit" + }, + { + "host": "f90aadfa-988c-4da5-a5db-1416c3333794", + "handler": "Add" + }, + { + "host": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "handler": "Edit" + }, + { + "host": "31b814db-01e4-407d-8fad-0f08dbb01999", + "handler": "Save" + }, + { + "host": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "handler": "Cancel" + }, + { + "host": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "handler": "Close" + }, + { + "host": "c8504c24-33e8-487a-91ce-2218b803fe01", + "handler": "ChangeItem" + }, + { + "host": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "handler": "ChangeItem" + }, + { + "host": "b19ae595-c2c1-4e08-9f20-6b1ccb3952d8", + "handler": "AddItem" + }, + { + "host": "d9f168c0-c5a9-4ff6-814e-009eb8d92cfb", + "handler": "RemoveItem" + }, + { + "host": "04e9a99b-1eef-4c39-a710-da6c8d1624ed", + "handler": "AddItem" + }, + { + "host": "269d430b-7c9f-4bbf-a838-6386562aefad", + "handler": "RemoveItem" + } + ] + }, + { + "id": "a7cb7d01-9df1-4a32-8202-99c9d0f4c339", + "path": null, + "name": "ApproveController.webcmd", + "refedHandlers": [ + { + "host": "2d57a211-6920-4cc5-9e1e-361d825a3642", + "handler": "submitApproveWithState" + }, + { + "host": "722fd986-cf74-45fe-95f4-66ca8cdebebb", + "handler": "cancelApproveWithState" + }, + { + "host": "280c69b7-c682-4192-8e87-aee4ab7bd26b", + "handler": "submitApproveWithBizDefKey" + }, + { + "host": "75e1c925-ef62-4914-8e27-8c4e97d43a63", + "handler": "submitApproveWithBizDefKey" + }, + { + "host": "a01473e3-f5b1-4984-a635-2a3bc1daa9b3", + "handler": "submitWithBizDefKey" + }, + { + "host": "b08a9e14-be2b-4941-af12-9230b1eb08d6", + "handler": "cancelSubmitWithDataId" + } + ] + }, + { + "id": "2eb7bbd1-fabd-4d0f-991d-7242f53225b1", + "path": null, + "name": "AttachmentController.webcmd", + "refedHandlers": [ + { + "host": "3ec7e83a-72fd-495a-ad6a-65814bce3cc4", + "handler": "UploadAndBatchAddRows" + }, + { + "host": "8301fb5f-fa86-41ce-af41-b581d67e1b8e", + "handler": "download" + } + ] + }, + { + "id": "3655a6c9-ca22-44c5-9a94-09871a4db918", + "path": "FSSC/ExpenseMrg/Expense/bo-expensefront/metadata/components", + "name": "ExpenseMrg_frm_TestCommand.webcmd", + "refedHandlers": [ + { + "host": "e3088a43-2e09-47a4-8677-b9d3779cb304", + "handler": "Test" + } + ] + }, + { + "id": "02fe2fde-09d6-4087-bc80-0ede61319964", + "path": "FSSC/ExpenseMrg/Expense/bo-expensefront/metadata/components", + "name": "ExpenseMrg_frm_CaculateCMD.webcmd", + "refedHandlers": [ + { + "host": "b74974d1-27fa-4d1b-a0b1-87966c199233", + "handler": "Caculate" + }, + { + "host": "17451014-b44b-419d-a7be-88c7a7c163d6", + "handler": "Caculate" + } + ] + }, + { + "id": "4d910b64-ab62-4c5f-b775-822f3ff69ac3", + "path": "FSSC/ExpenseMrg/Expense/bo-expensefront/metadata/components", + "name": "ExpenseMrg_frm_ExpenseExtend.webcmd", + "refedHandlers": [ + { + "host": "c3c56f45-bd40-4294-8df1-c756eb7efbb1", + "handler": "AddAndInit" + } + ] + }, + { + "id": "76a6ee73-c068-4834-be8c-ef14e80fe325", + "path": "Gsp/Web/WebCmp/bo-webcmp/metadata/webcmd", + "name": "DiscussionGroupController.webcmd", + "refedHandlers": [ + { + "host": "385d7a39-c401-458c-8c37-3d27863d26ac", + "handler": "queryComments" + }, + { + "host": "02401a4f-8511-4c08-b3f0-ecca43788888", + "handler": "queryAtUsers" + }, + { + "host": "9711820d-6aa9-45b6-9f50-e6cd3bfce637", + "handler": "addComment" + } + ] + }, + { + "id": "fae33747-0b18-4dbb-9027-1ecbc829c271", + "path": "FSSC/ExpenseMrg/Expense/bo-expensefront/metadata/components", + "name": "ExpenseMrg_frm_SendFRMSG.webcmd", + "refedHandlers": [ + { + "host": "3db96cf6-55a9-4765-8731-9ce50c21c1cc", + "handler": "SendFRMSG" + } + ] + } + ], + "serviceRefs": [], + "expressions": [ + { + "fieldId": "172bafa9-405a-4d56-8190-b7b61a20cc59", + "expression": [ + { + "type": "compute", + "value": "{\"expr\":\"if(Expense.id){\\r\\nreturn new Date().toLocaleDateString().replace(/\\\\//g,'-');\\r\\n}else{\\r\\n return '';\\r\\n}\\r\\n\",\"sexpr\":\"\"}" + } + ] + }, + { + "fieldId": "36078912-77f1-47d1-aa83-df25ec3496ec", + "expression": [ + { + "type": "readonly", + "value": "{\"expr\":\"if(parseInt(Expense.totalSum)>0){\\r\\n return false;\\r\\n}else{\\r\\n return true;\\r\\n}\",\"sexpr\":\"\"}" + } + ] + } + ] + }, + "options": { + "enableDragAndDropToModifyLayout": false + } +} \ No newline at end of file diff --git a/web-form-jitengine/src/test/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImplTest.java b/web-form-jitengine/src/test/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImplTest.java new file mode 100644 index 00000000..a48f483b --- /dev/null +++ b/web-form-jitengine/src/test/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImplTest.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.npmpackage.core.webservice; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class NpmPacakgeWebServiceImplTest { + + @Test + void fromCharCode() { +// NpmPacakgeWebServiceImpl impl=new NpmPacakgeWebServiceImpl(); +// String result= impl.fromCharCode(3,"guozhiqi"); +// System.out.println(result); +// +// +// String des= this.fromCharCode(3,result); +// System.out.println(des); + } + + public String fromCharCode(int offset, String source) { + char[] arrCharSource = source.toCharArray(); + StringBuilder builder = new StringBuilder(arrCharSource.length); + + for (char codePoint : arrCharSource) { + + builder.append((char) (codePoint - offset)); + } + return builder.toString(); + } +} diff --git a/web-form-metadata-api/pom.xml b/web-form-metadata-api/pom.xml new file mode 100644 index 00000000..a05ea9ea --- /dev/null +++ b/web-form-metadata-api/pom.xml @@ -0,0 +1,22 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-formmetadata-api + + jar + + + + io.iec.edp + caf-boot-starter-rest-server + + + diff --git a/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataCommonService.java b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataCommonService.java new file mode 100644 index 00000000..bf236659 --- /dev/null +++ b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataCommonService.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.formmetadata.api; + +import com.inspur.edp.web.formmetadata.api.entity.FormSuInfoEntity; + +public interface FormMetadataCommonService { + /** + * 依据业务对象id获取对应的关键应用信息 + * @param bizObjId + * @return + */ + FormSuInfoEntity getSuInfoWithBizobjId(String bizObjId); +} diff --git a/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataWebService.java b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataWebService.java new file mode 100644 index 00000000..f57cfc4a --- /dev/null +++ b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/FormMetadataWebService.java @@ -0,0 +1,79 @@ +package com.inspur.edp.web.formmetadata.api; + +import com.inspur.edp.web.formmetadata.api.entity.FormSuInfoEntity; +import com.inspur.edp.web.formmetadata.api.entity.ReplicateFormRequestBody; +import com.inspur.edp.web.formmetadata.api.entity.SuInfoWithBizobjIdEntity; +import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import java.util.List; + +@Path("/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface FormMetadataWebService { + /** + * 同步语言包到表单元数据 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Path("sync-language-package") + @POST + void SynchronizeLanuagePackage(@QueryParam("fileName") String fileName, @QueryParam("path") String path); + + /** + * 导出表单元数据中语言包 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Path("export-language-package") + @POST + void ExportLanguagePackage(@QueryParam("fileName") String fileName, @QueryParam("path") String path); + + /** + * 同步本地语言包到表单元数据 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Path("sync-local-language-package") + @POST + void SynchronizeLocalLanuagePackage(@QueryParam("fileName") String fileName, @QueryParam("path") String path); + + /** + * 获取启用的语种 + */ + @Path("language-enabled-list") + @GET + List GetEnabledLanguageList(); + + /** + * 获取系统内置的语种 + */ + @Path("language-built-in-list") + @GET + List GetBuiltinLanguageList(); + + /** + * 获取所有语种的列表 + */ + @Path("all-language-list") + @GET + List GetAllLanguageList(); + + /** + * 复制表单及关联元数据 + */ + @Path("replicate") + @POST + void ReplicateForm(@RequestBody ReplicateFormRequestBody replicateFormRequestBody); + + + @Path("get-suinfo-with-bizobjid") + @POST + FormSuInfoEntity getSuInfoWithBizobjId(@RequestBody SuInfoWithBizobjIdEntity bizobjIdEntity); +} diff --git a/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/FormSuInfoEntity.java b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/FormSuInfoEntity.java new file mode 100644 index 00000000..8beec112 --- /dev/null +++ b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/FormSuInfoEntity.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.formmetadata.api.entity; + +import lombok.Data; + +/** + * 表单关联su信息 + */ +@Data +public class FormSuInfoEntity { + + /** + * 表单关联关键应用code + */ + private String appCode; + /** + * 表单关联su code + */ + private String suCode; + + /** + * 表单关联命名空间 + */ + private String nameSpace; +} diff --git a/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/ReplicateFormRequestBody.java b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/ReplicateFormRequestBody.java new file mode 100644 index 00000000..16d4618f --- /dev/null +++ b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/ReplicateFormRequestBody.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.formmetadata.api.entity; + +public class ReplicateFormRequestBody { + /** + * 元数据id + */ + private String sourceMetadataId; + + public final String getSourceMetadataId() { + return this.sourceMetadataId; + } + + public final void setSourceMetadataId(String value) { + this.sourceMetadataId = value; + } + + /** + * 元数据文件相对路径 + */ + private String sourceMetadataRelativePath; + + public final String getSourceMetadataRelativePath() { + return this.sourceMetadataRelativePath; + } + + public final void setSourceMetadataRelativePath(String value) { + this.sourceMetadataRelativePath = value; + } + + /** + * 目标元数据编号 + */ + private String targetMetadataCode; + + public final String getTargetMetadataCode() { + return this.targetMetadataCode; + } + + public final void setTargetMetadataCode(String value) { + this.targetMetadataCode = value; + } + + /** + * 目标元数据名称 + */ + private String targetMetadataName; + + public final String getTargetMetadataName() { + return this.targetMetadataName; + } + + public final void setTargetMetadataName(String value) { + this.targetMetadataName = value; + } + + /** + * 目标工程名 + */ + private String targetProjectName; + + public final String getTargetProjectName() { + return this.targetProjectName; + } + + public final void setTargetProjectName(String value) { + this.targetProjectName = value; + } +} diff --git a/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/SuInfoWithBizobjIdEntity.java b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/SuInfoWithBizobjIdEntity.java new file mode 100644 index 00000000..2e6c11a9 --- /dev/null +++ b/web-form-metadata-api/src/main/java/com/inspur/edp/web/formmetadata/api/entity/SuInfoWithBizobjIdEntity.java @@ -0,0 +1,14 @@ +package com.inspur.edp.web.formmetadata.api.entity; + +import lombok.Data; + +/** + * 包含业务对象id参数实体 + */ +@Data +public class SuInfoWithBizobjIdEntity { + /** + * 业务对象id + */ + private String bizObjId; +} diff --git a/web-form-metadata/pom.xml b/web-form-metadata/pom.xml new file mode 100644 index 00000000..188e1605 --- /dev/null +++ b/web-form-metadata/pom.xml @@ -0,0 +1,67 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + jar + web-jitengine-formmetadata + + + + io.iec.edp + caf-i18n-framework-api + + + com.inspur.edp + i18n-resource-api + + + com.inspur.edp + formserver-viewmodel + + + com.inspur.edp + lcm-metadata-spi + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + lcm-metadata-common + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + cdp-sgf-api + + + com.inspur.edp + web-jitengine-formmetadata-api + + + org.junit.jupiter + junit-jupiter-api + + + io.iec.edp + caf-framework-licservice-api + + + com.inspur.edp + lcm-metadata-spi + + + + + diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java new file mode 100644 index 00000000..cb80d4c6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/config/FormMetadataConfiguration.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.formmetadata.config; + +import com.inspur.edp.web.formmetadata.api.FormMetadataCommonService; +import com.inspur.edp.web.formmetadata.lic.FormMetadataCreateLicControlListener; +import com.inspur.edp.web.formmetadata.service.FormMetadataCommonServiceImpl; +import com.inspur.edp.web.formmetadata.service.FormMetadataRTService; +import com.inspur.edp.web.formmetadata.webservice.FormMetadataWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration("com.inspur.edp.web.formmetadata.config.FormMetadataConfiguration") +public class FormMetadataConfiguration { + @Bean() + public RESTEndpoint formMetadataWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/form-metadata", new FormMetadataWebServiceImpl()); + } + + @Bean + public FormMetadataRTService formMetadataRTService() { + return new FormMetadataRTService(); + } + + @Bean + public FormMetadataCommonService formMetadataCommonService() { + return new FormMetadataCommonServiceImpl(); + } + + @Bean + public FormMetadataCreateLicControlListener getFormMetadataCreateLicControlListener() { + return new FormMetadataCreateLicControlListener(); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/constant/ReplicationConstant.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/constant/ReplicationConstant.java new file mode 100644 index 00000000..f47d2564 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/constant/ReplicationConstant.java @@ -0,0 +1,8 @@ +package com.inspur.edp.web.formmetadata.constant; + +public class ReplicationConstant { + /** + * 元数据工程文件后缀名 + */ + public static final String METADATA_PROJECT_FILE_SUFFIX = "mdproj"; +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/entity/FormRelateViewModelEntity.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/entity/FormRelateViewModelEntity.java new file mode 100644 index 00000000..672f7bd8 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/entity/FormRelateViewModelEntity.java @@ -0,0 +1,87 @@ +package com.inspur.edp.web.formmetadata.entity; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * 表单关联viewModel + * @author guozhiqi + */ +public class FormRelateViewModelEntity { + /** + * 关联的viewModel元数据 + */ + private GspMetadata viewModelMetadata; + + /** + * 关联表单元数据 + */ + private GspMetadata formMetadata; + + /** + * viewModel元数据id + */ + private String viewModelMetadataId; + + /** + * 表单元数据id + */ + private String formMetadataId; + + /** + * 表单code + */ + private String formCode; + + /** + * 表单name + */ + private String formName; + + public GspMetadata getViewModelMetadata() { + return viewModelMetadata; + } + + public void setViewModelMetadata(GspMetadata viewModelMetadata) { + this.viewModelMetadata = viewModelMetadata; + } + + public GspMetadata getFormMetadata() { + return formMetadata; + } + + public void setFormMetadata(GspMetadata formMetadata) { + this.formMetadata = formMetadata; + } + + public String getViewModelMetadataId() { + return viewModelMetadataId; + } + + public void setViewModelMetadataId(String viewModelMetadataId) { + this.viewModelMetadataId = viewModelMetadataId; + } + + public String getFormMetadataId() { + return formMetadataId; + } + + public void setFormMetadataId(String formMetadataId) { + this.formMetadataId = formMetadataId; + } + + public String getFormCode() { + return formCode; + } + + public void setFormCode(String formCode) { + this.formCode = formCode; + } + + public String getFormName() { + return formName; + } + + public void setFormName(String formName) { + this.formName = formName; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/FormMetadataSaveEventListener.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/FormMetadataSaveEventListener.java new file mode 100644 index 00000000..d7cc3c85 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/FormMetadataSaveEventListener.java @@ -0,0 +1,270 @@ +package com.inspur.edp.web.formmetadata.event; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventListener; +import com.inspur.edp.web.common.constant.MetadataConstant; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.service.FormMetataService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class FormMetadataSaveEventListener implements MetadataEventListener { + /** + * 元数据保存前事件 + */ + @Override + public void fireMetadataSavingEvent(MetadataEventArgs metadataEventArgs) { + + } + + /** + * 元数据保存后事件 + */ + @Override + public void fireMetadataSavedEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null + || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + + + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + // 同步本地语言包 + SyncLocalLanguagePackage(metadataEventArgs.getMetadata()); + } + } + + private void SyncLocalLanguagePackage(GspMetadata formMetadata) { + FormMetataService.exportLanguagePackage(formMetadata); + } + + @Override + public void fireMetadataDeletingEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null + || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + try { + // 获取表单元数据的文件名称 + String metaDataCode = metadataEventArgs.getMetadata().getHeader().getCode(); + String formMetadataRelativePath = metadataEventArgs.getMetadata().getRelativePath(); + + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject projInfo = metadataProjectService.getMetadataProjInfo(formMetadataRelativePath); + String projectPath = projInfo.getProjectPath(); + + //获取待删除的文件列表 仅删除当前目录下 + List relativeMetadataDeleteList = new ArrayList<>(); //generateDeleteList(metaDataCode, new File(formMetadataRelativePath)); + + // 读取表单元数据 解析其中的eapiid + // 如果传递的表单元数据中内容为空 + if (metadataEventArgs.getMetadata().getContent() == null) { + GspMetadata metadata = MetadataUtility.getInstance().getMetadata(metadataEventArgs.getMetadata().getHeader().getFileName(), metadataEventArgs.getMetadata().getRelativePath()); + if (metadata != null) { + metadataEventArgs.getMetadata().setContent(metadata.getContent()); + } + } + + if (metadataEventArgs.getMetadata().getContent() != null) { + String formMetadataStr = ((FormMetadataContent) metadataEventArgs.getMetadata().getContent()).getContents().toString(); + FormDOM formDOM = SerializeUtility.getInstance().deserialize(formMetadataStr, FormDOM.class); + if (formDOM.getModule().getSchemas() != null && formDOM.getModule().getSchemas().size() > 0) { + deleteRelateEapiMetadata(projectPath, formDOM); + } + + // 获取待删除的命令元数据 命令构件 ts文件 + try { + WebCommandMetadataDelete webCommandMetadataDelete = new WebCommandMetadataDelete(); + List webCmpAndTsDeleteList = webCommandMetadataDelete.generateWebCmpAndTsDeleteList(formDOM, projInfo); + relativeMetadataDeleteList.addAll(new ArrayList<>(webCmpAndTsDeleteList)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + relativeMetadataDeleteList.forEach(t -> { + File deleteFileInfo = new File(FileUtility.combine(formMetadataRelativePath, t)); + if (deleteFileInfo.exists()) { + // 执行元数据删除 + MetadataUtility.getInstance().getMetadataService().deleteMetadata(formMetadataRelativePath, t); + } + }); + + // 删除关联的表单源代码 + deleteRelateFormSourceCode(projectPath, projInfo.getName(), metaDataCode); + // 更新页面流元数据 + } catch (RuntimeException ex) { + ex.printStackTrace(); + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + + } + + /** + * 删除关联的源代码目录文件 + * + * @param projectPath + * @param projectName + * @param formCode + */ + private void deleteRelateFormSourceCode(String projectPath, String projectName, String formCode) { + String sourceCodeSrcPath = FileUtility.combine(projectPath, "src", "app", "projects", projectName.toLowerCase(), "src"); + String sourceCodeFormPath = FileUtility.combine(sourceCodeSrcPath, "app", formCode.toLowerCase()); + if (FileUtility.exists(sourceCodeFormPath)) { + FileUtility.deleteFolder(sourceCodeFormPath); + } + } + + @Override + public void fireMetadataDeletedEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null + || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + + // 如果删除的是webcmp 那么在删除之后将对应的ts文件进行删除 + if ("WebComponent".equals(metadataEventArgs.getMetadata().getHeader().getType())) { + String tsFileName = metadataEventArgs.getMetadata().getHeader().getCode() + ".ts"; + String tsFilePath = metadataEventArgs.getMetadata().getRelativePath(); + String tsFileNameAndPath = FileUtility.combine(tsFilePath, tsFileName); + try { + FileUtility.deleteFile(tsFileNameAndPath); + } catch (Exception ex) { + WebLogger.Instance.error(ex.getMessage() + ex.getStackTrace()); + } + } + + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + try { + // 获取表单元数据的文件名称 + String metaDataCode = metadataEventArgs.getMetadata().getHeader().getCode(); + String formMetadataRelativePath = metadataEventArgs.getMetadata().getRelativePath(); + + //获取待删除的文件列表 仅删除当前目录下 + List relativeMetadataDeleteList = generateDeleteList(metaDataCode, new File(formMetadataRelativePath)); + relativeMetadataDeleteList.forEach(t -> { + File deleteFileInfo = new File(FileUtility.combine(formMetadataRelativePath, t)); + if (deleteFileInfo.exists()) { + // 执行元数据删除 + MetadataUtility.getInstance().getMetadataService().deleteMetadata(formMetadataRelativePath, t); + } + }); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + // 如果是帮助元数据的删除 那么将其关联的res也要对应的删除 + if ("HelpMetadata".equals(metadataEventArgs.getMetadata().getHeader().getType())) { + try { + deleteRelateHelpMetadata(metadataEventArgs); + } catch (Exception ex) { + WebLogger.Instance.error(ex.getMessage() + ex.getStackTrace()); + } + } + } + + /** + * 删除帮助关联的元数据 + * + * @param metadataEventArgs + */ + private static void deleteRelateHelpMetadata(MetadataEventArgs metadataEventArgs) { + String fileName = metadataEventArgs.getMetadata().getHeader().getFileName(); + String name = metadataEventArgs.getMetadata().getHeader().getName(); + String relativePath = metadataEventArgs.getMetadata().getRelativePath(); + String projectRelativePath = MetadataUtility.getInstance().getMetadataProjectPath(relativePath); + String suffixRes = ".res"; + String suffixEnRes = ".en.lres"; + String suffixZhChtRes = ".zh-CHT.lres"; + + String relateResource = fileName + suffixRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateResource); + + String relateEnResource = fileName + suffixEnRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateEnResource); + + String relateZh_CHTResource = fileName + suffixZhChtRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateZh_CHTResource); + + String eapiName = name + "_hlp.eapi"; + String eapiFilePath=FileUtility.combine(projectRelativePath,"eapi"); + MetadataUtility.getInstance().getMetadataService().deleteMetadata(eapiFilePath, eapiName); + + String relateVO = name + "_hlp.vo"; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateVO); + + String relateVORes = relateVO + suffixRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateVORes); + + String relateVOEnRes = relateVO + suffixEnRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateVOEnRes); + + String relateVOZHCHTRes = relateVO + suffixZhChtRes; + MetadataUtility.getInstance().getMetadataService().deleteMetadata(relativePath, relateVOZHCHTRes); + } + + /** + * 删除关联的eapi元数据 + * + * @param projectPath + * @param formDOM + */ + private void deleteRelateEapiMetadata(String projectPath, FormDOM formDOM) { + Object objEapiId = formDOM.getModule().getSchemas().get(0).get("eapiId"); + if (objEapiId != null) { + String strEapiId = objEapiId.toString(); + GspMetadata eapiMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(strEapiId, projectPath); + if (eapiMetadata != null) { + // eapi 单独删除 + MetadataUtility.getInstance().getMetadataService().deleteMetadata(eapiMetadata.getRelativePath(), eapiMetadata.getHeader().getFileName()); + } + } + } + + + private List generateDeleteList(String metaDataCode, File relativePath) { + List deleteList = new ArrayList<>(); + String frmDotPrefix = metaDataCode + ".frm"; + String frmXiaPrefix = metaDataCode + "_frm"; + + // 表单关联资源文件 + deleteList.add(frmDotPrefix + ".en.lres"); + deleteList.add(frmDotPrefix + ".res"); + deleteList.add(frmDotPrefix + ".zh-CHT.lres"); + + // 表单元数据json文件 + deleteList.add(frmXiaPrefix + ".json"); + + // 表单关联状态机 + deleteList.add(frmXiaPrefix + ".sm"); + + // 表单元数据 关联VO 及其资源元数据 + deleteList.add(frmXiaPrefix + ".vo"); + deleteList.add(frmXiaPrefix + ".vo.en.lres"); + deleteList.add(frmXiaPrefix + ".vo.res"); + deleteList.add(frmXiaPrefix + ".vo.zh-CHT.lres"); + + + return deleteList; + } + + +} + diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/WebCommandMetadataDelete.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/WebCommandMetadataDelete.java new file mode 100644 index 00000000..6fe7edcd --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/event/WebCommandMetadataDelete.java @@ -0,0 +1,246 @@ +package com.inspur.edp.web.formmetadata.event; + +import com.google.common.base.Strings; +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.web.command.component.metadata.*; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +import java.util.*; + +class WebCommandMetadataDelete { + + public List generateWebCmpAndTsDeleteList(FormDOM json, MetadataProject projectInfo) { + List deleteList = new ArrayList<>(); + if (json.getModule() != null && json.getModule().getWebcmds() != null && json.getModule().getWebcmds().size() > 0) { + HashMap cmpList = new HashMap(8); + HashMap projectCmpList = new HashMap<>(); + for (HashMap c : json.getModule().getWebcmds()) { + try { + String cmdId = c.get("id").toString(); + WebCommandsMetadata metadata = getWebCommands(cmdId); + analysisComponentMetadata(metadata, cmpList, null, projectCmpList); + boolean hasServiceRef = analysisServiceRef(json, cmpList); + if (hasServiceRef) { + String webCmdFileName = c.get("name").toString(); + if (StringUtility.isNullOrEmpty(webCmdFileName)) { + webCmdFileName = metadata.getCode() + ".webcmd"; + } + deleteList.add(webCmdFileName); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + + } + } + if (json != null && json.getModule() != null && json.getModule().getServiceRefs() != null && json.getModule().getServiceRefs().size() > 0) { + List metadataList = MetadataUtility.getInstance().getMetadataList(projectInfo.getProjectPath()); + if (metadataList == null || metadataList.size() == 0) { + return deleteList; + } + + for (HashMap o : json.getModule().getServiceRefs()) { + if ("0".equals(o.get("isCommon").toString())) { + + String refCmpId = o.get("cmpId").toString(); + + + Optional findMetadata = metadataList.stream().filter((GspMetadata item) -> refCmpId.equals(item.getHeader().getId()) + ).findFirst(); + + if (findMetadata.isPresent()) { + String fileName = findMetadata.get().getHeader().getFileName(); + String relativeTsFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".ts"; + + // 获取文件目录下所有的关联ts文件 + //String[] frmRelativeTs = relativePath.list(new FileNameFilter(frmXiaPrefix + "[\\S]+.ts")); + deleteList.add(relativeTsFileName); + + // 获取文件目录下所有的关联webcmp文件 + String relativeWebCmpFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".webcmp"; + deleteList.add(relativeWebCmpFileName); + } + } + } + } + return deleteList; + } + + private void analysisComponentCommandItemList(List commandItemList, HashMap cmpList, + HashMap projectCmpList) throws Exception { + if (commandItemList != null && commandItemList.size() > 0) { + + WebComponentMetadata cmpMetadata = null; + for (CommandItem item : commandItemList) { + switch (item.getItemType()) { + case MethodRefer: + if (!cmpList.containsKey(((CmpMethodRefering) item).getComponentId())) { + if (!projectCmpList.containsKey(((CmpMethodRefering) item).getComponentId())) { + try { + cmpMetadata = getComponentMetadata(((CmpMethodRefering) item).getComponentId()); + if (cmpMetadata != null) { + cmpList.put(cmpMetadata.getId(), cmpMetadata); + projectCmpList.put(cmpMetadata.getId(), cmpMetadata); + } + } catch (Exception ex) { + throw new Exception("获取command元数据" + cmpMetadata.getId() + "失败", ex); + } + } else { + cmpMetadata = projectCmpList.get(((CmpMethodRefering) item).getComponentId()); + cmpList.put(cmpMetadata.getId(), cmpMetadata); + } + } + break; + case BranchCollection: + analysisComponentMetadata(null, cmpList, ((BranchCollectionCommandItem) item).getItems(), projectCmpList); + break; + default: + break; + + } + } + } + } + + private WebCommandsMetadata getWebCommands(String id) { + GspMetadata webCommandMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(id, ExecuteEnvironment.Design, false); + if (webCommandMetadata == null) { + return null; + } + return (WebCommandsMetadata) webCommandMetadata.getContent(); + } + + public WebComponentMetadata getComponentMetadata(String id) { + GspMetadata webComponentMetadata = MetadataUtility.getInstance().getMetadataWithEnvironment(id, ExecuteEnvironment.Design, false); + if (webComponentMetadata == null) { + throw new RuntimeException("load webComponent metadata is null,the metaDataId is " + id); + } + return (WebComponentMetadata) webComponentMetadata.getContent(); + } + + private void analysisComponentMetadata(WebCommandsMetadata metadata, HashMap cmpList, + List items, + HashMap projectCmpList) { + if (items == null || items.size() == 0) { + if (metadata != null && metadata.getCommands() != null && metadata.getCommands().size() > 0) { + for (WebCommand webCommandItem : metadata.getCommands()) { + try { + analysisComponentCommandItemList(webCommandItem.getItems(), cmpList, projectCmpList); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } else { + for (BranchCommandItem branchCommandItem : items) { + try { + analysisComponentCommandItemList(branchCommandItem.getItems(), cmpList, projectCmpList); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + private boolean hasServiceReference(List> serviceReferenceList, WebComponentMetadata component) throws Exception { + boolean flag = false; + for (HashMap serviceRef : serviceReferenceList) { + if (serviceRef.containsKey("name") && serviceRef.containsKey("path")) { + if (serviceRef.get("name") == null || serviceRef.get("path") == null) { + continue; + } + + if (serviceRef.get("name").toString().equals(component.getClassName()) && + serviceRef.get("path") == component.getSource()) { + flag = true; + break; + } + } + } + return flag; + } + + public boolean analysisServiceRef(FormDOM json, HashMap cmpList) throws Exception { + boolean hasServiceRef = false; + if (cmpList != null && cmpList.size() > 0) { + Iterator iter = cmpList.entrySet().iterator(); + while (iter.hasNext()) { + HashMap.Entry entry = (HashMap.Entry) iter.next(); + + if (json.getModule().getServiceRefs() == null) { + json.getModule().setServiceRefs(new ArrayList<>()); + } + + HashMap serviceRef = new HashMap<>(); + WebComponentMetadata component = (WebComponentMetadata) entry.getValue(); + if (component == null) { + continue; + } + if (component.isCommon()) { + continue; + } + + if (!component.isCommon()) { + hasServiceRef = true; + } + + if (!hasServiceReference(json.getModule().getServiceRefs(), component)) { + serviceRef.put("cmpId", component.getId()); + serviceRef.put("name", component.getClassName()); + String path = component.getSource(); + if (path == null || path.isEmpty()) { + path = getTSFileName(component.getId()); + if (!Strings.isNullOrEmpty(path)) { + component.setSource(path); + } + } + serviceRef.put("path", path); + + serviceRef.put("isCommon", component.isCommon() ? "1" : "0"); + serviceRef.put("alias", component.getClassName() + "1"); + + json.getModule().getServiceRefs().add(serviceRef); + } + } + } + return hasServiceRef; + } + + + /** + * 获取ts文件路径和名称 + */ + private String getTSFileName(String cmpId) throws Exception { + // 最理想的方式:路径来自webcmp构件路径,名称来自path(即元数据的Source属性) + // 先用webcmp的文件名构造,后续可以考虑调整 + if (cmpId == null || cmpId.isEmpty()) { + throw new Exception("获取ts文件名出错,对应的web构件id不能为空。"); + } + + GspMetadata metadata = MetadataUtility.getInstance().getMetadataWithEnvironment(cmpId, ExecuteEnvironment.Design, false); + + if (metadata != null) { + String path = metadata.getRelativePath(); + String cmpFileName = metadata.getHeader().getFileName(); + // 后缀为.webcmp + int suffixIndex = cmpFileName.lastIndexOf(".webcmp"); + String fileName; + if (suffixIndex > 0 && suffixIndex + 7 == cmpFileName.length()) { + fileName = cmpFileName.substring(0, suffixIndex); + } else if (cmpFileName.contains(metadata.getHeader().getCode())) { + fileName = cmpFileName; + } else { + throw new Exception("获取ts文件名出错,web构件上获取的文件名不对。"); + } + + return path + "/" + fileName + ".ts"; + } + + return null; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nService.java new file mode 100644 index 00000000..a3be67f0 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nService.java @@ -0,0 +1,289 @@ +package com.inspur.edp.web.formmetadata.i18n; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.I18nResource; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.entity.ResourceLocation; +import com.inspur.edp.lcm.metadata.api.entity.ResourceType; +import com.inspur.edp.lcm.metadata.spi.MetadataI18nService; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentContext; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.ComponentType; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; + +public class FormMetadataI18nService implements MetadataI18nService { + /** + * 从基础元数据中抽取资源元数据内容 + * + * @param metadata 待提取元数据 + * @return + */ + @Override + public final I18nResource getResourceItem(GspMetadata metadata) { + if (metadata == null || metadata.getContent() == null) { + return null; + } + return GetFormMetadataI18nResource(metadata); + } + + /** + * 合并(将资源对应的多语资源整合到当前元数据中) + * + * @param metadata + * @param resources + * @return + */ + @Override + public final GspMetadata merge(GspMetadata metadata, List resources) { + + return metadata; + } + + /** + * 根据表单元数据获取对应的资源项列表 + * + * @param formMetadata + * @return + */ + private I18nResource GetFormMetadataI18nResource(GspMetadata formMetadata) { + FormMetadataContent formMetadataContent = (FormMetadataContent) ((formMetadata.getContent() instanceof FormMetadataContent) ? formMetadata.getContent() : null); + if (formMetadataContent == null) { + return null; + } + + MetadataHeader formMetadataHeader = formMetadata.getHeader(); + + String i18nResourceItemBaseId = formMetadataHeader.getNameSpace() + I18nResourceConstant.FIRST_LEVEL_DELIMITER + + formMetadataHeader.getCode() + I18nResourceConstant.FIRST_LEVEL_DELIMITER + + formMetadataHeader.getType() + I18nResourceConstant.FIRST_LEVEL_DELIMITER; + + I18nResource i18nResource = new I18nResource(); + i18nResource.setResourceType(ResourceType.Metadata); + i18nResource.setResourceLocation(ResourceLocation.Frontend); + i18nResource.setLanguage(formMetadata.getHeader().getLanguage()); + i18nResource.setStringResources(this.GetI18nResourceItemCollection(formMetadataContent, i18nResourceItemBaseId)); + + return i18nResource; + } + + /** + * 从表单元数据内容中提取多语资源 + * + * @param formMetadataContent + * @return + */ + private I18nResourceItemCollection GetI18nResourceItemCollection(FormMetadataContent formMetadataContent, String i18nResourceItemBaseId) { + // 从表单元数据中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 表单元数据反序列化成FormDom + FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + if (formContent == null || formContent.getModule() == null || formContent.getModule().getComponents() == null) { + return i18nResourceItemCollection; + } + + ArrayList> components = formContent.getModule().getComponents(); + // 递归提取每个component中的组件及其对应的待国际化的值 + for (HashMap component : components) { + // 每个component是一个树结构 + // 表单树表现出浅而宽的特性,所以优先使用深度优先算法 + if (component != null) { + DepthFirstSearchTraverse(i18nResourceItemCollection, i18nResourceItemBaseId, component); + } + } + + return i18nResourceItemCollection; + } + + + /** + * 深度优先搜索遍历(DFS) + * + * @param i18nResourceItemCollection 资源项列表 + * @param i18nResourceItemBaseId 资源项根id + * @param component 表单component + * @return + */ + public ArrayList DepthFirstSearchTraverse(I18nResourceItemCollection i18nResourceItemCollection, String i18nResourceItemBaseId, HashMap component) { + ArrayList list = new ArrayList<>(); + + Stack> componentStack = new Stack<>(); + // 将当前节点入栈 + componentStack.push(component); + while (componentStack.size() != 0) { + // 节点出栈 + HashMap currentComponent = componentStack.pop(); + if (currentComponent == null) { + break; + } + + String componentType = ComponentUtility.getInstance().getType(currentComponent); + // 处理当前出栈的节点 提取对应的资源项 + HandlePoppedNode(i18nResourceItemCollection, i18nResourceItemBaseId, currentComponent); + + // 兄弟节点压栈 + AppendSiblingNode(componentStack, currentComponent); + + // 子节点压栈 + // 由于checkGroup中包含items属性且不包含具体的类型 所以针对checkGroup 不读取其items + if (!StringUtility.isNullOrEmpty(componentType) && + !"CheckGroup".equals(componentType)) { + AppendChildrenNode(componentStack, currentComponent); + } + } + + return list; + } + + /** + * 子节点入栈 + * + * @param componentStack + * @param currentComponent + */ + private void AppendChildrenNode(Stack> componentStack, HashMap currentComponent) { + if (currentComponent == null || currentComponent.isEmpty()) { + return; + } + ArrayList> childComponentCollection = GetChildComponents(currentComponent); + for (int i = childComponentCollection.size() - 1; i >= 0; i--) + { + HashMap childComponent = childComponentCollection.get(i); + if (childComponent != null) { + componentStack.push(childComponent); + } + } + } + + /** + * 追加兄弟节点:特殊处理非子组件属性中。如tabPage中的toolbar + * {"contents":{},"toolbar":{}, "editor":{}} + * + * @param componentStack + * @param currentComponent + */ + private static void AppendSiblingNode(Stack> componentStack, HashMap currentComponent) { + String componentType = ComponentUtility.getInstance().getType(currentComponent); + if (!StringUtility.isNullOrEmpty(componentType) && componentType.equals(ComponentType.TabPage)) { + HashMap toolbarObject = ComponentUtility.getInstance().GetToolbar(currentComponent); + if (toolbarObject != null) { + componentStack.push(toolbarObject); + } + } + } + + + /** + * 提取当前节点的国际化翻译项 + * + * @param i18nResourceItemCollection 国际化资源项 + * @param i18nResourceItemBaseId baseId + * @param currentComponent 当前待处理的节点 + */ + private void HandlePoppedNode(I18nResourceItemCollection i18nResourceItemCollection, String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection currentI18nResourceItemCollection = GetI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (currentI18nResourceItemCollection != null && currentI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(currentI18nResourceItemCollection); + } + } + + /** + * 提取具体的资源项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection GetI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 获取组件的多语资源项 + ComponentContext componentI18nResourceContext = new ComponentContext(currentComponent, i18nResourceItemBaseId); + I18nResourceItemCollection componentI18nResourceItemCollection = componentI18nResourceContext.extractI18nResource(); + if (componentI18nResourceItemCollection != null && componentI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(componentI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /** + * 获取子组件列表 + * + * @param component + * @return + */ + private ArrayList> GetChildComponents(HashMap component) { + ArrayList> childCompnentCollection = new ArrayList<>(); + + // 获取组件属性中包含的子组件 + ArrayList> childAttribtueCompnentCollection = GetAttribtueChildComponents(component); + if (childAttribtueCompnentCollection != null && !childAttribtueCompnentCollection.isEmpty()) { + childCompnentCollection.addAll(childAttribtueCompnentCollection); + } + + Object contents = component.get("contents"); + if (contents == null) { + // 尝试从items中获取子节点信息(兼容使用items属性存储子节点的场景,如ToolBar) + contents = component.get("items"); + if (contents == null) { + // 兼容datagrid + contents = component.get("fields"); + } + if (contents == null) { + return childCompnentCollection; + } + } + + // 如何从object转换成List> + // https://stackoverflow.com/questions/632570/cast-received-object-to-a-listobject-or-ienumerableobject + ArrayList contentsCollection = new ArrayList<>((List) contents); + for (Object localComponent : contentsCollection) { + // 从object转换成Dictionary + HashMap convertObject = ConvertToDictionaryObject(localComponent); + childCompnentCollection.add(convertObject); + } + + return childCompnentCollection; + } + + /** + * 侧边栏或tabPage的工具栏 + * + * @param component + * @return + */ + private ArrayList> GetAttribtueChildComponents(HashMap component) { + ArrayList> childAttribtueCompnentCollection = new ArrayList<>(); + // 侧边栏 或tab的工具栏 + if (ComponentUtility.getInstance().getType(component).equals(ComponentType.SIDEBAR)) { + HashMap toolbarAttributeObject = ComponentUtility.getInstance().GetToolbar(component); + // 仅在存在toolbar时处理 + if (toolbarAttributeObject != null) { + childAttribtueCompnentCollection.addAll(ComponentUtility.getInstance().GetItems(toolbarAttributeObject)); + } + return childAttribtueCompnentCollection; + } + + + return null; + } + + // 如何从object转换成Dictionary + // https://stackoverflow.com/questions/11576886/how-to-convert-object-to-dictionarytkey-tvalue-in-c + private static HashMap ConvertToDictionaryObject(Object targetObject) { + String json = SerializeUtility.getInstance().serialize(targetObject,false); + return SerializeUtility.getInstance().deserialize(json, HashMap.class); + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/I18nResourceItemManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/I18nResourceItemManager.java new file mode 100644 index 00000000..b315367e --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/I18nResourceItemManager.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.formmetadata.i18n; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import org.apache.commons.lang3.StringUtils; + +/** + * 资源项构造 + */ +public class I18nResourceItemManager { + /** + * 创建对应的资源项 + * + * @return + */ + private static I18nResourceItem createI18nResourceItem(String key, String value, String comment) { + if (StringUtils.isEmpty(key)) { + return null; + } + if (StringUtils.isEmpty(value)) { + value = ""; + } + if (StringUtils.isEmpty(comment)) { + comment = ""; + } + I18nResourceItem i18nResourceItem = new I18nResourceItem(); + i18nResourceItem.setKey(key); + i18nResourceItem.setValue(value); + i18nResourceItem.setComment(comment); + return i18nResourceItem; + } + + /** + * 创建对应的资源项 + * + * @param strBaseId 基础id + * @param key + * @param value + * @param comment + * @return + */ + public static I18nResourceItem createI18nResourceItem(String strBaseId, String key, + String value, String comment) { + if (StringUtils.isEmpty(comment)) { + comment = value; + } + + String strKey = MergeI18nResourceId(strBaseId, key); + return createI18nResourceItem(strKey, value, comment); + } + + /** + * 资源项id合并 + * + * @param strBaseId + * @param resourceId + * @return + */ + public static String MergeI18nResourceId(String strBaseId, String resourceId) { + if (StringUtils.isEmpty(strBaseId)) { + strBaseId = ""; + } + + // 针对资源项key中的点号 替换成下划线 + resourceId = resourceId.replace(".", "_"); + String strKey = strBaseId + resourceId; + return strKey; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/II18nResource.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/II18nResource.java new file mode 100644 index 00000000..c7bd239b --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/II18nResource.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.formmetadata.i18n; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; + +/** + * 多语资源接口 + */ +public interface II18nResource { + /** + * 多语资源项基础id + */ + String getI18nResourceBaseId(); + + /** + * 提取多语资源 + * + * @return 多语资源项集合 + */ + I18nResourceItemCollection extractI18nResource() ; +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/BaseComponent.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/BaseComponent.java new file mode 100644 index 00000000..190e492a --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/BaseComponent.java @@ -0,0 +1,49 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.II18nResource; + +import java.util.HashMap; + +/** + * 抽象组件 + * 每个组件都需实现II18nResource接口,所以将其提取AbstractComponent,而不是分散到组件实现中 + * @author noah + */ +public class BaseComponent implements IComponent, II18nResource { + /** + * 组件实体 + */ + private final HashMap ComponentEntity; + + @Override + public final HashMap getComponentEntity() { + return ComponentEntity; + } + + /** + * 国际化资源项 根id + */ + private final String I18nResourceBaseId; + + @Override + public final String getI18nResourceBaseId() { + return I18nResourceBaseId; + } + + + public BaseComponent(HashMap currentComponent, String i18nResourceBaseId) { + this.ComponentEntity = currentComponent; + this.I18nResourceBaseId = i18nResourceBaseId; + } + + /** + * 从组件中提取多语资源 + */ + @Override + public final I18nResourceItemCollection extractI18nResource() { + // 获取组件对应多语策略,提取多语资源项 + I18nResourceStrategyContext i18nResourceStrategyContext = new I18nResourceStrategyContext(this.getComponentEntity(), this.getI18nResourceBaseId()); + return i18nResourceStrategyContext.ExtractI18nResource(); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentContext.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentContext.java new file mode 100644 index 00000000..d04bc976 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentContext.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; + +import java.util.HashMap; + +/** + * 组件上下文 + * @author noah + */ +public class ComponentContext { + /** + * 组件 + */ + private final BaseComponent component; + + public ComponentContext(HashMap currentComponent, String curretnI18nResourceItemBaseId) { + component = new BaseComponent(currentComponent, curretnI18nResourceItemBaseId); + } + + /** + * 从组件中提取多语资源 + */ + public final I18nResourceItemCollection extractI18nResource() { + if (component == null) { + return null; + } + + return component.extractI18nResource(); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentUtility.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentUtility.java new file mode 100644 index 00000000..6badcbb6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/ComponentUtility.java @@ -0,0 +1,590 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * 组件处理utility + * + * @author noah + */ +public class ComponentUtility { + ///#region ComponentUtility Singleton + + /** + * 私有构造函数,避免继承与外部实例化 + */ + private ComponentUtility() { + + } + + private static final ComponentUtility componentUtilityInstance = new ComponentUtility(); + + public static ComponentUtility getInstance() { + return componentUtilityInstance; + } + + ///#endregion + + ///#region 常量 + + private static final String LINE_NUMBER_TITLE = "lineNumberTitle"; + private static final String PLACE_HOLDER = "placeHolder"; + private static final String PLACE_HOLDERCAMEL = "placeholder"; + private static final String CollapseText = "collapseText"; + private static final String ExpandText = "expandText"; + private static final String ControlSource = "controlSource"; + private static final String DIAGLOG_TITLE = "dialogTitle"; + private static final String ENUM_VALUES = "enumValues"; + private static final String CONTROL = "control"; + private static final String ENUM_DATA = "enumData"; + private static final String TAG_DATA = "tagData"; + private static final String NAV_DATA = "navData"; + private static final String EDITOR = "editor"; + private static final String FORMATTER = "formatter"; + private static final String TRUE_TEXT = "trueText"; + private static final String FALSE_TEXT = "falseText"; + private static final String ITEMS = "items"; + private static final String MAIN_TITLE = "mainTitle"; + private static final String SUB_TITLE = "subTitle"; + private static final String PROGRESS_DATA = "progressData"; + private static final String STEP_MESSAGES = "stepMessages"; + private static final String HEADER_GROUP = "headerGroup"; + private static final String GROUP_TEXT = "groupText"; + private static final String ModalConfig = "modalConfig"; + private static final String Content_Template = "contentTemplate"; + private static final String Toolbar_DATA = "toolbarData"; + ///#endregion + + private T getValue(HashMap component, String keyName) { + T componentValue = null; + + if (component == null || component.size() == 0) { + return componentValue; + } + + Object name = null; + if (component.containsKey(keyName)) { + name = component.get(keyName); + } + + if (name != null) { + try { + componentValue = (T) name; + } catch (RuntimeException e) { + String componentId = this.getId(component); + if (StringUtility.isNullOrEmpty(componentId)) { + componentId = getType(component); + if (StringUtility.isNullOrEmpty(componentId)) { + componentId = getName(component); + } + } + throw new GSPException("", String.format("Get %1$s's key '%2$s''s Value Failed, Error stack is:", componentId, keyName)); + } + } + + return componentValue; + } + + public final String getId(HashMap component) { + return this.getValue(component, "id"); + } + + public final String getType(HashMap component) { + return this.getValue(component, "type"); + } + + public final String getValue(HashMap component) { + // 兼容value类型是int、double等场景 + return getValueInStr(component, "value"); + } + + /** + * 根据指定的key获取对应的数值 + * + * @param component + * @param key + * @param backupKey + * @return + */ + + public final String getValueWithKey(HashMap component, String key, String backupKey) { + String componentValue = ""; + if (!StringUtility.isNullOrEmpty(key)) { + // 兼容value类型是int、double等场景 + componentValue = getValueInStr(component, key); + } + + if (StringUtility.isNullOrEmpty(componentValue) && !StringUtility.isNullOrEmpty(backupKey)) { + componentValue = getValueInStr(component, backupKey); + } + return componentValue; + } + + /** + * 根据指定的key获取对应的数值 + * + * @param component + * @param key + * @return + */ + + public final String getValueWithKey(HashMap component, String key) { + return getValueWithKey(component, key, ""); + } + + public final String getName(HashMap component) { + return getValueInStr(component, "name"); + } + + private String getValueInStr(HashMap component, String attributeName) { + if (StringUtility.isNullOrEmpty(attributeName)) { + return null; + } + Object componentNameObject = this.getValue(component, attributeName); + if (componentNameObject == null) { + return null; + } + if (componentNameObject instanceof Boolean) { + // 解決布尔类型toString后为True或False问题 + return componentNameObject.toString().toLowerCase(); + } else { + return componentNameObject.toString(); + } + } + + + public final String getCaption(HashMap component) { + return this.getValue(component, "caption"); + } + + public final String getTitle(HashMap component) { + return this.getValue(component, "title"); + } + + public final String getPresetQuerySolutionName(HashMap component) { + return this.getValue(component, "presetQuerySolutionName"); + } + + public final String getText(HashMap component) { + return this.getValue(component, "text"); + } + + public final String getHtml(HashMap component) { + return this.getValue(component, "html"); + } + + public final String getMainTitle(HashMap component) { + if (!this.checkAndIsString(component, "mainTitle")) { + return ""; + } + return this.getValue(component, "mainTitle"); + } + + /** + * 检测是否是字符串 + * + * @param component + * @param key + * @return + */ + private boolean checkAndIsString(HashMap component, String key) { + if (!component.containsKey(key)) { + return false; + } + // 如果不是字符串 + return (component.get(key) instanceof String); + } + + public final String getMainTitleName() { + return MAIN_TITLE; + } + + public final String getSubTitle(HashMap component) { + if (!this.checkAndIsString(component, "subTitle")) { + return ""; + } + return this.getValue(component, "subTitle"); + } + + public final String getSubTitleName() { + return SUB_TITLE; + } + + public final String getQueryName(HashMap component) { + if (!this.checkAndIsString(component, "queryName")) { + return ""; + } + return this.getValue(component, "queryName"); + } + + public final HashMap getProgressData(HashMap component) { + return GetAttributeObject(component, PROGRESS_DATA); + } + + public final String getProgressDataName(HashMap component) { + return PROGRESS_DATA; + } + + public final String getHeaderGroupName(HashMap component) { + return HEADER_GROUP; + } + + public final String getFieldRef(HashMap component) { + return this.getValue(component, "fieldRef"); + } + + public final boolean getCandidateNodeFlag(HashMap component) { + Boolean componentCandidateNodeFlag = this.getValue(component, "houxunquNode"); + if (componentCandidateNodeFlag == null) { + componentCandidateNodeFlag = false; + } + return componentCandidateNodeFlag; + } + + public final ArrayList> getHeaderGroup(HashMap component) { + return GetChildComponentCollection(component, HEADER_GROUP); + } + + + public final ArrayList> getStepMessages(HashMap component) { + return GetChildComponentCollection(component, STEP_MESSAGES); + } + + public final String getStepMessagesName(HashMap component) { + return STEP_MESSAGES; + } + + public final String getLineNumberTitle(HashMap component) { + return this.getValue(component, LINE_NUMBER_TITLE); + } + + public final String getGroupText(HashMap component) { + return this.getValue(component, GROUP_TEXT); + } + + public final String getUploadSelectText(HashMap component) { + return this.getValue(component, "uploadSelectText"); + } + + public final String getPreviewDefaultRename(HashMap component) { + if (!this.checkAndIsString(component, "previewDefaultRename")) { + return ""; + } + return this.getValue(component, "previewDefaultRename"); + } + + public final String getLabel(HashMap component) { + return this.getValue(component, ComponentNameType.LABEL); + } + + public List> getToolbarData(HashMap component) { + return GetChildComponentCollection(component, Toolbar_DATA); + } + + public String getToolbarDataName(HashMap component) { + return Toolbar_DATA; + } + + public final String getPlaceHolder(java.util.HashMap component) { + return getPlaceHolder(component, PLACE_HOLDER); + } + + + public final String getPlaceHolder(HashMap component, String placeHolder) { + return this.getValue(component, placeHolder); + } + + public final String getPlaceHolderCamel(HashMap component) { + return this.getValue(component, PLACE_HOLDERCAMEL); + } + + public final String getCollapseText(HashMap component) { + return this.getValue(component, CollapseText); + } + + public final String getExpandText(HashMap component) { + return this.getValue(component, ExpandText); + } + + public List> GetFieldsFromContentTemplate(HashMap component) { + return GetChildComponentCollection(component, "fields"); + } + + public HashMap GetInputGroupModalConfig(HashMap component) { + return GetAttributeObject(component, "modalConfig"); + } + + public ArrayList> getDataGridContextMenuItemChildren(HashMap component) { + return GetChildComponentCollection(component, "children"); + } + + /** + * controlSource + * + * @param component + * @return + */ + public final String GetControlSource(HashMap component) { + return this.getValue(component, ControlSource); + } + + public final String GetPlaceHolderName(HashMap component) { + return PLACE_HOLDER; + } + + public final String getBeginPlaceHolderName(HashMap component) { + return "beginPlaceHolder"; + } + + public final String getBeginPlaceHolder(java.util.HashMap component) { + return this.getValue(component, this.getBeginPlaceHolderName(component)); + } + + public final String getEndPlaceHolderName(HashMap component) { + return "endPlaceHolder"; + } + + public final String getEndPlaceHolder(java.util.HashMap component) { + return this.getValue(component, this.getEndPlaceHolderName(component)); + } + + public final String getExpandTextName(HashMap component) { + return ExpandText; + } + + public final String getCollapseTextName(HashMap component) { + return CollapseText; + } + + + public final String GetDiaglogTitle(HashMap component) { + String componentDialogTitle = this.getValue(component, DIAGLOG_TITLE); + if (StringUtility.isNullOrEmpty(componentDialogTitle)) { + componentDialogTitle = ""; + } + return componentDialogTitle; + } + + public List> GetToolbarContentsFromContentTemplate(HashMap component) { + return GetChildComponentCollection(component, "contents"); + } + + public final String GetDiaglogTitleName(HashMap component) { + return DIAGLOG_TITLE; + } + + public final String GetLineNumberTitleName(HashMap component) { + return LINE_NUMBER_TITLE; + } + + public final ArrayList> GetItems(HashMap component) { + return GetChildComponentCollection(component, "items"); + } + + public final String GetItemsName(HashMap component) { + return "items"; + } + + public final ArrayList> GetEnumData(HashMap component) { + return GetChildComponentCollection(component, ENUM_DATA); + } + + public final String GetEnumDataName(HashMap component) { + return ENUM_DATA; + } + + public List> GetNavData(HashMap component) { + return GetChildComponentCollection(component, NAV_DATA); + } + + public String GetNavDataName(HashMap component) { + return NAV_DATA; + } + + public final ArrayList> GetTagData(HashMap component) { + return GetChildComponentCollection(component, TAG_DATA); + } + + public final String GetTagDataName(HashMap component) { + return TAG_DATA; + } + + public final ArrayList> GetEnumValues(HashMap component) { + return GetChildComponentCollection(component, ENUM_VALUES); + } + + public final String GetEnumValuesName(HashMap component) { + return ENUM_VALUES; + } + + public final ArrayList> GetFieldConfigs(HashMap component) { + return GetChildComponentCollection(component, "fieldConfigs"); + } + + public ArrayList> getDataGridContextMenu(HashMap component) { + return GetChildComponentCollection(component, "contextMenuItems"); + } + + public final String getDataGridContextMenuName() { + return "contextMenuItems"; + } + + public final HashMap GetListFilterControl(HashMap component) { + return this.getValue(component, "control"); + } + + public HashMap GetListViewContentTemplate(HashMap component) { + Object contentTemplate = component.get(Content_Template); + + // 如果内容模板为字符串 那么不进行提取 + if (contentTemplate == null || contentTemplate instanceof String) { + return null; + } + return GetAttributeObject(component, Content_Template); + } + + + public final ArrayList> GetFilterList(HashMap component) { + return GetChildComponentCollection(component, "filterList"); + } + + public final ArrayList> GetToolbarCollection(HashMap component) { + return GetChildComponentCollection(component, "toolbar"); + } + + public final String GetAggregateTemplate(HashMap component) { + return this.getValue(component, "aggrTemplate"); + } + + public final String GetAggregateAttributeName(HashMap component) { + return "aggregate"; + } + + public List> GetFooterButtons(HashMap component) { + return GetChildComponentCollection(component, "footerButtons"); + } + + public final HashMap GetAggregate(HashMap component) { + return GetAttributeObject(component, "aggregate"); + } + + public final String GetGroupAggregateAttributeName(HashMap component) { + return "groupAggregate"; + } + + public final HashMap GetGroupAggregate(HashMap component) { + return GetAttributeObject(component, "groupAggregate"); + } + + public final String GetControlAttributeName(HashMap component) { + return CONTROL; + } + + public final HashMap GetControlAttributeObject(HashMap component) { + return GetAttributeObject(component, CONTROL); + } + + public final HashMap GetEditor(HashMap component) { + return GetAttributeObject(component, EDITOR); + } + + public final String GetEditorName(HashMap component) { + return EDITOR; + } + + public final HashMap GetFormatter(HashMap component) { + return GetAttributeObject(component, FORMATTER); + } + + public final String GetFormatterName(HashMap component) { + return FORMATTER; + } + + public final String GetTrueText(HashMap component) { + return this.getValue(component, TRUE_TEXT); + } + + public final String GetTrueTextName(HashMap component) { + return TRUE_TEXT; + } + + public final String GetFalseText(HashMap component) { + return this.getValue(component, FALSE_TEXT); + } + + public final String GetFalseTextName(HashMap component) { + return FALSE_TEXT; + } + + + public final HashMap GetToolbar(HashMap component) { + return GetAttributeObject(component, "toolbar"); + } + + /** + * 获取当前组件指定属性的子组件集合 + * + * @param component + * @param attributeName + * @return + */ + private ArrayList> GetChildComponentCollection(HashMap component, String attributeName) { + ArrayList> childCompnentCollection = new ArrayList<>(); + + Object attributeValue = component.get(attributeName); + + if (attributeValue == null) { + return childCompnentCollection; + } + + // 如何从object转换成List> + // https://stackoverflow.com/questions/632570/cast-received-object-to-a-listobject-or-ienumerableobject + ArrayList objectCollection = new ArrayList<>((List) attributeValue); + for (Object localComponent : objectCollection) { + // 从object转换成Dictionary + HashMap convertObject = ConvertToDictionaryObject(localComponent); + childCompnentCollection.add(convertObject); + } + + return childCompnentCollection; + } + + /** + * 获取当前指定属性(对象属性) + * + * @param component + * @param attributeName + * @return + */ + public final HashMap GetAttributeObject(HashMap component, String attributeName) { + HashMap attributeObject = null; + + if (component == null) { + return attributeObject; + } + + Object attributeValue = component.get(attributeName); + if (attributeValue == null) { + return attributeObject; + } + + // 从object转换成Dictionary + attributeObject = ConvertToDictionaryObject(attributeValue); + return attributeObject; + } + + // 如何从object转换成Dictionary + // https://stackoverflow.com/questions/11576886/how-to-convert-object-to-dictionarytkey-tvalue-in-c + private HashMap ConvertToDictionaryObject(Object targetObject) { + String json = SerializeUtility.getInstance().serialize(targetObject, false); + return SerializeUtility.getInstance().deserialize(json, HashMap.class); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyContext.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyContext.java new file mode 100644 index 00000000..50ef4e5f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyContext.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; + +import java.util.HashMap; + +/** + * 组件多语策略上下文 + */ +public class I18nResourceStrategyContext { + /** + * 组件策略 + */ + private final II18nResourceStrategy i18nResourceStrategy; + + /** + * 组件 + */ + private final HashMap component; + + /** + * 多语资源项基础ID + */ + private final String i18nResourceItemBaseId; + + public I18nResourceStrategyContext(HashMap currentComponent, String currentI18nResourceItemBaseId) { + this.component = currentComponent; + this.i18nResourceItemBaseId = currentI18nResourceItemBaseId; + + // 根据节点的类型,选用策略 + i18nResourceStrategy = I18nResourceStrategyFactory.getInstance().GetI18nResourceStrategy(currentComponent, currentI18nResourceItemBaseId); + } + + /** + * 获取多语资源 + */ + public final I18nResourceItemCollection ExtractI18nResource() { + if (i18nResourceStrategy == null) { + return null; + } + + return i18nResourceStrategy.extractI18nResource(i18nResourceItemBaseId, component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyFactory.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyFactory.java new file mode 100644 index 00000000..dcebae9f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceStrategyFactory.java @@ -0,0 +1,120 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy.*; +import com.inspur.edp.web.formmetadata.i18n.constant.ComponentType; + +import java.util.HashMap; + +/** + * 多语策略工厂 + */ +public class I18nResourceStrategyFactory { + + private static final HashMap dicComponentStrategies = new HashMap<>(); + + /** + * 静态单例属性 + */ + private static final I18nResourceStrategyFactory Instance = new I18nResourceStrategyFactory(); + + public static I18nResourceStrategyFactory getInstance() { + return Instance; + } + + private I18nResourceStrategyFactory() { + InitI18nResourceStrategyDictionary(); + } + + /** + * 更新多语资源策略字典 + */ + private void InitI18nResourceStrategyDictionary() { + // TODO: 进一步重构,将实例化策略的过程分离出去 + // 初始化意味着将很多的实例在启动时就进行了初始化 且不会释放 + dicComponentStrategies.put(ComponentType.TOOL_BAR_ITEM, new ToolBarItemI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.BUTTON, new ButtonI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.GRID_FIELD, new GridFieldI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.TREE_GRID_FIELD, new GridFieldI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.DATE_BOX, new DateBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.TEXT_BOX, new TextBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.CALENDAR, new CalendarI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.HTML_TEMPLATE, new HtmlTemplateI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.SECTION, new SectionI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.CHECK_GROUP, new CheckGroupI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.QUERY_SCHEME, new QuerySchemeI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.DATA_GRID, new DataGridI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.RADIO_GROUP, new RadioGroupI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.NUMERIC_BOX, new NumericBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.INPUT_GROUP, new InputGroupI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.MULTI_TEXT_BOX, new MultiTextBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.ENUM_FIELD, new EnumFieldI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.HELP_PROVIDER, new HelpProviderI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.TAG, new TagI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.FileUploadPreview, new FileUploadPreviewI18nResourceStrategy()); + + // 取消tags的国际化提取 + //dicComponentStrategies.Add(ComponentType.TAGS, new TagsI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.LIST_FILTER, new ListFilterI18nResourceStrategy()); + + + dicComponentStrategies.put(ComponentType.COMBOLIST, new ComboListI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.COMBOLOOKUP, new ComboLookupI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.LOOKUP, new LookupI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.LIST_NAV, new ListNavI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.SCROLL_SPY, new ScrollSpyI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.QUERY_FRAMEWORK, new QueryFrameworkI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.WIZARD, new WizardI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.TimePicker, new TimePickerI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.TimeSpinner, new TimeSpinnerI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.LanguageTextBox, new LanguageTextBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.DisplayField, new DefaultComponentI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.CheckBox, new DefaultComponentI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.TabToolbarItem, new DefaultComponentI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.DatePicker, new DatePickerI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.RichTextBox, new RichTextBoxI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.Image, new DefaultComponentI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.MultiSelect, new DefaultComponentI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.NumberRange, new NumberRangeI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.NumberSpinner, new NumberSpinnerI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.SwitchField, new DefaultComponentI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.FieldSet, new FieldSetI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.Footer, new FooterI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.Header, new HeaderI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.PersonnelSelector, new PersonnelSelectorI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.OrganizationSelector, new OrganizationSelectorI18nResourceStrategy()); + + dicComponentStrategies.put(ComponentType.ListView, new ListViewII18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.ExternalContainer, null); + dicComponentStrategies.put(ComponentType.Steps, null); + + dicComponentStrategies.put(ComponentType.NavTab, new NavTabI18nResourceStrategy()); + dicComponentStrategies.put(ComponentType.ViewChange, new ViewChangeI18nResourceStrategy()); + } + + /** + * 根据组件创建对应的多语策略 + */ + public final AbstractI18nResourceStrategy GetI18nResourceStrategy(HashMap currentComponent, String i18nResourceBaseId) { + // 获取组件的类型 + String componentType = ComponentUtility.getInstance().getType(currentComponent); + + if (StringUtility.isNullOrEmpty(componentType)) { + return null; + } + + + AbstractI18nResourceStrategy componentI18nResourceStrategy = dicComponentStrategies.get(componentType); + if (componentI18nResourceStrategy == null) { + return new DefaultComponentI18nResourceStrategy(); + } + return componentI18nResourceStrategy; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceUtility.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceUtility.java new file mode 100644 index 00000000..e16e5f2d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/I18nResourceUtility.java @@ -0,0 +1,117 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + + +import java.util.HashMap; +import java.util.List; + +public class I18nResourceUtility { + + private I18nResourceUtility() { + + } + + private static final I18nResourceUtility i18nResourceUtilityInstance = new I18nResourceUtility(); + + public static I18nResourceUtility GetInstance() { + return i18nResourceUtilityInstance; + } + + + /** + * 提取枚举属性中多语资源项 + * + * @return + */ + public final I18nResourceItemCollection ExtractEnumDataI18nResourceItemCollection(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, List> componentCollection, String enumAttributeName, String valueField, String textField){ + I18nResourceItemCollection enumValuesI18nResourceItemCollection = new I18nResourceItemCollection(); + + enumI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER; + for (HashMap component : componentCollection) { + I18nResourceItem i18nResourceItem = GetEnumItemI18nResourceItem(i18nResourceItemBaseId, enumI18nResourceItemBaseId + enumAttributeName, component, valueField, textField); + if (i18nResourceItem != null) { + enumValuesI18nResourceItemCollection.add(i18nResourceItem); + } + } + + return enumValuesI18nResourceItemCollection; + } + + /** + * 获取枚举项中多语资源项 + * + * @param enumI18nResourceItemBaseId + * @param enumItemObject + * @return + */ + + private I18nResourceItem GetEnumItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, java.util.HashMap enumItemObject, String valueField) { + return GetEnumItemI18nResourceItem(i18nResourceItemBaseId, enumI18nResourceItemBaseId, enumItemObject, valueField, "textField"); + } + + private I18nResourceItem GetEnumItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, java.util.HashMap enumItemObject) { + return GetEnumItemI18nResourceItem(i18nResourceItemBaseId, enumI18nResourceItemBaseId, enumItemObject, "valueField", "textField"); + } + + //C# TO JAVA CONVERTER NOTE: Java does not support optional parameters. Overloaded method(s) are created above: +//ORIGINAL LINE: private I18nResourceItem GetEnumItemI18nResourceItem(string i18nResourceItemBaseId, string enumI18nResourceItemBaseId, Dictionary enumItemObject, string valueField = "valueField", string textField = "textField") + private I18nResourceItem GetEnumItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap enumItemObject, String valueField, String textField) { + I18nResourceItem i18nResourceItem = null; + + // 属性为value的值 + String valueAtributeValue = ComponentUtility.getInstance().getValueWithKey(enumItemObject, valueField, "value"); + String nameAtributeValue = ComponentUtility.getInstance().getValueWithKey(enumItemObject, textField, "name"); + if (!StringUtility.isNullOrEmpty(valueAtributeValue)) { + String componentId = valueAtributeValue; + + String generatedComponentId = enumI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + } + + return i18nResourceItem; + } + + + /** + * 提取placeHolder属性中多语资源项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + public final I18nResourceItemCollection ExtractPlaceHolderI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String placeHolderValue = ComponentUtility.getInstance().getPlaceHolder(currentComponent); + String placeHolderName = ComponentUtility.getInstance().GetPlaceHolderName(currentComponent); + + String componentId = placeHolderName; + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + // 数字类型的控件 + if (!StringUtility.isNullOrEmpty(currentComponentType) && + "NumericBox".equals(currentComponentType)) { + String strControlSource = ComponentUtility.getInstance().GetControlSource(currentComponent); + if (!StringUtility.isNullOrEmpty(strControlSource) && + "Farris".equals(strControlSource)) { + currentComponentType = "NumberSpinner"; + } + } + + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, placeHolderValue, placeHolderValue); + i18nResourceItemCollection.add(i18nResourceItem); + + + return i18nResourceItemCollection; + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/IComponent.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/IComponent.java new file mode 100644 index 00000000..430d1048 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/IComponent.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import java.util.HashMap; + +/** + * 组件接口 + */ +public interface IComponent { + /** + * 组件实体 + *

+ * TODO: 抽象组件的实体接口及实体类(面向对象) + */ + HashMap getComponentEntity(); +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/II18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/II18nResourceStrategy.java new file mode 100644 index 00000000..9e515b95 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/II18nResourceStrategy.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.formmetadata.i18n.component; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; + +import java.util.*; + +/** + 组件策略接口 +*/ +public interface II18nResourceStrategy +{ + /** + 提取多语资源 + + @param i18nResourceItemBaseId + @param currentComponent + @return + */ + I18nResourceItemCollection extractI18nResource(String i18nResourceItemBaseId, HashMap currentComponent); +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/AbstractI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/AbstractI18nResourceStrategy.java new file mode 100644 index 00000000..7dfe047a --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/AbstractI18nResourceStrategy.java @@ -0,0 +1,123 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.II18nResourceStrategy; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy.ComponentIdFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy.ComponentIdType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy.IComponentIdStrategy; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; + +/** + * 组件多语策略抽象类 + * @author guozhiqi + */ +public abstract class AbstractI18nResourceStrategy implements II18nResourceStrategy { + /** + * 从组件中提取多语资源 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + public final I18nResourceItemCollection extractI18nResource(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection componentI18nResourceItemCollection = extractComponentI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (componentI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(componentI18nResourceItemCollection); + } + + // 提取属性中多语资源 + I18nResourceItemCollection attributeI18nResourceItemCollection = extractAttributeI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (attributeI18nResourceItemCollection != null && attributeI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(attributeI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /** + * 提取组件项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection extractComponentI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 提取当前组件的Id和Name + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItem i18nResourceItem = getComponentNameI18nResourceItem(i18nResourceItemBaseId, currentComponent); + if (i18nResourceItem != null) { + i18nResourceItemCollection.add(i18nResourceItem); + } + + // Extend: 组件中存在多个字段需要提取 + + return i18nResourceItemCollection; + } + + /** + * 提取组件name属性 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItem getComponentNameI18nResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + // 读取组件名称 + String componentName = getComponentName(currentComponent); + if (StringUtils.isEmpty(componentName)) { + componentName = ""; + } + + // 读取组件ID + String generatedComponentId = getComponentId(currentComponent); + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, componentName, componentName); + } + + /** + * 获取当前组件的名称 组件常见的属性设置 + * + * @param currentComponent + * @return + */ + protected String getComponentName(HashMap currentComponent) { + // 读取组件名称 + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.NAME); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(currentComponent); + } + + protected String getComponentId(HashMap currentComponent) { + IComponentIdStrategy componentIdStrategy = ComponentIdFactory.getInstance().creatComponentIdStrategy(ComponentIdType.ID); + if (componentIdStrategy == null) { + return null; + } + + return componentIdStrategy.getComponentId(currentComponent); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + return null; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ButtonI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ButtonI18nResourceStrategy.java new file mode 100644 index 00000000..d3f3ec48 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ButtonI18nResourceStrategy.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * @author noah + */ +public class ButtonI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TEXT); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CalendarI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CalendarI18nResourceStrategy.java new file mode 100644 index 00000000..d3ab9cd0 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CalendarI18nResourceStrategy.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * calendar 国际化参数提取 + * @author noah + */ +public class CalendarI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CheckGroupI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CheckGroupI18nResourceStrategy.java new file mode 100644 index 00000000..9de59c22 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/CheckGroupI18nResourceStrategy.java @@ -0,0 +1,93 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 复选框组 国际化参数提取 + * @author noah + */ +public class CheckGroupI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap currentComponent) { + // 读取组件名称 + // 从title属性中获取组件名称 + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(currentComponent); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从html属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection itemsI18nResourceItemCollection = extractComponentItemsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (itemsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(itemsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractComponentItemsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从items属性中提取多语资源 + ArrayList> childComponents = ComponentUtility.getInstance().GetItems(currentComponent); + I18nResourceItemCollection childComponentsI18nResourceItemCollection = exetractChildComponentsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, childComponents); + if (childComponentsI18nResourceItemCollection != null && childComponentsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection exetractChildComponentsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent, ArrayList> childComponentList) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtils.isEmpty(currentComponentType) || StringUtils.isEmpty(currentComponentType)) { + return null; + } + + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.ValueFieldKey,""); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.TextFieldKey,""); + + for (HashMap childComponent : childComponentList) { + // 属性为value的值 + String valueAtributeValue = ComponentUtility.getInstance().getValueWithKey(childComponent, strValueFieldKey, "value"); + String nameAtributeValue = ComponentUtility.getInstance().getValueWithKey(childComponent, strTextFieldKey, "name"); + if (!StringUtils.isEmpty(valueAtributeValue)) { + // 使用 "/"作为分隔符 + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + valueAtributeValue; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + } + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboListI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboListI18nResourceStrategy.java new file mode 100644 index 00000000..fbe3474e --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboListI18nResourceStrategy.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * 下拉控件 + * @author noah + */ +public class ComboListI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboLookupI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboLookupI18nResourceStrategy.java new file mode 100644 index 00000000..f633af2d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ComboLookupI18nResourceStrategy.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * 下拉帮助国际化参数提取 + * @author noah + */ +public class ComboLookupI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DataGridI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DataGridI18nResourceStrategy.java new file mode 100644 index 00000000..91d9a150 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DataGridI18nResourceStrategy.java @@ -0,0 +1,186 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * datagrid 国际化参数日趋策略 + * + * @author noah + */ +public class DataGridI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从lineNumberTitle属性中提取多语字段 + I18nResourceItemCollection LineNumberTitleI18nResourceItemCollection = ExtractComponentLineNumberTitleI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (LineNumberTitleI18nResourceItemCollection != null && LineNumberTitleI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(LineNumberTitleI18nResourceItemCollection); + } + + // 从headerGroup属性中提取多语字段 + String headerGroupI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + I18nResourceItemCollection headerGroupI18nResourceItemCollection = ExtractHeaderGroupResourceItemCollection(i18nResourceItemBaseId, headerGroupI18nResourceItemBaseId, currentComponent); + if (headerGroupI18nResourceItemCollection != null && headerGroupI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(headerGroupI18nResourceItemCollection); + } + + //提取grid 的操作列 + I18nResourceItemCollection operateButtonResourceItemCollection = ExtractComponentOperateButtonI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (operateButtonResourceItemCollection != null && operateButtonResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(operateButtonResourceItemCollection); + } + + // 提取上下问菜单中的title参数 + I18nResourceItemCollection contextMenuResourceItemCollection = extractContextMenu(i18nResourceItemBaseId, currentComponent); + if (contextMenuResourceItemCollection != null && contextMenuResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(contextMenuResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /** + * 提取列表上下文参数 + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection extractContextMenu(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + String contextMenuI18nResourceBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + "contextMenuItems" + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + ArrayList> contextMenuItemList = ComponentUtility.getInstance().getDataGridContextMenu(currentComponent); + if (contextMenuItemList != null) { + contextMenuItemList.forEach(t -> extractContextMenuItem(i18nResourceItemBaseId, contextMenuI18nResourceBaseId, t, i18nResourceItemCollection)); + } + return i18nResourceItemCollection; + } + + /** + * 提取列表上下文参数中的具体项及其children + * @param i18nResourceItemBaseId + * @param contextMenuResourceBaseId + * @param contextMenuItem + * @param contextMenuResourceCollection + */ + private void extractContextMenuItem(String i18nResourceItemBaseId, String contextMenuResourceBaseId, HashMap contextMenuItem, I18nResourceItemCollection contextMenuResourceCollection) { + String contextMenuItemId = ComponentUtility.getInstance().getId(contextMenuItem); + String title = ComponentUtility.getInstance().getTitle(contextMenuItem); + String resourceId = contextMenuResourceBaseId + contextMenuItemId; + I18nResourceItem contextMenuI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, resourceId, title, title); + contextMenuResourceCollection.add(contextMenuI18nResourceItem); + + //获取对应的children的值 + ArrayList> contextMenuItemChildren = ComponentUtility.getInstance().getDataGridContextMenuItemChildren(contextMenuItem); + if (contextMenuItemChildren != null) { + contextMenuItemChildren.forEach(t -> this.extractContextMenuItem(i18nResourceItemBaseId, contextMenuResourceBaseId, t, contextMenuResourceCollection)); + } + } + + /** + * 提取farris-grid的 操作列 编辑、删除 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection ExtractComponentOperateButtonI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType)) { + return null; + } + + String operateEditButtonAtributeName = "OperateEditButton"; + String operateEditButtonAtributeValue = "编辑"; + // 使用 "/"作为分隔符 + String generatedOperateEditButtonComponentId = currentComponentType + "/" + currentComponentId + "/" + operateEditButtonAtributeName; + I18nResourceItem editI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedOperateEditButtonComponentId, operateEditButtonAtributeValue, operateEditButtonAtributeValue); + i18nResourceItemCollection.add(editI18nResourceItem); + + + String operateDeleteButtonAtributeName = "OperateDeleteButton"; + String operateDeleteButtonAtributeValue = "删除"; + // 使用 "/"作为分隔符 + String generatedOperateDeleteButtonComponentId = currentComponentType + "/" + currentComponentId + "/" + operateDeleteButtonAtributeName; + I18nResourceItem deleteI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedOperateDeleteButtonComponentId, operateDeleteButtonAtributeValue, operateDeleteButtonAtributeValue); + i18nResourceItemCollection.add(deleteI18nResourceItem); + + + String operateColumnAtributeName = "OperateColumn"; + String operateColumnAtributeValue = "操作"; + // 使用 "/"作为分隔符 + String generatedOperateColumnComponentId = currentComponentType + "/" + currentComponentId + "/" + operateColumnAtributeName; + I18nResourceItem operateColumnI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedOperateColumnComponentId, operateColumnAtributeValue, operateColumnAtributeValue); + i18nResourceItemCollection.add(operateColumnI18nResourceItem); + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection ExtractComponentLineNumberTitleI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + String lineNumberTitleAtributeName = ComponentUtility.getInstance().GetLineNumberTitleName(currentComponent); + String lineNumberTitleAtributeValue = ComponentUtility.getInstance().getLineNumberTitle(currentComponent); + + // 使用 "/"作为分隔符 + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + lineNumberTitleAtributeName; + if (!StringUtility.isNullOrEmpty(lineNumberTitleAtributeValue)) { + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, lineNumberTitleAtributeValue, lineNumberTitleAtributeValue); + + i18nResourceItemCollection.add(i18nResourceItem); + } else { + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, "", ""); + i18nResourceItemCollection.add(i18nResourceItem); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection ExtractHeaderGroupResourceItemCollection(String i18nResourceItemBaseId, String headerGroupI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + headerGroupI18nResourceItemBaseId = headerGroupI18nResourceItemBaseId + ComponentUtility.getInstance().getHeaderGroupName(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + + ArrayList> headerGroupItemCollection = ComponentUtility.getInstance().getHeaderGroup(currentComponent); + + for (HashMap headerGroupItem : headerGroupItemCollection) { + if (!StringUtility.isNullOrEmpty(ComponentUtility.getInstance().getFieldRef(headerGroupItem)) || ComponentUtility.getInstance().getCandidateNodeFlag(headerGroupItem)) { + continue; + } + + String componentId = ComponentUtility.getInstance().getId(headerGroupItem); + String componentName = ComponentUtility.getInstance().getCaption(headerGroupItem); + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, headerGroupI18nResourceItemBaseId + componentId, componentName, componentName); + if (i18nResourceItem != null) { + i18nResourceItemCollection.add(i18nResourceItem); + } + } + + return i18nResourceItemCollection; + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DateBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DateBoxI18nResourceStrategy.java new file mode 100644 index 00000000..413baa63 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DateBoxI18nResourceStrategy.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * datebox 国际化提取策略 + * @author noah + */ +public class DateBoxI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DatePickerI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DatePickerI18nResourceStrategy.java new file mode 100644 index 00000000..5c3ec4c8 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DatePickerI18nResourceStrategy.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * datepicker 国际化参数提取 + * @author noah + */ +public class DatePickerI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DefaultComponentI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DefaultComponentI18nResourceStrategy.java new file mode 100644 index 00000000..75cbe47f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/DefaultComponentI18nResourceStrategy.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * 默认的组件策略 读取title属性作为文本显示 + * @author noah + */ +public class DefaultComponentI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/EnumFieldI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/EnumFieldI18nResourceStrategy.java new file mode 100644 index 00000000..c33a8175 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/EnumFieldI18nResourceStrategy.java @@ -0,0 +1,63 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 枚举字段国际化参数提取 + * @author noah + */ +public class EnumFieldI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.IdFieldKey, I18nResourceConstant.ValueFieldKey); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.TextFieldKey); + + // 从enumData中提取多语资源项 + ArrayList> enumValueCollection = ComponentUtility.getInstance().GetEnumData(currentComponent); + String enumDataAttributeName = ComponentUtility.getInstance().GetEnumDataName(currentComponent); + String enumDataI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent); + I18nResourceItemCollection enumDataI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractEnumDataI18nResourceItemCollection(i18nResourceItemBaseId, enumDataI18nResourceItemBaseId, enumValueCollection, enumDataAttributeName, strValueFieldKey, strTextFieldKey); + if (enumDataI18nResourceItemCollection != null && enumDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(enumDataI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FieldSetI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FieldSetI18nResourceStrategy.java new file mode 100644 index 00000000..3c763a37 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FieldSetI18nResourceStrategy.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; + +/** + * fieldset 国际化参数提取 + * @author noah + */ +public class FieldSetI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中收起、展开项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 提取收折文本 + I18nResourceItem collapseTextI18nResourceItem = ExtractCollapseTextResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(collapseTextI18nResourceItem); + + I18nResourceItem expandTextI18nResourceItem = ExtractExpandTextResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(expandTextI18nResourceItem); + + + return i18nResourceItemCollection; + } + + private I18nResourceItem ExtractCollapseTextResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String collapseTextValue = ComponentUtility.getInstance().getCollapseText(currentComponent); + String collapseTextName = ComponentUtility.getInstance().getCollapseTextName(currentComponent); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + collapseTextName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, collapseTextValue, collapseTextValue); + } + + private I18nResourceItem ExtractExpandTextResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String expandTextValue = ComponentUtility.getInstance().getExpandText(currentComponent); + String expandTextName = ComponentUtility.getInstance().getExpandTextName(currentComponent); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + expandTextName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, expandTextValue, expandTextValue); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FileUploadPreviewI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FileUploadPreviewI18nResourceStrategy.java new file mode 100644 index 00000000..4d27611a --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FileUploadPreviewI18nResourceStrategy.java @@ -0,0 +1,80 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; + +/** + * 附件上传、预览多语参数提取 + * @author guozhiqi + */ +public class FileUploadPreviewI18nResourceStrategy extends AbstractI18nResourceStrategy{ + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + I18nResourceItemCollection uploadSelectTextI18nResourceItemCollection = this.extractUploadSelectTextI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (uploadSelectTextI18nResourceItemCollection != null && uploadSelectTextI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(uploadSelectTextI18nResourceItemCollection); + } + + I18nResourceItemCollection previewDefaultNameI18nResourceItemCollection = this.extractPreviewDefaultNameI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (previewDefaultNameI18nResourceItemCollection != null && previewDefaultNameI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(previewDefaultNameI18nResourceItemCollection); + } + return i18nResourceItemCollection; + } + + /** + * 提取groupText属性中多语资源项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection extractUploadSelectTextI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String uploadSelectTextValue = ComponentUtility.getInstance().getUploadSelectText(currentComponent); + String uploadSelectTextName = "uploadSelectText"; + + String componentId = uploadSelectTextName; + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, uploadSelectTextValue, uploadSelectTextValue); + i18nResourceItemCollection.add(i18nResourceItem); + + return i18nResourceItemCollection; + } + + + private I18nResourceItemCollection extractPreviewDefaultNameI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String uploadSelectTextValue = ComponentUtility.getInstance().getPreviewDefaultRename(currentComponent); + String uploadSelectTextName = "previewDefaultRename"; + + String componentId = uploadSelectTextName; + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, uploadSelectTextValue, uploadSelectTextValue); + i18nResourceItemCollection.add(i18nResourceItem); + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FooterI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FooterI18nResourceStrategy.java new file mode 100644 index 00000000..7cb1d8c8 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/FooterI18nResourceStrategy.java @@ -0,0 +1,70 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; + +public class FooterI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中收起、展开项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 提取收折文本 + I18nResourceItem collapseTextI18nResourceItem = extractCollapseTextResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(collapseTextI18nResourceItem); + + I18nResourceItem expandTextI18nResourceItem = extractExpandTextResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(expandTextI18nResourceItem); + + + return i18nResourceItemCollection; + } + + private I18nResourceItem extractCollapseTextResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String collapseTextValue = ComponentUtility.getInstance().getCollapseText(currentComponent); + String collapseTextName = ComponentUtility.getInstance().getCollapseTextName(currentComponent); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + collapseTextName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, collapseTextValue, collapseTextValue); + } + + private I18nResourceItem extractExpandTextResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String expandTextValue = ComponentUtility.getInstance().getExpandText(currentComponent); + String expandTextName = ComponentUtility.getInstance().getExpandTextName(currentComponent); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + expandTextName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, expandTextValue, expandTextValue); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/GridFieldI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/GridFieldI18nResourceStrategy.java new file mode 100644 index 00000000..dd3cd4bc --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/GridFieldI18nResourceStrategy.java @@ -0,0 +1,154 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentContext; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +public class GridFieldI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.CAPTION); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection aggregateI18nResourceItemCollection = extractComponentAggregateI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (aggregateI18nResourceItemCollection != null && aggregateI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(aggregateI18nResourceItemCollection); + } + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.ValueFieldKey); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.TextFieldKey); + + // 从enumData中提取多语资源项 + ArrayList> enumValueCollection = ComponentUtility.getInstance().GetEnumData(currentComponent); + String enumDataAttributeName = ComponentUtility.getInstance().GetEnumDataName(currentComponent); + String enumDataI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent); + I18nResourceItemCollection enumDataI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractEnumDataI18nResourceItemCollection(i18nResourceItemBaseId, enumDataI18nResourceItemBaseId, enumValueCollection, enumDataAttributeName, strValueFieldKey, strTextFieldKey); + if (enumDataI18nResourceItemCollection != null && enumDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(enumDataI18nResourceItemCollection); + } + + // 从editor中提取多语资源项 + HashMap editorAttributeObject = ComponentUtility.getInstance().GetEditor(currentComponent); + // 排除grid中editor为枚举的值的提取 + if (editorAttributeObject != null && + !"EnumField".equals(ComponentUtility.getInstance().getType(editorAttributeObject))) { + String editorI18nResourceItemBaseId = i18nResourceItemBaseId + ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().GetEditorName(editorAttributeObject) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + ComponentContext componentI18nResourceContext = new ComponentContext(editorAttributeObject, editorI18nResourceItemBaseId); + I18nResourceItemCollection editorI18nResourceItemCollection = componentI18nResourceContext.extractI18nResource(); + if (editorI18nResourceItemCollection != null && editorI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(editorI18nResourceItemCollection); + } + } + + + // 从formatter中提取多语资源项 + HashMap formatterAttributeObject = ComponentUtility.getInstance().GetFormatter(currentComponent); + String formatterI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent); + I18nResourceItemCollection formatterI18nResourceItemCollection = extractFormatterI18nResource(i18nResourceItemBaseId, formatterI18nResourceItemBaseId, formatterAttributeObject); + if (formatterI18nResourceItemCollection != null && formatterI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(formatterI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractFormatterI18nResource(String i18nResourceItemBaseId, String fielI18nResourceItemBaseId, HashMap formatterObject) { + I18nResourceItemCollection formatterI18nResourceItemCollection = null; + if (StringUtility.isNullOrEmpty(fielI18nResourceItemBaseId) || formatterObject == null) { + return formatterI18nResourceItemCollection; + } + + String formatterI18nResourceItemBaseId = fielI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().GetFormatterName(formatterObject); + + // boolean目前仅用于formatter,后续提取成常量 + if ("boolean".equals(ComponentUtility.getInstance().getType(formatterObject))) + { + formatterI18nResourceItemCollection = new I18nResourceItemCollection(); + String trueTextValue = ComponentUtility.getInstance().GetTrueText(formatterObject); + String trueTextName = ComponentUtility.getInstance().GetTrueTextName(formatterObject); + I18nResourceItem trueTextI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, formatterI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + trueTextName, trueTextValue, trueTextValue); + formatterI18nResourceItemCollection.add(trueTextI18nResourceItem); + + String falseTextValue = ComponentUtility.getInstance().GetFalseText(formatterObject); + String falseTextName = ComponentUtility.getInstance().GetFalseTextName(formatterObject); + I18nResourceItem falseTextI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, formatterI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + falseTextName, falseTextValue, falseTextValue); + formatterI18nResourceItemCollection.add(falseTextI18nResourceItem); + } + + return formatterI18nResourceItemCollection; + } + + private I18nResourceItemCollection extractComponentAggregateI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从aggregate属性中提取多语资源项 + HashMap aggregateObject = ComponentUtility.getInstance().GetAggregate(currentComponent); + String aggregateAttributeName = ComponentUtility.getInstance().GetAggregateAttributeName(currentComponent); + I18nResourceItemCollection aggregateObjectI18nResourceItemCollection = extractAggregateTemplateI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, aggregateObject, aggregateAttributeName); + if (aggregateObjectI18nResourceItemCollection != null && aggregateObjectI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(aggregateObjectI18nResourceItemCollection); + } + + // 从groupAggregate属性中提取多语资源项 + HashMap groupAggregateObject = ComponentUtility.getInstance().GetGroupAggregate(currentComponent); + String groupAggregateAttributeName = ComponentUtility.getInstance().GetGroupAggregateAttributeName(currentComponent); + I18nResourceItemCollection groupAggregateObjectI18nResourceItemCollection = extractAggregateTemplateI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, groupAggregateObject, groupAggregateAttributeName); + if (groupAggregateObjectI18nResourceItemCollection != null && groupAggregateObjectI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(groupAggregateObjectI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractAggregateTemplateI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent, HashMap aggregateObject, String aggregateAttributeName) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + // 属性为AggregateTemplate的值 + String aggregateTemplateAtributeValue = ComponentUtility.getInstance().GetAggregateTemplate(aggregateObject); + + if (!StringUtility.isNullOrEmpty(aggregateTemplateAtributeValue)) { + // 使用合并属性的名称作为组件id + String componentId = aggregateAttributeName; + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, aggregateTemplateAtributeValue, aggregateTemplateAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HeaderI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HeaderI18nResourceStrategy.java new file mode 100644 index 00000000..466e53fe --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HeaderI18nResourceStrategy.java @@ -0,0 +1,73 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; + +/** + * header 组件的国际化提取 + */ +public class HeaderI18nResourceStrategy extends AbstractI18nResourceStrategy{ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // mainTitle 提取 + I18nResourceItem mainTitleI18nResourceItem = extractMainTitleResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(mainTitleI18nResourceItem); + + // subTitle提取 + I18nResourceItem subTitleI18nResourceItem = extractSubTitleResourceItem(i18nResourceItemBaseId, currentComponent); + i18nResourceItemCollection.add(subTitleI18nResourceItem); + + return i18nResourceItemCollection; + } + + private I18nResourceItem extractMainTitleResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String mainTitleValue = ComponentUtility.getInstance().getMainTitle(currentComponent); + String mainTitleName = ComponentUtility.getInstance().getMainTitleName(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + mainTitleName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, mainTitleValue, mainTitleValue); + } + + private I18nResourceItem extractSubTitleResourceItem(String i18nResourceItemBaseId, HashMap currentComponent) { + String subTitleValue = ComponentUtility.getInstance().getSubTitle(currentComponent); + String subTitleName = ComponentUtility.getInstance().getSubTitleName(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + subTitleName; + + return I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, subTitleValue, subTitleValue); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HelpProviderI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HelpProviderI18nResourceStrategy.java new file mode 100644 index 00000000..0976ba0d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HelpProviderI18nResourceStrategy.java @@ -0,0 +1,78 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; + +/** + * 帮助控件 + */ +public class HelpProviderI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + I18nResourceItemCollection dialogTitleI18nResourceItemCollection = ExtractDialogTitleI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (dialogTitleI18nResourceItemCollection != null && dialogTitleI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(dialogTitleI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /** + * 获取dialogTitle属性中多语资源项集合 + */ + private I18nResourceItemCollection ExtractDialogTitleI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从dialogTitle属性中提取多语字段 + String dialogTitleValue = ComponentUtility.getInstance().GetDiaglogTitle(currentComponent); + String dialogTitleName = ComponentUtility.getInstance().GetDiaglogTitleName(currentComponent); + if (!StringUtils.isEmpty(dialogTitleName)) { + String componentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + dialogTitleName; + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, dialogTitleValue, dialogTitleValue); + i18nResourceItemCollection.add(i18nResourceItem); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HtmlTemplateI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HtmlTemplateI18nResourceStrategy.java new file mode 100644 index 00000000..e6793832 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/HtmlTemplateI18nResourceStrategy.java @@ -0,0 +1,129 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HtmlTemplateI18nResourceStrategy extends AbstractI18nResourceStrategy { + private Pattern extractPattern = null; + private Pattern specificPattern = null; + + public HtmlTemplateI18nResourceStrategy() { + // 用于匹配{{}}结构的字符 + this.extractPattern = Pattern.compile("(?<=\\{\\{)[^}]*(?=\\}\\})"); + + // 用于匹配 ${Title:"name"} 类似的结构 + this.specificPattern = Pattern.compile("\\$\\{([^\\}]+):([^\\}]+)\\}"); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从html属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection htmlI18nResourceItemCollection = ExtractComponentHtmlI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (htmlI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(htmlI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection ExtractComponentHtmlI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从html属性中提取多语资源 + String htmlValue = ComponentUtility.getInstance().getHtml(currentComponent); + if (StringUtility.isNullOrEmpty(htmlValue)) { + return i18nResourceItemCollection; + } + + Matcher matcher = this.extractPattern.matcher(htmlValue); + while (matcher.find()) { + String i18nResourceExpress = matcher.group(); + int expressDelimiterIndex = i18nResourceExpress.indexOf("|"); + if (expressDelimiterIndex > 0) { + String componentIdStr = i18nResourceExpress.substring(0, expressDelimiterIndex).trim(); + + String[] componentIdStrArray = componentIdStr.split(java.util.regex.Pattern.quote("'"), -1); + + if (componentIdStrArray.length == 3) { + String componentId = componentIdStrArray[1]; + + System.out.println("componentId is: " + componentId); + + String generatedComponentId = componentId; + System.out.println(generatedComponentId); + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, "", ""); + + i18nResourceItemCollection.add(i18nResourceItem); + } + } + } + + Matcher specificMatcher = this.specificPattern.matcher(htmlValue); + + List resourceIdList = new ArrayList<>(); + while (specificMatcher.find()) { + int groupCount = specificMatcher.groupCount(); + if (groupCount != 2) { + continue; + } + String firstTitle = specificMatcher.group(1).trim(); + if (firstTitle == null) { + continue; + } + + while (firstTitle.startsWith("\"") || firstTitle.startsWith("'")) { + firstTitle = firstTitle.substring(1); + } + + while (firstTitle.endsWith("\"") || firstTitle.endsWith("'")) { + firstTitle = firstTitle.substring(0, firstTitle.length() - 1); + } + + String secondValue = specificMatcher.group(2); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + firstTitle; + + + // 确保添加到资源项的key 不进行重复 + if (!resourceIdList.contains(generatedComponentId)) { + while (secondValue.startsWith("\"") || secondValue.startsWith("'")) { + secondValue = secondValue.substring(1); + } + + while (secondValue.endsWith("\"") || secondValue.endsWith("'")) { + secondValue = secondValue.substring(0, secondValue.length() - 1); + } + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, secondValue, secondValue); + + i18nResourceItemCollection.add(i18nResourceItem); + + resourceIdList.add(generatedComponentId); + } + } + + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/InputGroupI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/InputGroupI18nResourceStrategy.java new file mode 100644 index 00000000..cb980360 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/InputGroupI18nResourceStrategy.java @@ -0,0 +1,135 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; +import java.util.List; + +public class InputGroupI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + + I18nResourceItemCollection groupTextI18nResourceItemCollection = this.extractGroupTextI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (groupTextI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(groupTextI18nResourceItemCollection); + } + + // 填充inputgroup 弹窗 + I18nResourceItemCollection modalConfigResourceItemCollection = extractModalConfigI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (modalConfigResourceItemCollection != null && modalConfigResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(modalConfigResourceItemCollection); + } + return i18nResourceItemCollection; + } + + /** + * 提取groupText属性中多语资源项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection extractGroupTextI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String groupTextValue = ComponentUtility.getInstance().getGroupText(currentComponent); + String groupTextName = "groupText"; + + String componentId = groupTextName; + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + String generatedComponentId = currentComponentType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + currentComponentId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, groupTextValue, groupTextValue); + i18nResourceItemCollection.add(i18nResourceItem); + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractModalConfigI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + HashMap modalConfigComponent = ComponentUtility.getInstance().GetInputGroupModalConfig(currentComponent); + if (modalConfigComponent == null || modalConfigComponent.size() == 0) { + return null; + } + + String modalConfigTitle = ComponentUtility.getInstance().getTitle(modalConfigComponent); + + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/modalconfig/"; + // inputgroup 弹窗标题 + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId + "title", modalConfigTitle, modalConfigTitle); + i18nResourceItemCollection.add(i18nResourceItem); + + I18nResourceItemCollection footerButtonResourceCollection = extractModalConfigFooterButtonsI18nResourceCollection(i18nResourceItemBaseId, generatedComponentId, currentComponent, modalConfigComponent); + if (footerButtonResourceCollection.size() > 0) { + i18nResourceItemCollection.addRange(footerButtonResourceCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractModalConfigFooterButtonsI18nResourceCollection(String i18nResourceItemBaseId, String parentResourceId, HashMap currentComponent, HashMap modalConfigComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + List> footerButtonsComponent = ComponentUtility.getInstance().GetFooterButtons(modalConfigComponent); + if (footerButtonsComponent != null && footerButtonsComponent.size() > 0) { + footerButtonsComponent.forEach((item) -> + { + String footerButtonType = ComponentUtility.getInstance().getType(item); + String footerButtonId = ComponentUtility.getInstance().getId(item); + String footerButtonText = ComponentUtility.getInstance().getText(item); + String generatedComponentId = parentResourceId + "footerButtons/" + footerButtonType + "/" + footerButtonId; + I18nResourceItem footerButtonI18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, footerButtonText, footerButtonText); + + i18nResourceItemCollection.add(footerButtonI18nResourceItem); + }); + } + return i18nResourceItemCollection; + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LanguageTextBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LanguageTextBoxI18nResourceStrategy.java new file mode 100644 index 00000000..6b6504bc --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LanguageTextBoxI18nResourceStrategy.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class LanguageTextBoxI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListFilterI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListFilterI18nResourceStrategy.java new file mode 100644 index 00000000..54c1bae7 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListFilterI18nResourceStrategy.java @@ -0,0 +1,128 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 过滤条资源管理策略 + */ +public class ListFilterI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从filterList属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection fieldConfigsI18nResourceItemCollection = extractFilterListI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (fieldConfigsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(fieldConfigsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + + } + + /** + * 提取过滤条列表资源项 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + private I18nResourceItemCollection extractFilterListI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 从filterList属性中提取多语资源 + ArrayList> childComponents = ComponentUtility.getInstance().GetFilterList(currentComponent); + I18nResourceItemCollection childComponentsI18nResourceItemCollection = extractChildComponentsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, childComponents); + if (childComponentsI18nResourceItemCollection != null && childComponentsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent, ArrayList> childComponentList) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + // 针对过滤条中的具体项进行处理 + for (HashMap childComponent : childComponentList) { + //获取具体项的id + String idAtributeValue = ComponentUtility.getInstance().getId(childComponent); + // 获取具体项的name + String nameAtributeValue = ComponentUtility.getInstance().getName(childComponent); + if (!StringUtility.isNullOrEmpty(idAtributeValue)) { + String componentId = idAtributeValue; + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId; + // 将具体项的name 添加至资源项中 + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + + //提取placeholder属性参数 + String placeHolderName = ComponentUtility.getInstance().GetPlaceHolderName(childComponent); + String placeHolderValue = ComponentUtility.getInstance().getPlaceHolder(childComponent); + String generatedPlaceHolderComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId + "/" + placeHolderName; + I18nResourceItem i18nPlaceholderResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedPlaceHolderComponentId, placeHolderValue, placeHolderValue); + i18nResourceItemCollection.add(i18nPlaceholderResourceItem); + + + // 子组件的属性中包含多语资源项 + I18nResourceItemCollection childComponentAttributeI18nResourceItemCollection = extractChildComponentAttributeI18nResourceItemCollection(i18nResourceItemBaseId, generatedComponentId, childComponent); + if (childComponentAttributeI18nResourceItemCollection != null && childComponentAttributeI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentAttributeI18nResourceItemCollection); + } + } + + + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, String componentI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + //从control属性获取对象 + I18nResourceItemCollection controlAttributeI18nResourceItemCollection = extractControlAttributeI18nResourceItemCollection(i18nResourceItemBaseId, componentI18nResourceItemBaseId, currentComponent); + if (controlAttributeI18nResourceItemCollection != null && controlAttributeI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(controlAttributeI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractControlAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, String componentI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 获取对应的control属性值 + HashMap controlAttributeObject = ComponentUtility.getInstance().GetControlAttributeObject(currentComponent); + + String controlAttributeName = ComponentUtility.getInstance().GetControlAttributeName(currentComponent); + componentI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER + controlAttributeName; + + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, I18nResourceConstant.ValueFieldKey); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, I18nResourceConstant.TextFieldKey); + + // 从enumValues中提取多语资源项 + ArrayList> enumValueCollection = ComponentUtility.getInstance().GetEnumValues(controlAttributeObject); + String enumValuesAttributeName = ComponentUtility.getInstance().GetEnumValuesName(controlAttributeObject); + + I18nResourceItemCollection enumValuesI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractEnumDataI18nResourceItemCollection(i18nResourceItemBaseId, componentI18nResourceItemBaseId, enumValueCollection, enumValuesAttributeName, strValueFieldKey, strTextFieldKey); + if (enumValuesI18nResourceItemCollection != null && enumValuesI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(enumValuesI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListNavI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListNavI18nResourceStrategy.java new file mode 100644 index 00000000..0c1b62a7 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListNavI18nResourceStrategy.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * ListNav + */ +public class ListNavI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListViewII18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListViewII18nResourceStrategy.java new file mode 100644 index 00000000..f345be10 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ListViewII18nResourceStrategy.java @@ -0,0 +1,166 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class ListViewII18nResourceStrategy extends AbstractI18nResourceStrategy { + + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) + { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 提取contentTemplate中的fields值 + // 从tagData中提取多语资源项 + HashMap listViewContentTemplate = ComponentUtility.getInstance().GetListViewContentTemplate(currentComponent); + if (listViewContentTemplate == null || listViewContentTemplate.size() == 0) + { + return i18nResourceItemCollection; + } + + String strListViewId = ComponentUtility.getInstance().getId(currentComponent); + + List> contentTemplateFields = ComponentUtility.getInstance().GetFieldsFromContentTemplate(listViewContentTemplate); + String listViewResourceId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + + strListViewId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + "contentTemplate"; + + + I18nResourceItemCollection resourceItemCollection = extractFieldsI18nResourceItemCollection(i18nResourceItemBaseId, listViewResourceId, contentTemplateFields); + if (resourceItemCollection != null) + { + i18nResourceItemCollection.addRange(resourceItemCollection); + } + + HashMap contentTemplateToolbar = ComponentUtility.getInstance().GetAttributeObject(listViewContentTemplate, "toolbar"); + if (contentTemplateToolbar != null) + { + List> contentTemplateToolbarContents = ComponentUtility.getInstance().GetToolbarContentsFromContentTemplate(contentTemplateToolbar); + if (contentTemplateToolbarContents != null && contentTemplateToolbarContents.size() > 0) + { + I18nResourceItemCollection toolbarContentsResourceCollection = extractToolbarContentsI18nResourceItemCollection(i18nResourceItemBaseId, listViewResourceId, contentTemplateToolbarContents); + if (toolbarContentsResourceCollection != null) + { + i18nResourceItemCollection.addRange(toolbarContentsResourceCollection); + } + } + } + + return i18nResourceItemCollection; + } + ///

+ /// 提取枚举属性中多语资源项 + /// + /// + private I18nResourceItemCollection extractToolbarContentsI18nResourceItemCollection(String i18nResourceItemBaseId, + String listViewI18nResourceItemBaseId, + List> componentCollection) + { + I18nResourceItemCollection contentTemplateI18nResourceItemCollection = new I18nResourceItemCollection(); + componentCollection.forEach((component)->{ + String textAtributeValue = ComponentUtility.getInstance().getText(component); + String idAtributeValue = ComponentUtility.getInstance().getId(component); + String typeAttributeValue = ComponentUtility.getInstance().getType(component); + + String generatedComponentId = + listViewI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + "toobar" + I18nResourceConstant.SECOND_LEVEL_DELIMITER + typeAttributeValue + I18nResourceConstant.SECOND_LEVEL_DELIMITER + idAtributeValue; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, textAtributeValue, textAtributeValue); + + if (i18nResourceItem != null) + { + contentTemplateI18nResourceItemCollection.add(i18nResourceItem); + } + }); + + + return contentTemplateI18nResourceItemCollection; + } + + + /// + /// 提取枚举属性中多语资源项 + /// + /// + private I18nResourceItemCollection extractFieldsI18nResourceItemCollection(String i18nResourceItemBaseId, + String listViewI18nResourceItemBaseId, + List> componentCollection) + { + I18nResourceItemCollection contentTemplateI18nResourceItemCollection = new I18nResourceItemCollection(); + + componentCollection.forEach((component)->{ + com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection i18nResourceItem = getContentTemplateFieldsI18nResourceItem(i18nResourceItemBaseId, listViewI18nResourceItemBaseId, component); + if (i18nResourceItem != null) + { + contentTemplateI18nResourceItemCollection.addRange(i18nResourceItem); + } + }); + + + return contentTemplateI18nResourceItemCollection; + } + + /// + /// 提取contentTemplate中fields中的具体项 + /// + /// + /// + /// + private I18nResourceItemCollection getContentTemplateFieldsI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap fieldItemObject) + { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + String nameAtributeValue = ComponentUtility.getInstance().getName(fieldItemObject); + String idAtributeValue = ComponentUtility.getInstance().getId(fieldItemObject); + String componentId = idAtributeValue; + + String generatedComponentId = enumI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + + ComponentUtility.getInstance().getType(fieldItemObject) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + + I18nResourceItemCollection fieldEnumResource = getContentTemplateFieldsI18nResourceItemEnumData(i18nResourceItemBaseId, generatedComponentId, fieldItemObject); + if (fieldEnumResource != null) + { + i18nResourceItemCollection.addRange(fieldEnumResource); + } + return i18nResourceItemCollection; + } + + /// + /// 提取contentTemplate中fields中的具体项 + /// + /// + /// + /// + private I18nResourceItemCollection getContentTemplateFieldsI18nResourceItemEnumData(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap fieldItemObject) + { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String strValueFieldKey = "value"; + String strTextFieldKey = "name"; + + // 从enumData中提取多语资源项 + List> enumValueCollection = ComponentUtility.getInstance().GetEnumData(fieldItemObject); + String enumDataAttributeName = ComponentUtility.getInstance().GetEnumDataName(fieldItemObject); + + I18nResourceItemCollection enumDataI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractEnumDataI18nResourceItemCollection(i18nResourceItemBaseId, enumI18nResourceItemBaseId, enumValueCollection, enumDataAttributeName, strValueFieldKey, strTextFieldKey); + if (enumDataI18nResourceItemCollection != null && enumDataI18nResourceItemCollection.size() > 0) + { + i18nResourceItemCollection.addRange(enumDataI18nResourceItemCollection); + } + return i18nResourceItemCollection; + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LookupI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LookupI18nResourceStrategy.java new file mode 100644 index 00000000..abd32d08 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/LookupI18nResourceStrategy.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class LookupI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/MultiTextBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/MultiTextBoxI18nResourceStrategy.java new file mode 100644 index 00000000..cec5374e --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/MultiTextBoxI18nResourceStrategy.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.*; + +/** + 默认的组件策略 读取title属性作为文本显示 +*/ +public class MultiTextBoxI18nResourceStrategy extends AbstractI18nResourceStrategy +{ + /** + 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) + { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + 获取组件属性中多语资源项集合 + + @param i18nResourceItemBaseId + @param currentComponent + @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) + { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NavTabI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NavTabI18nResourceStrategy.java new file mode 100644 index 00000000..1d43c997 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NavTabI18nResourceStrategy.java @@ -0,0 +1,79 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class NavTabI18nResourceStrategy extends AbstractI18nResourceStrategy { + + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 从tagData中提取多语资源项 + List> navDataCollection = ComponentUtility.getInstance().GetNavData(currentComponent); + String enumDataAttributeName = ComponentUtility.getInstance().GetNavDataName(currentComponent); + String tagDataI18nResourceItemBaseId = + ComponentUtility.getInstance().getType(currentComponent) + + I18nResourceConstant.SECOND_LEVEL_DELIMITER + + ComponentUtility.getInstance().getId(currentComponent); + + I18nResourceItemCollection navDataI18nResourceItemCollection = + extractNavDataI18nResourceItemCollection(i18nResourceItemBaseId, tagDataI18nResourceItemBaseId, navDataCollection, enumDataAttributeName); + if (navDataI18nResourceItemCollection != null && navDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(navDataI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /// + /// 提取枚举属性中多语资源项 + /// + /// + private I18nResourceItemCollection extractNavDataI18nResourceItemCollection(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, + List> componentCollection, String enumAttributeName) { + I18nResourceItemCollection enumValuesI18nResourceItemCollection = new I18nResourceItemCollection(); + + enumI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER; + String finalEnumI18nResourceItemBaseId = enumI18nResourceItemBaseId; + componentCollection.forEach((component) -> { + I18nResourceItem i18nResourceItem = getNavDataItemI18nResourceItem(i18nResourceItemBaseId, finalEnumI18nResourceItemBaseId + enumAttributeName, component); + if (i18nResourceItem != null) { + enumValuesI18nResourceItemCollection.add(i18nResourceItem); + } + }); + + return enumValuesI18nResourceItemCollection; + } + + /// + /// 获取枚举项中多语资源项 + /// + /// + /// + /// + private I18nResourceItem getNavDataItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap enumItemObject) { + String textAtributeValue = ComponentUtility.getInstance().getText(enumItemObject); + String idAtributeValue = ComponentUtility.getInstance().getId(enumItemObject); + + String componentId = idAtributeValue; + + String generatedComponentId = enumI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, textAtributeValue, textAtributeValue); + + + return i18nResourceItem; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberRangeI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberRangeI18nResourceStrategy.java new file mode 100644 index 00000000..62ac9a2f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberRangeI18nResourceStrategy.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class NumberRangeI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberSpinnerI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberSpinnerI18nResourceStrategy.java new file mode 100644 index 00000000..8e3e62a2 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumberSpinnerI18nResourceStrategy.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class NumberSpinnerI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumericBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumericBoxI18nResourceStrategy.java new file mode 100644 index 00000000..216bf8be --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/NumericBoxI18nResourceStrategy.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * NumericBox + */ +public class NumericBoxI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/OrganizationSelectorI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/OrganizationSelectorI18nResourceStrategy.java new file mode 100644 index 00000000..6bf367e5 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/OrganizationSelectorI18nResourceStrategy.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * 组织选择参数提取 + * @author guozhiqi + */ +public class OrganizationSelectorI18nResourceStrategy extends AbstractI18nResourceStrategy{ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/PersonnelSelectorI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/PersonnelSelectorI18nResourceStrategy.java new file mode 100644 index 00000000..68864d7b --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/PersonnelSelectorI18nResourceStrategy.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * 人员选择参数提取 + * @author guozhiqi + */ +public class PersonnelSelectorI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QueryFrameworkI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QueryFrameworkI18nResourceStrategy.java new file mode 100644 index 00000000..f3433656 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QueryFrameworkI18nResourceStrategy.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class QueryFrameworkI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.QUERY_NAME); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QuerySchemeI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QuerySchemeI18nResourceStrategy.java new file mode 100644 index 00000000..d7972eaf --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/QuerySchemeI18nResourceStrategy.java @@ -0,0 +1,168 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +public class QuerySchemeI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 获取当前组件的名称 + * + * @param currentComponent + * @return + */ + @Override + protected String getComponentName(HashMap currentComponent) { + // 读取组件名称 + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.PRESET_QUERY_SOLUTION_NAME); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(currentComponent); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从fieldConfigs属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection fieldConfigsI18nResourceItemCollection = extractFieldConfigsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (fieldConfigsI18nResourceItemCollection != null && fieldConfigsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(fieldConfigsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractFieldConfigsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从fieldConfigs属性中提取多语资源 + ArrayList> childComponents = ComponentUtility.getInstance().GetFieldConfigs(currentComponent); + I18nResourceItemCollection childComponentsI18nResourceItemCollection = extractChildComponentsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, childComponents); + if (childComponentsI18nResourceItemCollection != null && childComponentsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent, ArrayList> childComponentList) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + for (HashMap childComponent : childComponentList) { + String idAtributeValue = ComponentUtility.getInstance().getId(childComponent); + String nameAtributeValue = ComponentUtility.getInstance().getName(childComponent); + if (!StringUtility.isNullOrEmpty(idAtributeValue)) { + String componentId = idAtributeValue; + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + + //提取placeholder属性参数 + String placeHolderName = ComponentUtility.getInstance().GetPlaceHolderName(childComponent); + String placeHolderValue = ComponentUtility.getInstance().getPlaceHolder(childComponent); + String generatedPlaceHolderComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId + "/" + placeHolderName; + I18nResourceItem i18nPlaceholderResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedPlaceHolderComponentId, placeHolderValue, placeHolderValue); + i18nResourceItemCollection.add(i18nPlaceholderResourceItem); + + // 提取开始 placeHolder + String beginPlaceHolderName = ComponentUtility.getInstance().getBeginPlaceHolderName(childComponent); + String beginplaceHolderValue = ComponentUtility.getInstance().getBeginPlaceHolder(childComponent); + if (!StringUtility.isNullOrEmpty(beginplaceHolderValue)) { + String generatedBeginPlaceHolderComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId + "/" + beginPlaceHolderName; + I18nResourceItem i18nBeginPlaceholderResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedBeginPlaceHolderComponentId, beginplaceHolderValue, beginplaceHolderValue); + i18nResourceItemCollection.add(i18nBeginPlaceholderResourceItem); + } + + // 提取结束 endPlaceHolder + String endPlaceHolderName = ComponentUtility.getInstance().getEndPlaceHolderName(childComponent); + String endPlaceHolderValue = ComponentUtility.getInstance().getEndPlaceHolder(childComponent); + if (!StringUtility.isNullOrEmpty(endPlaceHolderValue)) { + String generatedEndPlaceHolderComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId + "/" + endPlaceHolderName; + I18nResourceItem i18nEndPlaceholderResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedEndPlaceHolderComponentId, endPlaceHolderValue, endPlaceHolderValue); + i18nResourceItemCollection.add(i18nEndPlaceholderResourceItem); + } + + + // 子组件的属性中包含多语资源项 + I18nResourceItemCollection childComponentAttributeI18nResourceItemCollection = extractChildComponentAttributeI18nResourceItemCollection(i18nResourceItemBaseId, generatedComponentId, childComponent); + if (childComponentAttributeI18nResourceItemCollection != null && childComponentAttributeI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentAttributeI18nResourceItemCollection); + } + } + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, String componentI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + //从control属性获取对象,然后在该对象的enumValues中获取资源项 + I18nResourceItemCollection controlAttributeI18nResourceItemCollection = extractControlAttributeI18nResourceItemCollection(i18nResourceItemBaseId, componentI18nResourceItemBaseId, currentComponent); + if (controlAttributeI18nResourceItemCollection != null && controlAttributeI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(controlAttributeI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractControlAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, String componentI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + HashMap controlAttributeObject = ComponentUtility.getInstance().GetControlAttributeObject(currentComponent); + + String controlAttributeName = ComponentUtility.getInstance().GetControlAttributeName(currentComponent); + componentI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER + controlAttributeName; + + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, I18nResourceConstant.ValueFieldKey); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, I18nResourceConstant.TextFieldKey); + + // 从enumValues中提取多语资源项 + ArrayList> enumValueCollection = ComponentUtility.getInstance().GetEnumValues(controlAttributeObject); + String enumValuesAttributeName = ComponentUtility.getInstance().GetEnumValuesName(controlAttributeObject); + + I18nResourceItemCollection enumValuesI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractEnumDataI18nResourceItemCollection(i18nResourceItemBaseId, componentI18nResourceItemBaseId, enumValueCollection, enumValuesAttributeName, strValueFieldKey, strTextFieldKey); + if (enumValuesI18nResourceItemCollection != null && enumValuesI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(enumValuesI18nResourceItemCollection); + } + + // 如果是帮助 提取对应的帮助标题 + String controlType = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, "controltype"); + if (!StringUtility.isNullOrEmpty(controlType) && controlType.equals("help")) { + String dialogTitleValue = ComponentUtility.getInstance().getValueWithKey(controlAttributeObject, "dialogTitle"); + String generateDialogTitleComponentId = componentI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + controlType + I18nResourceConstant.SECOND_LEVEL_DELIMITER + "dialogTitle"; + I18nResourceItem i18nDialogTitleResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generateDialogTitleComponentId, dialogTitleValue, dialogTitleValue); + i18nResourceItemCollection.add(i18nDialogTitleResourceItem); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RadioGroupI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RadioGroupI18nResourceStrategy.java new file mode 100644 index 00000000..a3254c15 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RadioGroupI18nResourceStrategy.java @@ -0,0 +1,94 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * radiogroup 国际化参数提取 + * @author noah + */ +public class RadioGroupI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap currentComponent) { + // 读取组件名称 + // 从title属性中获取组件名称 + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(currentComponent); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从html属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection itemsI18nResourceItemCollection = extractComponentItemsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (itemsI18nResourceItemCollection != null && itemsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(itemsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractComponentItemsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从items属性中提取多语资源 + ArrayList> childComponents = ComponentUtility.getInstance().GetEnumData(currentComponent); + I18nResourceItemCollection childComponentsI18nResourceItemCollection = extractChildComponentsI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent, childComponents); + if (childComponentsI18nResourceItemCollection != null && childComponentsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentsI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent, ArrayList> childComponentList) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + String strValueFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.ValueFieldKey); + String strTextFieldKey = ComponentUtility.getInstance().getValueWithKey(currentComponent, I18nResourceConstant.TextFieldKey); + + for (HashMap childComponent : childComponentList) { + String valueAtributeValue = ComponentUtility.getInstance().getValueWithKey(childComponent, strValueFieldKey, "value"); + String nameAtributeValue = ComponentUtility.getInstance().getValueWithKey(childComponent, strTextFieldKey, "name"); + if (!StringUtility.isNull(valueAtributeValue)) { + String componentId = valueAtributeValue; + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/" + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + } + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RichTextBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RichTextBoxI18nResourceStrategy.java new file mode 100644 index 00000000..db033ee6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/RichTextBoxI18nResourceStrategy.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class RichTextBoxI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ScrollSpyI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ScrollSpyI18nResourceStrategy.java new file mode 100644 index 00000000..cba0e133 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ScrollSpyI18nResourceStrategy.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + + +import java.util.ArrayList; +import java.util.HashMap; + +public class ScrollSpyI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String itemsI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + I18nResourceItemCollection itemsI18nResourceItemCollection = extractItemsI18nResourceItemCollection(i18nResourceItemBaseId, itemsI18nResourceItemBaseId, currentComponent); + if (itemsI18nResourceItemCollection != null && itemsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(itemsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractItemsI18nResourceItemCollection(String i18nResourceItemBaseId, String itemsI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从items属性中提取多语资源 + itemsI18nResourceItemBaseId += ComponentUtility.getInstance().GetItemsName(currentComponent); + itemsI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER; + ArrayList> childComponents = ComponentUtility.getInstance().GetItems(currentComponent); + + I18nResourceItemCollection childComponentsI18nResourceItemCollection = extractChildComponentI18nResourceItemCollection(i18nResourceItemBaseId, itemsI18nResourceItemBaseId, childComponents); + if (childComponentsI18nResourceItemCollection != null && childComponentsI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(childComponentsI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractChildComponentI18nResourceItemCollection(String i18nResourceItemBaseId, String itemsI18nResourceItemBaseId, ArrayList> childComponentList) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + for (HashMap childComponent : childComponentList) { + String idAtributeValue = ComponentUtility.getInstance().getId(childComponent); + String titleAtributeValue = ComponentUtility.getInstance().getTitle(childComponent); + if (!StringUtility.isNull(idAtributeValue)) { + String generatedComponentId = idAtributeValue; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, itemsI18nResourceItemBaseId + generatedComponentId, titleAtributeValue, titleAtributeValue); + i18nResourceItemCollection.add(i18nResourceItem); + } + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/SectionI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/SectionI18nResourceStrategy.java new file mode 100644 index 00000000..ba38d50d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/SectionI18nResourceStrategy.java @@ -0,0 +1,54 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +public class SectionI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + // 从html属性中提取多语字段 + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + I18nResourceItemCollection htmlI18nResourceItemCollection = extractComponentHtmlI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (htmlI18nResourceItemCollection != null && htmlI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(htmlI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractComponentHtmlI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String currentComponentType = ComponentUtility.getInstance().getType(currentComponent); + String currentComponentId = ComponentUtility.getInstance().getId(currentComponent); + if (StringUtility.isNullOrEmpty(currentComponentType) || StringUtility.isNullOrEmpty(currentComponentId)) { + return null; + } + + String generatedComponentId = currentComponentType + "/" + currentComponentId + "/"; + // 从mainTitile属性中提取多语资源 + String mainTitle = ComponentUtility.getInstance().getMainTitle(currentComponent); + String mainTitleName = ComponentUtility.getInstance().getMainTitleName(); + i18nResourceItemCollection.add(I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId + mainTitleName, mainTitle, mainTitle)); + + // 从subTitile属性中提取多语资源 + String subTitle = ComponentUtility.getInstance().getSubTitle(currentComponent); + String subTitleName = ComponentUtility.getInstance().getSubTitleName(); + i18nResourceItemCollection.add(I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId + subTitleName, subTitle, subTitle)); + return i18nResourceItemCollection; + } + + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagI18nResourceStrategy.java new file mode 100644 index 00000000..e22313a0 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagI18nResourceStrategy.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class TagI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.LABEL); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagsI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagsI18nResourceStrategy.java new file mode 100644 index 00000000..3498545d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TagsI18nResourceStrategy.java @@ -0,0 +1,98 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +public class TagsI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 从tagData中提取多语资源项 + ArrayList> tagDataCollection = ComponentUtility.getInstance().GetTagData(currentComponent); + String enumDataAttributeName = ComponentUtility.getInstance().GetTagDataName(currentComponent); + String tagDataI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent); + + I18nResourceItemCollection tagDataI18nResourceItemCollection = extractTagDataI18nResourceItemCollection(i18nResourceItemBaseId, tagDataI18nResourceItemBaseId, tagDataCollection, enumDataAttributeName); + if (tagDataI18nResourceItemCollection != null && tagDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(tagDataI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + + /** + * 提取枚举属性中多语资源项 + * + * @return + */ + private I18nResourceItemCollection extractTagDataI18nResourceItemCollection(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, ArrayList> componentCollection, String enumAttributeName) { + I18nResourceItemCollection enumValuesI18nResourceItemCollection = new I18nResourceItemCollection(); + + enumI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER; + for (HashMap component : componentCollection) { + I18nResourceItem i18nResourceItem = getTagDataItemI18nResourceItem(i18nResourceItemBaseId, enumI18nResourceItemBaseId + enumAttributeName, component); + if (i18nResourceItem != null) { + enumValuesI18nResourceItemCollection.add(i18nResourceItem); + } + } + + return enumValuesI18nResourceItemCollection; + } + + /** + * 获取枚举项中多语资源项 + * + * @param enumI18nResourceItemBaseId + * @param enumItemObject + * @return + */ + private I18nResourceItem getTagDataItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap enumItemObject) { + I18nResourceItem i18nResourceItem = null; + + + String nameAtributeValue = ComponentUtility.getInstance().getName(enumItemObject); + String idAtributeValue = ComponentUtility.getInstance().getId(enumItemObject); + if (!StringUtility.isNull(nameAtributeValue)) { + String componentId = idAtributeValue; + + String generatedComponentId = enumI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, nameAtributeValue, nameAtributeValue); + } + + return i18nResourceItem; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TextBoxI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TextBoxI18nResourceStrategy.java new file mode 100644 index 00000000..c1cb9ede --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TextBoxI18nResourceStrategy.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class TextBoxI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimePickerI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimePickerI18nResourceStrategy.java new file mode 100644 index 00000000..9a687580 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimePickerI18nResourceStrategy.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * timepicker 国际化参数提取 + * @author noah + */ +public class TimePickerI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + String componentName = componentNameStrategy.getComponentName(component); + + return componentName; + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimeSpinnerI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimeSpinnerI18nResourceStrategy.java new file mode 100644 index 00000000..4fadcc68 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/TimeSpinnerI18nResourceStrategy.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.I18nResourceUtility; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +/** + * timespinner 国际化参数提取 + * @author noah + */ +public class TimeSpinnerI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 默认的策略 使用title作为文本 + */ + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TITLE); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } + + /** + * TimePicker 提取placeHolder + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + // 从placeHolder属性中提取多语字段 + I18nResourceItemCollection placeHolderI18nResourceItemCollection = I18nResourceUtility.GetInstance().ExtractPlaceHolderI18nResourceItemCollection(i18nResourceItemBaseId, currentComponent); + if (placeHolderI18nResourceItemCollection != null && placeHolderI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(placeHolderI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ToolBarItemI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ToolBarItemI18nResourceStrategy.java new file mode 100644 index 00000000..bf7d0ad6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ToolBarItemI18nResourceStrategy.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameFactory; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.ComponentNameType; +import com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy.IComponentNameStrategy; + +import java.util.HashMap; + +public class ToolBarItemI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected String getComponentName(HashMap component) { + IComponentNameStrategy componentNameStrategy = ComponentNameFactory.getInstance().creatComponentNameStrategy(ComponentNameType.TEXT); + if (componentNameStrategy == null) { + return null; + } + + return componentNameStrategy.getComponentName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ViewChangeI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ViewChangeI18nResourceStrategy.java new file mode 100644 index 00000000..ed60ba8d --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/ViewChangeI18nResourceStrategy.java @@ -0,0 +1,78 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.HashMap; +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class ViewChangeI18nResourceStrategy extends AbstractI18nResourceStrategy { + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + // 从toolbarData中提取多语资源项 + List> navDataCollection = ComponentUtility.getInstance().getToolbarData(currentComponent); + String toolbarDataAttributeName = ComponentUtility.getInstance().getToolbarDataName(currentComponent); + String toolbarDataI18nResourceItemBaseId = + ComponentUtility.getInstance().getType(currentComponent) + + I18nResourceConstant.SECOND_LEVEL_DELIMITER + + ComponentUtility.getInstance().getId(currentComponent); + + I18nResourceItemCollection navDataI18nResourceItemCollection = + extractToolbarDataI18nResourceItemCollection(i18nResourceItemBaseId, toolbarDataI18nResourceItemBaseId, navDataCollection, toolbarDataAttributeName); + if (navDataI18nResourceItemCollection != null && navDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(navDataI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + /// + /// 提取枚举属性中多语资源项 + /// + /// + private I18nResourceItemCollection extractToolbarDataI18nResourceItemCollection(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, + List> componentCollection, String enumAttributeName) { + I18nResourceItemCollection enumValuesI18nResourceItemCollection = new I18nResourceItemCollection(); + + enumI18nResourceItemBaseId += I18nResourceConstant.SECOND_LEVEL_DELIMITER; + String finalEnumI18nResourceItemBaseId = enumI18nResourceItemBaseId; + componentCollection.forEach((component) -> { + I18nResourceItem i18nResourceItem = getToolbarDataItemI18nResourceItem(i18nResourceItemBaseId, finalEnumI18nResourceItemBaseId + enumAttributeName, component); + if (i18nResourceItem != null) { + enumValuesI18nResourceItemCollection.add(i18nResourceItem); + } + }); + + return enumValuesI18nResourceItemCollection; + } + + /// + /// 获取枚举项中多语资源项 + /// + /// + /// + /// + private I18nResourceItem getToolbarDataItemI18nResourceItem(String i18nResourceItemBaseId, String enumI18nResourceItemBaseId, HashMap enumItemObject) { + String textAtributeValue = ComponentUtility.getInstance().getTitle(enumItemObject); + String idAtributeValue = ComponentUtility.getInstance().getType(enumItemObject); + + String componentId = idAtributeValue; + + String generatedComponentId = enumI18nResourceItemBaseId + I18nResourceConstant.SECOND_LEVEL_DELIMITER + componentId; + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, generatedComponentId, textAtributeValue, textAtributeValue); + + + return i18nResourceItem; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/WizardI18nResourceStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/WizardI18nResourceStrategy.java new file mode 100644 index 00000000..d7b08109 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/i18nresourcestrategy/WizardI18nResourceStrategy.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.i18nresourcestrategy; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItem; +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.formmetadata.i18n.I18nResourceItemManager; +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Wizard组件策略 + * @author noah + */ +public class WizardI18nResourceStrategy extends AbstractI18nResourceStrategy { + /** + * 获取组件属性中多语资源项集合 + * + * @param i18nResourceItemBaseId + * @param currentComponent + * @return + */ + @Override + protected I18nResourceItemCollection extractAttributeI18nResourceItemCollection(String i18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + + String itemsI18nResourceItemBaseId = ComponentUtility.getInstance().getType(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER + ComponentUtility.getInstance().getId(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + I18nResourceItemCollection progressDataI18nResourceItemCollection = extractProgressDataI18nResourceItemCollection(i18nResourceItemBaseId, itemsI18nResourceItemBaseId, currentComponent); + if (progressDataI18nResourceItemCollection != null && progressDataI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(progressDataI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + private I18nResourceItemCollection extractProgressDataI18nResourceItemCollection(String i18nResourceItemBaseId, String itemsI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + itemsI18nResourceItemBaseId = itemsI18nResourceItemBaseId + ComponentUtility.getInstance().getProgressDataName(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + + HashMap progressDataObject = ComponentUtility.getInstance().getProgressData(currentComponent); + + I18nResourceItemCollection stepMessagesI18nResourceItemCollection = extractStepMessagesI18nResourceItemCollection(i18nResourceItemBaseId, itemsI18nResourceItemBaseId, progressDataObject); + if (stepMessagesI18nResourceItemCollection != null && stepMessagesI18nResourceItemCollection.size() > 0) { + i18nResourceItemCollection.addRange(stepMessagesI18nResourceItemCollection); + } + + return i18nResourceItemCollection; + } + + + private I18nResourceItemCollection extractStepMessagesI18nResourceItemCollection(String i18nResourceItemBaseId, String itemsI18nResourceItemBaseId, HashMap currentComponent) { + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + if (currentComponent == null || currentComponent.size() == 0) { + return i18nResourceItemCollection; + } + itemsI18nResourceItemBaseId = itemsI18nResourceItemBaseId + ComponentUtility.getInstance().getStepMessagesName(currentComponent) + I18nResourceConstant.SECOND_LEVEL_DELIMITER; + + ArrayList> stepMessageCollection = ComponentUtility.getInstance().getStepMessages(currentComponent); + + + for (HashMap stepMessageObject : stepMessageCollection) { + String componentId = ComponentUtility.getInstance().getId(stepMessageObject); + String componentName = ComponentUtility.getInstance().getTitle(stepMessageObject); + + I18nResourceItem i18nResourceItem = I18nResourceItemManager.createI18nResourceItem(i18nResourceItemBaseId, itemsI18nResourceItemBaseId + componentId, componentName, componentName); + if (i18nResourceItem != null) { + i18nResourceItemCollection.add(i18nResourceItem); + } + } + + return i18nResourceItemCollection; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/AbstractComponentIdStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/AbstractComponentIdStrategy.java new file mode 100644 index 00000000..70506e70 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/AbstractComponentIdStrategy.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 组件ID策略抽象类 + * @author noah + */ +public abstract class AbstractComponentIdStrategy implements IComponentIdStrategy { + @Override() + public String getComponentId(HashMap component) { + return ComponentUtility.getInstance().getId(component); + } + + @Override() + public ArrayList getComponentIdCollection(HashMap component) { + ArrayList idList = new ArrayList<>(); + + String defaultId = ComponentUtility.getInstance().getId(component); + idList.add(defaultId); + + return idList; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdFactory.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdFactory.java new file mode 100644 index 00000000..1a6916e0 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdFactory.java @@ -0,0 +1,59 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.HashMap; + +/** + * 组件id生成factory + * @author noah + */ +public class ComponentIdFactory { + private ComponentIdFactory() { + } + + /** + * 静态单例属性 + */ + private static final ComponentIdFactory Instance = new ComponentIdFactory(); + + public static ComponentIdFactory getInstance() { + return Instance; + } + + /** + * 缓存字典 避免重复创建 + */ + private final HashMap componentIdStrategyDictionary = new HashMap<>(); + + /** + * 根据组件Id类型创建组件Id策略 + * + * @return + */ + public final IComponentIdStrategy creatComponentIdStrategy(String componentIdType) { + if (StringUtility.isNullOrEmpty(componentIdType)) { + return null; + } + + + // 如果缓存字典中已包含 那么从缓存中读取该实例 + if (componentIdStrategyDictionary.containsKey(componentIdType)) { + return componentIdStrategyDictionary.get(componentIdType); + } + + IComponentIdStrategy componentIdStrategy; + if (ComponentIdType.HTML_TEMPLATE.equals(componentIdType)) { + componentIdStrategy = new HtmlTemplateIdStrategy(); + } else { + componentIdStrategy = new DefaultIdStrategy(); + } + + // 默认的策略不缓存 + if (componentIdStrategy != null) { + componentIdStrategyDictionary.put(componentIdType, componentIdStrategy); + } + + return componentIdStrategy; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdType.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdType.java new file mode 100644 index 00000000..89a65c27 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/ComponentIdType.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +/** + * 组件ID类型 + * + * @author noah + */ +public class ComponentIdType { + private ComponentIdType() { + } + + /** + * id + */ + public static final String ID = "id"; + /** + * htmlTemplate + */ + public static final String HTML_TEMPLATE = "htmlTemplate"; +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/DefaultIdStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/DefaultIdStrategy.java new file mode 100644 index 00000000..2d3af235 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/DefaultIdStrategy.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy.AbstractComponentIdStrategy; + +/** + * 默认组件Id策略 + * @author noah + */ +public class DefaultIdStrategy extends AbstractComponentIdStrategy { + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/HtmlTemplateIdStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/HtmlTemplateIdStrategy.java new file mode 100644 index 00000000..4e1c7434 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/HtmlTemplateIdStrategy.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.*; + +/** + 默认组件Id策略 +*/ +public class HtmlTemplateIdStrategy extends AbstractComponentIdStrategy +{ + @Override + public ArrayList getComponentIdCollection(HashMap component) { + // TODO: 从string中提取id集合 + ArrayList idList = new ArrayList<>(); + + String defaultId = ComponentUtility.getInstance().getId(component); + idList.add(defaultId); + + return idList; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/IComponentIdStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/IComponentIdStrategy.java new file mode 100644 index 00000000..c52e307b --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/idstrategy/IComponentIdStrategy.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.idstrategy; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * 组件ID策略接口 + */ +public interface IComponentIdStrategy { + /** + * 获取组件Id + */ + String getComponentId(HashMap component); + + /** + * 获取组件Id集合 + */ + ArrayList getComponentIdCollection(HashMap component); +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/AbstractComponentNameStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/AbstractComponentNameStrategy.java new file mode 100644 index 00000000..8d98509b --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/AbstractComponentNameStrategy.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +/** + * 组件名称策略抽象类 + * @author guozhiqi + */ +public abstract class AbstractComponentNameStrategy implements IComponentNameStrategy { + /** + * 从Name属性获取组件名称 + * + * @param component 参数 + * @return + */ + @Override() + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/CaptionStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/CaptionStrategy.java new file mode 100644 index 00000000..a3549a82 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/CaptionStrategy.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +/** + * caption 国际化参数提取 + * @author noah + */ +public class CaptionStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getCaption(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameFactory.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameFactory.java new file mode 100644 index 00000000..45d1ac0f --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameFactory.java @@ -0,0 +1,81 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.HashMap; + +/** + * 组件名称生成factory + * @author noah + */ +public class ComponentNameFactory { + private ComponentNameFactory() { + } + + /** + * 静态单例属性 + */ + private static final ComponentNameFactory Instance = new ComponentNameFactory(); + + public static ComponentNameFactory getInstance() { + return Instance; + } + + /** + * 缓存字典 避免重复创建 + */ + private final HashMap componentNameStrategyDictionary = new HashMap<>(); + + /** + * 根据组件名称类型创建组件名称策略 + * + * @param componentNameType + * @return + */ + public final IComponentNameStrategy creatComponentNameStrategy(String componentNameType) { + if (StringUtility.isNullOrEmpty(componentNameType)) { + return null; + } + + IComponentNameStrategy componentNameStrategy = null; + + // 如果缓存字典中已包含 那么从缓存中读取该实例 + if (componentNameStrategyDictionary.containsKey(componentNameType)) { + componentNameStrategy = componentNameStrategyDictionary.get(componentNameType); + return componentNameStrategy; + } + + switch (componentNameType) { + case ComponentNameType.TEXT: + componentNameStrategy = new TextStrategy(); + break; + case ComponentNameType.TITLE: + componentNameStrategy = new TitleStrategy(); + break; + case ComponentNameType.CAPTION: + componentNameStrategy = new CaptionStrategy(); + break; + case ComponentNameType.PRESET_QUERY_SOLUTION_NAME: + componentNameStrategy = new PresetQuerySolutionNameStrategy(); + break; + case ComponentNameType.QUERY_NAME: + componentNameStrategy = new QueryNameStrategy(); + break; + case ComponentNameType.LABEL: + componentNameStrategy = new LabelStrategy(); + break; + case ComponentNameType.NAME: + // 默认从Name中获取组件名 + default: + componentNameStrategy = new DefaultNameStrategy(); + break; + } + + // 默认的策略不缓存 + if (componentNameStrategy != null) { + componentNameStrategyDictionary.put(componentNameType, componentNameStrategy); + } + + return componentNameStrategy; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameType.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameType.java new file mode 100644 index 00000000..b7c0c578 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/ComponentNameType.java @@ -0,0 +1,39 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +/** + * 组件名称类型 + * + * @author noah + */ +public class ComponentNameType { + private ComponentNameType() { + } + + /** + * name + */ + public static final String NAME = "name"; + /** + * text + */ + public static final String TEXT = "text"; + /** + * title + */ + public static final String TITLE = "title"; + /** + * caption + */ + public static final String CAPTION = "caption"; + /** + * presetQuerySolutionName + */ + public static final String PRESET_QUERY_SOLUTION_NAME = "presetQuerySolutionName"; + + public static final String QUERY_NAME = "queryName"; + + /** + * 读取label属性 + */ + public static final String LABEL = "label"; +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/DefaultNameStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/DefaultNameStrategy.java new file mode 100644 index 00000000..a19b35e1 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/DefaultNameStrategy.java @@ -0,0 +1,9 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +/** + * 默认组件Name策略 + * @author noah + */ +public class DefaultNameStrategy extends AbstractComponentNameStrategy { + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/IComponentNameStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/IComponentNameStrategy.java new file mode 100644 index 00000000..c7501cc5 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/IComponentNameStrategy.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import java.util.*; + +/** + * 组件名称策略接口 + */ +public interface IComponentNameStrategy { + /** + * 获取组件名 + * + * @param component 组件 + * @return + */ + String getComponentName(HashMap component); +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/LabelStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/LabelStrategy.java new file mode 100644 index 00000000..c9d9fea6 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/LabelStrategy.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +public class LabelStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getLabel(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/PresetQuerySolutionNameStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/PresetQuerySolutionNameStrategy.java new file mode 100644 index 00000000..3386d108 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/PresetQuerySolutionNameStrategy.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +/** + * 预置筛选方案组件Name策略 + */ +public class PresetQuerySolutionNameStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getPresetQuerySolutionName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/QueryNameStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/QueryNameStrategy.java new file mode 100644 index 00000000..83940d39 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/QueryNameStrategy.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +public class QueryNameStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getQueryName(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TextStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TextStrategy.java new file mode 100644 index 00000000..584465d3 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TextStrategy.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +public class TextStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + String componentName = ComponentUtility.getInstance().getText(component); + return componentName; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TitleStrategy.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TitleStrategy.java new file mode 100644 index 00000000..ca8823a3 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/component/strategy/namestrategy/TitleStrategy.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.formmetadata.i18n.component.strategy.namestrategy; + +import com.inspur.edp.web.formmetadata.i18n.component.ComponentUtility; + +import java.util.HashMap; + +/** + * 标题提取 + * @author noah + */ +public class TitleStrategy extends AbstractComponentNameStrategy { + @Override + public String getComponentName(HashMap component) { + return ComponentUtility.getInstance().getTitle(component); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/ComponentType.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/ComponentType.java new file mode 100644 index 00000000..f83f766c --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/ComponentType.java @@ -0,0 +1,218 @@ +package com.inspur.edp.web.formmetadata.i18n.constant; + +/** + * 组件类型 + * + * @author noah + */ +public class ComponentType { + private ComponentType() { + } + ///#region 组件类型 + + /** + * 工具栏项 + */ + public static final String TOOL_BAR_ITEM = "ToolBarItem"; + + /** + * 按钮控件 + */ + public static final String BUTTON = "Button"; + + /** + * 列表控件字段 + */ + public static final String GRID_FIELD = "GridField"; + + /** + * 树列表控件字段 + */ + public static final String TREE_GRID_FIELD = "TreeGridField"; + + /** + * 日期控件 + */ + public static final String DATE_BOX = "DateBox"; + + /** + * 文本控件 + */ + public static final String TEXT_BOX = "TextBox"; + + /** + * 日历控件 + */ + public static final String CALENDAR = "Calendar"; + + /** + * Html模板控件 + */ + public static final String HTML_TEMPLATE = "HtmlTemplate"; + + /** + * Section控件 + */ + public static final String SECTION = "Section"; + + /** + * CheckGroup控件 + */ + public static final String CHECK_GROUP = "CheckGroup"; + + /** + * 显示控件 + */ + public static final String DisplayField = "DisplayField"; + + /** + * 多语控件 + */ + public static final String LanguageTextBox = "LanguageTextBox"; + + /** + * 查询方案控件 + */ + public static final String QUERY_SCHEME = "QueryScheme"; + + /** + * 数据列表 + */ + public static final String DATA_GRID = "DataGrid"; + + /** + * 标签 + */ + public static final String TAG = "Tag"; + + /** + * 附件上传预览组件类型 + */ + public static final String FileUploadPreview = "FileUploadPreview"; + /** + * 标签 + */ + public static final String TAGS = "Tags"; + + /** + * 过滤条 + */ + public static final String LIST_FILTER = "ListFilter"; + + /** + * 数字框 + */ + public static final String NUMERIC_BOX = "NumericBox"; + + /** + * 智能输入框类型 + */ + public static final String INPUT_GROUP = "InputGroup"; + + /** + * 富文本控件 + */ + public static final String MULTI_TEXT_BOX = "MultiTextBox"; + + /** + * 枚举字段 + */ + public static final String ENUM_FIELD = "EnumField"; + + /** + * 帮助控件 + * 从LookupEdit映射到HelpProvider + */ + public static final String HELP_PROVIDER = "LookupEdit"; + + /** + * 下拉列表 + */ + public static final String COMBOLIST = "ComboList"; + + /** + * 下拉帮助 + */ + public static final String COMBOLOOKUP = "ComboLookup"; + + /** + * 帮助 + */ + public static final String LOOKUP = "Lookup"; + + /** + * 组织选择类型 + */ + public static final String OrganizationSelector = "OrganizationSelector"; + + /** + * 人员选择类型 + */ + public static final String PersonnelSelector = "PersonnelSelector"; + + /** + * ListNav + */ + public static final String LIST_NAV = "ListNav"; + + /** + * Sidebar控件 + */ + public static final String SIDEBAR = "Sidebar"; + + /** + * Scrollspy + */ + public static final String SCROLL_SPY = "Scrollspy"; + + public static final String QUERY_FRAMEWORK = "QdpFramework"; + + public static final String WIZARD = "Wizard"; + + public static final String RADIO_GROUP = "RadioGroup"; + + public static final String TimePicker = "TimePicker"; + + public static final String TimeSpinner = "TimeSpinner"; + + public static final String CheckBox = "CheckBox"; + + public static final String TabToolbarItem = "TabToolbarItem"; + + public static final String TabPage = "TabPage"; + + public static final String Avatar = "Avatar"; + + public static final String DatePicker = "DatePicker"; + + public static final String RichTextBox = "RichTextBox"; + + public static final String Image = "Image"; + + public static final String InputGroup = "InputGroup"; + + public static final String ListView = "ListView"; + + public static final String MultiSelect = "MultiSelect"; + + public static final String NumberRange = "NumberRange"; + + public static final String NumberSpinner = "NumberSpinner"; + + public static final String ExternalContainer = "ExternalContainer"; + + public static final String SwitchField = "SwitchField"; + + public static final String FieldSet = "FieldSet"; + + public static final String Steps = "Steps"; + + public static final String Footer = "Footer"; + + public static final String Header = "Header"; + + public static final String NavTab = "NavTab"; + + public static final String ViewChange = "ViewChange"; + ///#endregion +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/I18nResourceConstant.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/I18nResourceConstant.java new file mode 100644 index 00000000..3bfe52ea --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/i18n/constant/I18nResourceConstant.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.i18n.constant; + +public class I18nResourceConstant { + /** + * 资源项第一级分隔符 逗号 + */ + public static final String FIRST_LEVEL_DELIMITER = "."; + + /** + * 资源项第二级分隔符 反斜线 + */ + public static final String SECOND_LEVEL_DELIMITER = "/"; + + /** + * 资源项第三级分隔符 $ + */ + public static final String THIRD_LEVEL_DELIMITER = "$"; + + /** + * 中文标识 + */ + public static final String ZH_CHS = "zh-CHS"; + + /** + * 英文标识 + */ + public static final String En = "en"; + + public static final String ZH_CHT = "zh-CHT"; + + /** + * 枚举对应的值field + */ + public static final String ValueFieldKey = "valueField"; + + /** + * 枚举对应的text field + */ + public static final String TextFieldKey = "textField"; + + /** + * 枚举对应的id field + */ + public static final String IdFieldKey = "idField"; +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/initialization/FormMetadataInitialization.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/initialization/FormMetadataInitialization.java new file mode 100644 index 00000000..ce12b4b7 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/initialization/FormMetadataInitialization.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.formmetadata.initialization; + +import com.inspur.edp.lcm.metadata.spi.MetadataContentManager; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/12 + */ +public class FormMetadataInitialization implements MetadataContentManager { + + @Override + public void build(GspMetadata metadata) { + FormMetadataContent webDevMetadata = new FormMetadataContent(); + if (metadata != null && metadata.getHeader() != null && !StringUtility.isNullOrEmpty(metadata.getHeader().getId())) { + webDevMetadata.setId(metadata.getHeader().getId()); + metadata.setContent(webDevMetadata); + } + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListener.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListener.java new file mode 100644 index 00000000..b96390ad --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListener.java @@ -0,0 +1,63 @@ +package com.inspur.edp.web.formmetadata.lic; + +import com.inspur.edp.lcm.metadata.spi.lic.LicControlExtendForIde; +import com.inspur.edp.lcm.metadata.spi.lic.MetadataCreateLicControlContext; +import com.inspur.edp.web.common.constant.MetadataConstant; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.licservice.api.manager.StandardControlFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 表单元数据创建授权控制 + */ +public class FormMetadataCreateLicControlListener implements LicControlExtendForIde { + private StandardControlFactory standardControlFactory = null; + private List MODULE_WITH_METADATA_TYPE_LIST = null; + + public FormMetadataCreateLicControlListener() { + this.initModuleWithMetadateType(); + this.standardControlFactory = SpringBeanUtils.getBean(StandardControlFactory.class); + } + + @Override + public void metadataCreateControl(MetadataCreateLicControlContext context) { + // 如果入参为空 那么不进行任何修饰 + if (context == null || context.getMetadataDto() == null || StringUtility.isNullOrEmpty(context.getMetadataDto().getType())) { + return; + } + // 仅控制PC表单和移动表单 + Optional optionalModuleWithMetadataType = this.needControl(context.getMetadataDto().getType()); + optionalModuleWithMetadataType.ifPresent(moduleWithMetadataType -> this.standardControlFactory.licStandardControl(moduleWithMetadataType.getModuleType())); + } + + /** + * 是否需要进行权限控制的元数据类型 + * + * @param metaType + * @return + */ + private Optional needControl(String metaType) { + return this.MODULE_WITH_METADATA_TYPE_LIST.stream().filter(t -> t.getMetadataTypeList().contains(metaType)).findFirst(); + } + + /** + * 初始化模块类型 + */ + private void initModuleWithMetadateType() { + this.MODULE_WITH_METADATA_TYPE_LIST = new ArrayList<>(2); + ModuleWithMetadataType formModuleType = new ModuleWithMetadataType(); + formModuleType.setModuleType("WDP"); + formModuleType.getMetadataTypeList().add(MetadataConstant.FORM_METADATA_TYPE); + this.MODULE_WITH_METADATA_TYPE_LIST.add(formModuleType); + + ModuleWithMetadataType mobileFormModuleType = new ModuleWithMetadataType(); + mobileFormModuleType.setModuleType("MDP"); + mobileFormModuleType.getMetadataTypeList().add(MetadataConstant.MOBILE_FORM_METADATA_TYPE); + this.MODULE_WITH_METADATA_TYPE_LIST.add(mobileFormModuleType); + + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/ModuleWithMetadataType.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/ModuleWithMetadataType.java new file mode 100644 index 00000000..107126e9 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/lic/ModuleWithMetadataType.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.formmetadata.lic; + +import java.util.ArrayList; +import java.util.List; + +/** + * 模块类型与元数据类型的映射关联 + */ +public class ModuleWithMetadataType { + /** + * 模块类型 + */ + private String moduleType; + /** + * 关联的元数据类型列表 + */ + private List metadataTypeList; + + public ModuleWithMetadataType() { + this.metadataTypeList = new ArrayList<>(2); + } + + public String getModuleType() { + return moduleType; + } + + public void setModuleType(String moduleType) { + this.moduleType = moduleType; + } + + public List getMetadataTypeList() { + return metadataTypeList; + } + + public void setMetadataTypeList(List metadataTypeList) { + this.metadataTypeList = metadataTypeList; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/manager/FormMetadataManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/manager/FormMetadataManager.java new file mode 100644 index 00000000..f1f870f4 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/manager/FormMetadataManager.java @@ -0,0 +1,56 @@ +package com.inspur.edp.web.formmetadata.manager; + +import com.inspur.edp.web.formmetadata.service.FormMetataService; +import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage; + +import java.util.List; + +/** + * @author guozhiqi + */ +public class FormMetadataManager { + ///FormMetadataManager Singleton + + /** + * 私有构造函数,避免继承与外部实例化 + */ + private FormMetadataManager() { + + } + + private static final FormMetadataManager formMetadataManagerInstance = new FormMetadataManager(); + + public static FormMetadataManager getInstance() { + return formMetadataManagerInstance; + } + + public final void synchronizeLanuagePackage(String formMetadataFileName, String formMetadataPath) { + FormMetataService.synchronizeLanuagePackage(formMetadataFileName, formMetadataPath); + } + + public final void exportLanguagePackage(String formMetadataFileName, String formMetadataPath) { + FormMetataService.exportLanguagePackage(formMetadataFileName, formMetadataPath); + } + + public final void synchronizeLocalLanuagePackage(String formMetadataFileName, String formMetadataPath) { + FormMetataService.synchronizeLocalLanuagePackage(formMetadataFileName, formMetadataPath); + } + + public final List getEnabledLanguageList() { + return FormMetataService.getEnabledLanguageList(); + } + + public final List getBuiltinLanguageList() { + return FormMetataService.getBuiltinLanguageList(); + } + + public final List getAllLanguageList() { + return FormMetataService.getAllLanguageList(); + } + + public final void replicateForm(String sourceMetadataId, String sourceMetadataRelativePath, String targetMetadataCode, String targetMetadataName, String targetProjectName) { + FormMetataService.replicateForm(sourceMetadataId, sourceMetadataRelativePath, targetMetadataCode, targetMetadataName, targetProjectName); + } + + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContent.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContent.java new file mode 100644 index 00000000..2545be16 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContent.java @@ -0,0 +1,101 @@ +package com.inspur.edp.web.formmetadata.metadata; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.TextNode; +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import com.inspur.edp.web.common.serialize.SerializeUtility; + +import java.util.Date; + + +public class FormMetadataContent extends AbstractMetadataContent { + + private String Id; + + @JsonProperty("Id") + public final String getId() { + return Id; + } + + public final void setId(String value) { + Id = value; + } + + + private JsonNode Contents; + + @JsonProperty("Contents") + public final JsonNode getContents() { + if (this.Contents != null && this.Contents instanceof TextNode) { + try { + this.Contents = SerializeUtility.getInstance().getDefaultObjectMapper().readTree(this.Contents.asText()); + }catch(Exception ex){ + throw new RuntimeException("表单元数据转换为JsonNode失败,对应元数据为:"+this.Contents.asText()); + } + } + return Contents; + } + + public final void setContents(JsonNode value) { + Contents = value; + } + + + private Date CreationDate; + + @JsonProperty("CreationDate") + public final Date getCreationDate() { + return CreationDate; + } + + public final void setCreationDate(Date value) { + CreationDate = value; + } + + + @Override + public FormMetadataContent clone() { + FormMetadataContent formMetaDataContent = new FormMetadataContent(); + formMetaDataContent.setId(this.getId()); + + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode newContent = mapper.treeToValue(mapper.valueToTree(this.getContents()), JsonNode.class); + formMetaDataContent.setContents(newContent); + } catch (JsonProcessingException e) { + e.printStackTrace(); + throw new RuntimeException("Form Content克隆失败, id=" + this.getId() + ", code=" + this.getCode() + ", name=" + this.getName()); + } + formMetaDataContent.setName(this.getName()); + formMetaDataContent.setCode(this.getCode()); + return formMetaDataContent; + } + + @JsonIgnore + public boolean isDynamic() { + if (Contents == null || Contents.isMissingNode() || Contents.isNull()) { + return false; + } + JsonNode renderMode = Contents.at("/options/renderMode"); + if (renderMode == null || renderMode.isMissingNode() || renderMode.isNull()) { + return false; + } + return "dynamic".equals(renderMode.asText()); + } + + @JsonIgnore + public boolean isCompile() { + if (Contents == null || Contents.isMissingNode() || Contents.isNull()) { + return true; + } + JsonNode renderMode = Contents.at("/options/renderMode"); + if (renderMode == null || renderMode.isMissingNode() || renderMode.isNull()) { + return true; + } + return "compile".equals(renderMode.asText()); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContentService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContentService.java new file mode 100644 index 00000000..c4660824 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/FormMetadataContentService.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.formmetadata.metadata; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.TupleFour; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +/** + * 表单元数据服务 + */ +public class FormMetadataContentService { + ///Singleton + private FormMetadataContentService() { + + } + + private static final FormMetadataContentService formMetadataService = new FormMetadataContentService(); + + public static FormMetadataContentService getInstance() { + return formMetadataService; + } + + public final FormDOM getFormContent(FormMetadataContent formMetadataContent) { + String sourceContent = SerializeUtility.getInstance().serialize(formMetadataContent.getContents(), false); + return SerializeUtility.getInstance().deserialize(sourceContent, FormDOM.class); + } + + /** + * 第一个参数formMetadataId + * 第二个参数formCode + * 第三个参数formName + * 第四个参数voId + * + * @param formMetadata + * @return + */ + public final TupleFour getParameterFromFormMetadata(GspMetadata formMetadata) { + if (formMetadata == null || formMetadata.getContent() == null) { + return null; + } + FormMetadataContent content = (FormMetadataContent) ((formMetadata.getContent() instanceof FormMetadataContent) ? formMetadata.getContent() : null); + if (content == null) { + return null; + } + + FormDOM formDOM = getFormContent(content); + if (formDOM != null && formDOM.getModule() != null && formDOM.getModule().getSchemas().size() > 0) { + String voId = formDOM.getModule().getSchemas().stream().findFirst().get().get("id").toString(); + String formCode = formDOM.getModule().getCode(); + String formName = formDOM.getModule().getName(); + String formMetadataId = formMetadata.getHeader().getId(); + return new TupleFour<>(formMetadataId, formCode, formName, voId); + } + return null; + } + + public final void setFormContent(FormMetadataContent formMetadataContent, FormDOM formDOM) { + String formDomStr = SerializeUtility.getInstance().serialize(formDOM, false); + JsonNode contentNode = SerializeUtility.getInstance().toJsonNode(formDomStr); + formMetadataContent.setContents(contentNode); + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDOM.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDOM.java new file mode 100644 index 00000000..049e1bb2 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDOM.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.formmetadata.metadata.formdom; + +import com.inspur.edp.web.formmetadata.metadata.module.Module; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/12 + */ +public class FormDOM { + private Module module; + + public Module getModule() { + return module; + } + + public void setModule(Module module) { + this.module = module; + } + + private FormOptions options; + + public FormOptions getOptions() { + if (this.options == null) { + this.options = new FormOptions(); + } + return options; + } + + public void setOptions(FormOptions options) { + this.options = options; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDomService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDomService.java new file mode 100644 index 00000000..03284cf0 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormDomService.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.formmetadata.metadata.formdom; + +import com.inspur.edp.web.formmetadata.metadata.module.ModuleService; + +import java.util.HashMap; + +/** + 表单DOM服务 + @author noah +*/ +public class FormDomService +{ + ///#region Singleton + private FormDomService() + { + + } + + private static final FormDomService formDomService = new FormDomService(); + public static FormDomService GetInstance() + { + return formDomService; + } + + public final String GetLanguage(FormDOM formDOM) + { + if (formDOM == null) + { + return null; + } + + return ModuleService.GetInstance().GetLanguage(formDOM.getModule()); + } + + + public final HashMap> GetLanguagePackage(FormDOM formDOM) + { + if (formDOM == null) + { + return null; + } + + return ModuleService.GetInstance().GetLanguagePackage(formDOM.getModule()); + } + + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormOptions.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormOptions.java new file mode 100644 index 00000000..2a9ed8ec --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/formdom/FormOptions.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.formmetadata.metadata.formdom; + +/** + * description: + * + * @author Noah Guo + * @date 2021/03/18 + */ + +public class FormOptions { + private boolean enableTextArea; + private boolean enableDragAndDropToModifyLayout; + /** + * 渲染方式 + * compile dynamic + */ + private String renderMode = "compile"; + + public String getRenderMode() { + return renderMode; + } + + public void setRenderMode(String renderMode) { + this.renderMode = renderMode; + } + + public boolean isEnableTextArea() { + return enableTextArea; + } + + public void setEnableTextArea(boolean enableTextArea) { + this.enableTextArea = enableTextArea; + } + + public boolean isEnableDragAndDropToModifyLayout() { + return enableDragAndDropToModifyLayout; + } + + public void setEnableDragAndDropToModifyLayout(boolean enableDragAndDropToModifyLayout) { + this.enableDragAndDropToModifyLayout = enableDragAndDropToModifyLayout; + } + + /** + * 标识是否解析表单 根据渲染模式来进行确定 + * @return + */ + public boolean isEnableFormJieXi() { + return this.renderMode.equals("dynamic"); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/i18nsetting/I18nSetting.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/i18nsetting/I18nSetting.java new file mode 100644 index 00000000..15b70f61 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/i18nsetting/I18nSetting.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.metadata.i18nsetting; + +/** + * 表单DOM(表单代码) + */ +public class I18nSetting { + /** + * 是否启用国际化 + */ + private boolean enableI18n; + + public final boolean getenableI18n() { + return enableI18n; + } + + public final void setenableI18n(boolean value) { + enableI18n = value; + } + + /** + * 国家或地区 + */ + private String region; + + public final String getregion() { + return region; + } + + public final void setregion(String value) { + region = value; + } + + /** + * 语言 + */ + private String language; + + public final String getlanguage() { + return language; + } + + public final void setlanguage(String value) { + language = value; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/languagepackage/LanguagePackage.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/languagepackage/LanguagePackage.java new file mode 100644 index 00000000..7a5f22ab --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/languagepackage/LanguagePackage.java @@ -0,0 +1,9 @@ +package com.inspur.edp.web.formmetadata.metadata.languagepackage; + +/** + 语言包 +*/ +public class LanguagePackage +{ + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/Module.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/Module.java new file mode 100644 index 00000000..9288d950 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/Module.java @@ -0,0 +1,363 @@ +package com.inspur.edp.web.formmetadata.metadata.module; + +import com.inspur.edp.web.formmetadata.metadata.i18nsetting.I18nSetting; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * 模块 + */ +public class Module { + //id + private String id; + + public final String getId() { + return id; + } + + public final void setId(String value) { + id = value; + } + + /** + * 编码 + */ + private String code; + + public final String getCode() { + return code; + } + + public final void setCode(String value) { + code = value; + } + + /** + * 名称 + */ + private String name; + + public final String getName() { + return name; + } + + public final void setName(String value) { + name = value; + } + + private String caption; + + public String getCaption() { + return caption; + } + + public void setCaption(String caption) { + this.caption = caption; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + private String creator; + private String creationDate; + private String updateVersion; + private String showTitle; + private String bootstrap; + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public String getCreationDate() { + return creationDate; + } + + public void setCreationDate(String creationDate) { + this.creationDate = creationDate; + } + + public String getUpdateVersion() { + return updateVersion; + } + + public void setUpdateVersion(String updateVersion) { + this.updateVersion = updateVersion; + } + + public String getShowTitle() { + return showTitle; + } + + public void setShowTitle(String showTitle) { + this.showTitle = showTitle; + } + + public String getBootstrap() { + return bootstrap; + } + + public void setBootstrap(String bootstrap) { + this.bootstrap = bootstrap; + } + + private String templateId; + + public String getTemplateId() { + return templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + + private ArrayList> schemas; + + public final ArrayList> getSchemas() { + return schemas; + } + + public final void setSchemas(ArrayList> value) { + schemas = value; + } + + private ArrayList> stateMachines; + + public final ArrayList> getStateMachines() { + return stateMachines; + } + + public final void setStateMachines(ArrayList> value) { + stateMachines = value; + } + + private ArrayList> viewmodels; + + public final ArrayList> getviewmodels() { + return viewmodels; + } + + public final void setviewmodels(ArrayList> value) { + viewmodels = value; + } + + private ArrayList> components; + + public final ArrayList> getComponents() { + return components; + } + + public final void setComponents(ArrayList> value) { + components = value; + } + + private ArrayList> webcmds; + + public final ArrayList> getWebcmds() { + return webcmds; + } + + public final void setWebcmds(ArrayList> value) { + webcmds = value; + } + + + + + + + private ArrayList> states; + + public ArrayList> getStates() { + return states; + } + + public void setStates(ArrayList> states) { + this.states = states; + } + + private ArrayList> contents; + + public ArrayList> getContents() { + return contents; + } + + public void setContents(ArrayList> contents) { + this.contents = contents; + } + + private List> expressions; + + public List> getExpressions() { + return expressions; + } + + public void setExpressions(List> expressions) { + this.expressions = expressions; + } + + + private ArrayList> serviceRefs; + + public final ArrayList> getServiceRefs() { + return serviceRefs; + } + + public final void setServiceRefs(ArrayList> value) { + serviceRefs = value; + } + + /** + * 外部组件 + */ + private ArrayList> externalComponents; + + public final ArrayList> getExternalComponents() { + return externalComponents; + } + + public final void setExternalComponents(ArrayList> value) { + externalComponents = value; + } + + /** + * TODO:升级结构后移除 + * 语言包 + * <语言, <控件id, 语言翻译>> + * 示例如下: + * "ctrlLangs": { + * "en": { + * "page-header-title": "cardForm1", + * "form_id": "id", + * "form_code": "code", + * "form_name": "name" + * } + * }, + */ + private HashMap> ctrlLangs; + + public final HashMap> getCtrlLangs() { + return ctrlLangs; + } + + public final void setCtrlLangs(HashMap> value) { + ctrlLangs = value; + } + + /** + * 国际化设置 + */ + private I18nSetting i18nSetting; + + public final I18nSetting getI18nSetting() { + return i18nSetting; + } + + public final void setI18nSetting(I18nSetting value) { + i18nSetting = value; + } + + + + + // 自定义代码 + + private List> sourceCodeRef; + + public List> getSourceCodeRef() { + return sourceCodeRef; + } + + public void setSourceCodeRef(List> sourceCodeRef) { + this.sourceCodeRef = sourceCodeRef; + } + + + + private boolean isComposedFrm; + + public boolean isComposedFrm() { + return isComposedFrm; + } + + public void setComposedFrm(boolean composedFrm) { + isComposedFrm = composedFrm; + } + + // 自定义代码 + private List> extraImports; + + public List> getExtraImports() { + return extraImports; + } + + public void setExtraImports(List> extraImports) { + this.extraImports = extraImports; + } + + private boolean isMobileApprove; + + public boolean isMobileApprove() { + return isMobileApprove; + } + + public void setMobileApprove(boolean mobileApprove) { + isMobileApprove = mobileApprove; + } + + + + private String projectName; + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + private Object declarations; + + public Object getDeclarations() { + return declarations; + } + + public void setDeclarations(Object declarations) { + this.declarations = declarations; + } + + + private HashMapcustomClass; + + public HashMap getCustomClass() { + return customClass; + } + + public void setCustomClass(HashMap customClass) { + this.customClass = customClass; + } + + private List> subscriptions; + + public List> getSubscriptions() { + return subscriptions; + } + + public void setSubscriptions(List> subscriptions) { + this.subscriptions = subscriptions; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/ModuleService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/ModuleService.java new file mode 100644 index 00000000..a366e8be --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/metadata/module/ModuleService.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.formmetadata.metadata.module; + +import java.util.*; + +/** + * 模块服务 + */ +public class ModuleService { + ///Singleton + private ModuleService() { + + } + + private static final ModuleService moduleService = new ModuleService(); + + public static ModuleService GetInstance() { + return moduleService; + } + + public final String GetLanguage(Module module) { + if (module == null || module.getI18nSetting() == null) { + return null; + } + + return module.getI18nSetting().getlanguage(); + } + + public final HashMap> GetLanguagePackage(Module module) { + if (module == null) { + return null; + } + + return module.getCtrlLangs(); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataReplicator.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataReplicator.java new file mode 100644 index 00000000..1a003e96 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataReplicator.java @@ -0,0 +1,285 @@ +package com.inspur.edp.web.formmetadata.replication; + + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.lcm.metadata.api.entity.MetadataType; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.command.component.metadata.CmpMethodRefering; +import com.inspur.edp.web.command.component.metadata.WebCommandsMetadata; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.io.File; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +/** + * 表单元数据复制器 + */ +public class FormMetadataReplicator { + private static final boolean IsDebug = true; + + /** + * 表单复制接口,目前仅支持同一个BO内复制 + * + * @param sourceMetadataId 待复制元数据id + * @param sourceMetadataRelativePath 待复制元数据路径 + * @param targetMetadataCode 目标元数据编号 + * @param targetMetadataName 目标元数据名称 + * @param targetProjectName 目标元数据所在工程名称 + */ + public final void replicate(String sourceMetadataId, String sourceMetadataRelativePath, String targetMetadataCode, String targetMetadataName, String targetProjectName) { + if (StringUtility.isNullOrEmpty(sourceMetadataId) || StringUtility.isNullOrEmpty(sourceMetadataRelativePath)) { + throw new GSPException("Web_Replicate", "待复制表单元数据ID或路径为空。请检查前端请求参数是否正常。"); + } + if (StringUtility.isNullOrEmpty(targetMetadataCode) || StringUtility.isNullOrEmpty(targetMetadataName)) { + throw new GSPException("Web_Replicate", "元数据Code或Name不能为空"); + } + + //根据当前表单元数据id 获取对应的元数据信息 + GspMetadata sourceFormMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(sourceMetadataId, sourceMetadataRelativePath); + if (sourceFormMetadata == null) { + throw new GSPException("Web_Replicate", "获取元数据为空。待获取元数据ID是:" + sourceMetadataId); + } + + // 获取待复制元数据所在工程名称 + String sourceProjectName = ProjectInformationManager.getProjectName(sourceFormMetadata); + if (StringUtility.isNullOrEmpty(sourceProjectName)) { + throw new GSPException("Web_Replicate", "待复制元数据所在工程的工程名为空。待复制元数据ID是:" + sourceMetadataId); + } + + // 初始化元数据复制上下文 + MetadataReplicationContext metadataReplicationContext = MetadataReplicationContextService.create(sourceProjectName, sourceFormMetadata, targetMetadataCode, targetMetadataName, targetProjectName); + MetadataReplicationContextService.updateMetadataReplicationContext(metadataReplicationContext); + + // 依据复制上下文 执行表单复制 + executeReplicate(metadataReplicationContext); + } + + + /** + * 复制表单元数据及关联的元数据 + * 目前仅支持同一个BO下复制(同一工程、不同工程) + * @param metadataReplicationContext 元数据复制上下文参数 + */ + private void executeReplicate(MetadataReplicationContext metadataReplicationContext) { + GspMetadata sourceFormMetadata = metadataReplicationContext.getSourceMetadata(); + + MetadataDto targetMetadataDescription = metadataReplicationContext.getTargetMetadataDescription(); + + // 复制表单元数据 + GspMetadata replicateFormMetadata = MetadataCloneManager.cloneMetadata(metadataReplicationContext); + + // 元数据创建前处理 + // 如果待保存元数据所在文件夹不存在,则创建文件夹 + String replicateFormMetadataAbsolutePath = MetadataUtility.getInstance().getAbsolutePath(replicateFormMetadata.getRelativePath()); + if (!FileUtility.exists(replicateFormMetadataAbsolutePath)) { + FileUtility.createDirectory(replicateFormMetadataAbsolutePath); + } + + // 磁盘中创建表单元数据 + MetadataUtility.getInstance().createMetadata(replicateFormMetadata); + + // 更新replicateFormMetadataContent + FormMetadataContent replicateFormMetadataContent = (FormMetadataContent) replicateFormMetadata.getContent(); + FormDOM replicateFormDOM = FormMetadataContentService.getInstance().getFormContent(replicateFormMetadataContent); + + // 1. 拷贝VO元数据及关联元数据 + FormMetadataVoManager.copyFormMetadataVo(metadataReplicationContext, sourceFormMetadata, targetMetadataDescription, replicateFormDOM, IsDebug); + + // 2. 表单关联状态机(从表单中获取stateMachineId) + FormMetadataSmManager.copyFormMetadataStateMachine(metadataReplicationContext, sourceFormMetadata, targetMetadataDescription, replicateFormDOM, IsDebug); + + // 3. 表单关联命令构件及服务构件 + copyFormMetadataCmd(metadataReplicationContext, sourceFormMetadata, targetMetadataDescription, replicateFormDOM); + + // 更新 Form Content + FormMetadataContentService.getInstance().setFormContent(replicateFormMetadataContent, replicateFormDOM); + + // 前置条件:保存前,对应的元数据文件已存在 + MetadataUtility.getInstance().saveMetadata(replicateFormMetadata); + } + + private void copyFormMetadataCmd(MetadataReplicationContext metadataReplicationContext, GspMetadata sourceFormMetadata, MetadataDto targetMetadataDescription, FormDOM replicateFormDOM) { + ArrayList> webcmdCollection = replicateFormDOM.getModule().getWebcmds(); + if (webcmdCollection != null && !webcmdCollection.isEmpty()) { + for (HashMap webcmd : webcmdCollection) { + String webcmdId = webcmd.containsKey("id") ? webcmd.get("id").toString() : ""; + GspMetadata webCmdMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(webcmdId, sourceFormMetadata.getRelativePath()); + if (webCmdMetadata == null) { + throw new GSPException("Web_Replicate", "复制表单元数据时,获取命令构件失败。待获取命令构件ID是:" + webcmdId); + } + + WebCommandsMetadata webCommandMetadataContent = (WebCommandsMetadata) webCmdMetadata.getContent(); + // 复制自定义命令构件及关联服务构件 + if (webCommandMetadataContent != null && webCommandMetadataContent.getExtendProperty() != null && !webCommandMetadataContent.getExtendProperty().isCommon()) { + // 拷贝这个命令构件 + MetadataDto webCommandMetadataDto = new MetadataDto(); + // TODO:如何保证正确替换code和name + webCommandMetadataDto.setCode(webCmdMetadata.getHeader().getCode().replace(webCommandMetadataContent.getExtendProperty().getFormCode(), targetMetadataDescription.getCode())); + webCommandMetadataDto.setName(webCmdMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + webCommandMetadataDto.setProjectName(targetMetadataDescription.getProjectName()); + webCommandMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath()); + + webCmdMetadata.setExtendProperty(webCmdMetadata.getExtendProperty().replace(sourceFormMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0], targetMetadataDescription.getCode().split(Pattern.quote("_"), -1)[0])); + + MetadataReplicationContext webCommandMetadataReplicationContext = new MetadataReplicationContext(); + webCommandMetadataReplicationContext.setSourceProjectName(metadataReplicationContext.getSourceProjectName()); + webCommandMetadataReplicationContext.setSourceMetadata(webCmdMetadata); + webCommandMetadataReplicationContext.setTargetMetadataDescription(webCommandMetadataDto); + + GspMetadata replicateWebCommandMetadata = MetadataCloneManager.cloneMetadata(webCommandMetadataReplicationContext); + MetadataUtility.getInstance().createMetadata(replicateWebCommandMetadata); + + // 更新表单内容关联webcmd + String oldWebCmdId = webcmd.get("id").toString(); + webcmd.put("id", replicateWebCommandMetadata.getHeader().getId()); + webcmd.put("name", replicateWebCommandMetadata.getHeader().getFileName()); + + // TODO: 具体化实现细节,避免性能问题 + // 更新ViewModels中关联webcmd + String viewModelCollectionStr = SerializeUtility.getInstance().serialize(replicateFormDOM.getModule().getviewmodels(),false); + viewModelCollectionStr = viewModelCollectionStr.replace(oldWebCmdId, webcmd.get("id").toString()); + ArrayList> temp = new ArrayList<>(); + replicateFormDOM.getModule().setviewmodels(SerializeUtility.getInstance().deserialize(viewModelCollectionStr, temp.getClass())); + //防止找不到Web构件 + String sourceProjectPath = metadataReplicationContext.getSourceMetadata().getRelativePath(); + //统一使用源工程路径查找 + replicateWebCommandMetadata.setRelativePath(sourceProjectPath); + // 查找自定义命令构件中使用的服务构件 + MetadataUtility.getInstance().getReferenceComponentMetadata(replicateWebCommandMetadata, this::UpdateWebComponentMetadata, metadataReplicationContext); + + // 保存命令元数据 + MetadataUtility.getInstance().saveMetadata(replicateWebCommandMetadata); + } + } + } + } + + + private void UpdateWebComponentMetadata(GspMetadata commandMetadata, CmpMethodRefering methodReferingItem, GspMetadata componentMetadata, Object... parameterArray) { + if (parameterArray.length != 1) { + return; + } + MetadataReplicationContext metadataReplicationContext = (MetadataReplicationContext) parameterArray[0]; + GspMetadata sourceFormMetadata = metadataReplicationContext.getSourceMetadata(); + String sourceProjectName = metadataReplicationContext.getSourceProjectName(); + MetadataDto targetMetadataDescription = metadataReplicationContext.getTargetMetadataDescription(); + + WebComponentMetadata componentMetadataContent = (WebComponentMetadata) componentMetadata.getContent(); + // 无需拷贝公共服务构件,仅拷贝自定义服务构件 + if (componentMetadataContent.isCommon()) { + return; + } + + MetadataUtility metadataUtility = MetadataUtility.getInstance(); + + // 拷贝这个服务构件 + + // 查找指定路径是否存在相同元数据,如果存在使用已有元数据,如果没有则创建一个 + + MetadataDto webComponentMetadataDto = new MetadataDto(); + // TODO:如何保证正确替换code和name + webComponentMetadataDto.setCode(componentMetadata.getHeader().getCode().replace(componentMetadataContent.getFormCode(), targetMetadataDescription.getCode())); + webComponentMetadataDto.setName(componentMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + webComponentMetadataDto.setProjectName(targetMetadataDescription.getProjectName()); + webComponentMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath()); + + // TODO:替换方式不准确,待优化 + componentMetadata.setExtendProperty(componentMetadata.getExtendProperty().replace(sourceFormMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0], targetMetadataDescription.getCode().split(Pattern.quote("_"), -1)[0])); + MetadataReplicationContext componentMetadataReplicationContext = new MetadataReplicationContext(); + componentMetadataReplicationContext.setSourceMetadata(componentMetadata); + componentMetadataReplicationContext.setSourceProjectName(metadataReplicationContext.getSourceProjectName()); + componentMetadataReplicationContext.setTargetMetadataDescription(webComponentMetadataDto); + + GspMetadata replicateWebComponentMetadata = MetadataCloneManager.cloneMetadata(componentMetadataReplicationContext); + + // TODO:提取RelativePath赋值操作,这样就无需先clone元数据再执行是否存在校验 + if (!CheckIfMetadataFileExits(replicateWebComponentMetadata)) { + metadataUtility.createMetadata(replicateWebComponentMetadata); + } else { + replicateWebComponentMetadata = metadataUtility.getMetadata(replicateWebComponentMetadata.getHeader().getFileName(), replicateWebComponentMetadata.getRelativePath()); + } + + // 更新命令构件关联的服务构件 + if (IsDebug) { + System.out.println("replicateWebComponentMetadataId: " + replicateWebComponentMetadata.getHeader().getId()); + } + methodReferingItem.setComponentId(replicateWebComponentMetadata.getHeader().getId()); + methodReferingItem.setComponentCode(replicateWebComponentMetadata.getHeader().getCode()); + methodReferingItem.setComponentName(replicateWebComponentMetadata.getHeader().getName()); + methodReferingItem.setComponentPath(replicateWebComponentMetadata.getRelativePath()); + + // 获取服务构件关联的文件 + String path = componentMetadataContent.getSource(); + //更新path + if (!path.equals(MetadataUtility.getInstance().getTypeScriptFileName(componentMetadata))) { + path = MetadataUtility.getInstance().getTypeScriptFileName(componentMetadata); + componentMetadataContent.setSource(path); + } + + // 拷贝服务构件关联的文件(.ts文件) + String absolutePath = MetadataUtility.getInstance().getAbsolutePath(path); + String oldFileContent = FileUtility.readAsString(absolutePath); + + // 更新服务构件 + String targetPath = path; + if (!sourceProjectName.equals(targetMetadataDescription.getProjectName())) { + targetPath = targetPath.replace(sourceProjectName, targetMetadataDescription.getProjectName()); + } + + String updateAbsolutPath = MetadataUtility.getInstance().getAbsolutePath(targetPath); + updateAbsolutPath = updateAbsolutPath.replace(componentMetadata.getHeader().getCode(), replicateWebComponentMetadata.getHeader().getCode()); + if (IsDebug) { + System.out.println(".ts file Path is: " + updateAbsolutPath); + } + File file = new File(updateAbsolutPath); + String filePath = file.getParent(); + String fileName = file.getName(); + if (IsDebug) { + System.out.println("file Path is: " + filePath); + System.out.println("file Name is: " + fileName); + } + FileUtility.writeFile(filePath, fileName, oldFileContent); + + // 更新服务构件 + WebComponentMetadata replicateComponentMetadataContent = (WebComponentMetadata) replicateWebComponentMetadata.getContent(); + replicateComponentMetadataContent.setSource(targetPath); + + metadataUtility.saveMetadata(replicateWebComponentMetadata); + } + + private boolean CheckIfMetadataFileExits(GspMetadata metadata) { + MetadataUtility metadataUtility = MetadataUtility.getInstance(); + + String absolutePath = metadataUtility.getAbsolutePath(metadata.getRelativePath()); + //元数据名称 + String metadataName = GetMetadataFullName(metadata); + + //元数据完整路径 + String fullPath = Paths.get(absolutePath).resolve(metadataName).toString(); + return FileUtility.exists(fullPath); + } + + private String GetMetadataFullName(GspMetadata metadata) { + MetadataService ser = SpringBeanUtils.getBean(MetadataService.class); + List metadataTypeList = ser.getMetadataTypeList(); + Optional first = metadataTypeList.stream().filter((type) -> type.getTypeCode().equals(metadata.getHeader().getType())).findFirst(); + return metadata.getHeader().getCode() + first.get().getPostfix(); + } + + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataSmManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataSmManager.java new file mode 100644 index 00000000..3fce2a6a --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataSmManager.java @@ -0,0 +1,57 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class FormMetadataSmManager { + public static void copyFormMetadataStateMachine(MetadataReplicationContext metadataReplicationContext, GspMetadata sourceFormMetadata, + MetadataDto targetMetadataDescription, FormDOM replicateFormDOM,boolean IsDebug) { + ArrayList> stateMachineCollection = replicateFormDOM.getModule().getStateMachines(); + if (stateMachineCollection != null && !stateMachineCollection.isEmpty()) { + for (HashMap stateMachine : stateMachineCollection) { + String stateMachineId = stateMachine.containsKey("uri") ? stateMachine.get("uri").toString() : ""; + + GspMetadata stateMachineMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(stateMachineId,sourceFormMetadata.getRelativePath()); + MetadataDto stateMachineMetadataDto = new MetadataDto(); + stateMachineMetadataDto.setCode(stateMachineMetadata.getHeader().getCode().replace(sourceFormMetadata.getHeader().getCode(), targetMetadataDescription.getCode())); + stateMachineMetadataDto.setName(stateMachineMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + stateMachineMetadataDto.setProjectName(targetMetadataDescription.getProjectName()); + stateMachineMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath()); + + + MetadataReplicationContext stateMachineMetadataReplicationContext = new MetadataReplicationContext(); + stateMachineMetadataReplicationContext.setSourceProjectName(metadataReplicationContext.getSourceProjectName()); + stateMachineMetadataReplicationContext.setSourceMetadata(stateMachineMetadata); + stateMachineMetadataReplicationContext.setTargetMetadataDescription(stateMachineMetadataDto); + + GspMetadata replicateStateMachineMetadata = MetadataCloneManager.cloneMetadata(stateMachineMetadataReplicationContext); + MetadataUtility.getInstance().createMetadata(replicateStateMachineMetadata); + + MetadataUtility.getInstance().saveMetadata(replicateStateMachineMetadata); + //原stateMachineId + stateMachineId = replicateStateMachineMetadata.getHeader().getId(); + // 更新表单内容statemachine + if (IsDebug) { + System.out.println("stateMachineId: " + stateMachineId); + } + stateMachine.put("uri", stateMachineId); + + // 更新表单关联statemachine + // 暂不更新ID:如果更新ID,还需更新表单中使用ID的地方 + stateMachine.put("name", stateMachine.get("name").toString().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + } + } + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataVoManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataVoManager.java new file mode 100644 index 00000000..9c358d6a --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/FormMetadataVoManager.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.sgf.api.common.ResourceType; +import com.inspur.edp.sgf.api.entity.SgMetadata; +import com.inspur.edp.sgf.api.service.EapiMetadataDtService; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class FormMetadataVoManager { + public static void copyFormMetadataVo(MetadataReplicationContext metadataReplicationContext, GspMetadata sourceFormMetadata, + MetadataDto targetMetadataDescription, FormDOM replicateFormDOM, boolean isDebug) { + ArrayList> schemaCollection = replicateFormDOM.getModule().getSchemas(); + if (schemaCollection != null && !schemaCollection.isEmpty()) { + for (HashMap schema : schemaCollection) { + // 1.1 获取并拷贝VO + String viewObjectId = schema.containsKey("id") ? schema.get("id").toString() : ""; + GspMetadata viewObjectMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(viewObjectId, sourceFormMetadata.getRelativePath()); + MetadataDto viewObjectMetadataDto = new MetadataDto(); + viewObjectMetadataDto.setCode(viewObjectMetadata.getHeader().getCode().replace(sourceFormMetadata.getHeader().getCode(), targetMetadataDescription.getCode())); + viewObjectMetadataDto.setName(viewObjectMetadata.getHeader().getName().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + viewObjectMetadataDto.setProjectName(targetMetadataDescription.getProjectName()); + viewObjectMetadataDto.setRelativePath(targetMetadataDescription.getRelativePath()); + + MetadataReplicationContext viewObjectMetadataReplicationContext = new MetadataReplicationContext(); + viewObjectMetadataReplicationContext.setSourceProjectName(metadataReplicationContext.getSourceProjectName()); + viewObjectMetadataReplicationContext.setSourceMetadata(viewObjectMetadata); + viewObjectMetadataReplicationContext.setTargetMetadataDescription(viewObjectMetadataDto); + + GspMetadata replicateViewObjectMetadata = MetadataCloneManager.cloneMetadata(viewObjectMetadataReplicationContext); + + MetadataUtility.getInstance().createMetadata(replicateViewObjectMetadata); + + MetadataUtility.getInstance().saveMetadata(replicateViewObjectMetadata); + + // 更新表单内容关联VO + schema.put("id", replicateViewObjectMetadata.getHeader().getId()); + + // 1.2 基于VO创建eapi + if (isDebug) { + System.out.println("viewObjectMetadata.RelativePath: " + replicateViewObjectMetadata.getRelativePath()); + } + + EapiMetadataDtService eapiMetadataDtService = SpringBeanUtils.getBean(EapiMetadataDtService.class); + GspMetadata metadata = eapiMetadataDtService.create(replicateViewObjectMetadata, replicateViewObjectMetadata.getRelativePath(), ResourceType.VO_ADVANCE); + SgMetadata eapiMetadata = (SgMetadata) metadata.getContent(); + // 1.3 更新表单关联epaiId + if (isDebug) { + System.out.println("eapId: " + eapiMetadata.getId()); + } + schema.put("eapiId", eapiMetadata.getId()); + + // 更新其他属性 + schema.put("code", schema.get("code").toString().replace(sourceFormMetadata.getHeader().getCode(), targetMetadataDescription.getCode())); + schema.put("name", schema.get("name").toString().replace(sourceFormMetadata.getHeader().getName(), targetMetadataDescription.getName())); + schema.put("sourceUri", schema.get("sourceUri").toString().replace(sourceFormMetadata.getHeader().getCode(), targetMetadataDescription.getCode())); + } + } + } + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataCloneManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataCloneManager.java new file mode 100644 index 00000000..4d6ecca1 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataCloneManager.java @@ -0,0 +1,268 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.formserver.viewmodel.GspViewModel; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.entity.MetadataReference; +import com.inspur.edp.lcm.metadata.common.configuration.MetadataSerializerHelper; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.command.component.metadata.WebCommandsMetadata; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +import java.util.ArrayList; +import java.util.UUID; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class MetadataCloneManager { + /** + * 元数据克隆 + * + * @param metadataReplicationContext + * @return + */ + public static GspMetadata cloneMetadata(MetadataReplicationContext metadataReplicationContext) { + GspMetadata sourceMetadata = metadataReplicationContext.getSourceMetadata(); + MetadataDto metadataDto = metadataReplicationContext.getTargetMetadataDescription(); + + // 复制前检测(仅支持同一个BO内复制--需保证) + // 现有元数据描述和元数据内容存在两个层次的数据一致性问题:元数据Code和元数据命名空间。当前,仅处理元数据Code上的数据不一致问题,元数据命令空间的数据不一致后续处理。 + if ((metadataDto.getNameSpace() != null && !metadataDto.getNameSpace().equals(sourceMetadata.getHeader().getNameSpace())) || (metadataDto.getBizobjectID() != null && !metadataDto.getBizobjectID().equals(sourceMetadata.getHeader().getBizobjectID()))) { + throw new GSPException("Web_Replicate", "目前仅支持同一个业务对象(Business Object)内的表单复制。如果需要其他场景的复制,请联系开发人员。"); + } + + GspMetadata replicateMetadata = new GspMetadata(); + + // 检测 MetadataDto + if (!StringUtility.isNullOrEmpty(metadataDto.getCode()) && StringUtility.isNullOrEmpty(metadataDto.getFileName())) { + metadataDto.setFileName(metadataDto.getCode() + sourceMetadata.getHeader().getFileName().substring(sourceMetadata.getHeader().getFileName().lastIndexOf("."))); + } + + // 复制MetadataHeader + replicateMetadata.setHeader(cloneMetadataHeader(sourceMetadata, metadataDto)); + + // 依赖关系置空 + replicateMetadata.setRefs(new ArrayList<>()); + + // 复制元数据内容实体 + replicateMetadata.setContent(cloneMetadataContent(sourceMetadata, metadataDto)); + + // 更新元数据内容(保证元数据描述和元数据内容的数据一致性) + IMetadataContent replicateMetadataContent = replicateMetadata.getContent(); + if (replicateMetadataContent instanceof GspViewModel) { + // 保证VO元数据,元数据描述的id和code与VO内容中数据的一致性 + executeGspViewModel(replicateMetadata, (GspViewModel) replicateMetadataContent); + } + + if (replicateMetadataContent instanceof FormMetadataContent) { + // 保证表单元数据中,元数据描述的id和code与表单内容中数据的一致性 + executeFormMetadataContent(replicateMetadata, (FormMetadataContent) replicateMetadataContent); + } + + if (replicateMetadataContent instanceof WebCommandsMetadata) { + // 保证命令构件元数据中,元数据描述的id和code与命令构件内容中数据的一致性 + executeWebCommand(replicateMetadata, (WebCommandsMetadata) replicateMetadataContent); + } + + if (replicateMetadataContent instanceof WebComponentMetadata) { + // 保证命令构件元数据中,元数据描述的id和code与命令构件内容中数据的一致性 + executeWebComponent(replicateMetadata, (WebComponentMetadata) replicateMetadataContent); + } + + // 复制元数据上其他属性 + replicateMetadata.setRelativePath(sourceMetadata.getRelativePath()); + if (metadataDto != null && !StringUtility.isNullOrEmpty(metadataDto.getRelativePath())) { + replicateMetadata.setRelativePath(metadataDto.getRelativePath()); + } + + replicateMetadata.setExtended(sourceMetadata.isExtended()); + if (metadataDto != null && metadataDto.isExtendable()) { + replicateMetadata.setExtended(metadataDto.isExtendable()); + } + + replicateMetadata.setExtendProperty(sourceMetadata.getExtendProperty()); + replicateMetadata.setPreviousVersion(null); + replicateMetadata.setVersion(null); + + return replicateMetadata; + } + + private static void executeWebComponent(GspMetadata replicateMetadata, WebComponentMetadata replicateMetadataContent) { + WebComponentMetadata replicateWebComponentMetadataContent = replicateMetadataContent; + replicateWebComponentMetadataContent.setId(replicateMetadata.getHeader().getId()); + replicateWebComponentMetadataContent.setCode(replicateMetadata.getHeader().getCode()); + + // TODO:优化实现方式 + replicateWebComponentMetadataContent.setFormCode(replicateMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0]); + + // 使用构件的序列化器 + com.inspur.edp.cdp.web.component.metadata.serializer.JsonSerializer jsonSerializer = new com.inspur.edp.cdp.web.component.metadata.serializer.JsonSerializer(); + replicateMetadata.setContent(jsonSerializer.DeSerialize(jsonSerializer.Serialize(replicateWebComponentMetadataContent))); + } + + private static void executeWebCommand(GspMetadata replicateMetadata, WebCommandsMetadata replicateMetadataContent) { + WebCommandsMetadata replicateWebCommandMetadataContent = replicateMetadataContent; + replicateWebCommandMetadataContent.setId(replicateMetadata.getHeader().getId()); + replicateWebCommandMetadataContent.setCode(replicateMetadata.getHeader().getCode()); + replicateWebCommandMetadataContent.setName(replicateMetadata.getHeader().getName()); + + replicateWebCommandMetadataContent.getExtendProperty().setFormCode(replicateMetadata.getHeader().getCode().split(Pattern.quote("_"), -1)[0]); + + + com.inspur.edp.web.command.component.serializer.WebCmdMetadataSerializer webCmdMetadataSerializer = new com.inspur.edp.web.command.component.serializer.WebCmdMetadataSerializer(); + JsonNode replicateGSPViewModelStr = webCmdMetadataSerializer.Serialize(replicateWebCommandMetadataContent); + + replicateMetadata.setContent(webCmdMetadataSerializer.DeSerialize(replicateGSPViewModelStr)); + + } + + private static void executeFormMetadataContent(GspMetadata replicateMetadata, FormMetadataContent replicateMetadataContent) { + FormMetadataContent replicateFormMetadataContent = replicateMetadataContent; + + replicateFormMetadataContent.setId(replicateMetadata.getHeader().getId()); + + FormDOM formDOM = FormMetadataContentService.getInstance().getFormContent(replicateFormMetadataContent); + formDOM.getModule().setId(replicateMetadata.getHeader().getCode()); + formDOM.getModule().setCode(replicateMetadata.getHeader().getCode()); + formDOM.getModule().setName(replicateMetadata.getHeader().getName()); + formDOM.getModule().setCaption(replicateMetadata.getHeader().getName()); + formDOM.getModule().setCreationDate(CommonUtility.getCurrentDateString()); + //更新工程名 + FormMetadataContentService.getInstance().setFormContent(replicateFormMetadataContent, formDOM); + } + + private static void executeGspViewModel(GspMetadata replicateMetadata, GspViewModel replicateMetadataContent) { + GspViewModel replicateGSPViewModel = replicateMetadataContent; + + String oldViewModelCode = replicateGSPViewModel.getCode(); + + String generatingAssemblyName = replicateGSPViewModel.getGeneratingAssembly().substring(0, replicateGSPViewModel.getGeneratingAssembly().lastIndexOf(".")); + + replicateGSPViewModel.setGeneratingAssembly(replicateGSPViewModel.getGeneratingAssembly().replace(generatingAssemblyName, replicateMetadata.getHeader().getNameSpace())); + + replicateGSPViewModel.setID(replicateMetadata.getHeader().getId()); + + replicateGSPViewModel.getVariables().setName(replicateGSPViewModel.getVariables().getName().replace(oldViewModelCode, replicateMetadata.getHeader().getCode())); + replicateGSPViewModel.setName(replicateMetadata.getHeader().getName()); + + replicateGSPViewModel.getVariables().setCode(replicateGSPViewModel.getVariables().getCode().replace(oldViewModelCode, replicateMetadata.getHeader().getCode())); + replicateGSPViewModel.setCode(replicateMetadata.getHeader().getCode()); + + MetadataContentSerializer transferSerializerManager = MetadataSerializerHelper.getInstance().getManager(replicateMetadata.getHeader().getType()); + if (transferSerializerManager == null) { + //throw new GSPException(MetadataExceptionUtil.Metadata_TransferSerializer, "未能正常获取元数据传输序列化器,请检查配置", null, ExceptionLevel.Error, false); + throw new GSPException("", "未能正常获取元数据传输序列化器,请检查配置", null, ExceptionLevel.Error, false); + } + + + String replicateGSPViewModelStr = transferSerializerManager.Serialize(replicateGSPViewModel).toString(); + String i18nResourceInfoPrefix = replicateMetadata.getHeader().getNameSpace() + "." + "Vo" + "."; + replicateGSPViewModelStr = replicateGSPViewModelStr.replace(i18nResourceInfoPrefix + oldViewModelCode, i18nResourceInfoPrefix + replicateGSPViewModel.getCode()); + + replicateMetadata.setContent(transferSerializerManager.DeSerialize(SerializeUtility.getInstance().readTree(replicateGSPViewModelStr))); + } + + private static IMetadataContent cloneMetadataContent(GspMetadata sourceMetadata, MetadataDto metadataDto) { + IMetadataContent metadataContent = null; + MetadataContentSerializer transferSerializerManager = MetadataSerializerHelper.getInstance().getManager(sourceMetadata.getHeader().getType()); + if (transferSerializerManager == null) { + //throw new GSPException(MetadataExceptionUtil.Metadata_TransferSerializer, "未能正常获取元数据传输序列化器,请检查配置", null, ExceptionLevel.Error, false); + throw new GSPException("", "未能正常获取元数据传输序列化器,请检查配置", null, ExceptionLevel.Error, false); + } + + if (sourceMetadata.getContent() != null) { + JsonNode content = transferSerializerManager.Serialize(sourceMetadata.getContent()); + metadataContent = transferSerializerManager.DeSerialize(content); + } + + if (metadataDto != null && !StringUtility.isNullOrEmpty(metadataDto.getContent())) { + JsonNode metadataDtoContent = SerializeUtility.getInstance().readTree(metadataDto.getContent()); + metadataContent = transferSerializerManager.DeSerialize(metadataDtoContent); + } + + return metadataContent; + } + + private static MetadataHeader cloneMetadataHeader(GspMetadata sourceMetadata, MetadataDto metadataDto) { + MetadataHeader metadataHeader = new MetadataHeader(); + + copyMetadataHeader(sourceMetadata, metadataHeader); + + tryToUpdateMetadataHeader(metadataDto, metadataHeader); + + return metadataHeader; + } + + private static void copyMetadataHeader(GspMetadata sourceMetadata, MetadataHeader targetMetadataHeader) { + targetMetadataHeader.setId(UUID.randomUUID().toString()); + targetMetadataHeader.setCertId(sourceMetadata.getHeader().getCertId()); + targetMetadataHeader.setNameSpace(sourceMetadata.getHeader().getNameSpace()); + targetMetadataHeader.setCode(sourceMetadata.getHeader().getCode() + "copy"); + targetMetadataHeader.setName(sourceMetadata.getHeader().getName() + "copy"); + targetMetadataHeader.setFileName(sourceMetadata.getHeader().getCode() + "copy" + sourceMetadata.getHeader().getFileName().substring(sourceMetadata.getHeader().getFileName().lastIndexOf("."))); + targetMetadataHeader.setType(sourceMetadata.getHeader().getType()); + targetMetadataHeader.setBizobjectID(sourceMetadata.getHeader().getBizobjectID()); + targetMetadataHeader.setLanguage(sourceMetadata.getHeader().getLanguage()); + targetMetadataHeader.setTranslating(sourceMetadata.getHeader().isTranslating()); + } + + private static void tryToUpdateMetadataHeader(MetadataDto metadataDto, MetadataHeader targetMetadataHeader) { + if (metadataDto == null) { + return; + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getId())) { + targetMetadataHeader.setId(metadataDto.getId()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getNameSpace())) { + targetMetadataHeader.setNameSpace(metadataDto.getNameSpace()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getCode())) { + targetMetadataHeader.setCode(metadataDto.getCode()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getName())) { + targetMetadataHeader.setName(metadataDto.getName()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getFileName())) { + targetMetadataHeader.setFileName(metadataDto.getFileName()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getType())) { + targetMetadataHeader.setType(metadataDto.getType()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getBizobjectID())) { + targetMetadataHeader.setBizobjectID(metadataDto.getBizobjectID()); + } + + if (!StringUtility.isNullOrEmpty(metadataDto.getLanguage())) { + targetMetadataHeader.setLanguage(metadataDto.getLanguage()); + } + + if (metadataDto.isTranslating()) { + targetMetadataHeader.setTranslating(metadataDto.isTranslating()); + } + } + + +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContext.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContext.java new file mode 100644 index 00000000..87cb0fed --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContext.java @@ -0,0 +1,63 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; + + +//TODO n转j n版代码存在[Serializable] +public class MetadataReplicationContext { + /** + * 待复制元数据 + */ + private GspMetadata sourceMetadata; + + public final GspMetadata getSourceMetadata() { + return this.sourceMetadata; + } + + public final void setSourceMetadata(GspMetadata value) { + this.sourceMetadata = value; + } + + /** + * 待复制元数据所在工程的名称 + */ + private String sourceProjectName; + + public final String getSourceProjectName() { + return this.sourceProjectName; + } + + public final void setSourceProjectName(String value) { + this.sourceProjectName = value; + } + + /** + * 目标元数据描述 + */ + private MetadataDto targetMetadataDescription; + + public final MetadataDto getTargetMetadataDescription() { + return this.targetMetadataDescription; + } + + public final void setTargetMetadataDescription(MetadataDto value) { + this.targetMetadataDescription = value; + } + + public MetadataReplicationContext() { + + } + + private MetadataReplicationContext createMetadataReplicationContext(String sourceProjectName, GspMetadata sourceFormMetadata, String targetMetadataCode, String targetMetadataName, String targetProjectName) { + MetadataReplicationContext metadataReplicationContext = new MetadataReplicationContext(); + metadataReplicationContext.setSourceMetadata(sourceFormMetadata); + metadataReplicationContext.setSourceProjectName(sourceProjectName); + metadataReplicationContext.setTargetMetadataDescription(new MetadataDto()); + metadataReplicationContext.getTargetMetadataDescription().setCode(targetMetadataCode); + metadataReplicationContext.getTargetMetadataDescription().setName(targetMetadataName); + metadataReplicationContext.getTargetMetadataDescription().setProjectName(targetProjectName); + + return metadataReplicationContext; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContextService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContextService.java new file mode 100644 index 00000000..85885f13 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/MetadataReplicationContextService.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataDto; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.regex.Pattern; + +public class MetadataReplicationContextService { + + /** + * 创建元数据复制上下文 + * + * @param sourceProjectName 源工程名称 + * @param sourceMetadata 待复制元数据 + * @param targetMetadataCode 复制后元数据编号 + * @param targetMetadataName 复制后元数据名称 + * @param targetProjectName 复制后元数据所在工程的工程名 + * @return + */ + public static MetadataReplicationContext create(String sourceProjectName, GspMetadata sourceMetadata, String targetMetadataCode, String targetMetadataName, String targetProjectName) { + MetadataReplicationContext metadataReplicationContext = new MetadataReplicationContext(); + metadataReplicationContext.setSourceMetadata(sourceMetadata); + metadataReplicationContext.setSourceProjectName(sourceProjectName); + + // 目标工程名为空时,使用源工程名 + if (StringUtility.isNullOrEmpty(targetProjectName)) { + targetProjectName = sourceProjectName; + } + MetadataDto metadataDto = new MetadataDto(); + metadataDto.setCode(targetMetadataCode); + metadataDto.setName(targetMetadataName); + metadataDto.setProjectName(targetProjectName); + metadataReplicationContext.setTargetMetadataDescription(metadataDto); + + return metadataReplicationContext; + } + + /** + * 更新元数据复制上下文参数 + * + * @param metadataReplicationContext + */ + public static void updateMetadataReplicationContext(MetadataReplicationContext metadataReplicationContext) { + GspMetadata sourceMetadata = metadataReplicationContext.getSourceMetadata(); + String sourceProjectName = metadataReplicationContext.getSourceProjectName(); + String targetProjectName = metadataReplicationContext.getTargetMetadataDescription().getProjectName(); + + if (sourceProjectName.equals(targetProjectName)) { + // 新拷贝的表单与待拷贝表单在同一个工程 + metadataReplicationContext.getTargetMetadataDescription().setRelativePath(sourceMetadata.getRelativePath()); + } else { + metadataReplicationContext.getTargetMetadataDescription().setRelativePath(sourceMetadata.getRelativePath().replace(sourceProjectName, targetProjectName)); + try { + // 根据原工程信息更新目标工程信息,避免引用的元数据无法获取到的问题 + String[] soureMetadataSegmentPathColleciton = sourceMetadata.getRelativePath().replace("\\", "/").split(Pattern.quote("/"), -1); + ProjectInformationManager.updateTargetProjectInformation(soureMetadataSegmentPathColleciton, sourceProjectName, targetProjectName); + } catch (RuntimeException e) { + throw new GSPException("Web_Replicate", "复制表单时,同步目标工程信息失败。源表单ID是:" + sourceMetadata.getHeader().getId() + "更多异常信息如下:" + e.getMessage(), e); + } + } + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/ProjectInformationManager.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/ProjectInformationManager.java new file mode 100644 index 00000000..55cef777 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/replication/ProjectInformationManager.java @@ -0,0 +1,175 @@ +package com.inspur.edp.web.formmetadata.replication; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataPackageHeader; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.entity.ProjectHeader; +import com.inspur.edp.lcm.metadata.api.mvnEntity.MavenPackageRefs; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.constant.ReplicationConstant; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * description: + * + * @author Noah Guo + * @date 2021/02/26 + */ +public class ProjectInformationManager { + public static void updateTargetProjectInformation(String[] soureMetadataSegmentPathColleciton, String sourceProjectName, String targetProjectName) { + MetadataProject soureMetadataProject = ProjectInformationManager.getSourceProjectInformation(soureMetadataSegmentPathColleciton, sourceProjectName); + + MetadataProject targetMetadataProject = getTargetProjectInformation(soureMetadataSegmentPathColleciton, targetProjectName); + + synchroizeProjectInformation(soureMetadataProject, targetMetadataProject); + + // 保存目标工程配置文件 + String targetMetadataProjectStr = SerializeUtility.getInstance().serialize(targetMetadataProject,false); + String targetProjectAbsolutePath = getTargetProjectAbsolutPath(soureMetadataSegmentPathColleciton, targetProjectName); + FileUtility.writeFile(targetProjectAbsolutePath, targetProjectName + "." + ReplicationConstant.METADATA_PROJECT_FILE_SUFFIX, targetMetadataProjectStr); + } + + private static MetadataProject getTargetProjectInformation(String[] soureMetadataSegmentPathColleciton, String targetProjectName) { + String targetProjectAbsolutPath = getTargetProjectAbsolutPath(soureMetadataSegmentPathColleciton, targetProjectName); + + return getProjectInformation(targetProjectAbsolutPath, targetProjectName); + } + + private static void synchroizeProjectInformation(MetadataProject soureMetadataProject, MetadataProject targetMetadataProject) { + // 同步 MetadataPackageRefs + if (soureMetadataProject.getMetadataPackageRefs() != null) { + for (int i = 0; i < soureMetadataProject.getMetadataPackageRefs().size(); i++) { + MetadataPackageHeader metadataPackageHeader = soureMetadataProject.getMetadataPackageRefs().get(i); + boolean existsSameMetadataPackageHeader = false; + if (targetMetadataProject.getMetadataPackageRefs() == null) { + targetMetadataProject.setMetadataPackageRefs(new ArrayList<>()); + } + for (int j = 0; j < targetMetadataProject.getMetadataPackageRefs().size(); j++) { + if (Objects.equals(targetMetadataProject.getMetadataPackageRefs().get(j).getName(), soureMetadataProject.getMetadataPackageRefs().get(i).getName())) { + existsSameMetadataPackageHeader = true; + break; + } + } + + if (!existsSameMetadataPackageHeader) { + targetMetadataProject.getMetadataPackageRefs().add(soureMetadataProject.getMetadataPackageRefs().get(i)); + } + } + } + + // 同步 ProjectRefs + if (soureMetadataProject.getProjectRefs() != null) { + for (int i = 0; i < soureMetadataProject.getProjectRefs().size(); i++) { + ProjectHeader projectPackageHeader = soureMetadataProject.getProjectRefs().get(i); + boolean existsSameProjectPackageHeader = false; + if (targetMetadataProject.getProjectRefs() == null) { + targetMetadataProject.setProjectRefs(new ArrayList<>()); + } + for (int j = 0; j < targetMetadataProject.getProjectRefs().size(); j++) { + if (Objects.equals(targetMetadataProject.getProjectRefs().get(j).getName(), soureMetadataProject.getProjectRefs().get(i).getName())) { + existsSameProjectPackageHeader = true; + break; + } + } + + if (!existsSameProjectPackageHeader) { + targetMetadataProject.getProjectRefs().add(soureMetadataProject.getProjectRefs().get(i)); + } + } + } + + // 同步 MavenPackageRefs + if (soureMetadataProject.getMavenPackageRefs() != null) { + for (int i = 0; i < soureMetadataProject.getMavenPackageRefs().size(); i++) { + MavenPackageRefs mavenHeader = soureMetadataProject.getMavenPackageRefs().get(i); + boolean existsSameMavenHeader = false; + if (targetMetadataProject.getMavenPackageRefs() == null) { + targetMetadataProject.setMavenPackageRefs(new ArrayList<>()); + } + for (int j = 0; j < targetMetadataProject.getMavenPackageRefs().size(); j++) { + if (Objects.equals(targetMetadataProject.getMavenPackageRefs().get(j).getGroupId(), soureMetadataProject.getMavenPackageRefs().get(i).getGroupId()) + && Objects.equals(targetMetadataProject.getMavenPackageRefs().get(j).getArtifactId(), soureMetadataProject.getMavenPackageRefs().get(i).getArtifactId())) { + existsSameMavenHeader = true; + break; + } + } + + if (!existsSameMavenHeader) { + targetMetadataProject.getMavenPackageRefs().add(soureMetadataProject.getMavenPackageRefs().get(i)); + } + } + } + } + + + private static String getTargetProjectAbsolutPath(String[] soureMetadataSegmentPathColleciton, String targetProjectName) { + StringBuilder targetProjectRelativePath = new StringBuilder(); + for (int i = 0; i <= 4; i++) { + if (i != 0) { + targetProjectRelativePath.append("/"); + } + + if (i == 3) { + // 替换工程名 + targetProjectRelativePath.append(targetProjectName); + } else { + targetProjectRelativePath.append(soureMetadataSegmentPathColleciton[i]); + } + } + + return MetadataUtility.getInstance().getAbsolutePath(targetProjectRelativePath.toString()); + } + + + public static MetadataProject getSourceProjectInformation(String[] soureMetadataSegmentPathColleciton, String sourceProjectName) { + if (soureMetadataSegmentPathColleciton == null || soureMetadataSegmentPathColleciton.length < 4) { + throw new GSPException("Web_Replicate", "源表单存储相对路径属性不包含工程名,请检查。"); + } + + StringBuilder sourceProjectRelativePath = new StringBuilder(); + for (int i = 0; i <= 4; i++) { + if (i != 0) { + sourceProjectRelativePath.append("/"); + } + sourceProjectRelativePath.append(soureMetadataSegmentPathColleciton[i]); + } + + String sourceProjectAbsolutPath = MetadataUtility.getInstance().getAbsolutePath(sourceProjectRelativePath.toString()); + return getProjectInformation(sourceProjectAbsolutPath, sourceProjectName); + } + + private static MetadataProject getProjectInformation(String projectAbsolutePath, String projectName) { + String projectFileFullPath = Paths.get(projectAbsolutePath).resolve(projectName + "." + ReplicationConstant.METADATA_PROJECT_FILE_SUFFIX).toString(); + String projectFileContent = FileUtility.readAsString(projectFileFullPath); + + return SerializeUtility.getInstance().deserialize(projectFileContent, MetadataProject.class); + } + + /** + * 基于元数据获取元数据所在工程 + * 变化点,抽离出来,后续优化 + * + * @param metadata 待查询元数据 + * @return 工程名 + */ + public static String getProjectName(GspMetadata metadata) { + if (metadata == null || StringUtility.isNullOrEmpty(metadata.getRelativePath())) { + return null; + } + + String[] metadataSegmentPathColleciton = metadata.getRelativePath().replace("\\", "/").split(Pattern.quote("/"), -1); + + if (metadataSegmentPathColleciton == null || metadataSegmentPathColleciton.length < 4) { + return null; + } + return metadataSegmentPathColleciton[3]; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializer.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializer.java new file mode 100644 index 00000000..4da31e95 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializer.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.formmetadata.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import io.iec.edp.caf.common.JSONSerializer; + +/** + * description:表单元数据内容序列化器 + * + * @author Noah Guo + * @date 2021/01/15 + */ +public class FormMetadataContentSerializer implements MetadataContentSerializer { + @Override + public JsonNode Serialize(IMetadataContent metadataContent){ + if (metadataContent == null) { + return null; + } + + ObjectMapper mapper = JSONSerializer.getObjectMapper(); + return mapper.valueToTree(metadataContent); + } + + @Override + public IMetadataContent DeSerialize(JsonNode formMetadataContentNode){ + if (formMetadataContentNode == null) { + return null; + } + + SerializeUtility serializeHelper = SerializeUtility.getInstance(); + JsonNode contentNode = formMetadataContentNode.get("Contents"); + if(JsonNodeType.STRING == contentNode.getNodeType()){ + ((ObjectNode)formMetadataContentNode).set("Contents", serializeHelper.readTree(contentNode.textValue())); + } + + ObjectMapper mapper = JSONSerializer.getObjectMapper(); + return mapper.convertValue(formMetadataContentNode, FormMetadataContent.class); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataJsonSerializer.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataJsonSerializer.java new file mode 100644 index 00000000..decf6202 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataJsonSerializer.java @@ -0,0 +1,55 @@ +package com.inspur.edp.web.formmetadata.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +public class FormMetadataJsonSerializer implements MetadataContentSerializer +{ + private static final FormMetadataJsonSerializer jsonSerializer = new FormMetadataJsonSerializer(); + + public static FormMetadataJsonSerializer getInstance() + { + return jsonSerializer; + } + + /** + Json反序列化接口 + + @param contentString + @return + */ + @Override + public final IMetadataContent DeSerialize(JsonNode contentString) + { + if (contentString == null) + { + return null; + } + + return SerializeUtility.getInstance().toObject(contentString, FormMetadataContent.class); + } + + /** + Json序列化接口 + + @param metadataContent + @return + */ + @Override + public final JsonNode Serialize(IMetadataContent metadataContent) + { + if (metadataContent == null) + { + return null; + } + else + { + FormMetadataContent metadata = (FormMetadataContent)((metadataContent instanceof FormMetadataContent) ? metadataContent : null); + return SerializeUtility.getInstance().valueToJson(metadata, PropertyNamingStrategy.UPPER_CAMEL_CASE); + } + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataTransferSerializer.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataTransferSerializer.java new file mode 100644 index 00000000..2022bdb9 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataTransferSerializer.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.formmetadata.serializer; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; + +public class FormMetadataTransferSerializer implements MetadataTransferSerializer { + private static final FormMetadataTransferSerializer transferJsonSerializer = new FormMetadataTransferSerializer(); + + public static FormMetadataTransferSerializer getTransferJsonSerializer() { + return transferJsonSerializer; + } + + /** + * Json反序列化接口 + * + * @param contentString + * @return + */ + @Override + public final IMetadataContent deserialize(String contentString) { + if (StringUtility.isNullOrEmpty(contentString)) { + return null; + } + return SerializeUtility.getInstance().deserialize(contentString, FormMetadataContent.class); + } + + /** + * Json序列化接口 + * + * @param metadataContent + * @return + */ + @Override + public final String serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } else { + FormMetadataContent metadata = (FormMetadataContent) ((metadataContent instanceof FormMetadataContent) ? metadataContent : null); + return SerializeUtility.getInstance().serialize(metadata, PropertyNamingStrategy.UPPER_CAMEL_CASE,false); + } + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataCommonServiceImpl.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataCommonServiceImpl.java new file mode 100644 index 00000000..2f37a603 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataCommonServiceImpl.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.formmetadata.service; + + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.api.FormMetadataCommonService; +import com.inspur.edp.web.formmetadata.api.entity.FormSuInfoEntity; +import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo; +import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +public class FormMetadataCommonServiceImpl implements FormMetadataCommonService { + + private final DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class); + + /** + * 依据业务对象获取对应的配置信息 + * + * @param bizObjId + * @return + */ + @Override + public FormSuInfoEntity getSuInfoWithBizobjId(String bizObjId) { + if (StringUtility.isNullOrEmpty(bizObjId)) { + throw new RuntimeException("根据业务对象获取对应关键应用信息,业务对象id不能为控"); + } + DevBasicBoInfo basicBoInfo = this.devBasicInfoService.getDevBasicBoInfo(bizObjId); + if (basicBoInfo == null) { + throw new RuntimeException(String.format("根据业务对象获取bo信息为控,对应业务对象id为:%s", bizObjId)); + } + FormSuInfoEntity formSuInfo = new FormSuInfoEntity(); + formSuInfo.setAppCode(basicBoInfo.getAppCode()); + formSuInfo.setSuCode(basicBoInfo.getSuCode()); + formSuInfo.setNameSpace(basicBoInfo.getBoNameSpace()); + return formSuInfo; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataRTService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataRTService.java new file mode 100644 index 00000000..00767c71 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetadataRTService.java @@ -0,0 +1,80 @@ +package com.inspur.edp.web.formmetadata.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.TupleFour; +import com.inspur.edp.web.formmetadata.entity.FormRelateViewModelEntity; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; + +import java.util.ArrayList; +import java.util.List; + +/** + * 表单元数据rtservice + */ +public class FormMetadataRTService { + /** + * 单个viewModel 获取关联的表单元数据 + * + * @param viewModelMetadata + * @return + */ + public List checkFormRelateToViewModel(GspMetadata viewModelMetadata) { + + if (viewModelMetadata == null) { + return null; + } + String relativePath = viewModelMetadata.getRelativePath(); + ArrayList filterType = new ArrayList<>(); + filterType.add(".frm"); + + List formMetadataList = MetadataUtility.getInstance().getMetadataList(relativePath, filterType); + if (formMetadataList == null || formMetadataList.size() == 0) { + return null; + } + List formRelateViewModelEntityList = new ArrayList<>(); + String viewModelId = viewModelMetadata.getHeader().getId(); + + formMetadataList.forEach(formMetadata -> { + // 如果对应的表单元数据内容为空 那么根据id重新获取对应元数据 + if (formMetadata.getContent() == null) { + formMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(formMetadata.getHeader().getId(), formMetadata.getRelativePath()); + } + TupleFour formParameter = FormMetadataContentService.getInstance().getParameterFromFormMetadata(formMetadata); + // 为了应对一个viewModel可能对应多个表单的情况 + if (formParameter != null && viewModelId.equals(formParameter.getItem4())) { + FormRelateViewModelEntity formRelateViewModelEntity = new FormRelateViewModelEntity(); + formRelateViewModelEntity.setFormMetadataId(formParameter.getItem1()); + formRelateViewModelEntity.setFormMetadata(formMetadata); + formRelateViewModelEntity.setFormCode(formParameter.getItem2()); + formRelateViewModelEntity.setFormName(formParameter.getItem3()); + formRelateViewModelEntity.setViewModelMetadataId(formParameter.getItem4()); + formRelateViewModelEntity.setViewModelMetadata(viewModelMetadata); + formRelateViewModelEntityList.add(formRelateViewModelEntity); + } + + }); + return formRelateViewModelEntityList; + } + + /** + * viewModel元数据集合获取对应的表单元数据列表 + * + * @param viewModelMetadataList + * @return + */ + public List checkFormRelateToViewModelList(List viewModelMetadataList) { + List formRelateViewModelEntities = new ArrayList<>(); + if (viewModelMetadataList == null || viewModelMetadataList.size() == 0) { + return formRelateViewModelEntities; + } + viewModelMetadataList.forEach(t -> { + List formRelateViewModelEntityListFromViewModel = checkFormRelateToViewModel(t); + if (formRelateViewModelEntityListFromViewModel != null && formRelateViewModelEntityListFromViewModel.size() > 0) { + formRelateViewModelEntities.addAll(formRelateViewModelEntityListFromViewModel); + } + + }); + return formRelateViewModelEntities; + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetataService.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetataService.java new file mode 100644 index 00000000..3368c173 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/service/FormMetataService.java @@ -0,0 +1,268 @@ +package com.inspur.edp.web.formmetadata.service; + +import com.inspur.edp.i18n.resource.api.II18nResourceDTManager; +import com.inspur.edp.i18n.resource.api.metadata.ResourceItem; +import com.inspur.edp.i18n.resource.api.metadata.ResourceItemCollection; +import com.inspur.edp.i18n.resource.api.metadata.ResourceMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.I18nResource; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.exception.MetadataNotFoundException; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; +import com.inspur.edp.web.formmetadata.replication.FormMetadataReplicator; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage; +import io.iec.edp.caf.i18n.framework.api.language.ILanguageService; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author guozhiqi + */ +public class FormMetataService { + public static void synchronizeLanuagePackage(String formMetadataFileName, String formMetadataPath) { + // (1) 获取表单元数据 + GspMetadata formMetadata = MetadataUtility.getInstance().getMetadata(formMetadataFileName, formMetadataPath); + // (2) 查找到关联的资源元数据 + GspMetadata currentResourceMetadata = getRefResourceMetadata(formMetadata.getHeader().getId(), formMetadataPath); + + // (3) 同步资源元数据上的语言包到表单元数据 + synchronizeLanuagePackage(formMetadata, currentResourceMetadata); + } + + /** + * 生成表单关联的中文资源元数据 + */ + public static void reSaveFormIfResourceNotExists(GspMetadata formMetadata, String baseFormPath) { + List resourceList = getFormResourceWithMetaData(formMetadata, I18nResourceConstant.ZH_CHS, baseFormPath); + if (resourceList == null || resourceList.isEmpty()) { + // 调用保存表单元数据接口,间接生成资源元数据 + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.saveMetadata(formMetadata, Paths.get(formMetadata.getRelativePath()).resolve(formMetadata.getHeader().getFileName()).toString()); + } + } + + /** + * 根据表单元数据获取对应的资源列表 + * + * @param metadata 元数据信息* + * @param language 语言列表 + * @param baseFormPath 传递的基础表单的路径 针对组合表单,传递的也是基础表单的路径 + */ + public static List getFormResourceWithMetaData(GspMetadata metadata, String language, String baseFormPath) { + II18nResourceDTManager resourceDtManager = SpringBeanUtils.getBean(II18nResourceDTManager.class); + // 当前语言未生效 + try { + List resourceList = resourceDtManager.getI18nResource(metadata, language, baseFormPath); + // 按语言进行过滤 + if (resourceList != null && resourceList.size() > 0) { + resourceList = resourceList + .stream() + .filter((t) -> language.equals(t.getLanguage())) + .collect(Collectors.toList()); + } + return resourceList; + } catch (MetadataNotFoundException ex) { + WebLogger.Instance.warn(ex.getMessage() + ex.getStackTrace()); + } catch (Exception ex) { + // 排除掉找不到对应的资源文件的异常 + String fileNotFoundException = "java.io.FileNotFoundException"; + if (ex.getMessage() != null && ex.getMessage().contains(fileNotFoundException)) { + WebLogger.Instance.warn(ex.getMessage()); + } else { + ex.printStackTrace(); + throw ex; + } + } + return null; + } + + /** + * 同步资源元数据的语言包到表单元数据 + */ + private static void synchronizeLanuagePackage(GspMetadata targetFormMetadata, GspMetadata sourceResourceMetadata) { + // (1) 从资源元数据中获取语言 + String currentLanguage = "en"; + // (2) 同步到表单元数据 + ResourceMetadata resourceMetadataContent = (ResourceMetadata) sourceResourceMetadata.getContent(); + ResourceItemCollection resourceItemCollection = resourceMetadataContent.getStringResources(); + + FormMetadataContent formMetadataContent = (FormMetadataContent) targetFormMetadata.getContent(); + FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + HashMap> ctrlLangs = formContent.getModule().getCtrlLangs(); + + + HashMap chosenLaguagePackage = ctrlLangs.get(currentLanguage); + HashMap updatedChosenLaguagePackage = new HashMap<>(chosenLaguagePackage); + for (Map.Entry item : chosenLaguagePackage.entrySet()) { + String key = item.getKey(); + boolean existSameKey = false; + for (ResourceItem resourceItem : resourceItemCollection) { + if (Objects.equals(resourceItem.getId(), item.getKey())) { + updatedChosenLaguagePackage.put(key, resourceItem.getValue()); + existSameKey = true; + break; + } + } + + if (!existSameKey) { + updatedChosenLaguagePackage.remove(key); + } + } + ctrlLangs.put(currentLanguage, updatedChosenLaguagePackage); + + FormMetadataContentService.getInstance().setFormContent(formMetadataContent, formContent); + + // 回写表单元数据 + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.saveMetadata(targetFormMetadata, targetFormMetadata.getRelativePath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + targetFormMetadata.getHeader().getFileName()); + } + + private static List getRefResourceMetadataHeaderCollection(String formMetadataId, String formMetadataPath) { + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + return metadataService.getResourceMetadata(formMetadataId, formMetadataPath); + } + + private static GspMetadata getRefResourceMetadata(String formMetadataId, String formMetadataPath) { + List resourceMetadataList = getRefResourceMetadataList(formMetadataId, formMetadataPath); + if (resourceMetadataList == null || resourceMetadataList.size() <= 0) { + return null; + } + + // 一个表单元数据仅能关联一个资源元数据 + return resourceMetadataList.get(0); + } + + private static List getRefResourceMetadataList(String formMetadataId, String formMetadataPath) { + List resourceMetadataHeaderCollection = getRefResourceMetadataHeaderCollection(formMetadataId, formMetadataPath); + + // 获取资源元数据 + return getResourceMetadata(resourceMetadataHeaderCollection, formMetadataPath); + } + + private static ArrayList getResourceMetadata(List resourceMetadataHeaderList, String formMetadataPath) { + if (resourceMetadataHeaderList == null || resourceMetadataHeaderList.size() <= 0 || StringUtility.isNullOrEmpty(formMetadataPath)) { + return null; + } + + ArrayList resourceMetadataList = new ArrayList<>(); + for (MetadataHeader resouceMetadataHeader : resourceMetadataHeaderList) { + String resouceMetadataFileName = resouceMetadataHeader.getFileName(); + GspMetadata resourceMetadata = MetadataUtility.getInstance().getMetadata(resouceMetadataFileName, formMetadataPath); + if (resourceMetadata != null) { + resourceMetadataList.add(resourceMetadata); + } + } + + return resourceMetadataList; + } + + /** + * 导出语言包 + */ + public static void exportLanguagePackage(String formMetadataFileName, String formMetadataPath) { + // (1) 获取表单元数据 + GspMetadata formMetadata = MetadataUtility.getInstance().getMetadata(formMetadataFileName, formMetadataPath); + exportLanguagePackage(formMetadata); + } + + /** + * 导出语言包 + */ + public static void exportLanguagePackage(GspMetadata formMetadata) { + if (formMetadata == null) { + return; + } + + FormMetadataContent formMetadataContent = (FormMetadataContent) formMetadata.getContent(); + FormDOM formDOM = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + + // 从表单文档中提取出语言包并保存为JSON文件 + HashMap> ctrlLangs = formDOM.getModule().getCtrlLangs(); + String ctrlLangsStr = SerializeUtility.getInstance().serialize(ctrlLangs, false); + String formMetadataFileName = formMetadata.getHeader().getFileName(); + String formMetadataPath = formMetadata.getRelativePath(); + + String languagePackageFileName = formMetadataFileName.replace(".frm", "_frm") + ".json"; + String languagePackageAbsoluteStoragePath = MetadataUtility.getInstance().getAbsolutePath(formMetadataPath); + FileUtility.writeFile(languagePackageAbsoluteStoragePath, languagePackageFileName, ctrlLangsStr); + } + + /** + * 同步本地语言包 + */ + public static void synchronizeLocalLanuagePackage(String formMetadataFileName, String formMetadataPath) { + GspMetadata formMetadata = MetadataUtility.getInstance().getMetadata(formMetadataFileName, formMetadataPath); + synchronizeLocalLanuagePackage(formMetadata); + } + + /** + * 同步本地语言包 + */ + public static void synchronizeLocalLanuagePackage(GspMetadata formMetadata) { + HashMap> localLanguagePackage = getLocalLanguagePackage(formMetadata.getHeader().getFileName(), formMetadata.getRelativePath()); + + synchronizeLocalLanuagePackage(formMetadata, localLanguagePackage); + } + + private static HashMap> getLocalLanguagePackage(String formMetadataFileName, String formMetadataPath) { + String languagePackageFileName = formMetadataFileName.replace(".frm", "_frm") + ".json"; + String languagePackageAbsoluteStoragePath = MetadataUtility.getInstance().getAbsolutePath(formMetadataPath); + String localLanguagePackageFullPath = Paths.get(languagePackageAbsoluteStoragePath).resolve(languagePackageFileName).toString(); + String localLanguagePackageStr = FileUtility.readAsString(localLanguagePackageFullPath); + + HashMap> temp = new HashMap<>(); + return SerializeUtility.getInstance().deserialize(localLanguagePackageStr, temp.getClass()); + } + + private static void synchronizeLocalLanuagePackage(GspMetadata targetFormMetadata, HashMap> sourceLocalLanguagePackage) { + FormMetadataContent formMetadataContent = (FormMetadataContent) targetFormMetadata.getContent(); + FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + + // TODO: 优化更新算法 + // 更新语言包 + formContent.getModule().setCtrlLangs(sourceLocalLanguagePackage); + + // 更新表单元数据内容 + FormMetadataContentService.getInstance().setFormContent(formMetadataContent, formContent); + + // 更新表单元数据 + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.saveMetadata(targetFormMetadata, Paths.get(targetFormMetadata.getRelativePath()).resolve(targetFormMetadata.getHeader().getFileName()).toString()); + } + + public static List getEnabledLanguageList() { + ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class); + return languageService.getEnabledLanguages(); + } + + public static List getBuiltinLanguageList() { + ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class); + return languageService.getBuiltinLanguages(); + } + + public static List getAllLanguageList() { + ILanguageService languageService = SpringBeanUtils.getBean(ILanguageService.class); + return languageService.getAllLanguages(); + } + + public static void replicateForm(String sourceMetadataId, String sourceMetadataRelativePath, String targetMetadataCode, String targetMetadataName, String targetProjectName) { + FormMetadataReplicator formMetadataReplicator = new FormMetadataReplicator(); + formMetadataReplicator.replicate(sourceMetadataId, sourceMetadataRelativePath, targetMetadataCode, targetMetadataName, targetProjectName); + } +} diff --git a/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/FormMetadataWebServiceImpl.java b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/FormMetadataWebServiceImpl.java new file mode 100644 index 00000000..345c6899 --- /dev/null +++ b/web-form-metadata/src/main/java/com/inspur/edp/web/formmetadata/webservice/FormMetadataWebServiceImpl.java @@ -0,0 +1,92 @@ +package com.inspur.edp.web.formmetadata.webservice; + +import com.inspur.edp.web.formmetadata.api.FormMetadataCommonService; +import com.inspur.edp.web.formmetadata.api.FormMetadataWebService; +import com.inspur.edp.web.formmetadata.api.entity.FormSuInfoEntity; +import com.inspur.edp.web.formmetadata.api.entity.ReplicateFormRequestBody; +import com.inspur.edp.web.formmetadata.api.entity.SuInfoWithBizobjIdEntity; +import com.inspur.edp.web.formmetadata.manager.FormMetadataManager; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage; + +import java.util.List; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/15 + */ +public class FormMetadataWebServiceImpl implements FormMetadataWebService { + /** + * 同步语言包到表单元数据 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Override + public void SynchronizeLanuagePackage(String fileName, String path) { + FormMetadataManager.getInstance().synchronizeLanuagePackage(fileName, path); + } + + /** + * 导出表单元数据中语言包 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Override + public void ExportLanguagePackage(String fileName, String path) { + FormMetadataManager.getInstance().exportLanguagePackage(fileName, path); + } + + /** + * 同步本地语言包到表单元数据 + * + * @param fileName 待同步表单元数据文件名 + * @param path 待同步表单元数据路径 + */ + @Override + public void SynchronizeLocalLanuagePackage(String fileName, String path) { + FormMetadataManager.getInstance().synchronizeLocalLanuagePackage(fileName, path); + } + + /** + * 获取启用的语种 + */ + @Override + public List GetEnabledLanguageList() { + return FormMetadataManager.getInstance().getEnabledLanguageList(); + } + + /** + * 获取系统内置的语种 + */ + @Override + public List GetBuiltinLanguageList() { + return FormMetadataManager.getInstance().getBuiltinLanguageList(); + } + + /** + * 获取所有语种的列表 + */ + @Override + public List GetAllLanguageList() { + return FormMetadataManager.getInstance().getAllLanguageList(); + } + + /** + * 复制表单及关联元数据 + */ + @Override + public void ReplicateForm(ReplicateFormRequestBody replicateFormRequestBody) { + FormMetadataManager.getInstance().replicateForm(replicateFormRequestBody.getSourceMetadataId(), replicateFormRequestBody.getSourceMetadataRelativePath(), replicateFormRequestBody.getTargetMetadataCode(), replicateFormRequestBody.getTargetMetadataName(), replicateFormRequestBody.getTargetProjectName()); + } + + @Override + public FormSuInfoEntity getSuInfoWithBizobjId(SuInfoWithBizobjIdEntity bizobjIdEntity) { + FormMetadataCommonService formMetadataCommonService = SpringBeanUtils.getBean(FormMetadataCommonService.class); + return formMetadataCommonService.getSuInfoWithBizobjId(bizobjIdEntity.getBizObjId()); + } +} + diff --git a/web-form-metadata/src/main/resources/META-INF/spring.factories b/web-form-metadata/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..d77af063 --- /dev/null +++ b/web-form-metadata/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.formmetadata.config.FormMetadataConfiguration diff --git a/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nServiceTest.java b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nServiceTest.java new file mode 100644 index 00000000..cbcf01a4 --- /dev/null +++ b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/FormMetadataI18nServiceTest.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.formmetadata.i18n; + +import com.inspur.edp.lcm.metadata.api.entity.I18nResourceItemCollection; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +import java.util.ArrayList; +import java.util.HashMap; + +class FormMetadataI18nServiceTest { + + //@Test + void getResourceItem() { + + I18nResourceItemCollection i18nResourceItemCollection = new I18nResourceItemCollection(); + String jsonContent = FileUtility.readAsString("D:\\InspurCode\\N转J之后代码\\web\\web-form-metadata\\src\\test\\java\\com\\inspur\\edp\\web\\formmetadata\\i18n\\form.json"); + FormDOM formDOM = SerializeUtility.getInstance().deserialize(jsonContent, FormDOM.class); + ArrayList> components = formDOM.getModule().getComponents(); + // 递归提取每个component中的组件及其对应的待国际化的值 + for (HashMap component : components) { + // 每个component是一个树结构 + // 表单树表现出浅而宽的特性,所以优先使用深度优先算法 + if (component != null) { + FormMetadataI18nService service = new FormMetadataI18nService(); + service.DepthFirstSearchTraverse(i18nResourceItemCollection, "", component); + } + } + } +} diff --git a/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/HtmlTemplateTest.java b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/HtmlTemplateTest.java new file mode 100644 index 00000000..984231a2 --- /dev/null +++ b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/HtmlTemplateTest.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.formmetadata.i18n; + +import org.junit.Test; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class HtmlTemplateTest { + + @Test + public void test() { + String pattern = "\\$\\{([^\\}]+):([^\\}]+)\\}"; + String source = "\\r\\n \\r\\n\\r\\n

${Title1:'页面标题1'}

${Title2:'页面标题22'}\\r\\n${Title3:'页面标题3'}<${Title4:'页面标题4'} div class=\\\"f-title-pagination\\\">\\r\\n \\r\\n \\r\\n"; + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(source); + while (m.find()) { + int groupCount = m.groupCount(); + System.out.println(groupCount); + System.out.println(m.group(1)); + System.out.println(m.group(2)); + } + + + } +} diff --git a/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/form.json b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/form.json new file mode 100644 index 00000000..635c8d48 --- /dev/null +++ b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/i18n/form.json @@ -0,0 +1,6558 @@ +{ + "module": { + "id": "GroupBTCZC", + "code": "GroupBTCZC", + "name": "GroupBT主从卡", + "caption": "GroupBT主从卡", + "type": "Module", + "creator": "wang-xh", + "creationDate": "2020-09-15T08:28:46.446Z", + "updateVersion": "191104", + "showTitle": true, + "bootstrap": "show-sub-table-by-card-template", + "schemas": [ + { + "extendProperties": { + "enableStdTimeFormat": false + }, + "id": "cef1b22f-3795-4f77-9aa5-15f16bae35c2", + "code": "GroupBTCZC_frm", + "name": "GroupBT主从卡_frm", + "sourceUri": "api/scm/sd/v1.0/GroupBTCZC_frm", + "sourceType": "vo", + "entities": [ + { + "id": "8a7d1c47-cc7e-4fc8-b0b6-f79c5eca524f", + "code": "GroupBT", + "name": "集团商旅", + "label": "groupBTs", + "type": { + "name": "GroupBT", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "c6062048-41c6-464a-81b2-031b191746ff", + "originalId": "c6062048-41c6-464a-81b2-031b191746ff", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "3a8a8079-a532-4973-927a-1b7d48dbfc33", + "originalId": "3a8a8079-a532-4973-927a-1b7d48dbfc33", + "code": "Version", + "name": "Version", + "label": "version", + "bindingField": "version", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "Version", + "bindingPath": "version", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "20fb6c64-53cc-46a5-bec2-02259c2a0be1", + "originalId": "20fb6c64-53cc-46a5-bec2-02259c2a0be1", + "code": "btPlatform", + "name": "商旅平台", + "label": "btPlatform", + "bindingField": "btPlatform", + "type": { + "$type": "EntityType", + "name": "btplatform1afa", + "primary": "btPlatform", + "fields": [ + { + "$type": "SimpleField", + "id": "1afa946c-6642-464b-a7fc-2d4f44f45d87", + "originalId": "1afa946c-6642-464b-a7fc-2d4f44f45d87", + "code": "btPlatform", + "name": "商旅平台", + "label": "btPlatform", + "bindingField": "btPlatform", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "btPlatform", + "bindingPath": "btPlatform", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "8c698bf5-cb3f-4023-8383-58d6ab9394c0", + "originalId": "8c698bf5-cb3f-4023-8383-58d6ab9394c0", + "code": "ptcOde", + "name": "商旅平台编号", + "label": "btPlatform_ptcOde", + "bindingField": "btPlatform_btPlatform_ptcOde", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "btPlatform.btPlatform_ptcOde", + "bindingPath": "btPlatform.btPlatform_ptcOde", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d2a9d99e-dab8-47be-bab7-2e1bd2183c0a", + "originalId": "d2a9d99e-dab8-47be-bab7-2e1bd2183c0a", + "code": "ptname", + "name": "商旅平台名称", + "label": "btPlatform_ptname", + "bindingField": "btPlatform_btPlatform_ptname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "btPlatform.btPlatform_ptname", + "bindingPath": "btPlatform.btPlatform_ptname", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "ec159a96-7bf7-4a3e-9b20-8ee292e9f153", + "originalId": "ec159a96-7bf7-4a3e-9b20-8ee292e9f153", + "code": "ptlocal", + "name": "平台位置", + "label": "btPlatform_ptlocal", + "bindingField": "btPlatform_btPlatform_ptlocal", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "shandong", + "name": "山东" + }, + { + "value": "sichuan", + "name": "四川" + }, + { + "value": "hunan", + "name": "湖南" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "btPlatform.btPlatform_ptlocal", + "bindingPath": "btPlatform.btPlatform_ptlocal", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "商旅平台" + }, + "path": "btPlatform", + "bindingPath": "btPlatform" + }, + { + "$type": "SimpleField", + "id": "38c3a0cd-ac2e-40ef-9455-045c73757c8e", + "originalId": "38c3a0cd-ac2e-40ef-9455-045c73757c8e", + "code": "groupid", + "name": "公司id", + "label": "groupid", + "bindingField": "groupid", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "groupid", + "bindingPath": "groupid", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "98d4cb5f-6033-4e6b-880b-b89da70e5f86", + "originalId": "98d4cb5f-6033-4e6b-880b-b89da70e5f86", + "code": "GROUPNAME", + "name": "公司名称", + "label": "groupname", + "bindingField": "groupname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "GROUPNAME", + "bindingPath": "groupname", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "3d4827d5-9415-4730-8241-24606c6b6032", + "originalId": "3d4827d5-9415-4730-8241-24606c6b6032", + "code": "TMCcODE", + "name": "TMC编号", + "label": "tmCcODE", + "bindingField": "tmCcODE", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "TMCcODE", + "bindingPath": "tmCcODE", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "27d1678c-c4a7-4edc-8e04-48ea7655421f", + "originalId": "27d1678c-c4a7-4edc-8e04-48ea7655421f", + "code": "AccessCount", + "name": "接入账户", + "label": "accessCount", + "bindingField": "accessCount", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "AccessCount", + "bindingPath": "accessCount", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "fd277c97-414a-433f-b14d-62ef24d82559", + "originalId": "fd277c97-414a-433f-b14d-62ef24d82559", + "code": "Accesspass", + "name": "接入密码", + "label": "accesspass", + "bindingField": "accesspass", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "Accesspass", + "bindingPath": "accesspass", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "2d20f75c-709c-468a-ac44-7c5b2a0177b7", + "originalId": "2d20f75c-709c-468a-ac44-7c5b2a0177b7", + "code": "advanceap", + "name": "是否提前审批", + "label": "advanceap", + "bindingField": "advanceap", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BooleanType", + "name": "Boolean", + "displayName": "布尔" + }, + "editor": { + "$type": "CheckBox" + }, + "path": "advanceap", + "bindingPath": "advanceap", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "eeda26e9-6534-4726-a4fe-ea8be27d7adb", + "originalId": "eeda26e9-6534-4726-a4fe-ea8be27d7adb", + "code": "scopeservice", + "name": "服务范围", + "label": "scopeservice", + "bindingField": "scopeservice", + "type": { + "$type": "ObjectType", + "name": "servicescopeEEda", + "fields": [ + { + "$type": "SimpleField", + "id": "eeda26e9-a3ad-45d7-9140-08fecefacc11", + "originalId": "a4d7b0a9-a3ad-45d7-9140-08fecefacc11", + "code": "servicescope", + "name": "服务范围", + "label": "servicescope", + "bindingField": "scopeservice_servicescope", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "plane", + "name": "飞机" + }, + { + "value": "train", + "name": "火车" + }, + { + "value": "hotel", + "name": "酒店" + }, + { + "value": "other", + "name": "其他" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "scopeservice.servicescope", + "bindingPath": "scopeservice.servicescope", + "multiLanguage": false + } + ], + "displayName": "服务范围" + }, + "path": "scopeservice", + "bindingPath": "scopeservice" + }, + { + "$type": "ComplexField", + "id": "2782cd63-b845-4b2c-a205-40f4b511a5e9", + "originalId": "2782cd63-b845-4b2c-a205-40f4b511a5e9", + "code": "SourceBill", + "name": "账单来源", + "label": "sourceBill", + "bindingField": "sourceBill", + "type": { + "$type": "ObjectType", + "name": "SourceBill2782", + "fields": [ + { + "$type": "SimpleField", + "id": "2782cd63-680c-4d3e-8a3a-d438c8fa2212", + "originalId": "d61b71e2-680c-4d3e-8a3a-d438c8fa2212", + "code": "SourceBill", + "name": "账单来源", + "label": "sourceBill", + "bindingField": "sourceBill_SourceBill", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "enumValues": [ + { + "value": "tmccreate", + "name": "tmc生成账单" + }, + { + "value": "notem", + "name": "我方生成账单" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "SourceBill.SourceBill", + "bindingPath": "sourceBill.sourceBill", + "multiLanguage": false + } + ], + "displayName": "账单来源" + }, + "path": "SourceBill", + "bindingPath": "sourceBill" + }, + { + "$type": "SimpleField", + "id": "d2c8c5c6-cc0b-47b7-8040-ddb127e689e1", + "originalId": "d2c8c5c6-cc0b-47b7-8040-ddb127e689e1", + "code": "billdata", + "name": "账单数据", + "label": "billdata", + "bindingField": "billdata", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "zhangqi", + "name": "账期" + }, + { + "value": "yibaoxiao", + "name": "已报销" + }, + { + "value": "zhangqi1", + "name": "账期1" + }, + { + "value": "zhangqi2", + "name": "账期2" + }, + { + "value": "zhangqi3", + "name": "账期3" + }, + { + "value": "zhangqi4", + "name": "账期4" + }, + { + "value": "zhangqi5", + "name": "账期5" + }, + { + "value": "zhangqi6", + "name": "账期6" + }, + { + "value": "yibaoxiao1", + "name": "已报销1" + }, + { + "value": "yibaoxiao2", + "name": "已报销2" + }, + { + "value": "yibaoxiao3", + "name": "已报销3" + }, + { + "value": "yibaoxiao4", + "name": "已报销4" + }, + { + "value": "yibaoxioa5", + "name": "已报销5" + }, + { + "value": "yibaoxioa6", + "name": "已报销6" + }, + { + "value": "yibaoxioa7", + "name": "已报销7" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "billdata", + "bindingPath": "billdata", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "95ded9d1-f56a-4e05-9ff9-e50e4f3cec5f", + "originalId": "95ded9d1-f56a-4e05-9ff9-e50e4f3cec5f", + "code": "plane", + "name": "机票", + "label": "plane", + "bindingField": "plane", + "type": { + "$type": "ObjectType", + "name": "datemanager95de", + "fields": [ + { + "$type": "SimpleField", + "id": "95ded9d1-1a82-4e12-8614-598d4a55e822", + "originalId": "dda7789a-1a82-4e12-8614-598d4a55e822", + "code": "datemanager", + "name": "datemanager", + "label": "datemanager", + "bindingField": "plane_datemanager", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "plane.datemanager", + "bindingPath": "plane.datemanager", + "multiLanguage": false + } + ], + "displayName": "datemanager" + }, + "path": "plane", + "bindingPath": "plane" + }, + { + "$type": "ComplexField", + "id": "6c83ca65-2b94-4bba-94d5-52300651caa7", + "originalId": "6c83ca65-2b94-4bba-94d5-52300651caa7", + "code": "train", + "name": "火车", + "label": "train", + "bindingField": "train", + "type": { + "$type": "ObjectType", + "name": "datemanager6c83", + "fields": [ + { + "$type": "SimpleField", + "id": "6c83ca65-1a82-4e12-8614-598d4a55e822", + "originalId": "dda7789a-1a82-4e12-8614-598d4a55e822", + "code": "datemanager", + "name": "datemanager", + "label": "datemanager", + "bindingField": "train_datemanager", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "train.datemanager", + "bindingPath": "train.datemanager", + "multiLanguage": false + } + ], + "displayName": "datemanager" + }, + "path": "train", + "bindingPath": "train" + }, + { + "$type": "ComplexField", + "id": "25cfad58-24e7-42cf-be77-3e790a21e3a1", + "originalId": "25cfad58-24e7-42cf-be77-3e790a21e3a1", + "code": "hotel", + "name": "酒店", + "label": "hotel", + "bindingField": "hotel", + "type": { + "$type": "ObjectType", + "name": "datemanager25cf", + "fields": [ + { + "$type": "SimpleField", + "id": "25cfad58-1a82-4e12-8614-598d4a55e822", + "originalId": "dda7789a-1a82-4e12-8614-598d4a55e822", + "code": "datemanager", + "name": "datemanager", + "label": "datemanager", + "bindingField": "hotel_datemanager", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "hotel.datemanager", + "bindingPath": "hotel.datemanager", + "multiLanguage": false + } + ], + "displayName": "datemanager" + }, + "path": "hotel", + "bindingPath": "hotel" + }, + { + "$type": "ComplexField", + "id": "c0de57e1-59a0-4844-ab91-2143e1aa7612", + "originalId": "c0de57e1-59a0-4844-ab91-2143e1aa7612", + "code": "contactu", + "name": "往来单位", + "label": "contactu", + "bindingField": "contactu", + "type": { + "$type": "ObjectType", + "name": "contactunitC0de", + "fields": [ + { + "$type": "ComplexField", + "id": "c0de57e1-8ac4-4376-89f6-6547e689784c", + "originalId": "fa45f7b8-8ac4-4376-89f6-6547e689784c", + "code": "contactunit", + "name": "往来单位", + "label": "contactunit", + "bindingField": "contactu_contactunit", + "type": { + "$type": "EntityType", + "name": "btplatformC0de", + "primary": "contactunit", + "fields": [ + { + "$type": "SimpleField", + "id": "c0de57e1-a892-46d0-94d5-1ecda6c84764", + "originalId": "7a27949c-a892-46d0-94d5-1ecda6c84764", + "code": "contactunit", + "name": "往来单位", + "label": "contactunit", + "bindingField": "contactu_contactunit", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "contactu.contactunit", + "bindingPath": "contactu.contactunit", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c0de57e1-e1e2-472a-9b99-4138dd8dd263", + "originalId": "bef4dbaa-e1e2-472a-9b99-4138dd8dd263", + "code": "ptcOde", + "name": "商旅平台编号", + "label": "contactunit_ptcOde", + "bindingField": "contactu_contactunit_contactunit_ptcOde", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "contactu.contactunit.contactunit_ptcOde", + "bindingPath": "contactu.contactunit.contactunit_ptcOde", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c0de57e1-de21-4edd-bfb4-8b005ecca03a", + "originalId": "0c038e70-de21-4edd-bfb4-8b005ecca03a", + "code": "ptname", + "name": "商旅平台名称", + "label": "contactunit_ptname", + "bindingField": "contactu_contactunit_contactunit_ptname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "contactu.contactunit.contactunit_ptname", + "bindingPath": "contactu.contactunit.contactunit_ptname", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c0de57e1-a3bc-4f6b-876c-c97bf60a0bc9", + "originalId": "3d768ee6-a3bc-4f6b-876c-c97bf60a0bc9", + "code": "ptlocal", + "name": "平台位置", + "label": "contactunit_ptlocal", + "bindingField": "contactu_contactunit_contactunit_ptlocal", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "shandong", + "name": "山东" + }, + { + "value": "sichuan", + "name": "四川" + }, + { + "value": "hunan", + "name": "湖南" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "contactu.contactunit.contactunit_ptlocal", + "bindingPath": "contactu.contactunit.contactunit_ptlocal", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "商旅平台" + }, + "path": "contactu.contactunit", + "bindingPath": "contactu.contactunit" + } + ], + "displayName": "往来单位" + }, + "path": "contactu", + "bindingPath": "contactu" + }, + { + "$type": "ComplexField", + "id": "d2517d58-494c-4047-ad27-9811e764433c", + "originalId": "d2517d58-494c-4047-ad27-9811e764433c", + "code": "currence", + "name": "币种", + "label": "currence", + "bindingField": "currence", + "type": { + "$type": "EntityType", + "name": "currencyDic4dfd", + "primary": "currence", + "fields": [ + { + "$type": "SimpleField", + "id": "4dfda39f-2361-4f88-9220-6b67b202700d", + "originalId": "4dfda39f-2361-4f88-9220-6b67b202700d", + "code": "currence", + "name": "币种", + "label": "currence", + "bindingField": "currence", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "currence", + "bindingPath": "currence", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "21f67db6-7239-4483-ad2c-dc79f519a195", + "originalId": "21f67db6-7239-4483-ad2c-dc79f519a195", + "code": "currencyinfo", + "name": "币种信息", + "label": "currence_currencyinfo", + "bindingField": "currence_currence_currencyinfo", + "type": { + "$type": "ObjectType", + "name": "currencyudt21f6", + "fields": [ + { + "$type": "SimpleField", + "id": "21f67db6-75d6-4052-8e73-8c8da6658568", + "originalId": "d3dbf529-75d6-4052-8e73-8c8da6658568", + "code": "currencyCode", + "name": "币种编号", + "label": "currencyCode", + "bindingField": "currence_currence_currencyinfo_currencyCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "currence.currence_currencyinfo.currencyCode", + "bindingPath": "currence.currence_currencyinfo.currencyCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "21f67db6-74b7-4a65-952b-ca86ca32f5b0", + "originalId": "66ac12ef-74b7-4a65-952b-ca86ca32f5b0", + "code": "currencyName", + "name": "币种名称", + "label": "currencyName", + "bindingField": "currence_currence_currencyinfo_currencyName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "currence.currence_currencyinfo.currencyName", + "bindingPath": "currence.currence_currencyinfo.currencyName", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "21f67db6-cd3f-4fa3-a0c6-f8383d09ca95", + "originalId": "375cb226-cd3f-4fa3-a0c6-f8383d09ca95", + "code": "currencyType", + "name": "币种种类", + "label": "currencyType", + "bindingField": "currence_currence_currencyinfo_currencyType", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "special", + "name": "特殊" + }, + { + "value": "commonc", + "name": "常用" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "currence.currence_currencyinfo.currencyType", + "bindingPath": "currence.currence_currencyinfo.currencyType", + "multiLanguage": false + } + ], + "displayName": "币种信息" + }, + "path": "currence.currence_currencyinfo", + "bindingPath": "currence.currence_currencyinfo" + } + ], + "entities": [], + "displayName": "币种字典" + }, + "path": "currence", + "bindingPath": "currence" + }, + { + "$type": "SimpleField", + "id": "0faec132-5899-4615-b657-5af7afcc10c0", + "originalId": "0faec132-5899-4615-b657-5af7afcc10c0", + "code": "planere", + "name": "机票预定时间", + "label": "planere", + "bindingField": "planere", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "planere", + "bindingPath": "planere", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "7b9c7dd8-bcb6-44a0-afdb-b849aa0c9057", + "originalId": "7b9c7dd8-bcb6-44a0-afdb-b849aa0c9057", + "code": "planeset", + "name": "机票出发时间", + "label": "planeset", + "bindingField": "planeset", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "planeset", + "bindingPath": "planeset", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "588a2cd2-a1b9-4da4-b181-cb5871f64dac", + "originalId": "588a2cd2-a1b9-4da4-b181-cb5871f64dac", + "code": "trainre", + "name": "火车预定时间", + "label": "trainre", + "bindingField": "trainre", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "trainre", + "bindingPath": "trainre", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "e619c764-5544-437b-a1c2-df01b22bc0a7", + "originalId": "e619c764-5544-437b-a1c2-df01b22bc0a7", + "code": "trainset", + "name": "火车出发时间", + "label": "trainset", + "bindingField": "trainset", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "trainset", + "bindingPath": "trainset", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "e020d0a8-3412-45cf-8277-a1189cd24ffc", + "originalId": "e020d0a8-3412-45cf-8277-a1189cd24ffc", + "code": "hotelre", + "name": "酒店预定时间", + "label": "hotelre", + "bindingField": "hotelre", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "hotelre", + "bindingPath": "hotelre", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "30396ebb-a370-4639-a16b-26f648db4e11", + "originalId": "30396ebb-a370-4639-a16b-26f648db4e11", + "code": "hotelset", + "name": "酒店离店时间", + "label": "hotelset", + "bindingField": "hotelset", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "hotelset", + "bindingPath": "hotelset", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "034f78df-e5a0-40fd-ac78-f7d3f0ec13d5", + "originalId": "034f78df-e5a0-40fd-ac78-f7d3f0ec13d5", + "code": "bugetpay", + "name": "预算费用", + "label": "bugetpay", + "bindingField": "bugetpay", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "bugetpay", + "bindingPath": "bugetpay", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "40ea892d-2120-4c1b-8575-394a6f189d02", + "originalId": "40ea892d-2120-4c1b-8575-394a6f189d02", + "code": "actrualpay", + "name": "实际费用", + "label": "actrualpay", + "bindingField": "actrualpay", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 18, + "precision": 3 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "actrualpay", + "bindingPath": "actrualpay", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "25da0e95-7aba-4ced-abaa-81983e32483d", + "originalId": "25da0e95-7aba-4ced-abaa-81983e32483d", + "code": "businessnum", + "name": "出差人数", + "label": "businessnum", + "bindingField": "businessnum", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "businessnum", + "bindingPath": "businessnum", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "baac25ae-32ec-4e51-ad41-fb41477b6381", + "originalId": "baac25ae-32ec-4e51-ad41-fb41477b6381", + "code": "perpay", + "name": "单人费用", + "label": "perpay", + "bindingField": "perpay", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BigNumericType", + "name": "BigNumber", + "displayName": "大数字", + "length": 18, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "perpay", + "bindingPath": "perpay", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6d455dfa-5e58-410b-ba3c-2454a75b6360", + "originalId": "6d455dfa-5e58-410b-ba3c-2454a75b6360", + "code": "aprrovety", + "name": "审核类型", + "label": "aprrovety", + "bindingField": "aprrovety", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "enumValues": [ + { + "value": "one", + "name": "一级" + }, + { + "value": "two", + "name": "二级" + }, + { + "value": "three", + "name": "三级" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "aprrovety", + "bindingPath": "aprrovety", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "11d1355c-530e-4ebe-a167-3573a81633f8", + "originalId": "11d1355c-530e-4ebe-a167-3573a81633f8", + "code": "currencymap", + "name": "币种1", + "label": "currencymap", + "bindingField": "currencymap", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "currencymap", + "bindingPath": "currencymap", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "2b37734c-d032-4127-8ecd-82dcc511e5b2", + "originalId": "2b37734c-d032-4127-8ecd-82dcc511e5b2", + "code": "mostmonth", + "name": "期望时间", + "label": "mostmonth", + "bindingField": "mostmonth", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "mostmonth", + "bindingPath": "mostmonth", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "1ac9fe65-8ece-4319-ad56-45769340bfcd", + "originalId": "1ac9fe65-8ece-4319-ad56-45769340bfcd", + "code": "acmonth", + "name": "实际时间", + "label": "acmonth", + "bindingField": "acmonth", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "acmonth", + "bindingPath": "acmonth", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c9c2d5e0-9d65-4b95-92f6-c1c4eab17e2e", + "originalId": "c9c2d5e0-9d65-4b95-92f6-c1c4eab17e2e", + "code": "resolveT", + "name": "解决时间", + "label": "resolveT", + "bindingField": "resolveT", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "resolveT", + "bindingPath": "resolveT", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "a29747fc-cd82-4c93-9c27-9f638448e76e", + "originalId": "a29747fc-cd82-4c93-9c27-9f638448e76e", + "code": "expectT", + "name": "期望解决时间", + "label": "expectT", + "bindingField": "expectT", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "expectT", + "bindingPath": "expectT", + "multiLanguage": false + } + ], + "entities": [ + { + "id": "2f39cada-0a65-4cc6-b940-556db976d714", + "code": "sprovider", + "name": "服务商往", + "label": "sproviders", + "type": { + "name": "sprovider", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "5844b5a4-4503-4d88-b626-4c6fa8bac3f7", + "originalId": "5844b5a4-4503-4d88-b626-4c6fa8bac3f7", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f577c3ea-f7ca-4458-814e-672937e76cf2", + "originalId": "f577c3ea-f7ca-4458-814e-672937e76cf2", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "556b80b3-1c4d-417f-ad2c-1a5a06d362a2", + "originalId": "556b80b3-1c4d-417f-ad2c-1a5a06d362a2", + "code": "sproCode", + "name": "服务商编号", + "label": "sproCode", + "bindingField": "sproCode", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "sproCode", + "bindingPath": "sproCode", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "156d0ffe-9694-4334-9f8d-f0393ee57408", + "originalId": "156d0ffe-9694-4334-9f8d-f0393ee57408", + "code": "sproName", + "name": "服务商名称", + "label": "sproName", + "bindingField": "sproName", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "sproName", + "bindingPath": "sproName", + "multiLanguage": false + }, + { + "$type": "ComplexField", + "id": "9c111d84-5456-4122-b528-80121ae5abde", + "originalId": "9c111d84-5456-4122-b528-80121ae5abde", + "code": "spcontact", + "name": "往来单位", + "label": "spcontact", + "bindingField": "spcontact", + "type": { + "$type": "ObjectType", + "name": "contactunit9c11", + "fields": [ + { + "$type": "ComplexField", + "id": "9c111d84-8ac4-4376-89f6-6547e689784c", + "originalId": "fa45f7b8-8ac4-4376-89f6-6547e689784c", + "code": "contactunit", + "name": "往来单位", + "label": "contactunit", + "bindingField": "spcontact_contactunit", + "type": { + "$type": "EntityType", + "name": "btplatform9c11", + "primary": "contactunit", + "fields": [ + { + "$type": "SimpleField", + "id": "9c111d84-a892-46d0-94d5-1ecda6c84764", + "originalId": "7a27949c-a892-46d0-94d5-1ecda6c84764", + "code": "contactunit", + "name": "往来单位", + "label": "contactunit", + "bindingField": "spcontact_contactunit", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "spcontact.contactunit", + "bindingPath": "spcontact.contactunit", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9c111d84-e1e2-472a-9b99-4138dd8dd263", + "originalId": "bef4dbaa-e1e2-472a-9b99-4138dd8dd263", + "code": "ptcOde", + "name": "商旅平台编号", + "label": "contactunit_ptcOde", + "bindingField": "spcontact_contactunit_contactunit_ptcOde", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "spcontact.contactunit.contactunit_ptcOde", + "bindingPath": "spcontact.contactunit.contactunit_ptcOde", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9c111d84-de21-4edd-bfb4-8b005ecca03a", + "originalId": "0c038e70-de21-4edd-bfb4-8b005ecca03a", + "code": "ptname", + "name": "商旅平台名称", + "label": "contactunit_ptname", + "bindingField": "spcontact_contactunit_contactunit_ptname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "spcontact.contactunit.contactunit_ptname", + "bindingPath": "spcontact.contactunit.contactunit_ptname", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9c111d84-a3bc-4f6b-876c-c97bf60a0bc9", + "originalId": "3d768ee6-a3bc-4f6b-876c-c97bf60a0bc9", + "code": "ptlocal", + "name": "平台位置", + "label": "contactunit_ptlocal", + "bindingField": "spcontact_contactunit_contactunit_ptlocal", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "EnumType", + "name": "Enum", + "displayName": "枚举", + "valueType": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "enumValues": [ + { + "value": "shandong", + "name": "山东" + }, + { + "value": "sichuan", + "name": "四川" + }, + { + "value": "hunan", + "name": "湖南" + } + ] + }, + "editor": { + "$type": "EnumField" + }, + "path": "spcontact.contactunit.contactunit_ptlocal", + "bindingPath": "spcontact.contactunit.contactunit_ptlocal", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "商旅平台" + }, + "path": "spcontact.contactunit", + "bindingPath": "spcontact.contactunit" + } + ], + "displayName": "往来单位" + }, + "path": "spcontact", + "bindingPath": "spcontact" + }, + { + "$type": "ComplexField", + "id": "b1901153-bc9d-4197-9fc8-ade1641ae95a", + "originalId": "b1901153-bc9d-4197-9fc8-ade1641ae95a", + "code": "servicedw", + "name": "服务单位", + "label": "servicedw", + "bindingField": "servicedw", + "type": { + "$type": "EntityType", + "name": "btplatformFe6F", + "primary": "servicedw", + "fields": [ + { + "$type": "SimpleField", + "id": "fe6f9569-e9dc-495f-bebd-cf004ec6469d", + "originalId": "fe6f9569-e9dc-495f-bebd-cf004ec6469d", + "code": "servicedw", + "name": "服务单位", + "label": "servicedw", + "bindingField": "servicedw", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "servicedw", + "bindingPath": "servicedw", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "e8adb731-2b40-4cf6-9178-5ea7dd47aa45", + "originalId": "e8adb731-2b40-4cf6-9178-5ea7dd47aa45", + "code": "ptcOde", + "name": "商旅平台编号", + "label": "servicedw_ptcOde", + "bindingField": "servicedw_servicedw_ptcOde", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "servicedw.servicedw_ptcOde", + "bindingPath": "servicedw.servicedw_ptcOde", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "18fa6038-7fc0-41c7-a395-4b9b8b9a73d9", + "originalId": "18fa6038-7fc0-41c7-a395-4b9b8b9a73d9", + "code": "ptname", + "name": "商旅平台名称", + "label": "servicedw_ptname", + "bindingField": "servicedw_servicedw_ptname", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "servicedw.servicedw_ptname", + "bindingPath": "servicedw.servicedw_ptname", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "商旅平台" + }, + "path": "servicedw", + "bindingPath": "servicedw" + }, + { + "$type": "SimpleField", + "id": "911232f4-3beb-4f63-a801-334ad6d3319a", + "originalId": "911232f4-3beb-4f63-a801-334ad6d3319a", + "code": "ysee", + "name": "营收额", + "label": "ysee", + "bindingField": "ysee", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BigNumericType", + "name": "BigNumber", + "displayName": "大数字", + "length": 36, + "precision": 3 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "ysee", + "bindingPath": "ysee", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "34f6b51e-d602-4900-8ed4-1affbfe6fc3f", + "originalId": "34f6b51e-d602-4900-8ed4-1affbfe6fc3f", + "code": "lrr", + "name": "利润", + "label": "lrr", + "bindingField": "lrr", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BigNumericType", + "name": "BigNumber", + "displayName": "大数字", + "length": 36, + "precision": 4 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "lrr", + "bindingPath": "lrr", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "服务商往" + } + }, + { + "id": "0c7c9fed-ea31-4eda-8a62-2931c68f29e2", + "code": "sprovider1", + "name": "服务商往1", + "label": "sprovider1s", + "type": { + "name": "sprovider1", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "210d022d-55ee-4844-8615-a82baa4ed41a", + "originalId": "210d022d-55ee-4844-8615-a82baa4ed41a", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "d31c99b7-608a-45f0-8ed9-d6b5b8a1ad49", + "originalId": "d31c99b7-608a-45f0-8ed9-d6b5b8a1ad49", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "22e239cc-fc3e-48da-a39b-dabf0f1ba8bd", + "originalId": "22e239cc-fc3e-48da-a39b-dabf0f1ba8bd", + "code": "code1", + "name": "商往1", + "label": "code1", + "bindingField": "code1", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "code1", + "bindingPath": "code1", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "2ca023be-6483-409b-a924-5870d3f43973", + "originalId": "2ca023be-6483-409b-a924-5870d3f43973", + "code": "code2", + "name": "商往2", + "label": "code2", + "bindingField": "code2", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateType", + "name": "Date", + "displayName": "日期" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "code2", + "bindingPath": "code2", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "74d8bdf3-d185-454a-a802-61984539a4ff", + "originalId": "74d8bdf3-d185-454a-a802-61984539a4ff", + "code": "code3", + "name": "商往3", + "label": "code3", + "bindingField": "code3", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "DateTimeType", + "name": "DateTime", + "displayName": "日期时间" + }, + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + }, + "path": "code3", + "bindingPath": "code3", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "221744dc-b0b6-4a2e-b09c-6deec360cc47", + "originalId": "221744dc-b0b6-4a2e-b09c-6deec360cc47", + "code": "cod4", + "name": "商往4", + "label": "cod4", + "bindingField": "cod4", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "TextType", + "name": "Text", + "displayName": "文本", + "length": 0 + }, + "editor": { + "$type": "MultiTextBox" + }, + "path": "cod4", + "bindingPath": "cod4", + "multiLanguage": false + } + ], + "entities": [ + { + "id": "d9c1577e-4b8a-4996-831c-e569a09571de", + "code": "sprovider1child", + "name": "服务商往1子", + "label": "sprovider1childs", + "type": { + "name": "sprovider1child", + "primary": "id", + "fields": [ + { + "$type": "SimpleField", + "id": "95562000-d8c2-440f-812f-9ddd746af0c6", + "originalId": "95562000-d8c2-440f-812f-9ddd746af0c6", + "code": "ID", + "name": "ID", + "label": "id", + "bindingField": "id", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ID", + "bindingPath": "id", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "c6e127df-6c2c-4be4-8ad8-12e6cda8ce02", + "originalId": "c6e127df-6c2c-4be4-8ad8-12e6cda8ce02", + "code": "ParentID", + "name": "ParentID", + "label": "parentID", + "bindingField": "parentID", + "defaultValue": "", + "require": true, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "ParentID", + "bindingPath": "parentID", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6c540196-0fa3-48d0-be38-37f9cccc1fd2", + "originalId": "6c540196-0fa3-48d0-be38-37f9cccc1fd2", + "code": "codechild1", + "name": "codechild1", + "label": "codechild1", + "bindingField": "codechild1", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "codechild1", + "bindingPath": "codechild1", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "f3e72fcc-aa3d-43b8-9390-5252ceee20fa", + "originalId": "f3e72fcc-aa3d-43b8-9390-5252ceee20fa", + "code": "codechild2", + "name": "codechild2", + "label": "codechild2", + "bindingField": "codechild2", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "StringType", + "name": "String", + "displayName": "字符串", + "length": 36 + }, + "editor": { + "$type": "TextBox" + }, + "path": "codechild2", + "bindingPath": "codechild2", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "9a4915e1-2a1f-4207-8eca-7f6f64cc4426", + "originalId": "9a4915e1-2a1f-4207-8eca-7f6f64cc4426", + "code": "codechild3", + "name": "codechild3", + "label": "codechild3", + "bindingField": "codechild3", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BooleanType", + "name": "Boolean", + "displayName": "布尔" + }, + "editor": { + "$type": "CheckBox" + }, + "path": "codechild3", + "bindingPath": "codechild3", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "dde6acee-b662-48f8-b1de-aff344688b75", + "originalId": "dde6acee-b662-48f8-b1de-aff344688b75", + "code": "codechild4", + "name": "codechild4", + "label": "codechild4", + "bindingField": "codechild4", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "NumericType", + "name": "Number", + "displayName": "数字", + "length": 0, + "precision": 0 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "codechild4", + "bindingPath": "codechild4", + "multiLanguage": false + }, + { + "$type": "SimpleField", + "id": "6cd616e9-8485-48bd-addf-eb7c1cf3f055", + "originalId": "6cd616e9-8485-48bd-addf-eb7c1cf3f055", + "code": "codechild5", + "name": "codechild5", + "label": "codechild5", + "bindingField": "codechild5", + "defaultValue": "", + "require": false, + "readonly": false, + "type": { + "$type": "BigNumericType", + "name": "BigNumber", + "displayName": "大数字", + "length": 36, + "precision": 2 + }, + "editor": { + "$type": "NumericBox" + }, + "path": "codechild5", + "bindingPath": "codechild5", + "multiLanguage": false + } + ], + "entities": [], + "displayName": "服务商往1子" + } + } + ], + "displayName": "服务商往1" + } + } + ], + "displayName": "集团商旅" + } + } + ], + "variables": [], + "eapiId": "c8ead2bc-fee0-4e87-aa24-4a6f389c2f6c" + } + ], + "states": [], + "contents": [], + "stateMachines": [ + { + "id": "GroupBTCZC_state_machine", + "name": "GroupBT主从卡状态机", + "uri": "55460bd1-80c5-41f3-9bd7-a0f54178ec7c" + } + ], + "viewmodels": [ + { + "id": "root-viewmodel", + "code": "root-viewmodel", + "name": "集团商旅", + "fields": [], + "stateMachine": "GroupBTCZC_state_machine", + "serviceRefs": [], + "commands": [ + { + "id": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "code": "Load1", + "name": "加载", + "params": [ + { + "name": "action", + "shownName": "初始动作", + "value": "{UISTATE~/root-component/action}", + "description": null + } + ], + "handlerName": "Load", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "code": "LoadAndCascadeAdd1", + "name": "加载并新增", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "LoadAndCascadeAdd", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "code": "LoadAndView1", + "name": "加载并查看", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "LoadAndView", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "code": "LoadAndEdit1", + "name": "加载并编辑", + "params": [ + { + "name": "id", + "shownName": "数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "LoadAndEdit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "89904e71-5b79-9caf-b9d6-77e878cc1552", + "code": "cascadeAdd1", + "name": "新增数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Create", + "description": null + } + ], + "handlerName": "cascadeAdd", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "code": "Edit1", + "name": "编辑数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Edit", + "description": null + } + ], + "handlerName": "Edit", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "31b814db-01e4-407d-8fad-0f08dbb01999", + "code": "Save1", + "name": "保存数据", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Save", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "code": "Cancel1", + "name": "取消变更", + "params": [ + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "Cancel", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "code": "Close1", + "name": "关闭", + "params": [ + { + "name": "url", + "shownName": "上级Url", + "value": "", + "description": null + }, + { + "name": "params", + "shownName": "路由参数", + "value": "", + "description": null + } + ], + "handlerName": "Close", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "c8504c24-33e8-487a-91ce-2218b803fe01", + "code": "ChangeItem1", + "name": "ChangeItem", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "prev", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "code": "ChangeItem2", + "name": "ChangeItem2", + "params": [ + { + "name": "id", + "shownName": "id", + "value": "{DATA~/root-component/id}", + "description": null + }, + { + "name": "type", + "shownName": "type", + "value": "next", + "description": "上一条prev;下一条next" + }, + { + "name": "parentId", + "shownName": "parentId", + "value": "{UISTATE~/root-component/innerData/WEB_FORM_ROUTER_PARENT_ID}", + "description": "当前卡片所属列表页的功能id" + }, + { + "name": "transitionAction", + "shownName": "状态迁移动作", + "value": "Cancel", + "description": null + } + ], + "handlerName": "ChangeItem", + "cmpId": "8172a979-2c80-4637-ace7-b13074d3f393", + "shortcut": {}, + "extensions": [] + }, + { + "id": "2b23e8db-a1af-4cbb-9767-debba60ea354", + "code": "rootviewmodeloverLoad1", + "name": "overLoad1", + "params": [ + { + "name": "load_数据id", + "shownName": "load_数据id", + "value": "{UISTATE~/root-component/id}", + "description": null + }, + { + "name": "execute_命令名称", + "shownName": "execute_命令名称", + "value": "Load1", + "description": null + }, + { + "name": "execute_框架id", + "shownName": "execute_框架id", + "value": "root-component", + "description": null + } + ], + "handlerName": "overLoad", + "cmpId": "b250f84f-a499-406a-9d6b-687a8b56d76c", + "shortcut": {}, + "extensions": [] + } + ], + "states": [ + { + "id": "2d3530ae-29cb-4fd2-b4f4-d932706db7b8", + "category": "locale", + "code": "rootpara1", + "name": "rootpara1", + "type": "String" + }, + { + "id": "4c3dadbb-d283-40d3-b092-241ea2c295fe", + "category": "locale", + "code": "rootpara", + "name": "rootpara", + "type": "Boolean" + } + ], + "bindTo": "/", + "enableUnifiedSession": false + }, + { + "id": "basic-form-viewmodel", + "code": "basic-form-viewmodel", + "name": "集团商旅", + "fields": [ + { + "type": "Form", + "id": "d2a9d99e-dab8-47be-bab7-2e1bd2183c0a", + "fieldName": "btPlatform_btPlatform_ptname", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "GroupBT.btPlatform_btPlatform_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "mapFields": "{'id':'btPlatform.btPlatform','ptname':'btPlatform.btPlatform_ptname','ptlocal':'btPlatform.btPlatform_ptlocal'}" + } + } + }, + { + "type": "Form", + "id": "ec159a96-7bf7-4a3e-9b20-8ee292e9f153", + "fieldName": "btPlatform_btPlatform_ptlocal", + "groupId": null, + "groupName": null, + "updateOn": "change", + "valueChanged": "basicformviewmodelsetvirValue1" + }, + { + "type": "Form", + "id": "38c3a0cd-ac2e-40ef-9455-045c73757c8e", + "fieldName": "groupid", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "98d4cb5f-6033-4e6b-880b-b89da70e5f86", + "fieldName": "groupname", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "TextBox" + } + } + }, + { + "type": "Form", + "id": "3d4827d5-9415-4730-8241-24606c6b6032", + "fieldName": "tmCcODE", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "RichTextBox" + } + } + }, + { + "type": "Form", + "id": "27d1678c-c4a7-4edc-8e04-48ea7655421f", + "fieldName": "accessCount", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "fd277c97-414a-433f-b14d-62ef24d82559", + "fieldName": "accesspass", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "2d20f75c-709c-468a-ac44-7c5b2a0177b7", + "fieldName": "advanceap", + "groupId": null, + "groupName": null, + "updateOn": "change" + }, + { + "type": "Form", + "id": "eeda26e9-a3ad-45d7-9140-08fecefacc11", + "fieldName": "scopeservice_servicescope", + "groupId": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "groupName": "枚举控件", + "updateOn": "change" + }, + { + "type": "Form", + "id": "2782cd63-680c-4d3e-8a3a-d438c8fa2212", + "fieldName": "sourceBill_SourceBill", + "groupId": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "groupName": "枚举控件", + "updateOn": "change" + }, + { + "type": "Form", + "id": "d2c8c5c6-cc0b-47b7-8040-ddb127e689e1", + "fieldName": "billdata", + "groupId": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "groupName": "枚举控件", + "updateOn": "change", + "fieldSchema": { + "editor": { + "$type": "RadioGroup" + } + } + }, + { + "type": "Form", + "id": "95ded9d1-1a82-4e12-8614-598d4a55e822", + "fieldName": "plane_datemanager", + "groupId": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "groupName": "枚举控件", + "updateOn": "change", + "fieldSchema": { + "name": "机票" + } + }, + { + "type": "Form", + "id": "6c83ca65-1a82-4e12-8614-598d4a55e822", + "fieldName": "train_datemanager", + "groupId": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "groupName": "枚举控件", + "updateOn": "change", + "fieldSchema": { + "name": "火车" + } + }, + { + "type": "Form", + "id": "25cfad58-1a82-4e12-8614-598d4a55e822", + "fieldName": "hotel_datemanager", + "groupId": null, + "groupName": null, + "updateOn": "change", + "fieldSchema": { + "name": "酒店" + } + }, + { + "type": "Form", + "id": "21f67db6-74b7-4a65-952b-ca86ca32f5b0", + "fieldName": "currence_currence_currencyinfo_currencyName", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "GroupBT.currence_currence_currencyinfo_currencyName", + "displayName": "currencyhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "currencyinfo.currencyName", + "valueField": "currencyinfo.currencyName", + "displayType": "List", + "helpId": "fea7cec1-dad6-438b-8cab-664d24d1a277", + "mapFields": "{'id':'currence.currence_currencyinfo.currencyCode','currencyinfo.currencyName':'currence.currence_currencyinfo.currencyName'}" + } + } + }, + { + "type": "Form", + "id": "0faec132-5899-4615-b657-5af7afcc10c0", + "fieldName": "planere", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "7b9c7dd8-bcb6-44a0-afdb-b849aa0c9057", + "fieldName": "planeset", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "maxValue": "", + "minValue": "2020-11-09 01:15:23" + } + } + }, + { + "type": "Form", + "id": "588a2cd2-a1b9-4da4-b181-cb5871f64dac", + "fieldName": "trainre", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "e619c764-5544-437b-a1c2-df01b22bc0a7", + "fieldName": "trainset", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "e020d0a8-3412-45cf-8277-a1189cd24ffc", + "fieldName": "hotelre", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + } + } + }, + { + "type": "Form", + "id": "30396ebb-a370-4639-a16b-26f648db4e11", + "fieldName": "hotelset", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "TimePicker" + } + } + }, + { + "type": "Form", + "id": "034f78df-e5a0-40fd-ac78-f7d3f0ec13d5", + "fieldName": "bugetpay", + "groupId": "bc27e4c0-73f8-434b-b87c-4e02003c093c", + "groupName": "数值控件", + "updateOn": "blur" + }, + { + "type": "Form", + "id": "40ea892d-2120-4c1b-8575-394a6f189d02", + "fieldName": "actrualpay", + "groupId": "bc27e4c0-73f8-434b-b87c-4e02003c093c", + "groupName": "数值控件", + "updateOn": "blur" + }, + { + "type": "Form", + "id": "25da0e95-7aba-4ced-abaa-81983e32483d", + "fieldName": "businessnum", + "groupId": "bc27e4c0-73f8-434b-b87c-4e02003c093c", + "groupName": "数值控件", + "updateOn": "blur" + }, + { + "type": "Form", + "id": "baac25ae-32ec-4e51-ad41-fb41477b6381", + "fieldName": "perpay", + "groupId": "bc27e4c0-73f8-434b-b87c-4e02003c093c", + "groupName": "数值控件", + "updateOn": "blur" + }, + { + "type": "Form", + "id": "6d455dfa-5e58-410b-ba3c-2454a75b6360", + "fieldName": "aprrovety", + "groupId": null, + "groupName": null, + "updateOn": "change", + "fieldSchema": { + "editor": { + "$type": "RadioGroup" + } + } + }, + { + "type": "Form", + "id": "2b37734c-d032-4127-8ecd-82dcc511e5b2", + "fieldName": "mostmonth", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + } + } + }, + { + "type": "Form", + "id": "1ac9fe65-8ece-4319-ad56-45769340bfcd", + "fieldName": "acmonth", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + } + } + }, + { + "type": "Form", + "id": "c9c2d5e0-9d65-4b95-92f6-c1c4eab17e2e", + "fieldName": "resolveT", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "DateBox", + "format": "'yyyy-MM-dd'" + } + } + }, + { + "type": "Form", + "id": "a29747fc-cd82-4c93-9c27-9f638448e76e", + "fieldName": "expectT", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "maxValue": "2020-11-09 18:09:19", + "minValue": "2020-11-09 19:10:22" + } + } + }, + { + "type": "Form", + "id": "c0de57e1-de21-4edd-bfb4-8b005ecca03a", + "fieldName": "contactu_contactunit_contactunit_ptname", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": { + "name": "往来单位", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "GroupBT.contactu_contactunit_contactunit_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "mapFields": "{'id':'contactu.contactunit.contactunit','ptname':'contactu.contactunit.contactunit_ptname'}" + } + } + } + ], + "serviceRefs": [], + "commands": [ + { + "id": "78706cba-de76-4d92-b5be-17a9ddd25b9b", + "code": "basicformviewmodelsetvirValue1", + "name": "setvirValue1", + "params": [], + "handlerName": "setvirValue", + "cmpId": "b250f84f-a499-406a-9d6b-687a8b56d76c", + "shortcut": {}, + "extensions": [] + }, + { + "id": "22ea0700-0814-4ef2-958b-fb0d48252c38", + "code": "basicformviewmodelbuttonzdy1", + "name": "buttonzdy1", + "params": [], + "handlerName": "buttonzdy", + "cmpId": "b250f84f-a499-406a-9d6b-687a8b56d76c", + "shortcut": {}, + "extensions": [] + } + ], + "states": [], + "bindTo": "/", + "parent": "root-viewmodel", + "enableValidation": false + }, + { + "id": "sprovider-component-viewmodel", + "code": "sprovider-component-viewmodel", + "name": "服务商往", + "fields": [ + { + "type": "Form", + "id": "556b80b3-1c4d-417f-ad2c-1a5a06d362a2", + "fieldName": "sproCode", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "name": "服务商编号" + } + }, + { + "type": "Form", + "id": "156d0ffe-9694-4334-9f8d-f0393ee57408", + "fieldName": "sproName", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "9c111d84-de21-4edd-bfb4-8b005ecca03a", + "fieldName": "spcontact_contactunit_contactunit_ptname", + "groupId": "01d18c77-72e5-41fe-a783-139e3c045dbb", + "groupName": "单位信息", + "updateOn": "blur", + "fieldSchema": { + "name": "往来单位", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "sprovider.spcontact_contactunit_contactunit_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "mapFields": "{'id':'spcontact.contactunit.contactunit','ptname':'spcontact.contactunit.contactunit_ptname','ptlocal':'spcontact.contactunit.contactunit_ptlocal'}" + }, + "require": true + } + }, + { + "type": "Form", + "id": "18fa6038-7fc0-41c7-a395-4b9b8b9a73d9", + "fieldName": "servicedw_servicedw_ptname", + "groupId": "01d18c77-72e5-41fe-a783-139e3c045dbb", + "groupName": "单位信息", + "updateOn": "blur", + "fieldSchema": { + "name": "服务单位", + "editor": { + "$type": "LookupEdit", + "dataSource": { + "uri": "sprovider.servicedw_servicedw_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "mapFields": "{'id':'servicedw.servicedw','ptname':'servicedw.servicedw_ptname'}" + } + } + }, + { + "type": "Form", + "id": "9c111d84-a3bc-4f6b-876c-c97bf60a0bc9", + "fieldName": "spcontact_contactunit_contactunit_ptlocal", + "groupId": "01d18c77-72e5-41fe-a783-139e3c045dbb", + "groupName": "单位信息", + "valueChanging": "", + "valueChanged": "", + "updateOn": "change", + "fieldSchema": { + "name": "往来平台位置", + "require": true + } + }, + { + "type": "Form", + "id": "5844b5a4-4503-4d88-b626-4c6fa8bac3f7", + "fieldName": "id", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "f577c3ea-f7ca-4458-814e-672937e76cf2", + "fieldName": "parentID", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "911232f4-3beb-4f63-a801-334ad6d3319a", + "fieldName": "ysee", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + }, + { + "type": "Form", + "id": "34f6b51e-d602-4900-8ed4-1affbfe6fc3f", + "fieldName": "lrr", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "states": [ + { + "id": "2923f22f-d89d-4eac-b7f6-cea390f9922f", + "category": "locale", + "code": "sproviderpara", + "name": "sproviderpara", + "type": "Boolean" + } + ], + "bindTo": "/sproviders", + "parent": "root-viewmodel", + "commands": [ + { + "id": "ba5fdf9a-1d20-46f0-aa5d-ce5f2ae83bf8", + "code": "sprovidercomponentviewmodelbuttonzdy1", + "name": "buttonzdy1", + "params": [], + "handlerName": "buttonzdy", + "cmpId": "b250f84f-a499-406a-9d6b-687a8b56d76c", + "shortcut": {}, + "extensions": [] + } + ], + "serviceRefs": [], + "enableValidation": true, + "pagination": { + "enable": false + } + }, + { + "id": "sprovider1-component-viewmodel", + "code": "sprovider1-component-viewmodel", + "name": "服务商往1", + "fields": [ + { + "type": "Form", + "id": "210d022d-55ee-4844-8615-a82baa4ed41a", + "fieldName": "id", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "d31c99b7-608a-45f0-8ed9-d6b5b8a1ad49", + "fieldName": "parentID", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "22e239cc-fc3e-48da-a39b-dabf0f1ba8bd", + "fieldName": "code1", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "2ca023be-6483-409b-a924-5870d3f43973", + "fieldName": "code2", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "74d8bdf3-d185-454a-a802-61984539a4ff", + "fieldName": "code3", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "maxValue": "2020-09-30 01:01:01", + "minValue": "2020-09-01 23:59:59" + } + } + }, + { + "type": "Form", + "id": "221744dc-b0b6-4a2e-b09c-6deec360cc47", + "fieldName": "cod4", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "Avatar" + } + } + } + ], + "states": [], + "bindTo": "/sprovider1s", + "parent": "root-viewmodel", + "commands": [], + "serviceRefs": [], + "enableValidation": true, + "pagination": { + "enable": false + } + }, + { + "id": "sprovider1child-component-viewmodel", + "code": "sprovider1child-component-viewmodel", + "name": "服务商往1子", + "fields": [ + { + "type": "Form", + "id": "95562000-d8c2-440f-812f-9ddd746af0c6", + "fieldName": "id", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "c6e127df-6c2c-4be4-8ad8-12e6cda8ce02", + "fieldName": "parentID", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "6c540196-0fa3-48d0-be38-37f9cccc1fd2", + "fieldName": "codechild1", + "groupId": null, + "groupName": null, + "updateOn": "blur" + }, + { + "type": "Form", + "id": "f3e72fcc-aa3d-43b8-9390-5252ceee20fa", + "fieldName": "codechild2", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "editor": { + "$type": "CheckGroup" + } + } + }, + { + "type": "Form", + "id": "9a4915e1-2a1f-4207-8eca-7f6f64cc4426", + "fieldName": "codechild3", + "groupId": null, + "groupName": null, + "updateOn": "change" + }, + { + "type": "Form", + "id": "dde6acee-b662-48f8-b1de-aff344688b75", + "fieldName": "codechild4", + "groupId": null, + "groupName": null, + "updateOn": "blur", + "fieldSchema": { + "require": true + } + }, + { + "type": "Form", + "id": "6cd616e9-8485-48bd-addf-eb7c1cf3f055", + "fieldName": "codechild5", + "groupId": "", + "groupName": "", + "valueChanging": "", + "valueChanged": "", + "updateOn": "blur", + "fieldSchema": {} + } + ], + "states": [], + "bindTo": "/sprovider1s/sprovider1childs", + "parent": "root-viewmodel", + "commands": [], + "serviceRefs": [], + "enableValidation": false, + "pagination": { + "enable": false + } + } + ], + "components": [ + { + "id": "root-component", + "type": "Component", + "viewModel": "root-viewmodel", + "componentType": "Frame", + "onInit": "rootviewmodeloverLoad1", + "contents": [ + { + "id": "root-layout", + "type": "ContentContainer", + "appearance": { + "class": "f-page f-page-card f-page-is-mainsubcard" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-nav", + "type": "ContentContainer", + "appearance": { + "class": "f-page-header-base" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "header-title-container", + "type": "ContentContainer", + "appearance": { + "class": "f-title" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "page-header-title", + "type": "HtmlTemplate", + "html": "

GroupBT主从卡

" + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + }, + { + "id": "page-header-toolbar", + "type": "ToolBar", + "appearance": { + "class": "col-7 f-toolbar" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "items": [ + { + "id": "button-add", + "type": "ToolBarItem", + "text": "新增", + "appearance": { + "class": "btn-primary" + }, + "disable": "!viewModel.stateMachine['canAdd']", + "visible": true, + "click": "cascadeAdd1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-edit", + "type": "ToolBarItem", + "text": "编辑", + "appearance": null, + "disable": "!viewModel.stateMachine['canEdit']", + "visible": true, + "click": "Edit1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-save", + "type": "ToolBarItem", + "text": "保存", + "appearance": null, + "disable": "!viewModel.stateMachine['canSave']", + "visible": true, + "click": "Save1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-cancel", + "type": "ToolBarItem", + "text": "取消", + "appearance": null, + "disable": "!viewModel.stateMachine['canCancel']", + "visible": true, + "click": "Cancel1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "button-close", + "type": "ToolBarItem", + "text": "关闭", + "appearance": null, + "disable": false, + "visible": true, + "click": "Close1", + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_7891", + "type": "ToolBarItem", + "appearance": null, + "disable": false, + "text": "按钮是否可见", + "visible": "viewModel.uiState['rootpara']===true && viewModel.sproviderComponentViewmodel.uiState['sproviderpara']===true", + "click": null, + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + }, + { + "id": "toolBarItem_8517", + "type": "ToolBarItem", + "appearance": null, + "disable": false, + "text": "按钮", + "visible": true, + "click": null, + "items": [ + { + "id": "toolBarItem_5668", + "type": "ToolBarItem", + "appearance": null, + "disable": "viewModel.uiState['rootpara']===true && viewModel.sproviderComponentViewmodel.uiState['sproviderpara']===false", + "text": "按钮是否禁用", + "visible": true, + "click": null + } + ], + "usageMode": "button", + "modalConfig": { + "modalCmp": null, + "mapFields": null, + "showHeader": true, + "title": "", + "showCloseButton": true, + "showMaxButton": true, + "width": 800, + "height": 600, + "showFooterButtons": true, + "footerButtons": [] + } + } + ], + "visible": true + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + }, + { + "id": "main-container", + "type": "ContentContainer", + "appearance": { + "class": "f-page-main" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "basic-form-component-ref", + "type": "ComponentRef", + "component": "basic-form-component", + "visible": true + }, + { + "id": "sprovider-component-ref", + "type": "ComponentRef", + "component": "sprovider-component", + "visible": true + }, + { + "id": "sprovider1-component-ref", + "type": "ComponentRef", + "component": "sprovider1-component", + "visible": true + }, + { + "id": "sprovider1child-component-ref", + "type": "ComponentRef", + "component": "sprovider1child-component", + "visible": true + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "visible": true, + "isScrollspyContainer": false, + "draggable": false + } + ], + "afterViewInit": "root-viewmodel.basic-form-viewmodel.basicformviewmodelsetvirValue1", + "visible": true + }, + { + "id": "basic-form-component", + "type": "Component", + "viewModel": "basic-form-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "basic-form-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "基本信息", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "basic-form-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "border": null, + "font": null, + "margin": null, + "padding": null, + "size": null, + "contents": [ + { + "id": "groupname_98d4cb5f_6033_4e6b_880b_b89da70e5f86_hsjy", + "type": "TextBox", + "title": "公司名称", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "groupname", + "field": "98d4cb5f-6033-4e6b-880b-b89da70e5f86" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "groupname", + "span": 1, + "titleSourceType": "static" + }, + { + "id": "btPlatform_btPlatform_ptname_d2a9d99e_dab8_47be_bab7_2e1bd2183c0a_8jo6", + "type": "LookupEdit", + "title": "商旅平台名称", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "btPlatform_btPlatform_ptname", + "field": "d2a9d99e-dab8-47be-bab7-2e1bd2183c0a" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "GroupBT.btPlatform_btPlatform_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'btPlatform.btPlatform','ptname':'btPlatform.btPlatform_ptname','ptlocal':'btPlatform.btPlatform_ptlocal'}", + "lookupStyle": "popup", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "btPlatform.btPlatform_ptname", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "CascadeStatus": "default", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "cascadeStatus": "enable", + "isTextArea": true, + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "btPlatform_btPlatform_ptlocal_ec159a96_7bf7_4a3e_9b20_8ee292e9f153_h2rb", + "type": "EnumField", + "title": "平台位置", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "btPlatform_btPlatform_ptlocal", + "field": "ec159a96-7bf7-4a3e-9b20-8ee292e9f153" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "shandong", + "name": "山东" + }, + { + "value": "sichuan", + "name": "四川" + }, + { + "value": "hunan", + "name": "湖南" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "btPlatform.btPlatform_ptlocal", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "groupid_38c3a0cd_ac2e_40ef_9455_045c73757c8e_zwgt", + "type": "TextBox", + "title": "公司id", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "groupid", + "field": "38c3a0cd-ac2e-40ef-9455-045c73757c8e" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "groupid", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "accessCount_27d1678c_c4a7_4edc_8e04_48ea7655421f_iryg", + "type": "MultiTextBox", + "title": "接入账户", + "binding": { + "type": "Form", + "path": "accessCount", + "field": "27d1678c-c4a7-4edc-8e04-48ea7655421f" + }, + "placeHolder": "", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "maxLength": 0, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "accessCount", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "accesspass_fd277c97_414a_433f_b14d_62ef24d82559_l8sq", + "type": "TextBox", + "title": "接入密码", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "accesspass", + "field": "fd277c97-414a-433f-b14d-62ef24d82559" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "accesspass", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "advanceap_2d20f75c_709c_468a_ac44_7c5b2a0177b7_8sv2", + "type": "CheckBox", + "title": "是否提前审批", + "checked": false, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "binding": { + "type": "Form", + "path": "advanceap", + "field": "2d20f75c-709c-468a-ac44-7c5b2a0177b7" + }, + "visible": true, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "vsize": null, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "holdPlace": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "advanceap", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "tmCcODE_3d4827d5_9415_4730_8241_24606c6b6032_bizi", + "type": "RichTextBox", + "title": "TMC编号", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "customEditorStyle": "", + "binding": { + "type": "Form", + "path": "tmCcODE", + "field": "3d4827d5-9415-4730-8241-24606c6b6032" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "theme": "snow", + "validation": null, + "value": null, + "maxLength": null, + "minLength": null, + "customToolbarPosition": "top", + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "tmCcODE", + "isTextArea": false, + "controlSource": "concise", + "span": 1, + "titleSourceType": "static" + }, + { + "id": "currence_currence_currencyinfo_currencyName_21f67db6_74b7_4a65_952b_ca86ca32f5b0_lzt9", + "type": "LookupEdit", + "title": "币种名称", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "currence_currence_currencyinfo_currencyName", + "field": "21f67db6-74b7-4a65-952b-ca86ca32f5b0" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "GroupBT.currence_currence_currencyinfo_currencyName", + "displayName": "currencyhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "currencyinfo.currencyName", + "valueField": "currencyinfo.currencyName", + "displayType": "List", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'currence.currence_currencyinfo.currencyCode','currencyinfo.currencyName':'currence.currence_currencyinfo.currencyName'}", + "lookupStyle": "popup", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "currence.currence_currencyinfo.currencyName", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "CascadeStatus": "default", + "helpId": "fea7cec1-dad6-438b-8cab-664d24d1a277", + "cascadeStatus": "enable", + "isTextArea": true, + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "planere_0faec132_5899_4615_b657_5af7afcc10c0_yct8", + "type": "DateBox", + "title": "机票预定时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "planere", + "field": "0faec132-5899-4615-b657-5af7afcc10c0" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": true, + "showType": 1, + "dateFormat": "yyyy-MM-dd HH:mm:ss", + "returnFormat": "yyyy-MM-dd HH:mm:ss", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "planere", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "planeset_7b9c7dd8_bcb6_44a0_afdb_b849aa0c9057_gm8p", + "type": "DateBox", + "title": "机票出发时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "planeset", + "field": "7b9c7dd8-bcb6-44a0-afdb-b849aa0c9057" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": true, + "showType": 1, + "dateFormat": "yyyy-MM-dd HH:mm:ss", + "returnFormat": "yyyy-MM-dd HH:mm:ss", + "maxValue": "", + "minValue": "2020-11-09 01:15:23", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "planeset", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "expectT_a29747fc_cd82_4c93_9c27_9f638448e76e_u7li", + "type": "DateBox", + "title": "期望解决时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "expectT", + "field": "a29747fc-cd82-4c93-9c27-9f638448e76e" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 4, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": "2020-11-09 18:09:19", + "minValue": "2020-11-09 19:10:22", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "expectT", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "trainset_e619c764_5544_437b_a1c2_df01b22bc0a7_sa9c", + "type": "DateBox", + "title": "火车出发时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "trainset", + "field": "e619c764-5544-437b-a1c2-df01b22bc0a7" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "trainset", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "hotelre_e020d0a8_3412_45cf_8277_a1189cd24ffc_zuf6", + "type": "DateBox", + "title": "酒店预定时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "hotelre", + "field": "e020d0a8-3412-45cf-8277-a1189cd24ffc" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "String", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "hotelre", + "format": "'yyyy-MM-dd'", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "hotelset_30396ebb_a370_4639_a16b_26f648db4e11_yb1w", + "type": "TimePicker", + "title": "酒店离店时间", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "hotelset", + "field": "30396ebb-a370-4639-a16b-26f648db4e11" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "use12Hours": false, + "format": "hh:mm:ss", + "placeHolder": "请选择时间", + "hourStep": 1, + "minuteStep": 1, + "secondStep": 1, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "editable": true, + "path": "hotelset", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "trainre_588a2cd2_a1b9_4da4_b181_cb5871f64dac_q9fm", + "type": "DateBox", + "title": "火车预定时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "trainre", + "field": "588a2cd2-a1b9-4da4-b181-cb5871f64dac" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": true, + "showType": 1, + "dateFormat": "yyyy-MM-dd HH:mm:ss", + "returnFormat": "yyyy-MM-dd HH:mm:ss", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "trainre", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "acmonth_1ac9fe65_8ece_4319_ad56_45769340bfcd_dh3j", + "type": "DateBox", + "title": "实际时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "acmonth", + "field": "1ac9fe65-8ece-4319-ad56-45769340bfcd" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 2, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "String", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "acmonth", + "format": "'yyyy-MM-dd'", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "1a29a8d0-2b90-4a77-95d0-004d27ac5804", + "type": "FieldSet", + "title": "枚举控件", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "scopeservice_servicescope_eeda26e9_a3ad_45d7_9140_08fecefacc11_snvu", + "type": "EnumField", + "title": "服务范围", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "scopeservice_servicescope", + "field": "eeda26e9-a3ad-45d7-9140-08fecefacc11" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "plane", + "name": "飞机" + }, + { + "value": "train", + "name": "火车" + }, + { + "value": "hotel", + "name": "酒店" + }, + { + "value": "other", + "name": "其他" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "scopeservice.servicescope", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "sourceBill_SourceBill_2782cd63_680c_4d3e_8a3a_d438c8fa2212_ybeq", + "type": "EnumField", + "title": "账单来源", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "sourceBill_SourceBill", + "field": "2782cd63-680c-4d3e-8a3a-d438c8fa2212" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "tmccreate", + "name": "tmc生成账单" + }, + { + "value": "notem", + "name": "我方生成账单" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "sourceBill.sourceBill", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "billdata_d2c8c5c6_cc0b_47b7_8040_ddb127e689e1_47wq", + "type": "RadioGroup", + "title": "账单数据", + "binding": { + "type": "Form", + "path": "billdata", + "field": "d2c8c5c6-cc0b-47b7-8040-ddb127e689e1" + }, + "placeHolder": "", + "enumData": [ + { + "value": "zhangqi", + "name": "账期" + }, + { + "value": "yibaoxiao", + "name": "已报销" + }, + { + "value": "zhangqi1", + "name": "账期1" + }, + { + "value": "zhangqi2", + "name": "账期2" + }, + { + "value": "zhangqi3", + "name": "账期3" + }, + { + "value": "zhangqi4", + "name": "账期4" + }, + { + "value": "zhangqi5", + "name": "账期5" + }, + { + "value": "zhangqi6", + "name": "账期6" + }, + { + "value": "yibaoxiao1", + "name": "已报销1" + }, + { + "value": "yibaoxiao2", + "name": "已报销2" + }, + { + "value": "yibaoxiao3", + "name": "已报销3" + }, + { + "value": "yibaoxiao4", + "name": "已报销4" + }, + { + "value": "yibaoxioa5", + "name": "已报销5" + }, + { + "value": "yibaoxioa6", + "name": "已报销6" + }, + { + "value": "yibaoxioa7", + "name": "已报销7" + } + ], + "isHorizontal": true, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "billdata", + "dataSourceType": "static", + "textField": "name", + "valueField": "value", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "plane_datemanager_95ded9d1_1a82_4e12_8614_598d4a55e822_qnpd", + "type": "EnumField", + "title": "机票", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "plane_datemanager", + "field": "95ded9d1-1a82-4e12-8614-598d4a55e822" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "plane.datemanager", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "train_datemanager_6c83ca65_1a82_4e12_8614_598d4a55e822_uqk6", + "type": "EnumField", + "title": "火车", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "train_datemanager", + "field": "6c83ca65-1a82-4e12-8614-598d4a55e822" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "train.datemanager", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "draggable": false, + "span": 4, + "columns": 4 + }, + { + "id": "resolveT_c9c2d5e0_9d65_4b95_92f6_c1c4eab17e2e_r6aa", + "type": "DateBox", + "title": "解决时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "resolveT", + "field": "c9c2d5e0-9d65-4b95-92f6-c1c4eab17e2e" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 2, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "String", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "resolveT", + "format": "'yyyy-MM-dd'", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "bc27e4c0-73f8-434b-b87c-4e02003c093c", + "type": "FieldSet", + "title": "数值控件", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "bugetpay_034f78df_e5a0_40fd_ac78_f7d3f0ec13d5_y9yh", + "type": "NumericBox", + "title": "预算费用", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "bugetpay", + "field": "034f78df-e5a0-40fd-ac78-f7d3f0ec13d5" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 2, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 18, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "bugetpay", + "isTextArea": true, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "actrualpay_40ea892d_2120_4c1b_8575_394a6f189d02_n8qr", + "type": "NumericBox", + "title": "实际费用", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "actrualpay", + "field": "40ea892d-2120-4c1b-8575-394a6f189d02" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 3, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 18, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "actrualpay", + "isTextArea": true, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "businessnum_25da0e95_7aba_4ced_abaa_81983e32483d_svou", + "type": "NumericBox", + "title": "出差人数", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "businessnum", + "field": "25da0e95-7aba-4ced-abaa-81983e32483d" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 0, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 0, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "businessnum", + "isTextArea": true, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "perpay_baac25ae_32ec_4e51_ad41_fb41477b6381_l4xj", + "type": "NumericBox", + "title": "单人费用", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "perpay", + "field": "baac25ae-32ec-4e51-ad41-fb41477b6381" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 2, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 18, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "perpay", + "isTextArea": true, + "canNull": true, + "bigNumber": true, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "draggable": false, + "span": 4, + "columns": 4 + }, + { + "id": "aprrovety_6d455dfa_5e58_410b_ba3c_2454a75b6360_30sl", + "type": "RadioGroup", + "title": "审核类型", + "binding": { + "type": "Form", + "path": "aprrovety", + "field": "6d455dfa-5e58-410b-ba3c-2454a75b6360" + }, + "placeHolder": "", + "enumData": [ + { + "value": "one", + "name": "一级" + }, + { + "value": "two", + "name": "二级" + }, + { + "value": "three", + "name": "三级" + } + ], + "isHorizontal": true, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "format": null, + "validation": null, + "value": null, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "aprrovety", + "dataSourceType": "static", + "textField": "name", + "valueField": "value", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "mostmonth_2b37734c_d032_4127_8ecd_82dcc511e5b2_hvhd", + "type": "DateBox", + "title": "期望时间", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "mostmonth", + "field": "2b37734c-d032-4127-8ecd-82dcc511e5b2" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 3, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "String", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "mostmonth", + "format": "'yyyy-MM-dd'", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "contactu_contactunit_contactunit_ptname_c0de57e1_de21_4edd_bfb4_8b005ecca03a_zsal", + "type": "LookupEdit", + "title": "往来单位", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "contactu_contactunit_contactunit_ptname", + "field": "c0de57e1-de21-4edd-bfb4-8b005ecca03a" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "GroupBT.contactu_contactunit_contactunit_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'contactu.contactunit.contactunit','ptname':'contactu.contactunit.contactunit_ptname'}", + "lookupStyle": "popup", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "contactu.contactunit.contactunit_ptname", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "CascadeStatus": "default", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "cascadeStatus": "enable", + "isTextArea": true, + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "hotel_datemanager_25cfad58_1a82_4e12_8614_598d4a55e822_dbi6", + "type": "EnumField", + "title": "酒店", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "hotel_datemanager", + "field": "25cfad58-1a82-4e12-8614-598d4a55e822" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "enumData": [ + { + "value": "reserve", + "name": "预定时间" + }, + { + "value": "setout", + "name": "出发时间" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "hotel.datemanager", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + } + ], + "controlsInline": true, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "sprovider-component", + "type": "Component", + "viewModel": "sprovider-component-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "sprovider-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "服务商往", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "sprovider-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "size": null, + "contents": [ + { + "id": "sproCode_556b80b3_1c4d_417f_ad2c_1a5a06d362a2_a43w", + "type": "TextBox", + "title": "服务商编号", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "sproCode", + "field": "556b80b3-1c4d-417f-ad2c-1a5a06d362a2" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "sproCode", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "sproName_156d0ffe_9694_4334_9f8d_f0393ee57408_60ey", + "type": "TextBox", + "title": "服务商名称", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "sproName", + "field": "156d0ffe-9694-4334-9f8d-f0393ee57408" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "sproName", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "01d18c77-72e5-41fe-a783-139e3c045dbb", + "type": "FieldSet", + "title": "单位信息", + "appearance": { + "class": "col-12 col-md-12 col-xl-12 col-el-12 px-0 px-0" + }, + "size": null, + "collapse": false, + "expandText": "", + "collapseText": "", + "contentTemplate": null, + "headerTemplate": null, + "contents": [ + { + "id": "spcontact_contactunit_contactunit_ptname_9c111d84_de21_4edd_bfb4_8b005ecca03a_1gph", + "type": "LookupEdit", + "title": "往来单位", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "spcontact_contactunit_contactunit_ptname", + "field": "9c111d84-de21-4edd-bfb4-8b005ecca03a" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "sprovider.spcontact_contactunit_contactunit_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'spcontact.contactunit.contactunit','ptname':'spcontact.contactunit.contactunit_ptname','ptlocal':'spcontact.contactunit.contactunit_ptlocal'}", + "lookupStyle": "popup", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "spcontact.contactunit.contactunit_ptname", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "CascadeStatus": "default", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "cascadeStatus": "enable", + "isTextArea": true, + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + }, + { + "id": "spcontact_contactunit_contactunit_ptlocal_9c111d84_a3bc_4f6b_876c_c97bf60a0bc9_n58p", + "type": "EnumField", + "title": "往来平台位置", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "spcontact_contactunit_contactunit_ptlocal", + "field": "9c111d84-a3bc-4f6b-876c-c97bf60a0bc9" + }, + "placeHolder": "", + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "enumData": [ + { + "value": "shandong", + "name": "山东" + }, + { + "value": "sichuan", + "name": "四川" + }, + { + "value": "hunan", + "name": "湖南" + } + ], + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "idField": "value", + "textField": "name", + "valueField": "value", + "multiSelect": false, + "uri": "", + "autoWidth": true, + "enableClear": true, + "onClear": null, + "valueChanged": null, + "onShown": null, + "onHidden": null, + "editable": false, + "beforeShow": null, + "beforeHide": null, + "path": "spcontact.contactunit.contactunit_ptlocal", + "viewType": "text", + "isTextArea": true, + "enableCancelSelected": false, + "dataSourceType": "static", + "span": 1, + "titleSourceType": "static", + "noSearch": false + }, + { + "id": "servicedw_servicedw_ptname_18fa6038_7fc0_41c7_a395_4b9b8b9a73d9_qo14", + "type": "LookupEdit", + "title": "服务单位", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "servicedw_servicedw_ptname", + "field": "18fa6038-7fc0-41c7-a395-4b9b8b9a73d9" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "dataSource": { + "uri": "sprovider.servicedw_servicedw_ptname", + "displayName": "btplatformhelp", + "idField": "id", + "type": "ViewObject" + }, + "textField": "ptname", + "valueField": "ptname", + "displayType": "TreeList", + "multiSelect": false, + "pageSize": null, + "pageIndex": null, + "pagination": null, + "dialogTitle": null, + "showMaxButton": null, + "showCloseButton": null, + "resizable": null, + "buttonAlign": null, + "mapFields": "{'id':'servicedw.servicedw','ptname':'servicedw.servicedw_ptname'}", + "lookupStyle": "popup", + "holdPlace": false, + "useTip": false, + "useFavorite": true, + "noSearch": false, + "enableToSelect": true, + "lookupPicking": null, + "lookupPicked": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "enableExtendLoadMethod": true, + "editable": false, + "enableFullTree": false, + "enableClear": true, + "clear": null, + "loadTreeDataType": "default", + "onShown": null, + "onHidden": null, + "beforeShow": null, + "beforeHide": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "servicedw.servicedw_ptname", + "expandLevel": -1, + "isRecordSize": false, + "enableCascade": false, + "CascadeStatus": "default", + "helpId": "446c8fc6-f1d2-4b6c-a364-9c50e1eeba6f", + "cascadeStatus": "enable", + "isTextArea": true, + "span": 1, + "titleSourceType": "static", + "useExtendInfo": false, + "textAlign": "left", + "selectFirstInNav": false, + "loadDataWhenOpen": true + } + ], + "sectionCollapseVisible": false, + "isScrollSpyItem": false, + "visible": true, + "draggable": false, + "span": 4, + "columns": 4 + }, + { + "id": "id_5844b5a4_4503_4d88_b626_4c6fa8bac3f7_n8b1", + "type": "TextBox", + "title": "ID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "id", + "field": "5844b5a4-4503-4d88-b626-4c6fa8bac3f7" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "id", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "parentID_f577c3ea_f7ca_4458_814e_672937e76cf2_dbfb", + "type": "TextBox", + "title": "ParentID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "parentID", + "field": "f577c3ea-f7ca-4458-814e-672937e76cf2" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "parentID", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "ysee_911232f4_3beb_4f63_a801_334ad6d3319a_9x8x", + "type": "NumericBox", + "title": "营收额", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "ysee", + "field": "911232f4-3beb-4f63-a801-334ad6d3319a" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "right", + "precision": 3, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": true, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "ysee", + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "lrr_34f6b51e_d602_4900_8ed4_1affbfe6fc3f_fjz7", + "type": "NumericBox", + "title": "利润", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "lrr", + "field": "34f6b51e-d602-4900-8ed4-1affbfe6fc3f" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "center", + "precision": 4, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": true, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "lrr", + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + } + ], + "controlsInline": true, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "sprovider1-component", + "type": "Component", + "viewModel": "sprovider1-component-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "sprovider1-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "服务商往1", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "sprovider1-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "size": null, + "contents": [ + { + "id": "id_210d022d_55ee_4844_8615_a82baa4ed41a_4vz6", + "type": "TextBox", + "title": "ID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "id", + "field": "210d022d-55ee-4844-8615-a82baa4ed41a" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "id", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "code1_22e239cc_fc3e_48da_a39b_dabf0f1ba8bd_xjhb", + "type": "TextBox", + "title": "商往1", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "code1", + "field": "22e239cc-fc3e-48da-a39b-dabf0f1ba8bd" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "code1", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "parentID_d31c99b7_608a_45f0_8ed9_d6b5b8a1ad49_ku73", + "type": "TextBox", + "title": "ParentID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "parentID", + "field": "d31c99b7-608a-45f0-8ed9-d6b5b8a1ad49" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "parentID", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "code2_2ca023be_6483_409b_a924_5870d3f43973_bj0j", + "type": "DateBox", + "title": "商往2", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "code2", + "field": "2ca023be-6483-409b-a924-5870d3f43973" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": false, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": null, + "minValue": null, + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "Date", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "code2", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "code3_74d8bdf3_d185_454a_a802_61984539a4ff_c4rt", + "type": "DateBox", + "title": "商往3", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "code3", + "field": "74d8bdf3-d185-454a-a802-61984539a4ff" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "validation": null, + "value": null, + "editable": true, + "dateRange": false, + "showTime": true, + "showType": 1, + "dateFormat": "yyyy-MM-dd", + "returnFormat": "yyyy-MM-dd", + "maxValue": "2020-09-30 01:01:01", + "minValue": "2020-09-01 23:59:59", + "disableDates": [], + "showWeekNumbers": false, + "dateRangeDatesDelimiter": "~", + "shortcuts": [], + "fieldType": "DateTime", + "useDefault": false, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "code3", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "cod4_221744dc_b0b6_4a2e_b09c_6deec360cc47_cn58", + "type": "Avatar", + "title": "商往4", + "size": null, + "disable": false, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "border": null, + "cover": "", + "maxSize": null, + "imgType": [ + "png", + "jpg", + "jpeg" + ], + "imgShape": "square", + "readonly": "!viewModel.stateMachine['editable']", + "imgTitle": null, + "imgChange": null, + "visible": true, + "require": false, + "binding": { + "type": "Form", + "path": "cod4", + "field": "221744dc-b0b6-4a2e-b09c-6deec360cc47" + }, + "path": "cod4", + "isTextArea": true, + "span": 1 + } + ], + "controlsInline": true, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + }, + { + "id": "sprovider1child-component", + "type": "Component", + "viewModel": "sprovider1child-component-viewmodel", + "componentType": "form-col-4", + "appearance": { + "class": "f-struct-wrapper" + }, + "onInit": "", + "contents": [ + { + "id": "sprovider1child-section", + "type": "Section", + "appearance": { + "class": "f-section-form f-section-in-mainsubcard" + }, + "visible": true, + "mainTitle": "服务商往1子", + "subTitle": "", + "headerClass": "", + "titleClass": "", + "extendedHeaderAreaClass": "", + "toolbarClass": "", + "extendedAreaClass": "", + "contentTemplateClass": "", + "fill": false, + "expanded": true, + "enableMaximize": false, + "enableAccordion": true, + "accordionMode": "default", + "showHeader": true, + "headerTemplate": "", + "titleTemplate": "", + "extendedHeaderAreaTemplate": "", + "toolbarTemplate": "", + "extendedAreaTemplate": "", + "contents": [ + { + "id": "sprovider1child-layout", + "type": "Form", + "appearance": { + "class": "f-form-layout farris-form farris-form-controls-inline" + }, + "size": null, + "contents": [ + { + "id": "id_95562000_d8c2_440f_812f_9ddd746af0c6_prbe", + "type": "TextBox", + "title": "ID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "id", + "field": "95562000-d8c2-440f-812f-9ddd746af0c6" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "id", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "parentID_c6e127df_6c2c_4be4_8ad8_12e6cda8ce02_bd50", + "type": "TextBox", + "title": "ParentID", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "parentID", + "field": "c6e127df-6c2c-4be4-8ad8-12e6cda8ce02" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "parentID", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "codechild1_6c540196_0fa3_48d0_be38_37f9cccc1fd2_q584", + "type": "TextBox", + "title": "codechild1", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "codechild1", + "field": "6c540196-0fa3-48d0-be38-37f9cccc1fd2" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "format": null, + "validation": null, + "value": null, + "maxLength": 36, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "holdPlace": false, + "isPassword": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "codechild1", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "codechild2_f3e72fcc_aa3d_43b8_9390_5252ceee20fa_t8a7", + "type": "CheckGroup", + "title": "codechild2", + "controlSource": "Farris", + "checked": false, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "binding": { + "type": "Form", + "path": "codechild2", + "field": "f3e72fcc-aa3d-43b8-9390-5252ceee20fa" + }, + "visible": true, + "size": null, + "holdPlace": false, + "isTextArea": true, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "setCheckboxData": "", + "items": [ + { + "value": "0", + "name": "值0" + }, + { + "value": "1", + "name": "值1" + }, + { + "value": "2", + "name": "值2" + }, + { + "value": "true", + "name": "是" + } + ], + "isHorizontal": true, + "splitter": null, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "dataSourceType": "static", + "textField": "name", + "valueField": "value", + "path": "codechild2", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "codechild4_dde6acee_b662_48f8_b1de_aff344688b75_5ht9", + "type": "NumericBox", + "title": "codechild4", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "codechild4", + "field": "dde6acee-b662-48f8-b1de-aff344688b75" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": true, + "disable": false, + "placeHolder": "", + "textAlign": "center", + "precision": 0, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "maxLength": 0, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "codechild4", + "isTextArea": true, + "canNull": true, + "bigNumber": false, + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + }, + { + "id": "codechild3_9a4915e1_2a1f_4207_8eca_7f6f64cc4426_co6t", + "type": "CheckBox", + "title": "codechild3", + "checked": false, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "binding": { + "type": "Form", + "path": "codechild3", + "field": "9a4915e1-2a1f-4207-8eca-7f6f64cc4426" + }, + "visible": true, + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "vsize": null, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "holdPlace": false, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "codechild3", + "isTextArea": true, + "span": 1, + "titleSourceType": "static" + }, + { + "id": "codechild5_6cd616e9_8485_48bd_addf_eb7c1cf3f055_k17i", + "type": "NumericBox", + "title": "codechild5", + "controlSource": "Farris", + "appearance": { + "class": "col-12 col-md-6 col-xl-3 col-el-3 col-el-2" + }, + "size": null, + "binding": { + "type": "Form", + "path": "codechild5", + "field": "6cd616e9-8485-48bd-addf-eb7c1cf3f055" + }, + "readonly": "!viewModel.stateMachine['editable']", + "require": false, + "disable": false, + "placeHolder": "", + "textAlign": "left", + "precision": 2, + "validation": null, + "maxValue": null, + "minValue": null, + "step": 1, + "useThousands": true, + "formatter": null, + "parser": null, + "canNull": true, + "bigNumber": true, + "maxLength": 36, + "holdPlace": false, + "valueChange": null, + "linkedLabelEnabled": false, + "linkedLabelClick": null, + "visible": true, + "isTextArea": true, + "tabindex": -1, + "hasDefaultFocus": false, + "focusState": null, + "titleWidth": null, + "path": "codechild5", + "span": 1, + "titleSourceType": "static", + "precisionSourceType": "static" + } + ], + "controlsInline": true, + "formAutoIntl": true, + "visible": true, + "draggable": false, + "columns": 4 + } + ], + "draggable": false + } + ], + "afterViewInit": "" + } + ], + "webcmds": [ + { + "id": "8172a979-2c80-4637-ace7-b13074d3f393", + "path": "/projects/packages/Inspur.GS.Gsp.Web.WebCmp/webcmd", + "name": "CardController.webcmd", + "refedHandlers": [ + { + "host": "e05264fb-796d-43fb-b83b-9e2f3866c328", + "handler": "Load" + }, + { + "host": "246a275c-88c9-4c8a-aa82-be6a950a4325", + "handler": "LoadAndAdd" + }, + { + "host": "70acc053-fa15-45be-851c-cf694e1bcaf7", + "handler": "LoadAndView" + }, + { + "host": "3e72ee6f-8f7b-4f29-aa0e-5887f2861117", + "handler": "LoadAndEdit" + }, + { + "host": "89904e71-5b79-9caf-b9d6-77e878cc1552", + "handler": "cascadeAdd" + }, + { + "host": "a323e27b-b9c6-4848-93b9-f117403a94ff", + "handler": "Edit" + }, + { + "host": "31b814db-01e4-407d-8fad-0f08dbb01999", + "handler": "Save" + }, + { + "host": "4f5ed2ec-8def-4a3c-8e7b-397ea93010e8", + "handler": "Cancel" + }, + { + "host": "f8f2dbef-56a3-4514-a3c4-c275d5ecf421", + "handler": "Close" + }, + { + "host": "c8504c24-33e8-487a-91ce-2218b803fe01", + "handler": "ChangeItem" + }, + { + "host": "4a0cfb1a-1262-41a2-aeb9-c8edd5c09683", + "handler": "ChangeItem" + } + ] + }, + { + "id": "b250f84f-a499-406a-9d6b-687a8b56d76c", + "path": "Scm/SD/ComBinForm/br-reimbursement/metadata/components", + "name": "GroupBTCZC_frm_setvirValue.webcmd", + "refedHandlers": [ + { + "host": "78706cba-de76-4d92-b5be-17a9ddd25b9b", + "handler": "setvirValue" + }, + { + "host": "22ea0700-0814-4ef2-958b-fb0d48252c38", + "handler": "buttonzdy" + }, + { + "host": "ba5fdf9a-1d20-46f0-aa5d-ce5f2ae83bf8", + "handler": "buttonzdy" + }, + { + "host": "2b23e8db-a1af-4cbb-9767-debba60ea354", + "handler": "overLoad" + } + ] + } + ], + "serviceRefs": [], + "projectName": "br-reimbursement", + "templateId": "show-sub-table-by-card-template", + "customClass": { + "root-component": "", + "basic-form-component": "" + } + }, + "options": { + "enableDragAndDropToModifyLayout": false, + "enableTextArea": true + } +} diff --git a/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListenerTest.java b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListenerTest.java new file mode 100644 index 00000000..aadd31cc --- /dev/null +++ b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/lic/FormMetadataCreateLicControlListenerTest.java @@ -0,0 +1,37 @@ +package com.inspur.edp.web.formmetadata.lic; + +import com.inspur.edp.web.common.constant.MetadataConstant; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.*; + +public class FormMetadataCreateLicControlListenerTest { + + @Test + public void metadataCreateControl() { + List MODULE_WITH_METADATA_TYPE_LIST = new ArrayList<>(); + ModuleWithMetadataType formModuleType = new ModuleWithMetadataType(); + formModuleType.setModuleType("WDP"); + formModuleType.getMetadataTypeList().add(MetadataConstant.FORM_METADATA_TYPE); + MODULE_WITH_METADATA_TYPE_LIST.add(formModuleType); + + ModuleWithMetadataType mobileFormModuleType = new ModuleWithMetadataType(); + mobileFormModuleType.setModuleType("MDP"); + mobileFormModuleType.getMetadataTypeList().add(MetadataConstant.MOBILE_FORM_METADATA_TYPE); + MODULE_WITH_METADATA_TYPE_LIST.add(mobileFormModuleType); + + String metaType = "Form"; + Optional filterModuleType = MODULE_WITH_METADATA_TYPE_LIST.stream().filter(t -> t.getMetadataTypeList().contains(metaType)).findFirst(); + assertTrue(filterModuleType.isPresent()); + assertEquals(filterModuleType.get().getModuleType(), "WDP"); + + String mobileMetaType = "MobileForm"; + filterModuleType = MODULE_WITH_METADATA_TYPE_LIST.stream().filter(t -> t.getMetadataTypeList().contains(mobileMetaType)).findFirst(); + assertTrue(filterModuleType.isPresent()); + assertEquals(filterModuleType.get().getModuleType(), "MDP"); + } +} \ No newline at end of file diff --git a/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializerTest.java b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializerTest.java new file mode 100644 index 00000000..80e1d8ab --- /dev/null +++ b/web-form-metadata/src/test/java/com/inspur/edp/web/formmetadata/serializer/FormMetadataContentSerializerTest.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.formmetadata.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import org.junit.jupiter.api.Test; + +class FormMetadataContentSerializerTest { + + // @Test + void serialize() { + FormMetadataContent formMetadataContent = new FormMetadataContent(); + formMetadataContent.setCode("ggg"); + formMetadataContent.setId("fdfdfdf"); + + + JsonNode result = SerializeUtility.getInstance().valueToJson(formMetadataContent, PropertyNamingStrategy.UPPER_CAMEL_CASE); + + + + } +} diff --git a/web-form-process-api/pom.xml b/web-form-process-api/pom.xml new file mode 100644 index 00000000..306327b8 --- /dev/null +++ b/web-form-process-api/pom.xml @@ -0,0 +1,19 @@ + + + + web + com.inspur.edp + 0.1.0-SNAPSHOT + + 4.0.0 + + web-form-process-api + + + 8 + 8 + + + \ No newline at end of file diff --git a/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java b/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java new file mode 100644 index 00000000..7f3b6c89 --- /dev/null +++ b/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java @@ -0,0 +1,5 @@ +package com.inspur.edp.web.form.process.api.service; + +public interface FormProcessService { + void publishFormFormatForNoCode(String formId, String boId, String microAppCode, String deviceType); +} diff --git a/web-form-process/pom.xml b/web-form-process/pom.xml new file mode 100644 index 00000000..854fdd3c --- /dev/null +++ b/web-form-process/pom.xml @@ -0,0 +1,58 @@ + + + + web + com.inspur.edp + 0.1.0-SNAPSHOT + + 4.0.0 + + web-form-process + + + io.iec.edp + caf-boot-starter-rest-server + 0.3.5 + + + com.inspur.edp + lcm-metadata-api + 0.1.23 + + + com.inspur.edp + lcm-metadata-api + 0.1.23 + compile + + + com.inspur.edp + metadata-businesstype-api + 0.1.3 + compile + + + io.iec.edp + caf-rpc-client + + + com.inspur.edp + wf-bizprocess-api + 0.1.9 + + + io.iec.edp + caf-business-object-api + 0.1.5 + + + com.inspur.edp + web-form-process-api + ${project.version} + + + + + \ No newline at end of file diff --git a/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java b/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java new file mode 100644 index 00000000..b700acc9 --- /dev/null +++ b/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.form.process.config; + +import com.inspur.edp.web.form.process.service.FormProcessServiceImpl; +import com.inspur.edp.web.form.process.service.FormProcessWebService; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration("com.inspur.ed.web.form.process.config.FormProcessConfiguration") +public class FormProcessConfiguration { + @Bean + public RESTEndpoint formProcessWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/form/form-process", new FormProcessWebService()); + } + + @Bean + public FormProcessServiceImpl getFormProcessService() { + return new FormProcessServiceImpl(); + } +} diff --git a/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java b/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java new file mode 100644 index 00000000..fb86ae8d --- /dev/null +++ b/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java @@ -0,0 +1,119 @@ +package com.inspur.edp.web.form.process.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.lcm.metadata.api.service.NoCodeService; +import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService; +import com.inspur.edp.web.form.process.api.service.FormProcessService; +import com.inspur.edp.wf.bizprocess.entity.FormFormat; +import com.inspur.edp.wf.bizprocess.entity.UrlParameter; +import com.inspur.edp.wf.bizprocess.service.FormFormatRpcService; +import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo; +import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.rpc.client.RpcClassHolder; + +import java.util.Arrays; +import java.util.List; + +public class FormProcessServiceImpl implements FormProcessService { + + private static class LazyHolder { + private static final FormProcessServiceImpl INSTANCE = new FormProcessServiceImpl(); + } + public FormProcessServiceImpl() {} + + public static final FormProcessServiceImpl getInstance() { + return LazyHolder.INSTANCE; + } + + public void publishFormFormat(String formId, String formPath) { + if (formPath == null || formPath.equals("")) { + throw new RuntimeException("参数path不允许为空。"); + } + + String unifiedPath = formPath.replace('\\', '/'); + if (unifiedPath.startsWith("/")) { + unifiedPath = unifiedPath.substring(1); // 去掉开头的/ + } + + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + + List mdList = metadataService.getMetadataList(unifiedPath); + GspMetadata md = mdList.stream().filter(item -> item.getHeader().getId().equals(formId)).findFirst().orElse(null); + if (md == null) { + throw new RuntimeException("找不到表单元数据: " + formId + "。文件路径:" + unifiedPath + "。"); + } + MetadataHeader header = md.getHeader(); + GspProject project = metadataService.getGspProjectInfo(unifiedPath); + String deploymentPath = project.getSuDeploymentPath(); + String projectName = project.getMetadataProjectName().toLowerCase(); + String url = "/" + deploymentPath + "/web/" + projectName + "/" + "index.html#/" + header.getCode(); + String boId = project.getBizobjectID(); + + pushFormFormat(formId, md, url, boId); + } + + @Override + public void publishFormFormatForNoCode(String formId, String boId, String microAppCode, String deviceType) { + + + // 获取表单 + NoCodeService noCodeService =SpringBeanUtils.getBean(NoCodeService.class); + GspMetadata formMetadata = noCodeService.getMetadata(formId); + + // 根据bo获取app/su路径 + DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class); + DevBasicBoInfo boInfo = devBasicInfoService.getDevBasicBoInfo(boId); + String deploymentPath = boInfo.getAppCode() + "/" + boInfo.getSuCode(); + + // \web\apps\scm\sd\web\bo-salesorder2103front + String devicePath = "mobile".equals(deviceType) ? "mob" : "web"; + String url = "/" + deploymentPath + "/" + devicePath + "/" + microAppCode + "/" + "index.html#/" + formMetadata.getHeader().getCode(); + + pushFormFormat(formId, formMetadata, url, boId); + } + + private void pushFormFormat(String formId, GspMetadata formMetadta, String url, String boId) { + // 组织参数,调用工作流接口。 + FormFormat ff = new FormFormat(); + ff.setId(formId); + ff.setCode(formMetadta.getHeader().getCode()); + ff.setName(formMetadta.getHeader().getName()); + ff.setUrlType("url"); + ff.setFormUrl(url); + + UrlParameter actionParam = new UrlParameter(); + actionParam.setCode("action"); + actionParam.setName("动作"); + actionParam.setValue("LoadAndView1"); + UrlParameter idParam = new UrlParameter(); + idParam.setCode("id"); + idParam.setName("内码"); + idParam.setValue("{\"expr\":\"DefaultFunction.GetContextParameter(\\\"dataId\\\")\",\"sexpr\":\"\"}\n"); + List list = Arrays.asList(actionParam, idParam); + // UrlParameter param1 = new UrlParameter(); + // param1.setCode("expr"); + // param1.setValue("DefaultFunction.GetContextParameter(\\\"dataId\\\")"); + // UrlParameter param2 = new UrlParameter(); + // param2.setCode("sexpr"); + // param2.setValue(""); + // List list = Arrays.asList(param1, param2); + ff.setUrlParameters(list); + ff.setFormatType("wf"); + + ff.setBizCategory(getBizTypeId(boId)); + + RpcClassHolder rpcHelper = SpringBeanUtils.getBean(RpcClassHolder.class); + FormFormatRpcService service = rpcHelper.getRpcClass(FormFormatRpcService.class); + service.addFormFormat(ff); + } + + private String getBizTypeId(String bizObjectId) { + MdBizTypeMappingService service = SpringBeanUtils.getBean(MdBizTypeMappingService.class); + List bizTypeIds = service.getBizTypeIdsByBoId(bizObjectId); + return bizTypeIds == null || bizTypeIds.size() == 0 ? "" : bizTypeIds.get(0); + } +} diff --git a/web-frontendproject-api/pom.xml b/web-frontendproject-api/pom.xml new file mode 100644 index 00000000..3aea7893 --- /dev/null +++ b/web-frontendproject-api/pom.xml @@ -0,0 +1,24 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-frontendproject-api + + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-jitengine-runtimebuild-api + + + diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormItem.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormItem.java new file mode 100644 index 00000000..ed00babe --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormItem.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.frontendproject.entity; + +import lombok.Data; + +/** + * @Title: ChosenFormItem + * @Description: com.inspur.edp.web.frontendproject.entity 选择的表单选项 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/14 10:55 + */ +@Data +public class ChosenFormItem { + /** + * 表单code + */ + private String formCode; + + /** + * 是否强制使用解析 + */ + private boolean isForceDynamicForm; + + @Override + public boolean equals(Object o) { + if (o instanceof ChosenFormItem) { + ChosenFormItem formItem = (ChosenFormItem) o; + return this.formCode.equals(formItem.getFormCode()); + } + return super.equals(o); + } + + @Override + public String toString() { + return "ChosenFormItem [formCode=" + formCode +", isForceDynamicForm=" + + isForceDynamicForm + "]"; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormList.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormList.java new file mode 100644 index 00000000..93390c06 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/ChosenFormList.java @@ -0,0 +1,138 @@ +package com.inspur.edp.web.frontendproject.entity; + +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 选中的表单元数据列表 + * + * @author guozhiqi + */ +public class ChosenFormList { + /** + * 私有构造方法 + */ + private ChosenFormList() { + } + + /** + * 获取新实例 每次调用都会创建新的实例 + * + * @return + */ + public static ChosenFormList getNewInstance() { + return new ChosenFormList(); + } + + private List itemList; + + /** + * 获取对应的选中表单code列表 + * 入股code列表实例为空,那么进行实例化 + * + * @return + */ + public List getItemList() { + if (itemList == null) { + itemList = new ArrayList<>(); + } + return itemList; + } + + /** + * 依据formCode获取对应的选中项 + * + * @param formCode + * @return + */ + public Optional getByFormCode(String formCode) { + if (!this.contains(formCode)) { + return Optional.ofNullable(null); + } + return this.getItemList().stream().filter(t -> t.getFormCode().equals(formCode)).findFirst(); + } + + /** + * 获取是否强制解析模式 + * + * @param formCode + * @return + */ + public boolean getIsDynamicFormByFormCode(String formCode) { + Optional selectChosenItem = this.getByFormCode(formCode); + return selectChosenItem.map(ChosenFormItem::isForceDynamicForm).orElse(false); + } + + /** + * 包含的列表项是否为空 + * + * @return + */ + public boolean isEmpty() { + return this.getItemList().isEmpty(); + } + + /** + * 包含的列表项不为空 + * @return + */ + public boolean isNotEmpty() { + return !this.isEmpty(); + } + + /** + * 是否包含指定的code + * + * @param formCode + * @return + */ + public boolean contains(String formCode) { + if (StringUtility.isNullOrEmpty(formCode)) { + return false; + } + return this.getItemList().stream().anyMatch(t -> t.getFormCode().equals(formCode)); + } + + /** + * 添加待生成、编译的表单code + * + * @param formCode + */ + public void add(String formCode) { + this.addOrUpdate(formCode, false); + } + + /** + * 添加待生成、编译的表单code + * + * @param formCode + */ + public void add(String formCode, boolean isForceDynamicForm) { + this.addOrUpdate(formCode, isForceDynamicForm); + } + + /** + * 新增或更新表单选项 + * + * @param formCode + * @param isForceDynamicForm + */ + public void addOrUpdate(String formCode, boolean isForceDynamicForm) { + if (StringUtility.isNullOrEmpty(formCode)) { + return; + } + + if (this.contains(formCode)) { + ChosenFormItem selectFormItem = this.getItemList().stream().filter(t -> t.getFormCode().equals(formCode)).findFirst().get(); + selectFormItem.setForceDynamicForm(isForceDynamicForm); + } else { + ChosenFormItem formItem = new ChosenFormItem(); + formItem.setFormCode(formCode); + formItem.setForceDynamicForm(isForceDynamicForm); + this.getItemList().add(formItem); + } + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/FrontendProjectGenerateParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/FrontendProjectGenerateParameter.java new file mode 100644 index 00000000..b6072e47 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/FrontendProjectGenerateParameter.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.frontendproject.entity; + +/** + * 前端工程生成参数 + */ +public class FrontendProjectGenerateParameter { + + /** + * 是否强制启用解析 + */ + private boolean forceUseJieXi = false; + + /** + * 工程路径 + */ + private String projectPath; + + /** + * 参与生成的表单列表 + */ + private ChosenFormList buildFormList; + + + public boolean isForceUseJieXi() { + return forceUseJieXi; + } + + public void setForceUseJieXi(boolean forceUseJieXi) { + this.forceUseJieXi = forceUseJieXi; + } + + public String getProjectPath() { + return projectPath; + } + + public void setProjectPath(String projectPath) { + this.projectPath = projectPath; + } + + public ChosenFormList getBuildFormList() { + if (buildFormList == null) { + buildFormList = ChosenFormList.getNewInstance(); + } + return buildFormList; + } + + public void setBuildFormList(ChosenFormList buildFormList) { + this.buildFormList = buildFormList; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/RestMessage.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/RestMessage.java new file mode 100644 index 00000000..fb40474b --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/RestMessage.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.frontendproject.entity; + + +/** + * npm包安装响应 + * + * @author noah + */ +public class RestMessage { + /** + * 是否执行成功标识 + */ + private boolean success = true; + /** + * 执行失败 错误信息提示 + */ + private String errorMessage; + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + + public Object getExtraData() { + return extraData; + } + + public void setExtraData(Object extraData) { + this.extraData = extraData; + } + + /** + * 额外的数据传递 + */ + public Object extraData; + + + public static RestMessage create() { + return new RestMessage(); + } + public static RestMessage createError(String errorMessage) { + RestMessage npmPackageResponse=new RestMessage(); + npmPackageResponse.setErrorMessage(errorMessage); + npmPackageResponse.setSuccess(false); + return npmPackageResponse; + } + +} + diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataItem.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataItem.java new file mode 100644 index 00000000..2e71be06 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataItem.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.frontendproject.entity.resolver; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import lombok.Data; + +/** + * resolve参数 + * + * @Title: ResolveFormMetadataItem + * @Description: com.inspur.edp.web.frontendproject.resolver + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/14 16:42 + */ +@Data +public class ResolveFormMetadataItem { + /** + * 表单关联的元数据 + */ + private GspMetadata gspMetadata; + /** + * 是否强制使用解析方式 请不要使用该参数直接判断表单是否解析 + * 如果要判断表单是否解析,请使用getCalculateIsDynamicForm()方法 + */ + private boolean isForceDynamicForm; + + /** + * 表单元数据标识的解析标识 + * 此参数只标识表单元数据得解析标识,不作为表单最终是否以解析模式运行得依据, + * 如果要判断表单是否解析,请使用getCalculateIsDynamicForm + */ + private boolean isFormDynamicTag; + + /** + * 合并是否解析表单标签 + * @return + */ + public boolean getCalculateIsDynamicForm() { + if (this.isForceDynamicForm) { + return true; + } + return this.isFormDynamicTag; + } + + +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataList.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataList.java new file mode 100644 index 00000000..08d8d69e --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/entity/resolver/ResolveFormMetadataList.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.frontendproject.entity.resolver; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.utility.ListUtility; + +import java.util.ArrayList; +import java.util.List; + +/** + * @Title: ResolveFormMetadataList + * @Description: com.inspur.edp.web.frontendproject.resolver + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/14 16:34 + */ +public class ResolveFormMetadataList { + + private ResolveFormMetadataList() { + } + + public static ResolveFormMetadataList getNewInstance() { + return new ResolveFormMetadataList(); + } + + private List resolveFormMetadataItemList; + + /** + * @return + */ + public List getResolveFormMetadataItemList() { + if (this.resolveFormMetadataItemList == null) { + this.resolveFormMetadataItemList = new ArrayList<>(); + } + return resolveFormMetadataItemList; + } + + /** + * 增加具体的元数据项 + * @param gspMetadata + * @param isForceDynamicForm + */ + public void add(GspMetadata gspMetadata, boolean isForceDynamicForm,boolean dynamicFormTag) { + if (this.getResolveFormMetadataItemList().stream().anyMatch(t -> t.getGspMetadata().equals(gspMetadata))) { + ResolveFormMetadataItem selectedFormMetadataItem = this.getResolveFormMetadataItemList().stream().filter(t -> t.getGspMetadata().equals(gspMetadata)).findFirst().get(); + selectedFormMetadataItem.setForceDynamicForm(isForceDynamicForm); + selectedFormMetadataItem.setFormDynamicTag(dynamicFormTag); + } else { + ResolveFormMetadataItem resolveFormMetadataItem = new ResolveFormMetadataItem(); + resolveFormMetadataItem.setGspMetadata(gspMetadata); + resolveFormMetadataItem.setForceDynamicForm(isForceDynamicForm); + resolveFormMetadataItem.setFormDynamicTag(dynamicFormTag); + this.getResolveFormMetadataItemList().add(resolveFormMetadataItem); + } + } + + /** + * 是否为空列表 + * + * @return + */ + public boolean isEmpty() { + return ListUtility.isEmpty(this.resolveFormMetadataItemList); + } + + /** + * 判断列表不为空 + * + * @return + */ + public boolean isNotEmpty() { + return !this.isEmpty(); + } + +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormDynamicParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormDynamicParameter.java new file mode 100644 index 00000000..6ee5c11f --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormDynamicParameter.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.frontendproject.webservice; + +/** + * 表单解析参数 + * + * @author guozhiqi + */ +public class FormDynamicParameter { + + /** + * 工程路径 + */ + private String projectPath; + /** + * 表单code 如果增加该参数 那么使用单独的表单解析 + * 如果不包含该参数 那么使用工程路径解析 + */ + private String formCode; + + /** + * 是否仅使用单个表单进行解析 + * 如果设置单个表单解析,那么formCode参数必须有值 + * 如果不是单个表单解析,那么formCode参数必须为空 + */ + private boolean useSingleForm = false; + + public String getProjectPath() { + return projectPath; + } + + public void setProjectPath(String projectPath) { + this.projectPath = projectPath; + } + + public String getFormCode() { + return formCode; + } + + public void setFormCode(String formCode) { + this.formCode = formCode; + } + + public boolean isUseSingleForm() { + return useSingleForm; + } + + public void setUseSingleForm(boolean useSingleForm) { + this.useSingleForm = useSingleForm; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebService.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebService.java new file mode 100644 index 00000000..a16e6d30 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebService.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +/** + * 表单元数据调试Uri Web API + */ +@Path("/") +public interface FormMetadataDebugUriWebService { + /** + * 获取PC表单元数据的部署uri + */ + @Path("/") + @GET + String getFormMetadataDebugUri(@QueryParam("formMetadataRelativePath") String formMetadataRelativePath, @QueryParam("formMetadataId") String formMetadataId); + + /** + * 获取表单元数据的部署uri + * + * @param formMetadataRelativePath + * @param formMetadataId + * @param formType + * @return + */ + @Path("/form-type") + @GET + String getFormMetadataDebugUriByFormType(@QueryParam("formMetadataRelativePath") String formMetadataRelativePath, + @QueryParam("formMetadataId") String formMetadataId, + @QueryParam("formType") String formType); +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebService.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebService.java new file mode 100644 index 00000000..1d582cfe --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebService.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import com.inspur.edp.web.common.entity.ResultMessage; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; + +@Path("/") +public interface FrontendProjectWebService { + + /** + * 判断当前工程是否是前端工程 + * @param projectPath 工程路径 + * @return + */ + @GET + @Path("/is-frontend-project") + boolean isFrontendProject(@QueryParam("projectPath") String projectPath); + + + @POST + @Path("/resolve") + void resolveFrontendProject(@QueryParam("projectPath") String projectPath); + + @POST + @Path("/generate") + void generateFrontendProject(@QueryParam("projectPath") String projectPath); + + @POST + @Path("/build") + ResultMessage buildFrontendProject(@QueryParam("projectPath") String projectPath); + + @POST + @Path("/resolve-generate") + void resolveAndGenerateFrontendProject(@QueryParam("projectPath") String projectPath); + + @POST + @Path("/resolve-generate-build") + ResultMessage resolveAndGenerateAndBuildFrontendProject(@QueryParam("projectPath") String projectPath); + + + @POST + @Path("/deploy") + void deployFrontendProject(@QueryParam("projectPath") String projectPath); + + @POST + @Path("/one-key-deploy") + void oneKeyDeployFrontendProject(@QueryParam("projectPath") String projectPath); + + /** + * 使用babel编译前端工程并部署。 + */ + @POST + @Path("/babel-build-deploy") + void babelBuildAndDeploy(@QueryParam("projectPath") String projectPath, @QueryParam("formCode") String formCode); + + /** + * 解析表单生成 解析表单预览 + * 仅生成该表单相关的依赖脚本 + * @param dynamicParameter 解析参数 + */ + @POST + @Path("/generate-for-interpretation") + ResultMessage generateFrontendProjectWithDynamic(@RequestBody FormDynamicParameter dynamicParameter); +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebService.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebService.java new file mode 100644 index 00000000..1ba2698b --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebService.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import com.inspur.edp.web.frontendproject.entity.RestMessage; + +import javax.ws.rs.Path; +import javax.ws.rs.GET; +import javax.ws.rs.QueryParam; + +@Path("/") +public interface ZeroCodeWebService { + + /** + * 请求跳转前加载对应文件内容 + * + * @param indexHtmlUrl 默认首页url地址 /web/apps/.../index.html + * @param options 可选参数 + * @return + */ + @GET() + @Path("/beforenavigate") + RestMessage beforeNavigateLoadFile(@QueryParam("url") String indexHtmlUrl, @QueryParam("routeUri") String routeUri, @QueryParam("options") String options); +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormFormatParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormFormatParameter.java new file mode 100644 index 00000000..a880afa9 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormFormatParameter.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import lombok.Getter; + +public class ZeroCodeFormFormatParameter { + + /** + * 表单格式配置ID + */ + @Getter + private String formFormatConfigId; + + @Getter + private IMetadataContent metadataContent; + + ZeroCodeFormFormatParameter(String formFormatConfigId, IMetadataContent metadataContent) { + this.formFormatConfigId = formFormatConfigId; + this.metadataContent = metadataContent; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormParameter.java new file mode 100644 index 00000000..5b96d781 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormParameter.java @@ -0,0 +1,130 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 零代码表单关联参数 + */ +public class ZeroCodeFormParameter { + + private GspMetadata metadata; + /** + * 表单元数据code + */ + private String code; + /** + * 表单源苏剧name + */ + private String name; + + /** + * 表单关联的元数据列表,例如 状态机 + */ + private List refMetadataParameters; + + /** + * 是否移动表单 + */ + private boolean isMobile=false; + + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getRefMetadataParameters() { + if (this.refMetadataParameters == null) { + this.refMetadataParameters = new ArrayList<>(); + } + return refMetadataParameters; + } + + public void setRefMetadataParameters(List refMetadataParameters) { + this.refMetadataParameters = refMetadataParameters; + } + + public GspMetadata getMetadata() { + return metadata; + } + + public void setMetadata(GspMetadata metadata) { + this.metadata = metadata; + } + + /** + * 获取指定类型的元数据 + * + * @param metadataTypeEnum + * @return + */ + public List getSpecialFormRefMetaData(JitMetadataTypeEnum metadataTypeEnum) { + List filterFormRefMetadataParameters = new ArrayList<>(); + this.getRefMetadataParameters().forEach(t -> { + if (t.getMetadataType() == metadataTypeEnum) { + filterFormRefMetadataParameters.add(t); + } + }); + return filterFormRefMetadataParameters; + } + + + /** + * 获取指定类型的元数据 + * + * @param metadataId 指定元数据id + * @param metadataTypeEnum + * @return + */ + public ZeroCodeFormRefMetadataParameter getSpecialFormRefMetaData(String metadataId, JitMetadataTypeEnum metadataTypeEnum) { + AtomicReference formRefMetadataParameter = new AtomicReference<>(); + this.getRefMetadataParameters().forEach(t -> { + if (t.getMetadataType() == metadataTypeEnum && t.getMetadata().getHeader().getId().equals(metadataId)) { + formRefMetadataParameter.set(t); + } + }); + if (formRefMetadataParameter == null) { + return null; + } + return formRefMetadataParameter.get(); + } + + public boolean isMobile() { + return isMobile; + } + + public void setMobile(boolean mobile) { + isMobile = mobile; + } + + // region 零代码中由表单格式合并得到的表单 + + private List formFormatList = new ArrayList<>(); + + public List getFormFormatList() { + return this.formFormatList; + } + + public void addFormFormat(String configId, IMetadataContent metadataContent) { + this.formFormatList.add(new ZeroCodeFormFormatParameter(configId, metadataContent)); + } + + // endregion +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormRefMetadataParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormRefMetadataParameter.java new file mode 100644 index 00000000..0a2c3641 --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeFormRefMetadataParameter.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; + +/** + * 零代码表单关联元数据 + */ +public class ZeroCodeFormRefMetadataParameter { + /** + * 元数据内容 + */ + private GspMetadata metadata; + /** + * 元数据类型 + */ + private JitMetadataTypeEnum metadataType; + + public JitMetadataTypeEnum getMetadataType() { + return metadataType; + } + + public void setMetadataType(JitMetadataTypeEnum metadataType) { + this.metadataType = metadataType; + } + + public GspMetadata getMetadata() { + return metadata; + } + + public void setMetadata(GspMetadata metadata) { + this.metadata = metadata; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameter.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameter.java new file mode 100644 index 00000000..38f4311f --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameter.java @@ -0,0 +1,135 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 零代码参数 + * + * @author noah + */ +public class ZeroCodeParameter { + /** + * 生成的源代码的根路径 + */ + private String absoluteBasePath; + + /** + * 工程名称 + */ + private String projectName; + + + /** + * 依赖node_modules 路径 + */ + private String relyNodeModulesPath; + + /** + * serviceunit路径 scm/sd + */ + private String serviceUnitPath; + + private String originalServiceUnitPath; + + /** + * 服务环境目录 + */ + private String serverPath; + /** + * 一个表单--->包含多个元数据 + */ + private List formParameters; + + /** + * 是否使用解析模式 + */ + private boolean useJieXiMode = false; + + public boolean isUseJieXiMode() { + return useJieXiMode; + } + + public void setUseJieXiMode(boolean useJieXiMode) { + this.useJieXiMode = useJieXiMode; + } + + public String getAbsoluteBasePath() { + return absoluteBasePath; + } + + public void setAbsoluteBasePath(String absoluteBasePath) { + if (!StringUtility.isNullOrEmpty(absoluteBasePath)) { + absoluteBasePath = FileUtility.getPlatformIndependentPath(absoluteBasePath); + } + this.absoluteBasePath = absoluteBasePath; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getRelyNodeModulesPath() { + return relyNodeModulesPath; + } + + public void setRelyNodeModulesPath(String relyNodeModulesPath) { + this.relyNodeModulesPath = relyNodeModulesPath; + } + + public String getServiceUnitPath() { + return serviceUnitPath; + } + + public void setServiceUnitPath(String serviceUnitPath) { + this.serviceUnitPath = serviceUnitPath; + } + + public List getFormParameters() { + if (formParameters == null) { + formParameters = new ArrayList<>(); + } + return formParameters; + } + + public void setFormParameters(List formParameters) { + this.formParameters = formParameters; + } + + public String getServerPath() { + return serverPath; + } + + public void setServerPath(String serverPath) { + this.serverPath = serverPath; + } + + /** + * 判定是否包含指定类型的表单数据 + * + * @param terminalType + * @return + */ + public boolean hasFormParameter(TerminalType terminalType) { + boolean isMobile = terminalType == TerminalType.MOBILE; + List filterFormParameterList = this.getFormParameters().stream().filter(t -> t.isMobile() == isMobile).collect(Collectors.toList()); + return filterFormParameterList != null && filterFormParameterList.size() > 0; + } + + public String getOriginalServiceUnitPath() { + return originalServiceUnitPath; + } + + public void setOriginalServiceUnitPath(String originalServiceUnitPath) { + this.originalServiceUnitPath = originalServiceUnitPath; + } +} diff --git a/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeService.java b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeService.java new file mode 100644 index 00000000..0c8649cc --- /dev/null +++ b/web-frontendproject-api/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeService.java @@ -0,0 +1,37 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +/** + * 零代码service 主要提供代码生成、编译、部署 + * @author noah + */ +public interface ZeroCodeService { + + /** + * 解析表单元数据 生成对应的webdev json文件 生成ts代码依赖 + * @param zeroCodeParameter + */ + @Deprecated() + void resolveMetadataAndGenerateSource(ZeroCodeParameter zeroCodeParameter); + + /** + * 编译生成后的代码 + * @param zeroCodeParameter + */ + @Deprecated() + void build(ZeroCodeParameter zeroCodeParameter); + + /** + * 部署编译后的交付物 + * @param zeroCodeParameter + */ + @Deprecated() + void deploy(ZeroCodeParameter zeroCodeParameter); + + + /** + * 解析、编译、部署 + * @param zeroCodeParameter 零代码入参 + */ + void resolveBuildAndDeploy(ZeroCodeParameter zeroCodeParameter); + +} diff --git a/web-frontendproject/pom.xml b/web-frontendproject/pom.xml new file mode 100644 index 00000000..110156cf --- /dev/null +++ b/web-frontendproject/pom.xml @@ -0,0 +1,64 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-jitengine-frontendproject + + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-pageflow-metadata + + + com.inspur.edp + web-jitengine-formmetadata + + + com.inspur.edp + web-jitengine + + + com.inspur.edp + ide-setting-api + + + com.inspur.edp + web-jitengine-frontendproject-api + + + com.inspur.edp + lcm-debugger-api + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + lcm-metadata-spi + + + com.inspur.edp + web-npmpackage-core + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache-api + + + com.inspur.edp + web-jitengine-runtimebuild-scriptcache + + + diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectCompiler.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectCompiler.java new file mode 100644 index 00000000..1f43c5a5 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectCompiler.java @@ -0,0 +1,170 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataCompilerContext; +import com.inspur.edp.lcm.metadata.spi.MetadataCompileAction; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.logger.WebLogger; +import com.inspur.edp.web.common.utility.ListUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteManager; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataList; +import com.inspur.edp.web.frontendproject.generate.FrontendProjectGenerate; +import com.inspur.edp.web.frontendproject.metadata.FormMetadataManager; +import com.inspur.edp.web.frontendproject.resolver.FormMetadataResolver; +import com.inspur.edp.web.jitengine.JITEngineManager; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 前端工程编译器 + * 通过元数据的回调事件进行调用 + * + * @author guozhiqi + */ +@Slf4j +public class FrontendProjectCompiler implements MetadataCompileAction { + /** + * 工程编译扩展实现 + */ + @Override + public void metadataCompile(MetadataCompilerContext context) { + if (context == null || StringUtility.isNullOrEmpty(context.getProjectPath())) { + log.error("the Project Path is Empty When Compiling a Project"); + throw new GSPException("MetadataCompile", "the Project Path is Empty "); + } + + System.out.println("begin compile frontend project"); + generateAndCompileFrontendProject(context); + + } + + /** + * 编译前端工程 + */ + private void generateAndCompileFrontendProject(MetadataCompilerContext context) { + // 因为此处涉及到元数据的变更检测 因此不在乎此处进行route.json 文件的保存 + // 编译前端工程:面向PC设备 + if (FormMetadataManager.checkFormMetadataExists(context.getProjectPath(), TerminalType.PC, ChosenFormList.getNewInstance(), false, false)) { + generateAndCompileFrontendProject(context.getProjectPath(), TerminalType.PC, false); + } + + if (FormMetadataManager.checkFormMetadataExists(context.getProjectPath(), TerminalType.MOBILE, ChosenFormList.getNewInstance(), false, false)) { + // 编译前端工程:面向Mobile设备 + generateAndCompileFrontendProject(context.getProjectPath(), TerminalType.MOBILE, false); + } + } + + /** + * 前端工程的编译分为四步:预编译、将表单元数据(.frm)解析成 JSON、基于 JSON 生成前端代码(如Angular、Vue等)、将前端代码构建成 JS + * + * @param projectPath 待编译工程路径 + */ + private void generateAndCompileFrontendProject(String projectPath, TerminalType terminalType, boolean isJieXiForm) { + + // 执行前端工程代码生成 如果生成失败 那么不进行编译动作 + if (generateFrontendProject(projectPath, terminalType)) { + return; + } + + // 将前端代码构建成 JS + buildFrontendProject(projectPath, terminalType); + } + + /** + * 生成前端工程代码 + * + * @param projectPath + * @param terminalType + * @return + */ + private boolean generateFrontendProject(String projectPath, TerminalType terminalType) { + // 1. 预编译(编译前检测) + List formMetadataInCurentProjectList = FrontendProjectUtility.getFormMetadataList(projectPath, terminalType); + if (ListUtility.isEmpty(formMetadataInCurentProjectList)) { + return true; + } + + ChangeDetectContext changeDetectContext = new ChangeDetectContext(); + changeDetectContext.setProjectPath(projectPath); + WebLogger.Instance.info("Web生成变更检测开始执行,对应工程路径为:" + projectPath); + ChangeDetectExecuteResult compileExecuteResult = ChangeDetectExecuteManager.execute(ChangeDetectExecuteType.Generate, changeDetectContext); + // 生成前编译检查 + if (!compileExecuteResult.isAllPass()) { + WebLogger.Instance.info(compileExecuteResult.getUnPassReason()); + + ResolveFormMetadataList formMetataList = FormMetadataManager.getFormMetadataList(projectPath, terminalType, ChosenFormList.getNewInstance()); + // 不存在表单,将其认定为非前端工程 + if (formMetataList.isEmpty()) { + log.debug("Debug_FrontendProjectCompiler_CompileFrontendProject: Current project is not a frontend project or has no forms!"); + return true; + } + // 2. 解析表单元数据 + FormMetadataResolver.resolveFormMetadatas(projectPath, formMetataList, terminalType); + + // 3. 基于 JSON 生成前端代码 + LoggerUtility.logToBrowser("开始执行Jit", LoggerLevelEnum.Info); + FrontendProjectGenerate.generateFrontendProject(projectPath, terminalType); + + // 生成完毕 执行元数据变更回写 + ChangeDetectExecuteManager.updateChangeset(ChangeDetectExecuteType.Generate, changeDetectContext); + } else { + WebLogger.Instance.info("Web生成变更检测,未发生变更,不执行前端代码生成。对应工程路径为:" + projectPath); + } + return false; + } + + /** + * 构建前端工程 + */ + public final void buildFrontendProject(String projectPath, boolean isJieXiForm) { + if (FormMetadataManager.checkFormMetadataExists(projectPath, TerminalType.PC, ChosenFormList.getNewInstance(), isJieXiForm, true)) { + buildFrontendProject(projectPath, TerminalType.PC); + } + if (FormMetadataManager.checkFormMetadataExists(projectPath, TerminalType.MOBILE, ChosenFormList.getNewInstance(), isJieXiForm, true)) { + buildFrontendProject(projectPath, TerminalType.MOBILE); + } + } + + /** + * 构建前端工程 + */ + public final void buildFrontendProject(String projectPath, TerminalType terminalType) { + // 增加编译前变更检测 + WebLogger.Instance.info("开始执行编译前变更检测,对应工程路径为:" + projectPath + ",表单类型:" + terminalType.getFormName()); + + ChangeDetectContext changeDetectContext = new ChangeDetectContext(); + changeDetectContext.setProjectPath(projectPath); + changeDetectContext.setTerminalType(terminalType); + ChangeDetectExecuteResult compileExecuteResult = ChangeDetectExecuteManager.execute(ChangeDetectExecuteType.Compile, changeDetectContext); + if (compileExecuteResult.isAllPass()) { + // 如果未检测完毕 那么不进行编译 + WebLogger.Instance.info("Web编译变更检测,未发生任何变更,不执行代码编译。对应工程路径为:" + projectPath + ",表单类型:" + terminalType.getFormName()); + } else { + WebLogger.Instance.info(compileExecuteResult.getUnPassReason()); + + JITEngineManager.buildFrontendProject(projectPath, ExecuteEnvironment.Design, terminalType); + + // 执行元数据变更回写 + ChangeDetectExecuteManager.updateChangeset(ChangeDetectExecuteType.Compile, changeDetectContext); + } + } + + /** + * 使用Babel构建前端工程 + * + * @param projectPath + */ + public final void buildFrontendProjectForBabel(String projectPath) { + JITEngineManager.buildFrontendProjectForBabel(projectPath); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java new file mode 100644 index 00000000..c3979e26 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectDeployer.java @@ -0,0 +1,310 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.ide.setting.api.entity.Deployment; +import com.inspur.edp.lcm.debugger.api.service.DebuggerService; +import com.inspur.edp.lcm.metadata.api.entity.ExtractContext; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.service.PackageGenerateService; +import com.inspur.edp.lcm.metadata.api.service.ProjectExtendService; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; +import com.inspur.edp.web.jitengine.dynamicform.DynamicFormMetaFileNameGenerator; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + + +/** + * 前端工程部署器: 将生成的前端文件部署到指定SU下 + * + * @author guozhiqi + */ +public class FrontendProjectDeployer { + /** + * 前端生成物部署 + * + * @param projectPath 工程路径 + */ + public final void deploy(String projectPath) { + if (StringUtility.isNullOrEmpty(projectPath)) { + return; + } + String projectName = GspProjectUtil.getProjectName(projectPath); + // 部署PC + deploy(projectPath, projectName, TerminalType.PC, false); + //部署mobile + deploy(projectPath, projectName, TerminalType.MOBILE, false); + + // 部署前端交付物至目标publish目录 + deployToPublish(projectPath); + } + + /** + * 前端生成物部署 + * + * @param projectPath 工程路径 + */ + public final void deployForJieXi(String projectPath, FormDynamicParameter jieXiParameter) { + if (StringUtility.isNullOrEmpty(projectPath)) { + return; + } + String projectName = GspProjectUtil.getProjectName(projectPath); + boolean isUseSingleForm = jieXiParameter != null && jieXiParameter.isUseSingleForm(); + + // 部署前端交付物至目标publish目录 + if (!isUseSingleForm) { + // 部署PC + deploy(projectPath, projectName, TerminalType.PC, isUseSingleForm); + //部署mobile + //deploy(projectPath, projectName, TerminalType.MOBILE, isJieXiForm); + deployToPublish(projectPath); + } else { + // 仅拷贝metadata.js 及其对应的service编译后的脚本 + String targetDeployBasePath = getTargetDeployBasePath(projectPath, TerminalType.PC); + String strFormPath = FileUtility.combine(projectPath, "src", FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic); + strFormPath = FileUtility.combine(strFormPath, "dynamicform", jieXiParameter.getFormCode().toLowerCase()); + + + String targetFormMetadataPath = FileUtility.combine(targetDeployBasePath, "web", projectName.toLowerCase(), jieXiParameter.getFormCode().toLowerCase()); + + if (FileUtility.exists(strFormPath)) { + // 进行文件拷贝 + // 拷贝对应的expression 和 i18n 文件夹 + String dynamicFormExpressionFolder = FileUtility.combine(strFormPath, "expressions"); + String targetFormExpressionFolder = FileUtility.combine(targetFormMetadataPath, "expressions"); + + String dynamicFormI18nFolder = FileUtility.combine(strFormPath, "i18n"); + String targetDynamicFormI18nFolder = FileUtility.combine(targetFormMetadataPath, "i18n"); + + if (FileUtility.exists(dynamicFormExpressionFolder)) { + FileUtility.copyFolder(dynamicFormExpressionFolder, targetFormExpressionFolder); + } + if (FileUtility.exists(dynamicFormI18nFolder)) { + FileUtility.copyFolder(dynamicFormI18nFolder, targetDynamicFormI18nFolder); + } + } + + // 执行metadata.js 文件拷贝 + String dynamicFormMetadataJsFilenmae = DynamicFormMetaFileNameGenerator.generateMetaFileName(jieXiParameter.getFormCode()); + String dynamicFormMetadataJs = FileUtility.combine(strFormPath, dynamicFormMetadataJsFilenmae); + String targetMetadataJsFilePath = FileUtility.combine(targetFormMetadataPath, dynamicFormMetadataJsFilenmae); + FileUtility.copyFile(dynamicFormMetadataJs, targetMetadataJsFilePath, true); + + //复制 + String strFormServicePath = FileUtility.combine(projectPath, "src", FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, "services", jieXiParameter.getFormCode().toLowerCase()); + String customServicePath = FileUtility.combine(strFormServicePath, "services", "dist-rollup"); + if (FileUtility.exists(customServicePath)) { + String targetFormMetadataServicePath = FileUtility.combine(targetFormMetadataPath, "dynamicjs"); + // 删除目标文件目录 + FileUtility.deleteFolder(targetFormMetadataServicePath); + FileUtility.copyFolder(customServicePath, targetFormMetadataServicePath); + } + + // 部署前端元数据 + DeployFrontMetadata(projectPath); + } + } + + /** + * 生成物部署 + * + * @param projectPath 工程路径 + * @param projectName 工程名称 + * @param terminalType 表单类型,分类PC和移动表单 + */ + private void deploy(String projectPath, String projectName, TerminalType terminalType, boolean isSingleDynamicForm) { +// this.deployInfo(projectPath, projectName, terminalType, true); +// if (!isSingleDynamicForm && terminalType == TerminalType.PC) { + this.deployInfo(projectPath, projectName, terminalType, false); +// } + } + + private void deployInfo(String projectPath, String projectName, TerminalType terminalType, boolean isJieXiForm) { + String sourceProjectProductPath = FrontendProjectUtility.getProjectSourceCodeBuildPath(projectPath, projectName, terminalType, isJieXiForm); + boolean isSourcePathExists = FileUtility.exists(sourceProjectProductPath); + if (isSourcePathExists) { + // 获取待部署的目标路径 + String targetDeployBasePath = getTargetDeployBasePath(projectPath, terminalType); + + // 将待部署文件拷贝到服务端部署目录 + deployFrontendProjectProduct(projectName, sourceProjectProductPath, targetDeployBasePath, terminalType); + + copyI18nResource(projectPath, targetDeployBasePath, projectName, terminalType, false); + } + } + + /** + * 部署前端交付物至publish目录 + * + * @param projectPath + */ + private void deployToPublish(String projectPath) { + try { + GspProject projectInfo = GspProjectUtil.getGspProject(projectPath); + String projectName = projectInfo.getMetadataProjectName(); + // 移除工程名后的路径 + projectPath = projectPath.substring(0, projectPath.toLowerCase().lastIndexOf(projectName.toLowerCase()) + projectName.length()); + + ExtractContext extractContext = new ExtractContext(); + extractContext.setProjectPath(projectPath); + extractContext.setDeployPath(projectInfo.getSuDeploymentPath()); + FrontendProjectExtractor projectExtractor = new FrontendProjectExtractor(); + projectExtractor.extract(extractContext); + } catch (Exception ex) { + LoggerUtility.logToBrowser("部署前端脚本至publish目录失败" + ex, LoggerLevelEnum.Info, true); + } + } + + private String getTargetDeployBasePath(String projectPath, TerminalType terminalType) { + String targetDeployBasePath = ""; + + // 获取默认的部署环境信息 + DebuggerService debuggerService = SpringBeanUtils.getBean(DebuggerService.class); + Deployment defaultDebuggerDeployment = debuggerService.getDefaultDebugServerStatus(); + GspProject projectInfo = GspProjectUtil.getGspProject(projectPath); + + String serverDeployPath = getDeployServerPath(defaultDebuggerDeployment); + + targetDeployBasePath = FileUtility.combine(serverDeployPath, "web", projectInfo.getSuDeploymentPath()); + + return targetDeployBasePath; + } + + /** + * 获取部署位置 + * + * @param defaultDebuggerDeployment + * @return + */ + private String getDeployServerPath(Deployment defaultDebuggerDeployment) { + String serverRootPath = ""; + if (defaultDebuggerDeployment == null || + "localhost".equalsIgnoreCase(defaultDebuggerDeployment.getName()) || + "current server".equalsIgnoreCase(defaultDebuggerDeployment.getName())) { + // 获取服务器端部署目录 + serverRootPath = FileUtility.getCurrentWorkPath(false); + + } else { + if (StringUtility.isNullOrEmpty(defaultDebuggerDeployment.getServerPath())) { + throw new RuntimeException("默认环境未设置路径"); + } + System.out.println("use default debugger deploy,the path is " + defaultDebuggerDeployment.getServerPath()); + serverRootPath = defaultDebuggerDeployment.getServerPath(); + } + return serverRootPath; + } + + public final void deployForBabel(String projectPath) { + if (StringUtility.isNullOrEmpty(projectPath)) { + return; + } + + String projectName = GspProjectUtil.getProjectName(projectPath); + String ProductPathForBabel = FileUtility.combine(FrontendProjectConstant.FRONTEND_PROJECT_COMPILE_PATH, FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_BABEL, FrontendProjectConstant.PROJECT_BUILD_PATH); + String sourcePath = FileUtility.combine(projectPath, ProductPathForBabel, projectName + "forbabel"); + boolean isSourcePathExists = FileUtility.exists(sourcePath); + if (!isSourcePathExists) { + return; + } + + String targetBaseDeployPath = ""; + // 获取默认的部署环境信息 + DebuggerService debuggerService = SpringBeanUtils.getBean(DebuggerService.class); + Deployment defaultDebuggerDeployment = debuggerService.getDefaultDebugServerStatus(); + GspProject projectInfo = GspProjectUtil.getGspProject(projectPath); + + String deployServerPath = this.getDeployServerPath(defaultDebuggerDeployment); + targetBaseDeployPath = FileUtility.combine(deployServerPath, "web", projectInfo.getSuDeploymentPath()); + System.out.println(targetBaseDeployPath); + // 将待部署文件拷贝到服务端部署目录 + DeployFrontendProjectProductsForBabel(projectName, sourcePath, targetBaseDeployPath); + + copyI18nResource(projectPath, targetBaseDeployPath, projectName, TerminalType.PC, true); + + // 调用元数据的部署,把元数据也部署过去。 + long beforeDT = System.currentTimeMillis(); + DeployFrontMetadata(projectPath); + long afterDt = System.currentTimeMillis(); + long ts = afterDt - beforeDT; + System.out.println("部署前端元数据所需的时间为" + ts + "ms"); + } + + /** + * 复制i18n资源文件 + * + * @param projectPath + * @param targetPath + * @param projectName + * @param terminalType + * @param isBabel + */ + private void copyI18nResource(String projectPath, String targetPath, String projectName, TerminalType terminalType, boolean isBabel) { + String i18nResourceRelavtivePath = FrontendProjectUtility.getI18nResourceRelativeProductPath(terminalType); + String sourceI18nResourcePath = java.nio.file.Paths.get(projectPath).resolve(i18nResourceRelavtivePath).toString(); + + String formPublishPath = FrontendProjectUtility.getFormPublishPath(terminalType); + String targetI18nResourcePath = FileUtility.combine(targetPath, formPublishPath, projectName); + if (isBabel) { + targetI18nResourcePath = FileUtility.combine(targetPath, formPublishPath, projectName + "forbabel"); + } + + if ((new java.io.File(sourceI18nResourcePath)).isDirectory()) { + FileUtility.copyFolder(sourceI18nResourcePath, targetI18nResourcePath); + } + } + + /** + * 拷贝前端工程生成物到服务端部署目录 + */ + private void deployFrontendProjectProduct(String projectName, String sourcePath, String destinationBasePath, TerminalType terminalType) { + if (StringUtility.isNullOrEmpty(projectName) || StringUtility.isNullOrEmpty(sourcePath) || StringUtility.isNullOrEmpty(destinationBasePath)) { + return; + } + + String formPublishPath = FrontendProjectUtility.getFormPublishPath(terminalType); + String destinationPath = FileUtility.combine(destinationBasePath, formPublishPath, projectName); + + copyProducts(sourcePath, destinationPath); + } + + /** + * 拷贝前端工程生成物到服务端部署目录,使用babel快速编译时使用 + */ + private void DeployFrontendProjectProductsForBabel(String projectName, String sourcePath, String destinationBasePath) { + if (StringUtility.isNullOrEmpty(projectName) || StringUtility.isNullOrEmpty(sourcePath) || StringUtility.isNullOrEmpty(destinationBasePath)) { + return; + } + String destinationPath = FileUtility.combine(destinationBasePath, FrontendProjectConstant.FORM_PUBLISH_PATH, projectName + "forbabel"); + + copyProducts(sourcePath, destinationPath); + } + + /** + * 拷贝生成物到指定目录 + */ + private void copyProducts(String sourcePath, String destinationPath) { + if (StringUtility.isNullOrEmpty(sourcePath) || StringUtility.isNullOrEmpty(destinationPath)) { + return; + } + + FileUtility.copyFolder(sourcePath, destinationPath); + } + + private void DeployFrontMetadata(String projectPath) { + + PackageGenerateService packageGenerateService = SpringBeanUtils.getBean(PackageGenerateService.class); + packageGenerateService.generatePackage(projectPath); + + ProjectExtendService projectExtendService = SpringBeanUtils.getBean(ProjectExtendService.class); + ExtractContext extractContext = new ExtractContext(); + extractContext.setProjectPath(projectPath); + + projectExtendService.extract(projectPath); + + projectExtendService.migration(projectPath); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectExtractor.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectExtractor.java new file mode 100644 index 00000000..ec288138 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectExtractor.java @@ -0,0 +1,156 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.lcm.metadata.api.entity.ExtractContext; +import com.inspur.edp.lcm.metadata.spi.ExtractAction; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + + +/** + * 前端工程提取器 + */ +@Slf4j +public class FrontendProjectExtractor implements ExtractAction { + + /** + * 提取生成物到指定目录 + * + * @param context + */ + @Override + public void extract(ExtractContext context) { + if (context == null || StringUtility.isNullOrEmpty(context.getProjectPath())) { + return; + } + // 目录A->(拷贝)->目录B + String projectName = GspProjectUtil.getProjectName(context.getProjectPath()); + + extract(context, projectName, TerminalType.PC); + extract(context, projectName, TerminalType.MOBILE); + } + + /** + * 提取交付物 + * + * @param context 提取交付物上下文参数 + * @param terminalType 类型 分为PC和移动 + */ + private void extract(ExtractContext context, String projectName, TerminalType terminalType) { + + String projectPath = context.getProjectPath(); + // TODO: 规范工程类型后,开放这部分代码 + // string projectType = FrontendProjectUtility.GetProjectType(projectPath); + // if (projectType != "frontend") // 非前端工程,直接返回 + // { + // return; + // } + // 表单元数据打包后目录 + String sourceExtractPath = getSourceExtractPath(projectPath, projectName, terminalType, false); + + boolean isSourcePathExists = FileUtility.exists(sourceExtractPath); + if (!isSourcePathExists) { + return; + } + + String targetExtractBasePath = getTargetBaseExtractPath(context, projectPath, projectName, terminalType); + + copyFrontendProjectExtract(projectName, sourceExtractPath, targetExtractBasePath, terminalType); + + if (terminalType == TerminalType.PC) { + // 提取解析脚本到publish目录 + projectPath = FileUtility.combine(projectPath, "metadata"); + String sourceDynamicFormJs = TerminalType.PC.getResolveBasePath(projectPath, true); + if (FileUtility.exists(sourceDynamicFormJs)) { + String formPublishPath = FrontendProjectUtility.getFormPublishPath(terminalType); + String targetExtractPath = FileUtility.combine(targetExtractBasePath, formPublishPath, projectName); + FileUtility.copyFolder(sourceDynamicFormJs, targetExtractPath); + } + } + + copyI18nResource(projectPath, targetExtractBasePath, projectName, terminalType); + } + + /** + * 获取源路径 + * + * @param projectPath + * @param projectName + * @param terminalType + * @return + */ + private String getSourceExtractPath(String projectPath, String projectName, TerminalType terminalType, boolean isJieXiForm) { + String projectProductPath = FrontendProjectUtility.getProjectRelativeProductPath(terminalType, isJieXiForm); + return FileUtility.combine(projectPath, "metadata", projectProductPath, projectName); + } + + private String getTargetBaseExtractPath(ExtractContext context, String projectPath, String projectName, TerminalType terminalType) { + String targetExtractBasePath = ""; + if (context.getDeployPath().indexOf(context.getProjectPath()) == 0) { + // 表示部署路径和工程路径一致 + // projectPath C:\projects\publish\publish\publish\bo-publishfrontpublish + // deployPath C:\projects\publish\publish\publish\bo-publishfrontpublish\publish\server\apps\publish\publish + String[] publishPath = FileUtility.getPlatformIndependentPath(context.getDeployPath()).substring(FileUtility.getPlatformIndependentPath(context.getProjectPath()).length()).split("/"); + List publishPathSplitList = Arrays.stream(publishPath).filter(t -> !StringUtility.isNullOrEmpty(t)).collect(Collectors.toList()); + if (publishPathSplitList.size() >= 2) { + publishPathSplitList.set(1, "web"); + String generateFullPublishPath = String.join("/", publishPathSplitList); + generateFullPublishPath = FileUtility.combine(context.getProjectPath(), generateFullPublishPath); + return generateFullPublishPath; + } + } + int lastPublishIndex = context.getDeployPath().lastIndexOf(FrontendProjectConstant.PROJECT_PUBLISH_PATH); + if (lastPublishIndex != -1) { + targetExtractBasePath = FileUtility.combine(context.getDeployPath().substring(0, lastPublishIndex + FrontendProjectConstant.PROJECT_PUBLISH_PATH.length()), "web", context.getDeployPath().substring(lastPublishIndex + FrontendProjectConstant.PROJECT_PUBLISH_PATH.length() + 1 + "nstack".length() + 1)); + } else { + targetExtractBasePath = FileUtility.combine(projectPath, FrontendProjectConstant.PROJECT_PUBLISH_PATH, "web", context.getDeployPath()); + } + + return targetExtractBasePath; + } + + private void copyI18nResource(String projectPath, String targetPath, String projectName, TerminalType terminalType) { + String i18nResourceRelavtivePath = FrontendProjectUtility.getI18nResourceRelativeProductPath(terminalType); + String sourceI18nResourcePath = java.nio.file.Paths.get(projectPath).resolve(i18nResourceRelavtivePath).toString(); + + String formPublishPath = FrontendProjectUtility.getFormPublishPath(terminalType); + String targetI18nResourcePath = FileUtility.combine(targetPath, formPublishPath, projectName); + + if ((new java.io.File(sourceI18nResourcePath)).isDirectory()) { + FileUtility.copyFolder(sourceI18nResourcePath, targetI18nResourcePath); + } + } + + + /** + * 拷贝前端工程提取物到部署目录 + */ + private void copyFrontendProjectExtract(String projectName, String sourceExtractPath, String targetExtractBasePath, TerminalType terminalType) { + log.debug(String.format("Debug_CopyFrontendProjectExtract: projectName: %1$s, sourcePath: %2$s, destinationBasePath: %3$s", projectName, sourceExtractPath, targetExtractBasePath)); + + if (StringUtility.isNullOrEmpty(projectName) || StringUtility.isNullOrEmpty(sourceExtractPath) || StringUtility.isNullOrEmpty(targetExtractBasePath)) { + return; + } + String formPublishPath = FrontendProjectUtility.getFormPublishPath(terminalType); + String targetExtractPath = FileUtility.combine(targetExtractBasePath, formPublishPath, projectName); + copyExtract(sourceExtractPath, targetExtractPath); + } + + /** + * 拷贝提取物到指定目录 + */ + private void copyExtract(String sourcePath, String destinationPath) { + if (StringUtility.isNullOrEmpty(sourcePath) || StringUtility.isNullOrEmpty(destinationPath)) { + return; + } + + FileUtility.copyFolder(sourcePath, destinationPath); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java new file mode 100644 index 00000000..d71a7cda --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java @@ -0,0 +1,122 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.web.common.entity.ResultCode; +import com.inspur.edp.web.common.entity.ResultMessage; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.frontendproject.build.FrontendProjectBuild; +import com.inspur.edp.web.frontendproject.deploy.FrontendProjectDeploy; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.formdynamic.FormDynamicMetadataResolver; +import com.inspur.edp.web.frontendproject.formdynamic.FormDynamicParameterValidator; +import com.inspur.edp.web.frontendproject.formdynamic.FormDynamicSourceCodeGenerate; +import com.inspur.edp.web.frontendproject.generate.FrontendProjectGenerate; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; + +public class FrontendProjectManager { + private FrontendProjectManager() { + + } + + private static class FrontendProjectManagerInstance { + public static FrontendProjectManager frontendProjectManager = new FrontendProjectManager(); + } + + public static FrontendProjectManager getInstance() { + return FrontendProjectManagerInstance.frontendProjectManager; + } + + + /** + * 解析表单元数据 + * + * @param projectPath + */ + public final void resolveFormMetadatas(String projectPath) { + FrontendProjectService.getInstance().resolveFormMetadatas(projectPath, ChosenFormList.getNewInstance()); + } + + public final void ResolveAndGenerateFrontendProject(String projectPath) { + FrontendProjectService.getInstance().resolveFormMetadatas(projectPath, ChosenFormList.getNewInstance()); + FrontendProjectGenerate.generateFrontendProject(projectPath); + } + + /** + * 解析、生成、编译前端工程 + * + * @param projectPath + * @return + */ + public final ResultMessage resolveAndGenerateAndBuildFrontendProject(String projectPath) { + + // 编译前操作 判定是否需要执行更新操作 + NpmPackageResponse npmPackageResponse = NpmPackageCheckUpdate.check(); + if (!npmPackageResponse.isSuccess()) { + return ResultCode.custom(2000, npmPackageResponse.getErrorMessage()); + } + + // 解析元数据 + FrontendProjectService.getInstance().resolveFormMetadatas(projectPath, ChosenFormList.getNewInstance()); + // 生成对应代码 + FrontendProjectGenerate.generateFrontendProject(projectPath); + // 执行代码编译 + FrontendProjectBuild.buildFrontendProject(projectPath, false); + + return ResultCode.success(); + } + + + /** + * @param projectPath + * @param buildFormList 参与编译的表单列表 + */ + public final void babelBuildAndDeploy(String projectPath, ChosenFormList buildFormList) { + FrontendProjectService service = FrontendProjectService.getInstance(); + service.resolveFormMetadatas(projectPath, buildFormList); + FrontendProjectGenerate.generateFrontendProjectForBabel(projectPath); + FrontendProjectBuild.buildFrontendProjectForBabel(projectPath); + FrontendProjectDeploy.deployFrontendProjectForBabel(projectPath); + } + + /** + * 生成解析表单的依赖项 + * + * @return + */ + public final ResultMessage resolveAndGenerateFrontendProjectWithDynamic(FormDynamicParameter dynamicParameter) { + // 生成前校验 判定是否需要执行更新操作 + // 此参数要求isSingleForm参数必须为true + FormDynamicParameterValidator.validate(dynamicParameter); + + //由于解析型表单传递的元数据路径包含forms 因此此处重新进行获取真实的元数据路径 + String projectPath = MetadataUtility.getInstance().getMetadataProjectPath(dynamicParameter.getProjectPath()); + dynamicParameter.setProjectPath(projectPath); + + ChosenFormList buildFormList = ChosenFormList.getNewInstance(); + // 依据是工程还是单个表单进行解析表单的生成 + // 如果是单个表单解析 那么输出至独立的位置 + // 如果是工程级别的构造,如果所有表单均是解析类型 + // 如果是工程级别的构造,如果部分表单是解析类型 + if (dynamicParameter.isUseSingleForm()) { + // 如果单表单 + buildFormList.add(dynamicParameter.getFormCode(), true); + } + + // 执行元数据解析 + FormDynamicMetadataResolver.resolve(dynamicParameter, buildFormList); + + + // 执行代码编译 + if (!dynamicParameter.isUseSingleForm()) { + // 执行代码生成 + FormDynamicSourceCodeGenerate.generate(dynamicParameter, buildFormList); + FrontendProjectBuild.buildFrontendProject(dynamicParameter.getProjectPath(), dynamicParameter.isUseSingleForm()); + } + + // 执行代码部署 + // 单个表单的解析 整体工程的解析 + FrontendProjectDeploy.deployFrontendProjectForJieXi(dynamicParameter); + return ResultCode.success(); + } + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectService.java new file mode 100644 index 00000000..8eb3d41a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectService.java @@ -0,0 +1,65 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.debuguri.FormMetadataDebugUriService; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.resolver.FormMetadataResolver; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +public class FrontendProjectService { + + private FrontendProjectService() { + + } + + private static class FrontendProjectServiceInstance { + public static FrontendProjectService frontendProjectService = new FrontendProjectService(); + } + + public static FrontendProjectService getInstance() { + return FrontendProjectServiceInstance.frontendProjectService; + } + + public final boolean isFrontendProject(String projectPath) { + String projectType = getProjectType(projectPath); + return projectType.equals(FrontendProjectConstant.FRONTEND_PROJECT_TYPE); + } + + private String getProjectType(String projectPath) { + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_GetProjectType", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + try { + // 提供基于全路径的接口 + return FrontendProjectUtility.getProjectType(projectPath); + } catch (RuntimeException exception) { + throw new GSPException("WEB_GetProjectType", String.format("Error When Getting Project Type. Current Project Path is: %1$s", projectPath), exception); + } + } + + /** + * 解析表单元数据 + * 生成对应的json文件 + * + * @param buildFormList 参与编译的表单code列表 + */ + public final void resolveFormMetadatas(String projectPath, ChosenFormList buildFormList) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_ResolveFormMetadatas", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + FormMetadataResolver.resolveFormMetadatas(projectPath, buildFormList); + } + + + public static String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId, String formType) { + return FormMetadataDebugUriService.getFormMetadataDebugUri(formMetadataRelativePath, formMetadataId, formType); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectUtility.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectUtility.java new file mode 100644 index 00000000..1a9aa25a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectUtility.java @@ -0,0 +1,184 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author guozhiqi + */ +public class FrontendProjectUtility { + private FrontendProjectUtility() { + + } + + /** + * 获取工程类型:前端工程和非前端工程 + */ + public static String getProjectType(String projectPath) { + if (StringUtility.isNullOrEmpty(projectPath)) { + return FrontendProjectConstant.NON_FRONTEND_PROJECT_TYPE; + } + + // TODO: 更新算法,提供基于文件后缀的查找方法 + // 历史原因,只能根据当前是否包含表单来区分前端工程和非前端工程 + List formMetataList = getAllTypeFormMetadata(projectPath); + if (formMetataList != null && !formMetataList.isEmpty()) { + return FrontendProjectConstant.FRONTEND_PROJECT_TYPE; + } else { + return FrontendProjectConstant.NON_FRONTEND_PROJECT_TYPE; + } + } + + /** + * 获取工程包含的表单个数 + */ + public static List getAllTypeFormMetadata(String projectPath) { + MetadataService metadataProjectService = SpringBeanUtils.getBean(MetadataService.class); + // .frm 和 .mfrm 后缀 + return metadataProjectService.getMetadataList(projectPath, new ArrayList<>(Arrays.asList(FrontendProjectConstant.FORM_METADATA_SUFFIX, FrontendProjectConstant.MOBILE_FORM_METADATA_SUFFIX))); + } + + /** + * 获取工程包含的表单个数 + */ + public static List getFormMetadataList(String projectPath, TerminalType terminalType) { + return MetadataUtility.getInstance().getMetadataListInProject(projectPath, terminalType.getFormMetadataSuffix()); + } + + ///#region 工程构建相关路径 + + /** + * 获取待部署工程相对当前工程的生成路径 + */ + public static String getProjectRelativeProductPath(TerminalType terminalType, boolean isJieXiForm) { + String projectProductPath = ""; + + switch (terminalType) { + case PC: + if (isJieXiForm) { + projectProductPath = FrontendProjectConstant.DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_Dynamic_PATH; + } else { + projectProductPath = FrontendProjectConstant.DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_PATH; + } + break; + case MOBILE: + projectProductPath = FrontendProjectConstant.MOBILE_DEPLOYABLE_PROJECT_RELATIVE_PRODUCT_PATH; + break; + default: + throw new GSPException("Web_GetProjectRelativeProductPath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return projectProductPath; + } + + /** + * 获取工程下前端代码编译脚本对应目录 + * + * @param projectPath 工程路径 + * @param projectName 工程名称 + * @param terminalType 表单类型 + * @return + */ + public static String getProjectSourceCodeBuildPath(String projectPath, String projectName, TerminalType terminalType, boolean isJieXiForm) { + if (isJieXiForm) { + return FileUtility.combine(projectPath, FrontendProjectUtility.getProjectRelativeProductPath(terminalType, isJieXiForm)); + } + return FileUtility.combine(projectPath, FrontendProjectUtility.getProjectRelativeProductPath(terminalType, isJieXiForm), projectName); + } + + /** + * 获取表单部署目录 + */ + public static String getFormPublishPath(TerminalType terminalType) { + String formPublishPath = ""; + + switch (terminalType) { + case PC: + formPublishPath = FrontendProjectConstant.FORM_PUBLISH_PATH; + break; + case MOBILE: + formPublishPath = FrontendProjectConstant.MOBILE_FORM_PUBLISH_PATH; + break; + default: + throw new GSPException("Web_GetFormPublishPath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return formPublishPath; + } + + /** + * 获取待部署工程相对当前工程的生成路径 + */ + public static String getI18nResourceRelativeProductPath(TerminalType terminalType) { + String i18nResourceRelativePath = ""; + + switch (terminalType) { + case PC: + i18nResourceRelativePath = FrontendProjectConstant.PC_I18N_RESOURCE_RELATIVE_PRODUCT_PATH; + break; + case MOBILE: + i18nResourceRelativePath = FrontendProjectConstant.MOBILE_I18N_RESOURCE_RELATIVE_PRODUCT_PATH; + break; + default: + throw new GSPException("Web_GetI18nResourceRelativeProductPath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return i18nResourceRelativePath; + } + + + /** + * 获取表单使用服务的相对生成路径 + */ + public static String getServiceRelativeProductPath(TerminalType terminalType, boolean isJieXiForm) { + String serviceRelativeProductPath = ""; + switch (terminalType) { + case PC: + if (isJieXiForm) { + serviceRelativeProductPath = FrontendProjectConstant.SERVICES_RELATIVE_PRODUCT_Dynamic_PATH; + } else { + serviceRelativeProductPath = FrontendProjectConstant.SERVICES_RELATIVE_PRODUCT_PATH; + } + break; + case MOBILE: + // 待生成service文件夹路径 + serviceRelativeProductPath = FrontendProjectConstant.MOBILE_SERVICES_RELATIVE_PRODUCT_PATH; + break; + default: + throw new GSPException("Web_GetServiceRelativeProductPath", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + return serviceRelativeProductPath; + } + + /** + * 获取含开发根路径的工程路径 + */ + public static String getProjectPathWithDevRootPath(String projectPath) { + String projectPathWithDevRootPath = projectPath; + + if (checkIfStartsWithDevRoot(projectPath)) { + return projectPathWithDevRootPath; + } else { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + projectPathWithDevRootPath = java.nio.file.Paths.get(devRootPath).resolve(projectPath).toString(); + return projectPathWithDevRootPath; + } + } + + private static boolean checkIfStartsWithDevRoot(String projectPath) { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + return StringUtility.startWith(FileUtility.getPlatformIndependentPath(projectPath), FileUtility.getPlatformIndependentPath(devRootPath)); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/NpmPackageCheckUpdate.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/NpmPackageCheckUpdate.java new file mode 100644 index 00000000..13234889 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/NpmPackageCheckUpdate.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.frontendproject; + +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.core.webservice.NpmPacakgeWebServiceImpl; + +public class NpmPackageCheckUpdate { + public static NpmPackageResponse check() { + NpmPacakgeWebServiceImpl npmPacakgeWebServiceImpl = new NpmPacakgeWebServiceImpl(); + return npmPacakgeWebServiceImpl.checkUpdate(); + } + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/build/FrontendProjectBuild.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/build/FrontendProjectBuild.java new file mode 100644 index 00000000..9469c2da --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/build/FrontendProjectBuild.java @@ -0,0 +1,54 @@ +package com.inspur.edp.web.frontendproject.build; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.entity.ResultCode; +import com.inspur.edp.web.common.entity.ResultMessage; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectCompiler; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import com.inspur.edp.web.frontendproject.NpmPackageCheckUpdate; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +public class FrontendProjectBuild { + public static ResultMessage buildFrontendProject(String projectPath, boolean isJieXiForm) { + // 编译前操作 判定是否需要执行更新操作 + NpmPackageResponse npmPackageResponse = NpmPackageCheckUpdate.check(); + if (!npmPackageResponse.isSuccess()) { + return ResultCode.custom(2000, npmPackageResponse.getErrorMessage()); + } + + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_BuildFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + //获取webdev路径 包含根路径 + String webDevPathWithRoot = FileUtility.combine(projectPath, "src", "webdev"); + try { + FrontendProjectCompiler frontendProjectCompiler = new FrontendProjectCompiler(); + frontendProjectCompiler.buildFrontendProject(projectPath, isJieXiForm); + } catch (RuntimeException exception) { + throw new GSPException("WEB_BuildFrontendProject", String.format("Error When Building a Frontend. Current Project Path is: %1$s", projectPath), exception); + } + return ResultCode.success(); + } + + public static void buildFrontendProjectForBabel(String projectPath) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_BuildFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + //获取webdev路径 包含根路径 + try { + FrontendProjectCompiler frontendProjectCompiler = new FrontendProjectCompiler(); + frontendProjectCompiler.buildFrontendProjectForBabel(projectPath); + } catch (RuntimeException exception) { + throw new GSPException("WEB_BuildFrontendProject", String.format("Error When Building a Frontend. Current Project Path is: %1$s", projectPath), exception); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteManager.java new file mode 100644 index 00000000..18ab50e9 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteManager.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.frontendproject.changedetect; + +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; + +/** + * @Title: ChangeDetectExecuteManager + * @Description: 变更检测执行服务manager 对外暴露统一的使用方式 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/22 15:05 + */ +public class ChangeDetectExecuteManager { + /** + * 执行对应的变更检测动作 对应的执行服务从枚举中获取 + * + * @param executeType + * @param detectContext + * @return + */ + public static ChangeDetectExecuteResult execute(ChangeDetectExecuteType executeType, ChangeDetectContext detectContext) { + detectContext.setExecuteType(executeType); + return executeType.getExecuteService().execute(detectContext); + } + + /** + * 变更检测后回写 + * @param executeType + * @param detectContext + */ + public static void updateChangeset(ChangeDetectExecuteType executeType, ChangeDetectContext detectContext) { + detectContext.setExecuteType(executeType); + executeType.getExecuteService().updateChangeset(detectContext); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteResult.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteResult.java new file mode 100644 index 00000000..b3700970 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteResult.java @@ -0,0 +1,70 @@ +package com.inspur.edp.web.frontendproject.changedetect; + +/** + * @Title: ChangeDetectExecuteResult + * @Description: 变更检测执行结果 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 11:03 + */ +public class ChangeDetectExecuteResult { + /** + * 定义当前的执行类型 + * 为generate 或 compile + */ + private ChangeDetectExecuteType currentExecuteType = ChangeDetectExecuteType.Generate; + + /** + * 是否所有的变更检测项均已通过 + */ + private boolean allPass = false; + + /** + * 未变更检测通过项 具体的未通过原因 + */ + private String unPassReason; + + public ChangeDetectExecuteType getCurrentExecuteType() { + return this.currentExecuteType; + } + + public boolean isAllPass() { + return this.allPass; + } + + public String getUnPassReason() { + return this.unPassReason; + } + + private ChangeDetectExecuteResult() { + } + + /** + * 获取对应的检测通过的结果定义 + * + * @return + */ + public static ChangeDetectExecuteResult getPassResult(ChangeDetectExecuteType changeDetectExecuteType) { + ChangeDetectExecuteResult executeResult = new ChangeDetectExecuteResult(); + executeResult.allPass = true; + executeResult.currentExecuteType = changeDetectExecuteType; + executeResult.unPassReason = null; + return executeResult; + } + + /** + * 获取对应的检测不通过结果定义 + * + * @param changeDetectExecuteType + * @param unPassReason + * @return + */ + public static ChangeDetectExecuteResult getUnPassResult(ChangeDetectExecuteType changeDetectExecuteType, String unPassReason) { + ChangeDetectExecuteResult executeResult = new ChangeDetectExecuteResult(); + executeResult.allPass = false; + executeResult.currentExecuteType = changeDetectExecuteType; + executeResult.unPassReason = unPassReason; + return executeResult; + } + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteService.java new file mode 100644 index 00000000..39542f8e --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteService.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.frontendproject.changedetect; + +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; + +/** + * @Title: ChangeDetectService + * @Description: 变更检测服务service 接口定义 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 10:59 + */ +public interface ChangeDetectExecuteService { + /** + * 变更检测 + * + * @param detectContext 变更检测上下文参数 + * @return + */ + ChangeDetectExecuteResult execute(ChangeDetectContext detectContext); + + /** + * 更新对应的变更记录 + * + * @param detectContext + */ + void updateChangeset(ChangeDetectContext detectContext); +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteType.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteType.java new file mode 100644 index 00000000..ac36e66e --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ChangeDetectExecuteType.java @@ -0,0 +1,76 @@ +package com.inspur.edp.web.frontendproject.changedetect; + +import com.inspur.edp.web.frontendproject.changedetect.compile.CompileChangeDetectExecuteServiceImpl; +import com.inspur.edp.web.frontendproject.changedetect.generate.GenerateChangeDetectExecuteServiceImpl; + +/** + * @Title: ChangeDetectExecuteType + * @Description: 变更检测类型定义 用于区分是生成还是编译动作 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 11:00 + */ +public enum ChangeDetectExecuteType { + /** + * 变更检测执行类型 生成动作 + */ + Generate("generate", "生成检测") { + /** + * 获取对应的执行服务实例 + * + * @return + */ + @Override + public ChangeDetectExecuteService getExecuteService() { + return new GenerateChangeDetectExecuteServiceImpl(); + } + }, + + /** + * 变更检测执行类型 编译动作 + */ + Compile("compile", "编译检测") { + /** + * 获取对应的执行服务实例 + * + * @return + */ + @Override + public ChangeDetectExecuteService getExecuteService() { + return new CompileChangeDetectExecuteServiceImpl(); + } + }; + + private final String value; + private final String description; + + ChangeDetectExecuteType(String value, String description) { + this.value = value; + this.description = description; + } + + /** + * 获取对应的执行服务实例 + * + * @return + */ + public abstract ChangeDetectExecuteService getExecuteService(); + + /** + * 获取对应变更检测类型定义的实际参数值 + * + * @return + */ + public String getValue() { + return value; + } + + /** + * 获取对应变更检测类型定义的描述信息 + * + * @return + */ + public String getDescription() { + return description; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ExcludePathEntity.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ExcludePathEntity.java new file mode 100644 index 00000000..4747e329 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/ExcludePathEntity.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.frontendproject.changedetect; + +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; + +/** + * @Title: ExcludePathEntity + * @Description: com.inspur.edp.web.frontendproject.compileactionextend + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/20 17:06 + */ +@Data +public class ExcludePathEntity { + private String parentDir; + private File parentDirFile; + private String name; + + public ExcludePathEntity(String parentDir, String name) { + this.parentDir = parentDir; + this.name = name; + if (!StringUtils.isEmpty(this.parentDir)) { + this.parentDirFile = new File(this.parentDir); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/AbstractCompileChangeDetectStepExecuteService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/AbstractCompileChangeDetectStepExecuteService.java new file mode 100644 index 00000000..eaf2202c --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/AbstractCompileChangeDetectStepExecuteService.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.frontendproject.changedetect.compile; + +import com.inspur.edp.web.frontendproject.changedetect.step.AbstractChangeDetectStepExecuteService; + +/** + * @Title: AbstractCompileChangeDetectStepExecuteService + * @Description: 编译 变更检测 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 19:16 + */ +public abstract class AbstractCompileChangeDetectStepExecuteService extends AbstractChangeDetectStepExecuteService { + @Override + protected String getPrefixTip() { + return "Web依赖变更检测,编译:"; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectExecuteServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectExecuteServiceImpl.java new file mode 100644 index 00000000..41596f89 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectExecuteServiceImpl.java @@ -0,0 +1,61 @@ +package com.inspur.edp.web.frontendproject.changedetect.compile; + +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteService; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; + +import java.util.List; + +/** + * @Title: CompileChangeDetectExecuteService + * @Description: 变更检测 编译动作实现 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 20:11 + */ +public class CompileChangeDetectExecuteServiceImpl implements ChangeDetectExecuteService { + /** + * 变更检测 + * + * @param detectContext 变更检测上下文参数 + * @return + */ + @Override + public ChangeDetectExecuteResult execute(ChangeDetectContext detectContext) { + List orderedChangeDetectTypeList = CompileChangeDetectType.getOrderedList(); + + ChangeDetectStepExecuteResult stepExecuteResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Compile); + for (CompileChangeDetectType t : orderedChangeDetectTypeList) { + ChangeDetectStepExecuteService executeService = t.getChangeDetectStep(); + stepExecuteResult = executeService.execute(detectContext); + if (!stepExecuteResult.isPass()) { + break; + } + } + + if (stepExecuteResult.isPass()) { + return ChangeDetectExecuteResult.getPassResult(ChangeDetectExecuteType.Compile); + } else { + return ChangeDetectExecuteResult.getUnPassResult(ChangeDetectExecuteType.Compile, stepExecuteResult.getReason()); + } + + } + + /** + * 更新对应的变更记录 + * + * @param detectContext + */ + @Override + public void updateChangeset(ChangeDetectContext detectContext) { + List orderedChangeDetectTypeList = CompileChangeDetectType.getOrderedList(); + + for (CompileChangeDetectType t : orderedChangeDetectTypeList) { + ChangeDetectStepExecuteService executeService = t.getChangeDetectStep(); + executeService.updateChangeset(detectContext); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectType.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectType.java new file mode 100644 index 00000000..a040ce04 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/CompileChangeDetectType.java @@ -0,0 +1,55 @@ +package com.inspur.edp.web.frontendproject.changedetect.compile; + +import com.inspur.edp.web.frontendproject.changedetect.compile.stepexecute.FileChangeStepExecuteImpl; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Title: CompileChangeDetectType + * @Description: 编译依赖的变更检测类型 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 10:57 + */ +public enum CompileChangeDetectType { + FileChange(1, "文件变更检测") { + @Override + public ChangeDetectStepExecuteService getChangeDetectStep() { + return new FileChangeStepExecuteImpl(); + } + }; + + /** + * 执行序号 + */ + private int order = 1; + /** + * 描述信息 + */ + private final String description; + + CompileChangeDetectType(int order, String description) { + this.order = order; + this.description = description; + } + + /** + * 获取编译对应的步骤执行实例 + * + * @return + */ + public abstract ChangeDetectStepExecuteService getChangeDetectStep(); + + /** + * 获取编译变更检测步骤按顺序执行列表 + * + * @return + */ + public static List getOrderedList() { + return Arrays.stream(values()).sorted(Comparator.comparing(t -> t.order)).collect(Collectors.toList()); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/stepexecute/FileChangeStepExecuteImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/stepexecute/FileChangeStepExecuteImpl.java new file mode 100644 index 00000000..bac27a05 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/compile/stepexecute/FileChangeStepExecuteImpl.java @@ -0,0 +1,179 @@ +package com.inspur.edp.web.frontendproject.changedetect.compile.stepexecute; + +import com.inspur.edp.lcm.metadata.api.entity.OperationEnum; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.Base64Utility; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.ExcludePathEntity; +import com.inspur.edp.web.frontendproject.changedetect.compile.AbstractCompileChangeDetectStepExecuteService; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; +import com.inspur.edp.web.npmpackage.core.npminstall.PackageJsonPathGenerator; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @Title: FileChangeStepExecuteImpl + * @Description: com.inspur.edp.web.frontendproject.changedetect.compile.stepexecute + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 19:45 + */ +public class FileChangeStepExecuteImpl extends AbstractCompileChangeDetectStepExecuteService implements ChangeDetectStepExecuteService { + /** + * 步骤执行器参数 + * + * @param context 变更检测上下文参数 + * @return + */ + @Override + public ChangeDetectStepExecuteResult execute(ChangeDetectContext context) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Compile); + + String srcAppPath = this.getSrcAppPath(context); + String srcDistRollup = FileUtility.combine(srcAppPath, "dist-rollup"); + if (!FileUtility.exists(srcDistRollup)) { + executeResult.setPass(false); + executeResult.setReason(this.generateReasonWithPrefix("dist-rollup目录不存在")); + return executeResult; + } + + // 仅在pc 表单类型下检测 + if (context.getTerminalType() == TerminalType.PC) { + String srcOutTscPath = FileUtility.combine(srcAppPath, "out-tsc"); + if (!FileUtility.exists(srcOutTscPath)) { + executeResult.setPass(false); + executeResult.setReason(this.generateReasonWithPrefix("out-tsc目录不存在")); + return executeResult; + } + + // 由于移动表单采用的是生成创建node_modules链接 因此 编译时不进行验证 + String srcNodeModulesPath = FileUtility.combine(srcAppPath, "node_modules"); + if (!FileUtility.exists(srcNodeModulesPath)) { + executeResult.setPass(false); + executeResult.setReason(this.generateReasonWithPrefix("node_modules目录不存在")); + return executeResult; + } + + } + + MetadataProjectService projectService = this.getMetadataProjectService(); + List excludePathEntityList = this.getNeedExcludePathList(context); + // 检测源代码是否发生变更 + boolean fileChangedFlag = projectService.isFileChanged(srcAppPath, OperationEnum.WEB_GENERATE, (dir, name) -> { + // 如果进行了排除 那么不进行目录检测 + boolean matchExcludePathFlag = excludePathEntityList.stream().anyMatch(t -> t.getParentDir() != null && + t.getParentDirFile().equals(dir) && + Objects.equals(t.getName(), name)); + return !matchExcludePathFlag; + }); + if (fileChangedFlag) { + executeResult.setPass(false); + executeResult.setReason(this.generateReasonWithPrefix("ts源代码发生变更")); + return executeResult; + } + + // 执行npm版本检测 + String currentServerPath = FileUtility.getCurrentWorkPath(false); + String serverPackageJsonPath = PackageJsonPathGenerator.generate(currentServerPath, false); + if (FileUtility.exists(serverPackageJsonPath)) { + try { + String base64EncodeValue = Base64Utility.encode(FileUtility.readAsString(serverPackageJsonPath)).substring(0, 32); + boolean packageJsonFileChanged = projectService.isFileChanged(context.getProjectPath(), serverPackageJsonPath, base64EncodeValue, OperationEnum.WEB_GENERATE); + if (packageJsonFileChanged) { + executeResult.setUnPassReason("node_modules发生变更"); + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + + return executeResult; + } + + /** + * 针对元数据的变更回写动作 + * + * @param context + * @return + */ + @Override + public ChangeDetectStepExecuteResult updateChangeset(ChangeDetectContext context) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Compile); + + MetadataProjectService projectService = getMetadataProjectService(); + String srcAppPath = this.getSrcAppPath(context); + List excludePathEntityList = this.getNeedExcludePathList(context); + // 检测源代码是否发生变更 + projectService.updateFileChanges(srcAppPath, OperationEnum.WEB_GENERATE, (dir, name) -> { + // 如果进行了排除 那么布进行目录检测 + boolean matchExcludePathFlag = excludePathEntityList.stream().anyMatch(t -> t.getParentDir() != null && + t.getParentDirFile().equals(dir) && + Objects.equals(t.getName(), name)); + return !matchExcludePathFlag; + }); + + // 更新node_modules依赖的package.json 文件 + String currentServerPath = FileUtility.getCurrentWorkPath(false); + String serverPackageJsonPath = PackageJsonPathGenerator.generate(currentServerPath, false); + if (FileUtility.exists(serverPackageJsonPath)) { + try { + String base64EncodeValue = Base64Utility.encode(FileUtility.readAsString(serverPackageJsonPath)).substring(0, 32); + projectService.updateFileChanges(context.getProjectPath(), serverPackageJsonPath, base64EncodeValue, OperationEnum.WEB_GENERATE); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + } + + return executeResult; + } + + /** + * 获取需要进行文件目录检测的路径列表 + * + * @param context + * @return + */ + private List getNeedCheckPathList(ChangeDetectContext context) { + List checkPathList = new ArrayList<>(10); + + String srcAppPath = this.getSrcAppPath(context); + + checkPathList.add(new ExcludePathEntity(srcAppPath, "projects")); + checkPathList.add(new ExcludePathEntity(srcAppPath, "angular.json")); + checkPathList.add(new ExcludePathEntity(srcAppPath, "package.json")); + checkPathList.add(new ExcludePathEntity(srcAppPath, "tsconfig.json")); + return checkPathList; + } + + /** + * 不检测文件变化 + * + * @param context + * @return + */ + private List getNeedExcludePathList(ChangeDetectContext context) { + List excludePathList = new ArrayList<>(); + // 排除dist-rollup的变更 + String srcAppPath = this.getSrcAppPath(context); + ExcludePathEntity excludeDistRollupPathEntity = new ExcludePathEntity(srcAppPath, "dist-rollup"); + excludePathList.add(excludeDistRollupPathEntity); + + ExcludePathEntity excludeNodeModulesPathEntity = new ExcludePathEntity(srcAppPath, "node_modules"); + excludePathList.add(excludeNodeModulesPathEntity); + + + ExcludePathEntity excludeOuttscPathEntity = new ExcludePathEntity(srcAppPath, "out-tsc"); + excludePathList.add(excludeOuttscPathEntity); + + return excludePathList; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/context/ChangeDetectContext.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/context/ChangeDetectContext.java new file mode 100644 index 00000000..8188092f --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/context/ChangeDetectContext.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.frontendproject.changedetect.context; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import lombok.Data; + +/** + * @Title: ChangeDetectContext + * @Description: 变更检测上下文参数 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 16:30 + */ +@Data +public class ChangeDetectContext { + /** + * 变更检测的工程路径 参数 + */ + private String projectPath; + + /** + * 变更检测关联的表单类型 + */ + private TerminalType terminalType = TerminalType.PC; + + /** + * 设置变更检测类型 默认为生成动作 + */ + private ChangeDetectExecuteType executeType = ChangeDetectExecuteType.Generate; +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/AbstractGenerateChangeDetectStepExecuteService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/AbstractGenerateChangeDetectStepExecuteService.java new file mode 100644 index 00000000..dbb774c0 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/AbstractGenerateChangeDetectStepExecuteService.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.step.AbstractChangeDetectStepExecuteService; + +/** + * @Title: AbstractGenerateChangeDetectStepExecuteService + * @Description: 生成步骤对应的步骤执行 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 19:15 + */ +public abstract class AbstractGenerateChangeDetectStepExecuteService extends AbstractChangeDetectStepExecuteService { + + @Override + protected String getPrefixTip() { + return "Web依赖变更检测,生成:"; + } + + protected String getAppConfigJsonPath(ChangeDetectContext context) { + return FileUtility.combine(context.getProjectPath(), this.appConfigJsonName); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectExecuteServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectExecuteServiceImpl.java new file mode 100644 index 00000000..9ae9448f --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectExecuteServiceImpl.java @@ -0,0 +1,67 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate; + +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteService; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; + +import java.util.List; + +/** + * @Title: GenerateChangeDetectExecuteService + * @Description: 变更检测 生成动作实现 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 20:12 + */ +public class GenerateChangeDetectExecuteServiceImpl implements ChangeDetectExecuteService { + + // 当前执行动作的检测类型为生成动作 + private final ChangeDetectExecuteType currentChangeDetectType = ChangeDetectExecuteType.Generate; + + /** + * 变更检测 + * 获取生成需要执行的变更检测步骤,按照顺序依次执行 + * 如果上一个步骤的执行结果为变更检测未通过,那么后续的变更检测都不再执行 + * + * @param detectContext 变更检测上下文参数 + * @return + */ + @Override + public ChangeDetectExecuteResult execute(ChangeDetectContext detectContext) { + ChangeDetectStepExecuteResult stepExecuteResult = ChangeDetectStepExecuteResult.getPassResult(this.currentChangeDetectType); + // 获取排序后的生成变更检测步骤列表 + List orderedChangeDetectTypeList = GenerateChangeDetectStepType.getOrderedList(); + + for (GenerateChangeDetectStepType t : orderedChangeDetectTypeList) { + ChangeDetectStepExecuteService executeService = t.getChangeDetectStep(); + stepExecuteResult = executeService.execute(detectContext); + if (!stepExecuteResult.isPass()) { + break; + } + } + + if (stepExecuteResult.isPass()) { + return ChangeDetectExecuteResult.getPassResult(this.currentChangeDetectType); + } else { + return ChangeDetectExecuteResult.getUnPassResult(this.currentChangeDetectType, stepExecuteResult.getReason()); + } + } + + /** + * 更新对应的变更记录 + * + * @param detectContext + */ + @Override + public void updateChangeset(ChangeDetectContext detectContext) { + List orderedChangeDetectTypeList = GenerateChangeDetectStepType.getOrderedList(); + + for (GenerateChangeDetectStepType t : orderedChangeDetectTypeList) { + ChangeDetectStepExecuteService executeService = t.getChangeDetectStep(); + executeService.updateChangeset(detectContext); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectStepType.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectStepType.java new file mode 100644 index 00000000..34cc6c43 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/GenerateChangeDetectStepType.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate; + +import com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute.FileChangeStepExecuteImpl; +import com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute.MetadataChangeStepExecuteImpl; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Title: GenerateChangeDetectType + * @Description: 生成动作对应的变更检测步骤类型 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 10:55 + */ +public enum GenerateChangeDetectStepType { + /** + * 文件变更检测步骤 + */ + FileChange(1,"文件变更检测") { + @Override + public ChangeDetectStepExecuteService getChangeDetectStep() { + return new FileChangeStepExecuteImpl(); + } + }, + /** + * 元数据变更检测步骤 + */ + MetadataChange(2,"元数据变更检测") { + @Override + public ChangeDetectStepExecuteService getChangeDetectStep() { + return new MetadataChangeStepExecuteImpl(); + } + }; + + private final int order; + + private final String description; + + GenerateChangeDetectStepType(int order, String description) { + this.order = order; + this.description = description; + } + + public abstract ChangeDetectStepExecuteService getChangeDetectStep(); + + /** + * 获取编译变更检测步骤按顺序执行列表 + * + * @return + */ + public static List getOrderedList() { + return Arrays.stream(values()).sorted(Comparator.comparing(t -> t.order)).collect(Collectors.toList()); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/FileChangeStepExecuteImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/FileChangeStepExecuteImpl.java new file mode 100644 index 00000000..7afa3a2a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/FileChangeStepExecuteImpl.java @@ -0,0 +1,155 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute; + +import com.inspur.edp.lcm.metadata.api.entity.OperationEnum; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.ExcludePathEntity; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.generate.AbstractGenerateChangeDetectStepExecuteService; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @Title: WebDevFileChangeStepExecuteImpl + * @Description: 文件变更检测步骤 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 16:51 + */ +public class FileChangeStepExecuteImpl extends AbstractGenerateChangeDetectStepExecuteService implements ChangeDetectStepExecuteService { + /** + * 步骤执行器参数 生成对应文件变更检测执行 + * + * @param context 变更检测上下文参数 + * @return 文件变更执行结果 + */ + @Override + public ChangeDetectStepExecuteResult execute(ChangeDetectContext context) { + ChangeDetectStepExecuteResult changeDetectStepExecuteResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + String srcWebDevPath = this.getSrcWebDevPath(context); + if (!FileUtility.exists(srcWebDevPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix(context.getTerminalType().getWebDevPathName() + "目录不存在")); + return changeDetectStepExecuteResult; + } + + MetadataProjectService metadataProjectService = this.getMetadataProjectService(); + // 判断webdev文件是否包含变更 主要目标是jit的排除项文件 + // webdev 目录判断 排除package.json 文件 + List excludePathEntityList = this.getNeedExcludePathList(context); + boolean webDevFileChangeFlag = metadataProjectService.isFileChanged(srcWebDevPath, OperationEnum.WEB_GENERATE, (dir, name) -> { + // 如果进行了排除 那么不进行目录检测 + boolean matchExcludePathFlag = excludePathEntityList.stream().anyMatch(t -> t.getParentDir() != null && + t.getParentDirFile().equals(dir) && + Objects.equals(t.getName(), name)); + return !matchExcludePathFlag; + }); + if (webDevFileChangeFlag) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix(context.getTerminalType().getWebDevPathName() + "存在文件变更")); + return changeDetectStepExecuteResult; + } + + String srcAppPath = this.getSrcAppPath(context); + + if (context.getTerminalType() == TerminalType.PC) { + // 判断源代码工程目录是否存在 + String srcAppProjectsPath = FileUtility.combine(srcAppPath, "projects"); + if (!FileUtility.exists(srcAppProjectsPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("ts源代码目录不存在")); + return changeDetectStepExecuteResult; + } + + // 检查angular.json 文件是否存在 + String angularJsonPath = FileUtility.combine(srcAppPath, this.angularJsonName); + if (!FileUtility.exists(angularJsonPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("angular.json文件不存在")); + return changeDetectStepExecuteResult; + } + + // tsconfig.json 文件是否存在 + String tsConfigJsonPath = FileUtility.combine(srcAppPath, this.tsConfigJsonName); + if (!FileUtility.exists(tsConfigJsonPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("tsconfig.json文件不存在")); + return changeDetectStepExecuteResult; + } + + // 判断app.config.json 文件是否存在 + String appConfigJsonPath = this.getAppConfigJsonPath(context); + if (!FileUtility.exists(appConfigJsonPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("app.config.json文件不存在")); + return changeDetectStepExecuteResult; + } + // 检测app.config.json 文件是否发生变更 + boolean appConfigJsonChangedFlag = metadataProjectService.isFileChanged(appConfigJsonPath, OperationEnum.WEB_GENERATE); + if (appConfigJsonChangedFlag) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("app.config.json文件发生变更")); + return changeDetectStepExecuteResult; + } + } else { + // 由于移动表单在生成时创建node_modules + String nodeModulesPath = FileUtility.combine(srcAppPath, "node_modules"); + if (!FileUtility.exists(nodeModulesPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("node_modules目录不存在")); + return changeDetectStepExecuteResult; + } + } + + // package.json 文件是否存在 + String packageJsonPath = FileUtility.combine(srcAppPath, this.packageJsonName); + if (!FileUtility.exists(packageJsonPath)) { + changeDetectStepExecuteResult.setUnPassReason(this.generateReasonWithPrefix("package.json文件不存在")); + return changeDetectStepExecuteResult; + } + + return changeDetectStepExecuteResult; + } + + /** + * 针对元数据的变更回写动作 + * + * @param context + * @return + */ + @Override + public ChangeDetectStepExecuteResult updateChangeset(ChangeDetectContext context) { + ChangeDetectStepExecuteResult stepExecuteResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + + MetadataProjectService metadataProjectService = this.getMetadataProjectService(); + + // 回写webdev的变更 + // webdev 目录判断 排除package.json 文件 + List excludePathEntityList = this.getNeedExcludePathList(context); + metadataProjectService.updateFileChanges(this.getSrcWebDevPath(context), OperationEnum.WEB_GENERATE,(dir, name)->{ + // 如果进行了排除 那么不进行目录检测 + boolean matchExcludePathFlag = excludePathEntityList.stream().anyMatch(t -> t.getParentDir() != null && + t.getParentDirFile().equals(dir) && + Objects.equals(t.getName(), name)); + return !matchExcludePathFlag; + }); + // 回写app.config.json 文件变更 + if (context.getTerminalType() == TerminalType.PC) { + metadataProjectService.updateFileChanges(this.getAppConfigJsonPath(context), OperationEnum.WEB_GENERATE); + } + + return stepExecuteResult; + } + + /** + * 不检测文件变化 + * + * @param context + * @return + */ + private List getNeedExcludePathList(ChangeDetectContext context) { + List excludePathList = new ArrayList<>(); + String webDevPath = this.getSrcWebDevPath(context); + ExcludePathEntity excludeWebDevPackageJsonPathEntity = new ExcludePathEntity(webDevPath, "package.json"); + excludePathList.add(excludeWebDevPackageJsonPathEntity); + return excludePathList; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImpl.java new file mode 100644 index 00000000..4193e09d --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImpl.java @@ -0,0 +1,248 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.OperationEnum; +import com.inspur.edp.lcm.metadata.api.entity.uri.MetadataURI; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.ListUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import com.inspur.edp.web.frontendproject.changedetect.generate.AbstractGenerateChangeDetectStepExecuteService; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteResult; +import com.inspur.edp.web.frontendproject.changedetect.step.ChangeDetectStepExecuteService; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.metadata.FormMetadataManager; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Title: MetadataChangeStepExecuteImpl + * @Description: 生成动作依赖元数据变更 步骤 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 16:50 + */ +public class MetadataChangeStepExecuteImpl extends AbstractGenerateChangeDetectStepExecuteService implements ChangeDetectStepExecuteService { + /** + * lres的正则匹配 + */ + private static final Pattern lresPattern = Pattern.compile(".frm.[a-zA-Z-_]+.lres", Pattern.COMMENTS | Pattern.CASE_INSENSITIVE); + + /** + * 步骤执行器参数 + * + * @param context 变更检测上下文参数 + * @return + */ + @Override + public ChangeDetectStepExecuteResult execute(ChangeDetectContext context) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + MetadataProjectService metadataProjectService = this.getMetadataProjectService(); + // 首先进行元数据变化的检测 如果发生变化 那么认定需要重新生成 + // 工程目录下所有的元数据变更检测 + boolean webRelyMetadataChanged = metadataProjectService.isMetadataChanged(context.getProjectPath(), OperationEnum.WEB_GENERATE, this::checkFilePath); + if (webRelyMetadataChanged) { + executeResult.setUnPassReason(this.generateReasonWithPrefix("元数据发生变化")); + return executeResult; + } + + // 获取此工程下的所有表单元数据 + ChangeDetectStepExecuteResult formRelyMetadataExecuteResult = checkFormRelyMetadataChanged(context, metadataProjectService, ExecuteType.Check); + if (!formRelyMetadataExecuteResult.isPass()) { + return formRelyMetadataExecuteResult; + } + + return executeResult; + + } + + private boolean checkFilePath(File pathname) { + if (pathname.isFile()) { + // 当前针对res、lres 仅进行form的验证 其他元数据的res 不进行验证 + String filePath = pathname.getPath(); + String fileExtension = FileUtility.getFileExtension(filePath); + if (StringUtility.isNullOrEmpty(fileExtension)) { + return true; + } + // 仅处理res和lres 保留表单对应 + if (fileExtension.equals(".res") || fileExtension.equals(".lres")) { + // 表示当前文件为资源文件类型 + // 针对res文件 仅仅保留frm的资源文件 其他的资源文件一律不进行检测 + if (filePath.endsWith(".frm.res")) { + return true; + } + + //lres 匹配 + Matcher m = lresPattern.matcher(filePath); + return m.find(); + } + } + return true; + } + + + /** + * 检测表单依赖的元数据是否发生变更 + * + * @param context + * @param metadataProjectService + * @return + */ + private ChangeDetectStepExecuteResult checkFormRelyMetadataChanged(ChangeDetectContext context, MetadataProjectService metadataProjectService, ExecuteType executeType) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + if (FormMetadataManager.checkFormMetadataExists(context.getProjectPath(), TerminalType.PC, ChosenFormList.getNewInstance(), false, false)) { + ChangeDetectStepExecuteResult formMetadataListRelyMetadataChangedFlag = checkFormMetadataListRelyMetadataChanged(context, metadataProjectService, TerminalType.PC, executeType); + if (!formMetadataListRelyMetadataChangedFlag.isPass()) { + return formMetadataListRelyMetadataChangedFlag; + } + } + + if (FormMetadataManager.checkFormMetadataExists(context.getProjectPath(), TerminalType.MOBILE, ChosenFormList.getNewInstance(), false, false)) { + ChangeDetectStepExecuteResult formMetadataListRelyMetadataChangedFlag = checkFormMetadataListRelyMetadataChanged(context, metadataProjectService, TerminalType.MOBILE, executeType); + if (!formMetadataListRelyMetadataChangedFlag.isPass()) { + return formMetadataListRelyMetadataChangedFlag; + } + } + + return executeResult; + } + + private ChangeDetectStepExecuteResult checkFormMetadataListRelyMetadataChanged(ChangeDetectContext context, MetadataProjectService metadataProjectService, TerminalType terminalType, ExecuteType executeType) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + List formMetadataInCurentProjectList = FrontendProjectUtility.getFormMetadataList(context.getProjectPath(), terminalType); + if (!ListUtility.isEmpty(formMetadataInCurentProjectList)) { + for (GspMetadata t : formMetadataInCurentProjectList) { + ChangeDetectStepExecuteResult checkSpecialFormRelyMetadataChangedFlag = checkSpecialFormRelyMetadataChanged(context, metadataProjectService, t, executeType); + if (!checkSpecialFormRelyMetadataChangedFlag.isPass()) { + return checkSpecialFormRelyMetadataChangedFlag; + } + + } + } + return executeResult; + } + + private ChangeDetectStepExecuteResult checkSpecialFormRelyMetadataChanged(ChangeDetectContext context, MetadataProjectService metadataProjectService, GspMetadata t, ExecuteType executeType) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + if (t.getContent() == null) { + // 表示通过列表形式获取到的元数据content为空 那么单独进行元数据的读取 + t.setContent(MetadataUtility.getInstance().getMetadataWithIdAndPath(t.getHeader().getId(), t.getRelativePath()).getContent()); + } + FormMetadataContent formMetadataContent = (FormMetadataContent) t.getContent(); + FormDOM formContent = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + + // 如果存在组合表单 那么直接跳过元数据检测 + if (formContent.getModule().getExternalComponents() != null && !formContent.getModule().getExternalComponents().isEmpty()) { + executeResult.setUnPassReason("存在组合表单,跳过元数据变更检测,对应表单为:" + formContent.getModule().getCode()); + return executeResult; + } + + ArrayList> currentStateMachineList = formContent.getModule().getStateMachines(); + ChangeDetectStepExecuteResult stateMachineExecuteResult = checkStateMachineMetadataChanged(context, metadataProjectService, formContent, currentStateMachineList, executeType); + if (!stateMachineExecuteResult.isPass()) { + return stateMachineExecuteResult; + } + ArrayList> currentWebCmdList = formContent.getModule().getWebcmds(); + ChangeDetectStepExecuteResult webCmdExecuteResult = checkWebCmdMetadataChanged(context, metadataProjectService, formContent, currentWebCmdList, executeType); + if (!webCmdExecuteResult.isPass()) { + return webCmdExecuteResult; + } + return executeResult; + } + + /** + * 检测命令元数据是否发生变化 + * + * @param context + * @param metadataProjectService + * @param formContent + * @param currentWebCmdList + * @return + */ + private ChangeDetectStepExecuteResult checkWebCmdMetadataChanged(ChangeDetectContext context, MetadataProjectService metadataProjectService, FormDOM formContent, ArrayList> currentWebCmdList, ExecuteType executeType) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + if (currentWebCmdList != null && !currentWebCmdList.isEmpty()) { + for (HashMap webCmdItem : currentWebCmdList) { + String webCmdId = webCmdItem.get("id").toString(); + if (executeType == ExecuteType.Check) { + boolean webCmdChangedFlag = metadataProjectService.isRefMetadataChanged(context.getProjectPath(), OperationEnum.WEB_GENERATE, new MetadataURI(webCmdId)); + if (webCmdChangedFlag) { + executeResult.setUnPassReason(this.generateReasonWithPrefix("命令元数据发生变化,对应表单:" + formContent.getModule().getCode() + ",对应命令元数据ID为:" + webCmdId)); + break; + } + } else { + metadataProjectService.updateRefMetadataChanged(context.getProjectPath(), OperationEnum.WEB_GENERATE, new MetadataURI(webCmdId)); + } + } + } + return executeResult; + } + + /** + * 检测表单关联状态机 + * + * @param context + * @param metadataProjectService + * @param formContent + * @param currentStateMachineList + * @return + */ + private ChangeDetectStepExecuteResult checkStateMachineMetadataChanged(ChangeDetectContext context, MetadataProjectService metadataProjectService, FormDOM formContent, ArrayList> currentStateMachineList, ExecuteType executeType) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + if (currentStateMachineList != null && !currentStateMachineList.isEmpty()) { + for (HashMap smItem : currentStateMachineList) { + String smItemMetadataId = (String) smItem.get("uri"); + if (!StringUtility.isNullOrEmpty(smItemMetadataId)) { + if (executeType == ExecuteType.Check) { + boolean smItemMetadataChangedFlag = metadataProjectService.isRefMetadataChanged(context.getProjectPath(), OperationEnum.WEB_GENERATE, new MetadataURI(smItemMetadataId)); + if (smItemMetadataChangedFlag) { + executeResult.setUnPassReason(this.generateReasonWithPrefix("状态机元数据发生变化,对应表单:" + formContent.getModule().getCode() + ",对应状态机元数据ID为:" + smItemMetadataId)); + break; + } + } else { + metadataProjectService.updateRefMetadataChanged(context.getProjectPath(), OperationEnum.WEB_GENERATE, new MetadataURI(smItemMetadataId)); + } + } + } + } + return executeResult; + } + + /** + * 针对元数据的变更回写动作 + * + * @param context + * @return + */ + @Override + public ChangeDetectStepExecuteResult updateChangeset(ChangeDetectContext context) { + ChangeDetectStepExecuteResult executeResult = ChangeDetectStepExecuteResult.getPassResult(ChangeDetectExecuteType.Generate); + MetadataProjectService metadataProjectService = this.getMetadataProjectService(); + // 首先进行元数据变化的检测 如果发生变化 那么认定需要重新生成 + metadataProjectService.updateMetadataChanges(context.getProjectPath(), OperationEnum.WEB_GENERATE, this::checkFilePath); + + // 更新表单依赖元数据变更 + checkFormRelyMetadataChanged(context, metadataProjectService, ExecuteType.UpdateChangeset); + + return executeResult; + } + + public enum ExecuteType { + Check, + UpdateChangeset + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/AbstractChangeDetectStepExecuteService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/AbstractChangeDetectStepExecuteService.java new file mode 100644 index 00000000..e49fedb4 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/AbstractChangeDetectStepExecuteService.java @@ -0,0 +1,87 @@ +package com.inspur.edp.web.frontendproject.changedetect.step; + +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * @Title: AbstractChangeDetectStepExecuteService + * @Description: com.inspur.edp.web.frontendproject.changedetect + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 19:08 + */ +public abstract class AbstractChangeDetectStepExecuteService implements ChangeDetectStepExecuteService { + + protected String webDevPathName = "webdev"; + + protected String webSrcPathName = "src"; + + protected String webSrcAppPathName = "app"; + + protected String webSrcAppProjectsPathName = "projects"; + + protected String angularJsonName = "angular.json"; + + protected String packageJsonName = "package.json"; + + protected String tsConfigJsonName = "tsconfig.json"; + + protected String appConfigJsonName = "app.config.json"; + + /** + * 定义变更检测步骤执行的提示信息前缀 + * + * @return 自定义的提示信息前缀 + */ + protected abstract String getPrefixTip(); + + /** + * 获取对应的元数据projectService + * + * @return + */ + protected MetadataProjectService getMetadataProjectService() { + return SpringBeanUtils.getBean(MetadataProjectService.class); + } + + /** + * 获取src/app 目录 路径 + * + * @param context + * @return + */ + protected String getSrcAppPath(ChangeDetectContext context) { + return FileUtility.combine(context.getProjectPath(), this.webSrcPathName, context.getTerminalType().getAppPathName()); + } + + + /** + * 获取src 目录 路径 + * + * @param context + * @return + */ + protected String getSrcPath(ChangeDetectContext context) { + return FileUtility.combine(context.getProjectPath(), this.webSrcPathName); + } + + /** + * 获取src/webdev 目录 路径 + * + * @param context + * @return + */ + protected String getSrcWebDevPath(ChangeDetectContext context) { + return FileUtility.combine(context.getProjectPath(), this.webSrcPathName, context.getTerminalType().getWebDevPathName()); + } + + /** + * @param reason + * @return + */ + protected String generateReasonWithPrefix(String reason) { + return this.getPrefixTip() + reason; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteResult.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteResult.java new file mode 100644 index 00000000..2b0c8581 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteResult.java @@ -0,0 +1,84 @@ +package com.inspur.edp.web.frontendproject.changedetect.step; + +import com.inspur.edp.web.frontendproject.changedetect.ChangeDetectExecuteType; + +/** + * @Title: ChangeDetectStepExecuteResult + * @Description: 变更检测具体步骤执行结果 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 11:41 + */ +public class ChangeDetectStepExecuteResult { + /** + * 是否执行验证通过 + */ + private boolean pass; + /** + * 如果未验证通过 具体的未通过原因 + */ + private String reason; + + /** + * 当前执行变更检测类型 + */ + private ChangeDetectExecuteType currentExecuteType = ChangeDetectExecuteType.Generate; + + public boolean isPass() { + return pass; + } + + public void setPass(boolean pass) { + this.pass = pass; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public ChangeDetectExecuteType getCurrentExecuteType() { + return currentExecuteType; + } + + public void setCurrentExecuteType(ChangeDetectExecuteType currentExecuteType) { + this.currentExecuteType = currentExecuteType; + } + + /** + * 私有 无参构造方法 避免直接构造 + */ + private ChangeDetectStepExecuteResult() { + } + + private ChangeDetectStepExecuteResult(ChangeDetectExecuteType currentExecuteType, boolean isPass, String unPassReason) { + this.currentExecuteType = currentExecuteType; + this.pass = isPass; + this.reason = unPassReason; + } + + /** + * @param currentExecuteType + * @return + */ + public static ChangeDetectStepExecuteResult getPassResult(ChangeDetectExecuteType currentExecuteType) { + return new ChangeDetectStepExecuteResult(currentExecuteType, true, null); + } + + public static ChangeDetectStepExecuteResult getUnPassResult(ChangeDetectExecuteType currentExecuteType, String reason) { + return new ChangeDetectStepExecuteResult(currentExecuteType, false, reason); + } + + /** + * 设置未通过原因 并同步设置状态为未通过 + * @param reason + */ + public void setUnPassReason(String reason) { + this.reason = reason; + this.pass = false; + } + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteService.java new file mode 100644 index 00000000..7cb55450 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/changedetect/step/ChangeDetectStepExecuteService.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.frontendproject.changedetect.step; + +import com.inspur.edp.web.frontendproject.changedetect.context.ChangeDetectContext; + +/** + * @Title: ChangeDetectStepExecutor + * @Description: 变更检测步骤执行接口 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/6/21 11:40 + */ +public interface ChangeDetectStepExecuteService { + /** + * 步骤执行器参数 + * @param context 变更检测上下文参数 + * @return + */ + ChangeDetectStepExecuteResult execute(ChangeDetectContext context); + + /** + * 针对元数据的变更回写动作 + * @param context + * @return + */ + ChangeDetectStepExecuteResult updateChangeset(ChangeDetectContext context); + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FormMetadataDebugUriConfiguration.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FormMetadataDebugUriConfiguration.java new file mode 100644 index 00000000..a1230d4a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FormMetadataDebugUriConfiguration.java @@ -0,0 +1,33 @@ +package com.inspur.edp.web.frontendproject.config; + +import com.inspur.edp.web.frontendproject.debuguri.FormMetadataDebugUriWithMobile; +import com.inspur.edp.web.frontendproject.debuguri.FormMetadataDebugUriWithPC; +import com.inspur.edp.web.frontendproject.webservice.FormMetadataDebugUriWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * description: 表单预览接口 configuration + * + * @author Noah Guo + * @date 2021/01/16 + */ +@Configuration +public class FormMetadataDebugUriConfiguration { + @Bean() + public RESTEndpoint formMetadataDebugUriWebServiceEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/form-debug-uri", new FormMetadataDebugUriWebServiceImpl() { + }); + } + + @Bean + public FormMetadataDebugUriWithPC getFormMetadataDebugUriInPC() { + return new FormMetadataDebugUriWithPC(); + } + + @Bean + public FormMetadataDebugUriWithMobile getFormMetadataDebugUriInMobile() { + return new FormMetadataDebugUriWithMobile(); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FrontendProjectConfiguration.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FrontendProjectConfiguration.java new file mode 100644 index 00000000..119c6140 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/FrontendProjectConfiguration.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.frontendproject.config; + +import com.inspur.edp.web.frontendproject.webservice.FrontendProjectWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/16 + */ +@Configuration() +public class FrontendProjectConfiguration { + + @Bean() + public RESTEndpoint frontendProjectWebServiceEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/frontend-project", new FrontendProjectWebServiceImpl()); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/ZeroCodeConfiguration.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/ZeroCodeConfiguration.java new file mode 100644 index 00000000..5a15458a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/config/ZeroCodeConfiguration.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.frontendproject.config; + +import com.inspur.edp.web.frontendproject.webservice.ZeroCodeWebServiceImpl; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ZeroCodeConfiguration { + @Bean + public ZeroCodeServiceImpl zeroCodeServiceImpl() { + return new ZeroCodeServiceImpl(); + } + + @Bean() + public RESTEndpoint zeroCodeWebServiceEndPoint() { + return new RESTEndpoint("/runtime/main/v1.0/zerocode", new ZeroCodeWebServiceImpl() { + }); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/customservice/SourceServicePathGenerator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/customservice/SourceServicePathGenerator.java new file mode 100644 index 00000000..c021cf0b --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/customservice/SourceServicePathGenerator.java @@ -0,0 +1,55 @@ +package com.inspur.edp.web.frontendproject.customservice; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; + +/** + * 自定义代码构件 + * + * @author guozhiqi + */ +public class SourceServicePathGenerator { + + /** + * 获取自定义代码路径 + * + * @param projectPath + * @param terminalType + * @return + */ + public static String getSourceServiceProductPath(String projectPath, TerminalType terminalType, boolean isSingleDynamicForm) { + String serviceRelativeProductPath = FrontendProjectUtility.getServiceRelativeProductPath(terminalType, isSingleDynamicForm); + return FileUtility.combine(projectPath, serviceRelativeProductPath); + } + + /** + * 获取命令控件ts的部署位置 + * + * @param projectPath + * @param terminalType + * @param isSingleDynamicForm + * @return + */ + public static String getTargetServiceProductPath(String projectPath, TerminalType terminalType, boolean isSingleDynamicForm) { + String targetServiceProductPath = ""; + + if (terminalType == TerminalType.PC) { + if (isSingleDynamicForm) { + // 定义解析表单service的部署路径 主要目的是部署解析表单依赖js + targetServiceProductPath = projectPath + "/src" + "/" + FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic; + } else { + targetServiceProductPath = projectPath + "/src" + "/app/projects" + "/" + GspProjectUtil.getProjectName(projectPath) + "/src/app"; + } + } else if (terminalType == TerminalType.MOBILE) { + targetServiceProductPath = projectPath + "/src" + "/mobileapp" + "/src/apps"; + } else { + throw new GSPException("WEB_GenerateFrontendProject", "暂不支持的终端类型:" + terminalType + "。请联系管理员处理。"); + } + + return targetServiceProductPath; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/AbstractFormMetadataDebugUri.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/AbstractFormMetadataDebugUri.java new file mode 100644 index 00000000..d80b07f9 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/AbstractFormMetadataDebugUri.java @@ -0,0 +1,98 @@ +package com.inspur.edp.web.frontendproject.debuguri; + +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.service.RouteMetataService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * @Title: AbstractFormMetadataDebugUri + * @Description: com.inspur.edp.web.frontendproject.debuguri 合并移动和PC的公共代码部分 + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/4 17:04 + */ +public abstract class AbstractFormMetadataDebugUri { + protected TerminalType terminalType; + + public AbstractFormMetadataDebugUri(TerminalType terminalType) { + this.terminalType = terminalType; + } + + /** + * 提取debuguri地址 + * @param formMetadataRelativePath + * @param formMetadataId + * @return + */ + public abstract String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId); + + /** + * 判断是否为PC表单 + * + * @return + */ + protected boolean isPc() { + return this.terminalType == TerminalType.PC; + } + + /** + * 获取工程目录下得页面流元数据信息 + * + * @param projectPath 工程路径 + * @return + */ + protected PageFlowMetadataEntity getRouteMetadataContent(String projectPath) { + PageFlowMetadataEntity pageFlowMetadataEntity = null; + + // 1.获取路由元数据中内容 + GspAppConfig appConfig = GspAppConfigService.getCurrent().getOrCreateAppConfig(projectPath); + // 非前端工程 + if (appConfig == null) { + return null; + } + // 2.获取路由元数据中内容 + if (isPc()) { + pageFlowMetadataEntity = RouteMetataService.getRouteMetadataContentWithMetadataIdAndProjectPath(appConfig.getPageFlowMetadataID(), appConfig.getPageFlowMetadataFileName(), projectPath); + } else { + pageFlowMetadataEntity = RouteMetataService.getRouteMetadataContentWithMetadataIdAndProjectPath(appConfig.getMobilePageFlowMetadataID(), appConfig.getMobilePageFlowMetadataFileName(), projectPath); + } + + return pageFlowMetadataEntity; + } + + protected String getFormMetadataRouteUriWithDevPath(String projectPath, String formMetadataId) { + String routeUri = ""; + + if (StringUtility.isNullOrEmpty(projectPath) || StringUtility.isNullOrEmpty(formMetadataId)) { + return routeUri; + } + + PageFlowMetadataEntity pageFlowMetadataEntity = getRouteMetadataContent(projectPath); + if (pageFlowMetadataEntity == null) { + return routeUri; + } + + routeUri = PageFlowMetadataEntity.GetPageRouteUri(pageFlowMetadataEntity, formMetadataId); + + return routeUri; + } + + protected String getFormMetadataRouteUriWithoutDevPath(String projectPath, String formMetadataId) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + return getFormMetadataRouteUriWithDevPath(projectPath, formMetadataId); + } + + protected String getFormMetadataRouteUri(String formMetadataRelativePath, String formMetadataId) { + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProject = metadataProjectService.getMetadataProjInfo(formMetadataRelativePath); + + return getFormMetadataRouteUriWithoutDevPath(metadataProject.getProjectPath(), formMetadataId); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriService.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriService.java new file mode 100644 index 00000000..aa320e64 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriService.java @@ -0,0 +1,36 @@ +package com.inspur.edp.web.frontendproject.debuguri; + +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * description: 表单调试地址 + * + * @author Noah Guo + * @date 2021/03/17 + */ +public class FormMetadataDebugUriService { + /** + * 获取表单调试地址 + * + * @param formMetadataRelativePath 表单所在工程路径 + * @param formMetadataId 表单元数据id + * @param formType 表单类型 + * @return + */ + public static String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId, String formType) { + String debugUri; + switch (formType) { + case "mobile": + debugUri = SpringBeanUtils.getBean(FormMetadataDebugUriWithMobile.class).getFormMetadataDebugUri(formMetadataRelativePath, formMetadataId); + break; + case "pc": + default: + debugUri = SpringBeanUtils.getBean(FormMetadataDebugUriWithPC.class).getFormMetadataDebugUri(formMetadataRelativePath, formMetadataId); + break; + } + + return debugUri; + } + + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithMobile.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithMobile.java new file mode 100644 index 00000000..99bb58bb --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithMobile.java @@ -0,0 +1,85 @@ +package com.inspur.edp.web.frontendproject.debuguri; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContentService; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * description:移动表单调试Url地址 + * + * @author Noah Guo + * @date 2021/03/17 + */ +public class FormMetadataDebugUriWithMobile extends AbstractFormMetadataDebugUri { + public FormMetadataDebugUriWithMobile() { + super(TerminalType.MOBILE); + } + + @Override + public String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId) { + // 1. 获取表单元数据对应route Uri + String formRouteUri = getFormMetadataRouteUri(formMetadataRelativePath, formMetadataId); + + // 获取表单实体,进而获取表单代码 + String defaultPageUri = ""; + + // RefCommonService refCommonService = SpringBeanUtils.getBean(RefCommonService.class); + // GspMetadata metadata = refCommonService.getRefMetadata(formMetadataId); + // 进行元数据的调用借口获取方式调整 + GspMetadata metadata=MetadataUtility.getInstance().getMetadataWithEnvironment(formMetadataId, ExecuteEnvironment.Design,false); + FormMetadataContent formMetadataContent = (FormMetadataContent) metadata.getContent(); + FormDOM formDom = FormMetadataContentService.getInstance().getFormContent(formMetadataContent); + HashMap component = null; + ArrayList> components = formDom.getModule().getComponents(); + if (components != null && !components.isEmpty()) { + // 使用第一组件作为默认组件 + component = components.get(0); + } + + if (component == null) { + defaultPageUri = ""; + } else { + if (component.containsKey("route")) { + HashMap routeObject = convertToDictionaryObject(component.get("route")); + if (routeObject.containsKey("uri")) { + defaultPageUri = routeObject.get("uri").toString(); + } + } + + if (StringUtility.isNullOrEmpty(defaultPageUri)) { + defaultPageUri = component.get("id").toString(); + } + } + + // 2. 获取部署路径 + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProject = metadataProjectService.getMetadataProjInfo(formMetadataRelativePath); + GspProject gspProject = GspProjectUtil.getGspProject(metadataProject.getProjectPath()); + + String projectName = GspProjectUtil.getProjectName(metadataProject.getProjectPath()); + + String formPublishPath = FrontendProjectUtility.getFormPublishPath(TerminalType.MOBILE); + return "/" + gspProject.getSuDeploymentPath().toLowerCase() + "/" + formPublishPath + "/" + projectName + "/" + "index.html" + "#" + "/" + formRouteUri + "/" + defaultPageUri; + } + + + private HashMap convertToDictionaryObject(Object targetObject) { + String json = SerializeUtility.getInstance().serialize(targetObject, false); + return SerializeUtility.getInstance().deserialize(json, HashMap.class); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithPC.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithPC.java new file mode 100644 index 00000000..531dd3b7 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/debuguri/FormMetadataDebugUriWithPC.java @@ -0,0 +1,39 @@ +package com.inspur.edp.web.frontendproject.debuguri; + +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * description: 表单调试Url地址 + * + * @author Noah Guo + * @date 2021/03/17 + */ +public class FormMetadataDebugUriWithPC extends AbstractFormMetadataDebugUri { + public FormMetadataDebugUriWithPC() { + super(TerminalType.PC); + } + + @Override + public String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId) { + // 1. 获取表单元数据对应route Uri + String routeUri = getFormMetadataRouteUri(formMetadataRelativePath, formMetadataId); + + // 2. 获取部署路径 + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProject = metadataProjectService.getMetadataProjInfo(formMetadataRelativePath); + GspProject gspProject = GspProjectUtil.getGspProject(metadataProject.getProjectPath()); + String deploymentPath = "/" + gspProject.getSuDeploymentPath().toLowerCase(); + + String projectName = GspProjectUtil.getProjectName(metadataProject.getProjectPath()); + + return deploymentPath + "/" + FrontendProjectConstant.FORM_PUBLISH_PATH + "/" + projectName + "/" + "index.html" + "#" + routeUri; + } + + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/FrontendProjectDeploy.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/FrontendProjectDeploy.java new file mode 100644 index 00000000..c1111ed7 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/FrontendProjectDeploy.java @@ -0,0 +1,59 @@ +package com.inspur.edp.web.frontendproject.deploy; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectDeployer; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +public class FrontendProjectDeploy { + public static void deployFrontendProject(String projectPath) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_DeployFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + try { + FrontendProjectDeployer frontendProjectDeployer = new FrontendProjectDeployer(); + frontendProjectDeployer.deploy(projectPath); + } catch (RuntimeException exception) { + throw new GSPException("WEB_DeployFrontendProject", String.format("Error When Deploying a Frontend. Current Project Path is: %1$s", projectPath), exception); + } + } + + /** + * 解析表单的部署 + * @param dynamicParameter + */ + public static void deployFrontendProjectForJieXi(FormDynamicParameter dynamicParameter) { + String projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(dynamicParameter.getProjectPath()); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_DeployFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + try { + FrontendProjectDeployer frontendProjectDeployer = new FrontendProjectDeployer(); + frontendProjectDeployer.deployForJieXi(projectPath,dynamicParameter); + } catch (RuntimeException exception) { + throw new GSPException("WEB_DeployFrontendProject", String.format("Error When Deploying a Frontend. Current Project Path is: %1$s", projectPath), exception); + } + } + + public static void deployFrontendProjectForBabel(String projectPath) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_DeployFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + try { + FrontendProjectDeployer frontendProjectDeployer = new FrontendProjectDeployer(); + frontendProjectDeployer.deployForBabel(projectPath); + } catch (RuntimeException exception) { + throw new GSPException("WEB_DeployFrontendProject", String.format("Error When Deploying a Frontend. Current Project Path is: %1$s", projectPath), exception); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/SingleDynamicFormDeploy.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/SingleDynamicFormDeploy.java new file mode 100644 index 00000000..79331ecb --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/deploy/SingleDynamicFormDeploy.java @@ -0,0 +1,39 @@ +package com.inspur.edp.web.frontendproject.deploy; + +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; + +/** + * @Title: SingleDynamicFormDeploy + * @Description: com.inspur.edp.web.frontendproject.deploy 单个解析表单得部署过程 + * + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/12 16:39 + */ +public class SingleDynamicFormDeploy { + public void deploy(String targetDeployBasePath, String projectName, String projectPath,FormDynamicParameter dynamicParameter){ + + String strFormMetadataFilePath = FileUtility.combine(projectPath, "metadata"); + String targetFormMetadataPath = FileUtility.combine(targetDeployBasePath, "web", projectName.toLowerCase(), dynamicParameter.getFormCode().toLowerCase()); + + if (FileUtility.exists(strFormMetadataFilePath)) { + // 首先进行文件目录删除 + //FileUtility.deleteFolder(targetFormMetadataPath); + // 进行文件拷贝 + FileUtility.copyFolder(strFormMetadataFilePath, targetFormMetadataPath); + } + + //复制 + String strFormServicePath = FileUtility.combine(projectPath, "src", FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_Dynamic, "services", dynamicParameter.getFormCode().toLowerCase()); + String customServicePath = FileUtility.combine(strFormServicePath, "services", "dist-rollup"); + if (FileUtility.exists(customServicePath)) { + //String targetFormMetadataServicePath = FileUtility.combine(targetFormMetadataPath, "services"); + String targetFormMetadataServicePath = targetFormMetadataPath; + // 删除目标文件目录 + //FileUtility.deleteFolder(targetFormMetadataServicePath); + FileUtility.copyFolder(customServicePath, targetFormMetadataServicePath); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicMetadataResolver.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicMetadataResolver.java new file mode 100644 index 00000000..005a65e0 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicMetadataResolver.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.frontendproject.formdynamic; + +import com.inspur.edp.web.frontendproject.FrontendProjectService; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; + +/** + * 解析型表单 元数据解析 + * + * @author guozhiqi + */ +public class FormDynamicMetadataResolver { + /** + * 元数据解析 + * + * @param dynamicParameter + */ + public static void resolve(FormDynamicParameter dynamicParameter, ChosenFormList buildFormList) { + + // 执行工程参数得提取 + FrontendProjectService.getInstance().resolveFormMetadatas(dynamicParameter.getProjectPath(), buildFormList); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicParameterValidator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicParameterValidator.java new file mode 100644 index 00000000..f987d39c --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicParameterValidator.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.frontendproject.formdynamic; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; + +/** + * 表单解析参数校验 + * + * @author guozhiqi + */ +public class FormDynamicParameterValidator { + public static void validate(FormDynamicParameter dynamicParameter) { + + if (StringUtility.isNullOrEmpty(dynamicParameter.getProjectPath())) { + throw new GSPException("", "表单解析工程路径不能为空,请设置!"); + } + + if (dynamicParameter.isUseSingleForm() && StringUtility.isNullOrEmpty(dynamicParameter.getFormCode())) { + throw new GSPException("10001", "已启用单个表单解析,请设置表单编号"); + } + + // 如果不是单表单解析 且设置了formCode + if (!dynamicParameter.isUseSingleForm() && !StringUtility.isNullOrEmpty(dynamicParameter.getFormCode())) { + throw new GSPException("10001", "使用工程级别表单解析,请勿设置表单编号"); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicSourceCodeGenerate.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicSourceCodeGenerate.java new file mode 100644 index 00000000..f341e942 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicSourceCodeGenerate.java @@ -0,0 +1,25 @@ +package com.inspur.edp.web.frontendproject.formdynamic; + +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.entity.FrontendProjectGenerateParameter; +import com.inspur.edp.web.frontendproject.generate.FrontendProjectGenerate; +import com.inspur.edp.web.frontendproject.webservice.FormDynamicParameter; + +/** + * 解析表单代码生成 + */ +public class FormDynamicSourceCodeGenerate { + /** + * 执行代码生成 + * @param jieXiParameter + */ + public static void generate(FormDynamicParameter jieXiParameter, ChosenFormList buildFormList){ + FrontendProjectGenerateParameter generateParameter = new FrontendProjectGenerateParameter(); + // 如果是单个表单 那么强制执行解析 如果是工程级别 那么按照表单具体的参数配置进行 + generateParameter.setForceUseJieXi(jieXiParameter.isUseSingleForm()); + generateParameter.setProjectPath(jieXiParameter.getProjectPath()); + generateParameter.setBuildFormList(buildFormList); + + FrontendProjectGenerate.generateFrontendProject(generateParameter); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicTagGetter.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicTagGetter.java new file mode 100644 index 00000000..eb05c40f --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/formdynamic/FormDynamicTagGetter.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.frontendproject.formdynamic; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; + +/** + * @Title: FormDynamicTagGeberator + * @Description: com.inspur.edp.web.frontendproject.formdynamic + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/5/16 11:13 + */ +public class FormDynamicTagGetter { + /** + * 从表单元数据中获取是否解析表单得标识 + * + * @param gspMetadata 表单元数据 + * @return + */ + public static boolean getDynamicFormTagWithGspMetadata(GspMetadata gspMetadata) { + if (gspMetadata == null || gspMetadata.getContent() == null) { + return false; + } + String formDom = ((FormMetadataContent) gspMetadata.getContent()).getContents().toString(); + // 反序列化表单元数据 + FormDOM json = SerializeUtility.getInstance().deserialize(formDom, FormDOM.class); + return json.getOptions().isEnableFormJieXi(); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java new file mode 100644 index 00000000..1ecf3f0b --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/generate/FrontendProjectGenerate.java @@ -0,0 +1,108 @@ +package com.inspur.edp.web.frontendproject.generate; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.FrontendProjectConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.EnvironmentException; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectUtility; +import com.inspur.edp.web.frontendproject.customservice.SourceServicePathGenerator; +import com.inspur.edp.web.frontendproject.entity.FrontendProjectGenerateParameter; +import com.inspur.edp.web.frontendproject.metadata.FormMetadataManager; +import com.inspur.edp.web.jitengine.JITEngineManager; +import io.iec.edp.caf.commons.exception.ExceptionLevel; + +/** + * 前端工程代码生成 + * + * @author guozhiqi + */ +public class FrontendProjectGenerate { + public static void generateFrontendProject(String projectPath) { + FrontendProjectGenerateParameter generateParameter = new FrontendProjectGenerateParameter(); + generateParameter.setProjectPath(projectPath); + + generateFrontendProject(generateParameter); + } + + public static void generateFrontendProject(FrontendProjectGenerateParameter generateParameter) { + String projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(generateParameter.getProjectPath()); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_ResovleFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + // 调整工程路径参数 + generateParameter.setProjectPath(projectPath); + + try { + + if (FormMetadataManager.checkFormMetadataExists(projectPath, TerminalType.PC, generateParameter.getBuildFormList(), generateParameter.isForceUseJieXi(), true)) { + generateFrontendProject(generateParameter, TerminalType.PC); + } + + if (FormMetadataManager.checkFormMetadataExists(projectPath, TerminalType.MOBILE, generateParameter.getBuildFormList(), generateParameter.isForceUseJieXi(), true)) { + generateFrontendProject(generateParameter, TerminalType.MOBILE); + } + } catch (EnvironmentException ex) { + throw new GSPException("WEB_ResovleFrontendProject", ex.getMessage(), ex); + } catch (RuntimeException exception) { + throw new GSPException("WEB_ResovleFrontendProject", String.format("Error When Generating a Frontend Project. Current Project Path is: %1$s。%2$s", projectPath, exception.getMessage()), exception); + } + } + + + public static void generateFrontendProject(String projectPath, TerminalType terminalType) { + FrontendProjectGenerateParameter generateParameter = new FrontendProjectGenerateParameter(); + generateParameter.setProjectPath(projectPath); + generateFrontendProject(generateParameter, terminalType); + } + + /** + * 基于解析后的表单代码生成前端工程 + */ + private static void generateFrontendProject(FrontendProjectGenerateParameter generateParameter, TerminalType terminalType) { + // TODO refNodeMOdules 设置为了null 需调整 + boolean isJieXiForm = generateParameter != null && generateParameter.isForceUseJieXi(); + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + if (!FileUtility.isAbsolute(devRootPath)) { + devRootPath = FileUtility.getAbsolutePathHead(devRootPath) + devRootPath; + } + JITEngineManager.generateFrontendProject(generateParameter, devRootPath, terminalType); + String targetServiceProductPath = SourceServicePathGenerator.getTargetServiceProductPath(generateParameter.getProjectPath(), terminalType, isJieXiForm); + + String sourceServiceProductPath = SourceServicePathGenerator.getSourceServiceProductPath(generateParameter.getProjectPath(), terminalType, generateParameter.isForceUseJieXi()); + boolean isPathExists = FileUtility.exists(sourceServiceProductPath); + if (isPathExists) { + FileUtility.copyFolder(sourceServiceProductPath, targetServiceProductPath); + } + } + + public static void generateFrontendProjectForBabel(String projectPath) { + projectPath = FrontendProjectUtility.getProjectPathWithDevRootPath(projectPath); + + if (StringUtility.isNullOrEmpty(projectPath)) { + throw new GSPException("WEB_ResovleFrontendProject", "Current Project Path is Null or Empty", null, ExceptionLevel.Warning); + } + + try { + + JITEngineManager.generateFrontendProjectForBabel(projectPath); + + // 生成后动作 + String babelProjectName = GspProjectUtil.getProjectName(projectPath) + "forbabel"; + String targetServiceProductPath = projectPath + "/src" + "/" + FrontendProjectConstant.PROJECT_GENERATE_PATH_FOR_BABEL + "/projects" + "/" + babelProjectName + "/src/app"; + String sourceServiceProductPath = java.nio.file.Paths.get(projectPath).resolve(FrontendProjectConstant.SERVICES_RELATIVE_PRODUCT_PATH).toString(); + boolean isPathExists = FileUtility.exists(sourceServiceProductPath); + if (isPathExists) { + FileUtility.copyFolder(sourceServiceProductPath, targetServiceProductPath); + } + } catch (EnvironmentException ex) { + throw new GSPException("WEB_ResovleFrontendProject", ex.getMessage(), ex); + } catch (RuntimeException exception) { + throw new GSPException("WEB_ResovleFrontendProject", String.format("Error When Generating a Frontend Project. Current Project Path is: %1$s。 %2$s", projectPath, exception.getMessage()), exception); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/metadata/FormMetadataManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/metadata/FormMetadataManager.java new file mode 100644 index 00000000..474f7a3c --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/metadata/FormMetadataManager.java @@ -0,0 +1,134 @@ +package com.inspur.edp.web.frontendproject.metadata; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.RandomUtility; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.formdynamic.FormDynamicTagGetter; +import com.inspur.edp.web.frontendproject.pageflow.PageFlowMetadataManager; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataList; +import com.inspur.edp.web.pageflow.metadata.entity.Page; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.service.PageFlowMetadataUpdateService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +/** + * 表单元数据管理 + * + * @author guozhiqi + */ +public class FormMetadataManager { + + /** + * 检查表单元数据是否存在 + */ + public static boolean checkFormMetadataExists(String projectPath, TerminalType terminalType, ChosenFormList buildFormList, boolean isJieXiForm, boolean saveRouteJson) { + return FormMetadataManager.getFormMetadataList(projectPath, terminalType, buildFormList, saveRouteJson).isNotEmpty(); + } + + + /** + * 获取表单元数据列表 默认会保存页面流文件内容至route.json + */ + public static ResolveFormMetadataList getFormMetadataList(String projectPath, TerminalType terminalType, ChosenFormList buildFormList) { + return getFormMetadataList(projectPath, terminalType, buildFormList, true); + } + + /** + * 解析表单元数据列表 + * 为了支持元数据变更检测 ,所以增加参数saveRouteJson,布进行route.json 文件保存动作 + * + * @param projectPath + * @param terminalType + * @param buildFormList + * @param saveRouteJson + * @return + */ + public static ResolveFormMetadataList getFormMetadataList(String projectPath, TerminalType terminalType, ChosenFormList buildFormList, boolean saveRouteJson) { + // 1.从工程中读取工程配置文件 + GspAppConfig appConfigurationInfo = GspAppConfigService.getCurrent().getOrCreateAppConfig(projectPath); + + // 2.获取路由元数据中内容 + ResolveFormMetadataList formMetadataList = ResolveFormMetadataList.getNewInstance(); + PageFlowMetadataEntity pageFlowMetadataEntity; + + // 如果为空那么设置其为默认值 + if (buildFormList == null) { + buildFormList = ChosenFormList.getNewInstance(); + } + + if (buildFormList.isNotEmpty()) { + String id = RandomUtility.newGuid(); + PageFlowMetadataEntity fullPageFlowEntity = PageFlowMetadataUpdateService.getInstance().createPageFlowMetadataEntity(id, projectPath, terminalType.getFormMetadataSuffix()); + pageFlowMetadataEntity = PageFlowMetadataManager.filterPageFlowPages(fullPageFlowEntity, buildFormList); + } else { + pageFlowMetadataEntity = PageFlowMetadataManager.getPageFlowEntityList(projectPath, appConfigurationInfo, terminalType); + + // 页面流不存在、页面流中没有表单时返回空列表 + if (pageFlowMetadataEntity == null || pageFlowMetadataEntity.getPages() == null || pageFlowMetadataEntity.getPages().length == 0) { + return formMetadataList; + } + } + + // 3.将路由元数据内容暂存到指定目录下 + if (saveRouteJson) { + PageFlowMetadataManager.saveRouteMetadata(pageFlowMetadataEntity, projectPath, terminalType); + } + + // 4.获取待编译表单元数据集合 + formMetadataList = getFormMetadataList(pageFlowMetadataEntity.getPages(), projectPath); + + return formMetadataList; + } + + + /** + * 根据页面流文件信息获取对应的表单元数据信息 + * + * @param pages + * @return + */ + private static ResolveFormMetadataList getFormMetadataList(Page[] pages, String projectPath) { + ResolveFormMetadataList matchedFormMetadataList = ResolveFormMetadataList.getNewInstance(); + + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + for (Page page : pages) { + String pageRelativePath = modifyPageRelativePath(page.getRelativePath(), projectPath); + + if (!metadataService.isMetadataExist(pageRelativePath, page.getFileName())) { + throw new RuntimeException("页面流文件(后缀为.pf)中包含绝对路径,需调整为相对路径。 请打开页面流文件,通过将表单从页面流中先移除再添加的方式,自动进行调整。 对应表单元数据为:" + page.getName() + ",当前绝对路径为:" + page.getRelativePath()); + } + GspMetadata currentRouteMetadata = metadataService.loadMetadata(page.getFileName(), pageRelativePath); + + // 读取元数据得解析状态标识 + boolean dynamicFormTag = FormDynamicTagGetter.getDynamicFormTagWithGspMetadata(currentRouteMetadata); + + matchedFormMetadataList.add(currentRouteMetadata, page.isForceDynamicForm(), dynamicFormTag); + } + + + return matchedFormMetadataList; + } + + /** + * 修正页面相对路径 避免由于绝对路径问题导致生成异常 + * + * @param relativePath + * @param projectPath + * @return + */ + private static String modifyPageRelativePath(String relativePath, String projectPath) { + String inDependentRelativePath = FileUtility.getPlatformIndependentPath(relativePath); + String inDependentProjectPath = FileUtility.getPlatformIndependentPath(projectPath); + // 如果包含工程路径 + if (inDependentRelativePath.contains(inDependentProjectPath)) { + String tempRelativePath = inDependentRelativePath.substring(inDependentRelativePath.lastIndexOf(inDependentProjectPath)); + return tempRelativePath; + } + return inDependentRelativePath; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/pageflow/PageFlowMetadataManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/pageflow/PageFlowMetadataManager.java new file mode 100644 index 00000000..424ebdfb --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/pageflow/PageFlowMetadataManager.java @@ -0,0 +1,178 @@ +package com.inspur.edp.web.frontendproject.pageflow; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.exception.MetadataNotFoundException; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPageFlowMetadataEntityService; +import com.inspur.edp.web.pageflow.metadata.entity.Page; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.service.PageFlowMetadataUpdateService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.nio.file.Paths; +import java.util.ArrayList; + +/** + * 页面流元数据manager + * @author guozhiqi + */ +public class PageFlowMetadataManager { + + private PageFlowMetadataManager() { + } + + /** + * 过滤指定的表单集合 + */ + public static PageFlowMetadataEntity filterPageFlowPages(PageFlowMetadataEntity pageFlowMetadataEntity, ChosenFormList buildFormList) { + // 如果过滤的表单集合为空或个数为空 那么认为不进行过滤 + if (buildFormList == null || buildFormList.isEmpty()) { + return pageFlowMetadataEntity; + } + // 定义一个新的页面流实体 + Object tempVar = pageFlowMetadataEntity.clone(); + PageFlowMetadataEntity filterPageFlowMetadataEntity = (PageFlowMetadataEntity) ((tempVar instanceof PageFlowMetadataEntity) ? tempVar : null); + if (filterPageFlowMetadataEntity == null) { + return pageFlowMetadataEntity; + } + + ArrayList pageList = new ArrayList<>(); + for (int i = 0; i < pageFlowMetadataEntity.getPages().length; i++) { + Page pageItem = pageFlowMetadataEntity.getPages()[i]; + String formCode = pageItem.getCode(); + // 区分大小写 + if (buildFormList.contains(formCode)) { + pageItem.setForceDynamicForm(buildFormList.getIsDynamicFormByFormCode(formCode)); + pageList.add(pageItem); + } + } + + filterPageFlowMetadataEntity.setPages(pageList.toArray(new Page[0])); + return filterPageFlowMetadataEntity; + } + + + /** + * 获取或创建对应的页面流 + */ + public static PageFlowMetadataEntity getPageFlowEntityList(String projectPath, GspAppConfig appConfigInfo, TerminalType terminalType) { + PageFlowMetadataEntity pageFlowMetadataEntity = null; + + if (!checkIfStorePageFlowId(projectPath, appConfigInfo, terminalType)) { + pageFlowMetadataEntity = createPageFlowEntity(projectPath, terminalType); + } else { + GspMetadata pageFlowMetadata = getPageFlowMetadata(projectPath, appConfigInfo, terminalType); + if (pageFlowMetadata == null) { + pageFlowMetadataEntity = null; + } else { + pageFlowMetadataEntity = (PageFlowMetadataEntity) (pageFlowMetadata.getContent()); + } + + // 兼容没有页面流元数据的场景 + if (pageFlowMetadataEntity == null) { + pageFlowMetadataEntity = createPageFlowEntity(projectPath, terminalType); + } + } + + return pageFlowMetadataEntity; + } + + /** + * 保存页面流元数据内容至工程目录下 + * @param pageFlowMetadataEntity + * @param targetStorageBasePath + * @param terminalType + */ + public static void saveRouteMetadata(PageFlowMetadataEntity pageFlowMetadataEntity, String targetStorageBasePath, TerminalType terminalType) { + String projectName = GspProjectUtil.getProjectName(targetStorageBasePath); + + AdaptedPageFlowMetadataEntity adaptedPageFlowMetadataEntity = AdaptedPageFlowMetadataEntityService.generateAdaptedPageFlowMetadataEntity(pageFlowMetadataEntity); + String metadataContent = AdaptedPageFlowMetadataEntityService.serialize(adaptedPageFlowMetadataEntity); + + String projectFormRelativeResolvePath = JITEngineManager.getProjectFormRelativeResolvePath(terminalType, false); + if (adaptedPageFlowMetadataEntity.getPages() != null && !adaptedPageFlowMetadataEntity.getPages().isEmpty()) { + FileUtility.writeFile(Paths.get(targetStorageBasePath).resolve(projectFormRelativeResolvePath).toString(), projectName + JITEngineConstants.ProjectRouteFileExtension, metadataContent); + } + } + + private static boolean checkIfStorePageFlowId(String projectPath, GspAppConfig appConfigInfo, TerminalType terminalType) { + boolean alreadyStoragedPageFlowId = true; + switch (terminalType) { + case PC: + if (StringUtility.isNullOrEmpty(appConfigInfo.getPageFlowMetadataID())) { + alreadyStoragedPageFlowId = false; + } + break; + case MOBILE: + if (StringUtility.isNullOrEmpty(appConfigInfo.getMobilePageFlowMetadataID())) { + alreadyStoragedPageFlowId = false; + } + break; + default: + throw new GSPException("Web_CheckIfStoragePageFlowId", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + return alreadyStoragedPageFlowId; + } + + /** + * 创建页面流元数据(没有表单时不创建,返回null) + */ + private static PageFlowMetadataEntity createPageFlowEntity(String projectPath, TerminalType terminalType) { + + // (1) 创建元数据 + GspMetadata routeMetadata = PageFlowMetadataUpdateService.getInstance().createRouteMetadataInMemory(projectPath, terminalType); + PageFlowMetadataEntity pageFlowMetadataEntity = (PageFlowMetadataEntity) routeMetadata.getContent(); + if (pageFlowMetadataEntity.getPages().length == 0) { + return null; + } + + // (2) 持久化页面流元数据 + String routeMetadataRelativePath = PageFlowMetadataUpdateService.getInstance().createRouteMetadataInDisk(routeMetadata); + + // (3) 回写appconfigInfo + GspAppConfigService.getCurrent().updateAppConfigFile(terminalType, routeMetadata.getHeader().getId(), routeMetadata.getHeader().getFileName(), routeMetadataRelativePath); + + return pageFlowMetadataEntity; + } + + private static GspMetadata getPageFlowMetadata(String projectPath, GspAppConfig appConfigInfo, TerminalType terminalType) { + // 获取元数据前,更新元数据上下文 + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.setMetadataUri(projectPath); + + String pageFlowMetadataID = ""; + switch (terminalType) { + case PC: + pageFlowMetadataID = appConfigInfo.getPageFlowMetadataID(); + break; + case MOBILE: + pageFlowMetadataID = appConfigInfo.getMobilePageFlowMetadataID(); + break; + default: + throw new GSPException("Web_GetPageFlowMetadata", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + // 判断元数据是否存在 + try { + GspMetadata pageFlowMetadata = metadataService.getRefMetadata(projectPath, pageFlowMetadataID); + return pageFlowMetadata; + } catch (MetadataNotFoundException ex) { + // 如果捕获到元数据找不到异常 那么重新进行元数据的创建 + LoggerUtility.log("找不到对应页面流元数据,对应页面流元数据id为:" + appConfigInfo.getPageFlowMetadataID(), LoggerLevelEnum.Info); + return null; + } + + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/resolver/FormMetadataResolver.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/resolver/FormMetadataResolver.java new file mode 100644 index 00000000..19215fbc --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/resolver/FormMetadataResolver.java @@ -0,0 +1,116 @@ +package com.inspur.edp.web.frontendproject.resolver; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.formmetadata.i18n.constant.I18nResourceConstant; +import com.inspur.edp.web.formmetadata.service.FormMetataService; +import com.inspur.edp.web.frontendproject.customservice.SourceServicePathGenerator; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataItem; +import com.inspur.edp.web.frontendproject.entity.resolver.ResolveFormMetadataList; +import com.inspur.edp.web.frontendproject.metadata.FormMetadataManager; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitengine.expressions.ExpressionManifest; +import com.inspur.edp.web.jitengine.expressions.ExpressionManifestManager; +import com.inspur.edp.web.jitengine.i18nresource.GenerateResourceManager; +import com.inspur.edp.web.jitengine.i18nresource.GeneratedI18nResourceList; + +import java.util.HashMap; + +/** + * 表单元数据解析 + * + * @author guozhiqi + */ +public class FormMetadataResolver { + /** + * 表单元数据解析 + * + * @param projectPath + * @param buildFormList + */ + public static void resolveFormMetadatas(String projectPath, ChosenFormList buildFormList) { + + if (buildFormList == null) { + throw new RuntimeException("表单元数据提取,buildFormList参数不能为空"); + } + ResolveFormMetadataList formMetadataList = FormMetadataManager.getFormMetadataList(projectPath, TerminalType.PC, buildFormList); + if (formMetadataList.isNotEmpty()) { + // 当前指定表单参与编译 仅影响PC + resolveFormMetadatas(projectPath, formMetadataList, TerminalType.PC); + } + + ResolveFormMetadataList mobileFormMetadataList = FormMetadataManager.getFormMetadataList(projectPath, TerminalType.MOBILE, ChosenFormList.getNewInstance()); + if (mobileFormMetadataList.isNotEmpty()) { + resolveFormMetadatas(projectPath, mobileFormMetadataList, TerminalType.MOBILE); + } + } + + /** + * 解析表单元数据,从 .frm 解析成 .json + */ + public static void resolveFormMetadatas(String projectPath, ResolveFormMetadataList formMetadataList, TerminalType terminalType) { + + String serviceProductPath = SourceServicePathGenerator.getSourceServiceProductPath(projectPath, terminalType, false); + + // 首先整体移除webdev目录下得services文件目录 + FileUtility.forceDelete(serviceProductPath); + + /** + * 获取解析表单的service路径 + */ + String dynamicServiceProductPath = SourceServicePathGenerator.getSourceServiceProductPath(projectPath, terminalType, true); + FileUtility.forceDelete(dynamicServiceProductPath); + + + HashMap projectCmpList = new HashMap<>(); + + for (ResolveFormMetadataItem resolveFormMetadataItem : formMetadataList.getResolveFormMetadataItemList()) { + GeneratedI18nResourceList i18nResourceList = new GeneratedI18nResourceList(); + GeneratedI18nResourceList zhI18nResourceList = new GeneratedI18nResourceList(); + GeneratedI18nResourceList zhCHTI18nResourceList = new GeneratedI18nResourceList(); + String i18nResourceKeyPrefix = ""; + + // 定义表单关联的表达式 + ExpressionManifest expressionManifest = new ExpressionManifest(); + + // 解析前检测 + // TODO:尝试获取资源元数据,如果不存在则生成 为了保证中文资源必须存在 + String formPath = resolveFormMetadataItem.getGspMetadata().getRelativePath(); + FormMetataService.reSaveFormIfResourceNotExists(resolveFormMetadataItem.getGspMetadata(), formPath); + + String targetResolveBasePath = terminalType.getResolveBasePath(projectPath, resolveFormMetadataItem.getCalculateIsDynamicForm()); + + if (resolveFormMetadataItem.getCalculateIsDynamicForm()) { + // 如果是解析表单 那么进行基础路径得修正 + targetResolveBasePath = FileUtility.combine(targetResolveBasePath, resolveFormMetadataItem.getGspMetadata().getHeader().getCode().toLowerCase()); + } + + serviceProductPath = SourceServicePathGenerator.getSourceServiceProductPath(projectPath, terminalType, resolveFormMetadataItem.getCalculateIsDynamicForm()); + + // 解析页面流中定义的表单元数据 + JITEngineManager.ResolveFormMetadata(resolveFormMetadataItem, formPath, projectPath, targetResolveBasePath, serviceProductPath, projectCmpList, + i18nResourceList, zhI18nResourceList, zhCHTI18nResourceList, expressionManifest, i18nResourceKeyPrefix, ExecuteEnvironment.Design, false); + + if (!resolveFormMetadataItem.getCalculateIsDynamicForm()) { + GenerateResourceManager.generateI18nJsonFile(i18nResourceList, FileUtility.combine(targetResolveBasePath, "i18n", resolveFormMetadataItem.getGspMetadata().getHeader().getCode().toLowerCase(), "i18n"), ""); + GenerateResourceManager.generateI18nJsonFile(zhCHTI18nResourceList, FileUtility.combine(targetResolveBasePath, "i18n", resolveFormMetadataItem.getGspMetadata().getHeader().getCode().toLowerCase(), "i18n"), I18nResourceConstant.ZH_CHT + ".json"); + } else { + GenerateResourceManager.generateI18nJsonFile(i18nResourceList, FileUtility.combine(targetResolveBasePath, "i18n"), ""); + GenerateResourceManager.generateI18nJsonFile(zhCHTI18nResourceList, FileUtility.combine(targetResolveBasePath, "i18n"), I18nResourceConstant.ZH_CHT + ".json"); + } + GenerateResourceManager.generateZhI18nJsonFile(zhI18nResourceList, targetResolveBasePath, String.format("%1$s.resource.json", resolveFormMetadataItem.getGspMetadata().getHeader().getFileName().toLowerCase())); + + // 写入表单表达式json文件 仅在PC下构造表达式 + if (terminalType == TerminalType.PC) { + ExpressionManifestManager.writeExpressionJson(expressionManifest, targetResolveBasePath, resolveFormMetadataItem.getCalculateIsDynamicForm()); + } + } + + projectCmpList.clear(); + } + + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebServiceImpl.java new file mode 100644 index 00000000..a7c50697 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FormMetadataDebugUriWebServiceImpl.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import com.inspur.edp.web.frontendproject.FrontendProjectService; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/15 + */ +public class FormMetadataDebugUriWebServiceImpl implements FormMetadataDebugUriWebService { + /** + * 获取PC表单元数据的部署uri + */ + @Override + public String getFormMetadataDebugUri(String formMetadataRelativePath, String formMetadataId) { + return FrontendProjectService.getFormMetadataDebugUri(formMetadataRelativePath, formMetadataId, "pc"); + } + + /** + * 获取表单元数据的部署uri + * + * @param formMetadataRelativePath + * @param formMetadataId + * @param formType + * @return + */ + @Override + public String getFormMetadataDebugUriByFormType(String formMetadataRelativePath, + String formMetadataId, + String formType) { + return FrontendProjectService.getFormMetadataDebugUri(formMetadataRelativePath, formMetadataId, formType); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebServiceImpl.java new file mode 100644 index 00000000..251f0413 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/FrontendProjectWebServiceImpl.java @@ -0,0 +1,118 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.entity.ResultCode; +import com.inspur.edp.web.common.entity.ResultMessage; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.FrontendProjectManager; +import com.inspur.edp.web.frontendproject.FrontendProjectService; +import com.inspur.edp.web.frontendproject.build.FrontendProjectBuild; +import com.inspur.edp.web.frontendproject.deploy.FrontendProjectDeploy; +import com.inspur.edp.web.frontendproject.entity.ChosenFormList; +import com.inspur.edp.web.frontendproject.generate.FrontendProjectGenerate; + +import java.util.Arrays; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/15 + */ +public class FrontendProjectWebServiceImpl implements FrontendProjectWebService { + + @Override + public boolean isFrontendProject(String projectPath) { + return FrontendProjectService.getInstance().isFrontendProject(projectPath); + } + + @Override + public void resolveFrontendProject(String projectPath) { + FrontendProjectManager.getInstance().resolveFormMetadatas(projectPath); + } + + @Override + public void generateFrontendProject(String projectPath) { + FrontendProjectGenerate.generateFrontendProject(projectPath); + } + + @Override + public ResultMessage buildFrontendProject(String projectPath) { + try { + return FrontendProjectBuild.buildFrontendProject(projectPath, false); + } catch (GSPException ex) { + if (ex.getCause() != null && ex.getCause() instanceof RuntimeException) { + RuntimeException causeException = (RuntimeException) ex.getCause(); + return ResultCode.failure(causeException.getMessage()); + } + } catch (Exception ex) { + return ResultCode.failure(ex.getMessage() + Arrays.toString(ex.getStackTrace())); + } + return ResultCode.success(); + } + + @Override + public void resolveAndGenerateFrontendProject(String projectPath) { + FrontendProjectManager.getInstance().ResolveAndGenerateFrontendProject(projectPath); + } + + @Override + public ResultMessage resolveAndGenerateAndBuildFrontendProject(String projectPath) { + try { + return FrontendProjectManager.getInstance().resolveAndGenerateAndBuildFrontendProject(projectPath); + } catch (Exception ex) { + if (ex instanceof GSPException) { + if (ex.getCause() != null && ex.getCause() instanceof RuntimeException) { + RuntimeException causeException = (RuntimeException) ex.getCause(); + return ResultCode.failure(causeException.getMessage()); + } + } + return ResultCode.failure(ex.getMessage() + Arrays.toString(ex.getStackTrace())); + } + } + + @Override + public void deployFrontendProject(String projectPath) { + FrontendProjectDeploy.deployFrontendProject(projectPath); + } + + @Override + public void oneKeyDeployFrontendProject(String projectPath) { + FrontendProjectManager.getInstance().resolveAndGenerateAndBuildFrontendProject(projectPath); + FrontendProjectDeploy.deployFrontendProject(projectPath); + } + + /** + * 使用babel编译前端工程并部署。 + */ + @Override + public void babelBuildAndDeploy(String projectPath, String formCode) { + ChosenFormList buildFormList = ChosenFormList.getNewInstance(); + if (!StringUtility.isNullOrEmpty(formCode)) { + buildFormList.add(formCode); + } + FrontendProjectManager.getInstance().babelBuildAndDeploy(projectPath, buildFormList); + } + + /** + * 解析类型表单的预览动作 + * 理论上只输出该表单依赖项即可 + * + * @param dynamicParameter + */ + @Override + public ResultMessage generateFrontendProjectWithDynamic(FormDynamicParameter dynamicParameter) { + try { + return FrontendProjectManager.getInstance().resolveAndGenerateFrontendProjectWithDynamic(dynamicParameter); + } catch (GSPException ex) { + if (ex.getCause() != null && ex.getCause() instanceof RuntimeException) { + RuntimeException causeException = (RuntimeException) ex.getCause(); + return ResultCode.failure(causeException.getMessage()); + } + } catch (Exception ex) { + return ResultCode.failure(ex.getMessage() + Arrays.toString(ex.getStackTrace())); + } + return ResultCode.success(); + } +} + diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebServiceImpl.java new file mode 100644 index 00000000..ac6f59d2 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/webservice/ZeroCodeWebServiceImpl.java @@ -0,0 +1,73 @@ +package com.inspur.edp.web.frontendproject.webservice; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.frontendproject.entity.RestMessage; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.ScriptCacheResponse; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerVersionManager; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 零代码web服务 + * + * @author guozhiqi + */ +public class ZeroCodeWebServiceImpl implements ZeroCodeWebService { + + @Override + public RestMessage beforeNavigateLoadFile(String indexHtmlUrl, String routeUri, String options) { + if (StringUtility.isNullOrEmpty(indexHtmlUrl)) { + throw new RuntimeException("请设置默认首页参数"); + } + if (StringUtility.isNullOrEmpty(routeUri)) { + throw new RuntimeException("请设置路由参数"); + } + // 调整成为/ 形式 + String indexHtmlPath = FileUtility.getPlatformIndependentPath(indexHtmlUrl); + String indexHtmlName = "index.html"; + if (!StringUtils.endsWith(indexHtmlPath, indexHtmlName)) { + throw new RuntimeException("默认首页参数必须以index.html作为后缀,请修正!"); + } + String projectPath = indexHtmlPath.substring(0, indexHtmlPath.length() - indexHtmlName.length()); + if (StringUtility.isNullOrEmpty(projectPath) || projectPath.equals("/")) { + throw new RuntimeException("请设置正确的路径参数,例如:apps/scm/sd/sales/index.html"); + } + + String[] arrProjectPathSplit = projectPath.split("/"); + // 获取对应的工程名 + String projectName = arrProjectPathSplit[arrProjectPathSplit.length - 1]; + + if (projectPath.endsWith("/")) { + projectPath = projectPath.substring(0, projectPath.length() - 1); + } + if (projectPath.startsWith("/")) { + projectPath = projectPath.substring(1); + } + ScriptCacheResponse scriptCacheResponse = LocalServerVersionManager.getSingleInstance().checkVersionWithProjectNameAndRelativePath(projectName, projectPath); + if (!scriptCacheResponse.isSuccess()) { + throw new RuntimeException(scriptCacheResponse.getErrorMessage()); + } + + // 执行路由跳转 + try { + String indexHtml = indexHtmlPath.startsWith("/") ? indexHtmlPath.substring(1) : indexHtmlPath; + // 判断html是否存在 + + String redirectUrl = "/" + indexHtml + "#/" + routeUri; + ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + HttpServletResponse response = servletRequestAttributes.getResponse(); + assert response != null; + response.sendRedirect(redirectUrl); + } catch (IOException e) { + e.printStackTrace(); + } + + // 进行页面跳转 + return RestMessage.create(); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeConstants.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeConstants.java new file mode 100644 index 00000000..9c0e7e7a --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeConstants.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +/** + * 零代码配置常量 + * + * @author noah + */ +public class ZeroCodeConstants { + /** + * 零代码配置界面 + */ + public static String ZeroCodePath = "zerocode"; + + public static String ZeroCodeRelativePath="web/runtime/projects"; + + public static String ZeroCodeRtcRelativePath="web/runtime/projects"; +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterInitialization.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterInitialization.java new file mode 100644 index 00000000..453005c6 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterInitialization.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +public class ZeroCodeParameterInitialization { + public static void initialize(ZeroCodeParameter zeroCodeParameter) { + if (zeroCodeParameter == null) { + return; + } + String currentServerPath = FileUtility.getCurrentWorkPath(); + // 为node_modules 设置默认值 + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getRelyNodeModulesPath())) { + String devRootPath = FileUtility.combine(currentServerPath, ZeroCodeConstants.ZeroCodeRelativePath); + String refNodeModulesPath = FileUtility.getPlatformIndependentPath(FileUtility.combine(devRootPath, "node_modules")); + zeroCodeParameter.setRelyNodeModulesPath(refNodeModulesPath); + } + + + // 设置安装盘server路径 + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getServerPath())) { + zeroCodeParameter.setServerPath(currentServerPath); + } + + // 如果su路径不为空 + if (!StringUtility.isNullOrEmpty(zeroCodeParameter.getServiceUnitPath())) { + // 设置源su路径 + zeroCodeParameter.setOriginalServiceUnitPath(zeroCodeParameter.getServiceUnitPath()); + String serviceUnitPath = zeroCodeParameter.getServiceUnitPath(); + if (!serviceUnitPath.startsWith("apps")) { + // 在serviceUnit 路径前面追加apps + serviceUnitPath = "apps" + FileUtility.DIRECTORY_SEPARATOR_CHAR + serviceUnitPath; + zeroCodeParameter.setServiceUnitPath(serviceUnitPath.toLowerCase()); + } + } else { + zeroCodeParameter.setServiceUnitPath("apps"); + } + + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getAbsoluteBasePath())) { + // 设置 + String absolutePath = FileUtility.combine(currentServerPath, ZeroCodeConstants.ZeroCodeRtcRelativePath, ZeroCodeConstants.ZeroCodePath, zeroCodeParameter.getOriginalServiceUnitPath(), zeroCodeParameter.getProjectName().toLowerCase()); + zeroCodeParameter.setAbsoluteBasePath(absolutePath); + } + + + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterValidator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterValidator.java new file mode 100644 index 00000000..68efefb7 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeParameterValidator.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.web.common.utility.StringUtility; + +public class ZeroCodeParameterValidator { + /** + * 编译入参参数验证 + * + * @param zeroCodeParameter + */ + public static void validate(ZeroCodeParameter zeroCodeParameter) { + if (zeroCodeParameter == null) { + throw new RuntimeException("零代码编译入参不能为null"); + } + + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getAbsoluteBasePath())) { + throw new RuntimeException("零代码编译入参路径参数absoluteBasePath不能为空"); + } + + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getProjectName())) { + throw new RuntimeException("零代码编译入参工程名称projectName不能为空"); + } + if (StringUtility.isNullOrEmpty(zeroCodeParameter.getRelyNodeModulesPath())) { + throw new RuntimeException("零代码编译入参依赖node_modules 路径不能为空"); + } + + if (zeroCodeParameter.getFormParameters() == null || zeroCodeParameter.getFormParameters().size() == 0) { + throw new RuntimeException("零代码编译入参,至少包含一个表单参数"); + } + if(StringUtility.isNullOrEmpty(zeroCodeParameter.getServiceUnitPath())){ + throw new RuntimeException("服务单元serviceUnitPath参数未配置"); + } + } + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImpl.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImpl.java new file mode 100644 index 00000000..51f80145 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImpl.java @@ -0,0 +1,69 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import com.inspur.edp.web.frontendproject.zerocode.operation.ZeroCodeManager; + +public class ZeroCodeServiceImpl implements ZeroCodeService { + + + /** + * 解析表单元数据 生成对应的webdev json文件 生成ts代码依赖 + * + * @param zeroCodeParameter + */ + @Override + public void resolveMetadataAndGenerateSource(ZeroCodeParameter zeroCodeParameter) { + prepareOperate(zeroCodeParameter); + + ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter); + } + + /** + * 编译生成后的代码 + * + * @param zeroCodeParameter + */ + @Override + public void build(ZeroCodeParameter zeroCodeParameter) { + prepareOperate(zeroCodeParameter); + + ZeroCodeManager.getInstance().build(zeroCodeParameter); + } + + /** + * 部署编译后的交付物 + * + * @param zeroCodeParameter + */ + @Override + public void deploy(ZeroCodeParameter zeroCodeParameter) { + prepareOperate(zeroCodeParameter); + + ZeroCodeManager.getInstance().deploy(zeroCodeParameter); + } + + /** + * 解析、编译、部署 + * + * @param zeroCodeParameter + */ + @Override + public void resolveBuildAndDeploy(ZeroCodeParameter zeroCodeParameter) { + prepareOperate(zeroCodeParameter); + + ZeroCodeManager.getInstance().saveZeroCodeParameterMetadataIntoJson(zeroCodeParameter); + ZeroCodeManager.getInstance().generateSource(zeroCodeParameter); + ZeroCodeManager.getInstance().build(zeroCodeParameter); + ZeroCodeManager.getInstance().deploy(zeroCodeParameter); + } + + /** + * 执行前操作 + * @param zeroCodeParameter + */ + private void prepareOperate(ZeroCodeParameter zeroCodeParameter){ + ZeroCodeParameterInitialization.initialize(zeroCodeParameter); + // 入参验证 + ZeroCodeParameterValidator.validate(zeroCodeParameter); + + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/CommandMetadataOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/CommandMetadataOperation.java new file mode 100644 index 00000000..73fbbf99 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/CommandMetadataOperation.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.cdp.web.component.metadata.define.WebComponentMetadata; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.zerocode.operation.services.ServicePathGenerator; +import com.inspur.edp.web.jitengine.metadataanalysis.CommandsAnalysis; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.jitengine.metadataparser.commandservice.CommandServiceAnalysis; + +import java.util.HashMap; + +class CommandMetadataOperation { + public void save(FormDOM json, ZeroCodeFormParameter formParameter, String webDevPath, String formMetadataName) { + CommandsAnalysis commandsAnalysis = new CommandsAnalysis(ExecuteEnvironment.Runtime, false); + HashMap cmpCacheList = new HashMap<>(); + commandsAnalysis.resolveCommand(json, formMetadataName, webDevPath, cmpCacheList, null, null); + } + + public void saveCommandSourceCode(FormDOM json,String webDevPath) { + String servicesSourceDir = ServicePathGenerator.getServicesSourceDir(webDevPath); + CommandServiceAnalysis.resolveCommandService(json, null, servicesSourceDir, webDevPath, ExecuteEnvironment.Runtime, false); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/EapiMetadataOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/EapiMetadataOperation.java new file mode 100644 index 00000000..f48a97ff --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/EapiMetadataOperation.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.EapiMetadataManager; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormRefMetadataParameter; + +import java.util.HashMap; +import java.util.List; + +class EapiMetadataOperation { + public void save(FormDOM json, String formMetadataName, String webDevPath, ZeroCodeFormParameter formParameter) { + if (json == null || json.getModule() == null || json.getModule().getCode() == null + || json.getModule().getSchemas() == null || json.getModule().getSchemas().size() == 0) { + return; + } + StringBuilder eapis = new StringBuilder(); + eapis.append("["); + int index = 0; + // VO-EAPI(vo和eapi是一对一的关系) + List> schemas = json.getModule().getSchemas(); + EapiMetadataManager eapiMetadataManager = new EapiMetadataManager(ExecuteEnvironment.Design, false); + for (HashMap item : schemas) { + if (index > 0) { + eapis.append(","); + } + //获取对应的EapiID 如果可以读取到 + String strEapiID = item.containsKey("eapiId") ? item.get("eapiId").toString() : ""; + // 如果获取到EapiID 那么根据EapiID去读取对应的元数据 + IMetadataContent eapiMetadataContent = null; + + ZeroCodeFormRefMetadataParameter formRefMetadataParameter = formParameter.getSpecialFormRefMetaData(strEapiID, JitMetadataTypeEnum.Eapi); + if (formRefMetadataParameter != null) { + eapiMetadataContent = formRefMetadataParameter.getMetadata().getContent(); + String eapiJson = ""; + eapiJson = eapiMetadataManager.serialize(eapiMetadataContent, PropertyNamingStrategy.UPPER_CAMEL_CASE); + eapis.append(eapiJson); + index += 1; + } + + } + eapis.append("]"); + eapiMetadataManager.saveMetadataFile(webDevPath, + formMetadataName.toLowerCase() + ".eapi.json", eapis.toString()); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormExpressionOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormExpressionOperation.java new file mode 100644 index 00000000..f79d82e6 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormExpressionOperation.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.jitengine.expressions.ExpressionFormGenerator; +import com.inspur.edp.web.jitengine.expressions.ExpressionManifest; +import com.inspur.edp.web.jitengine.expressions.ExpressionManifestManager; +import com.inspur.edp.web.jitengine.expressions.ModuleFormExpressions; +import com.inspur.edp.web.jitengine.expressions.utility.ExpressionUtility; + +public class FormExpressionOperation { + public void save(FormDOM json, ZeroCodeFormParameter formParameter, String webDevPath, TerminalType terminalType) { + // 定义表单关联的表达式 + ExpressionManifest expressionManifest = new ExpressionManifest(); + // 设置表达式 manifest.json 文件的code及其对应的文件名 + expressionManifest.setFormModuleCode(json.getModule().getCode()); + expressionManifest.setManifestJsonPath(ExpressionUtility.getExpressionManifestJsonPath(json.getModule().getCode())); + + ///获取表单对应的表达式 + ModuleFormExpressions moduleFormExpressions = ExpressionFormGenerator.generate(json, null, null); + // 仅仅在包含表达式时才进行添加 + if (moduleFormExpressions != null && moduleFormExpressions.getExpressions() != null && moduleFormExpressions.getExpressions().size() > 0) { + expressionManifest.getExpressions().add(moduleFormExpressions); + } + // 写入表单表达式json文件 仅在PC下构造表达式 + if (terminalType == TerminalType.PC) { + ExpressionManifestManager.writeExpressionJson(expressionManifest, webDevPath, false); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormMetadataContentOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormMetadataContentOperation.java new file mode 100644 index 00000000..7a696a3e --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/FormMetadataContentOperation.java @@ -0,0 +1,111 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.formmetadata.metadata.FormMetadataContent; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormFormatParameter; +import com.inspur.edp.web.jitengine.metadatamanager.FormMetadataManager; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPage; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; + +/** + * 表单元数据保存 + */ +class FormMetadataContentOperation { + + /** + * 表单源苏剧保存 + * + * @param webDevPath + * @param formParameter + */ + public void save(String webDevPath, ZeroCodeFormParameter formParameter, AdaptedPage adaptedPage) { + String strFormDom = ((FormMetadataContent) formParameter.getMetadata().getContent()).getContents().toString(); + String formMetadataFileName = formParameter.getMetadata().getHeader().getFileName(); + // 保存表单元数据到webdev + save(webDevPath, formMetadataFileName, strFormDom); + + FormDOM formDOM = SerializeUtility.getInstance().deserialize(strFormDom, FormDOM.class); + + // 构造页面流需要数据 + adaptedPage.setId(formParameter.getMetadata().getHeader().getId()); + adaptedPage.setCode(formDOM.getModule().getCode()); + adaptedPage.setName(formDOM.getModule().getName()); + adaptedPage.setFileName(formParameter.getMetadata().getHeader().getFileName()); + adaptedPage.setRouteUri(formDOM.getModule().getCode()); + + + // command命令元数据保存 + CommandMetadataOperation commandMetadataOperation = new CommandMetadataOperation(); + commandMetadataOperation.save(formDOM, formParameter, webDevPath, formMetadataFileName); + + //eapi 元数据保存 + EapiMetadataOperation eapiMetadataOperation = new EapiMetadataOperation(); + eapiMetadataOperation.save(formDOM, formMetadataFileName, webDevPath, formParameter); + + // 状态机元数据保存 + StateMachineMetadataOperation stateMachineMetadataOperation = new StateMachineMetadataOperation(); + stateMachineMetadataOperation.save(formDOM, formParameter, webDevPath, formMetadataFileName); + + // 表达式构造 + FormExpressionOperation formExpressionOperation = new FormExpressionOperation(); + TerminalType terminalType = formParameter.isMobile() ? TerminalType.MOBILE : TerminalType.PC; + formExpressionOperation.save(formDOM, formParameter, webDevPath, terminalType); + } + + public void saveFormFormat(String webDevPath, ZeroCodeFormParameter formParameter, ZeroCodeFormFormatParameter formFormatParameter, AdaptedPage adaptedPage) { + String configId = formFormatParameter.getFormFormatConfigId(); + String formatPath = FileUtility.combine("form-format", configId); + String jsonFilePath = FileUtility.combine(webDevPath, formatPath); + + String strFormDom = ((FormMetadataContent) formFormatParameter.getMetadataContent()).getContents().toString(); + String formMetadataFileName = formParameter.getMetadata().getHeader().getFileName(); + // 保存表单元数据到webdev/form-format/{configId} + save(jsonFilePath, formMetadataFileName, strFormDom); + + FormDOM formDOM = SerializeUtility.getInstance().deserialize(strFormDom, FormDOM.class); + + // 构造页面流需要数据 + adaptedPage.setId(configId); + String formCode = formDOM.getModule().getCode(); + String pageCode = formCode + "_" + configId.substring(0, 8); + String pageName = formDOM.getModule().getName()+"_" + configId.substring(0, 8); + adaptedPage.setCode(pageCode); + adaptedPage.setName(pageName); + adaptedPage.setRouteUri(pageCode); + String fullName = FileUtility.combine(formatPath, formParameter.getMetadata().getHeader().getFileName()); + adaptedPage.setFileName(fullName); + + // command命令元数据保存 + CommandMetadataOperation commandMetadataOperation = new CommandMetadataOperation(); + commandMetadataOperation.save(formDOM, formParameter, jsonFilePath, formMetadataFileName); + + //eapi 元数据保存 + EapiMetadataOperation eapiMetadataOperation = new EapiMetadataOperation(); + eapiMetadataOperation.save(formDOM, formMetadataFileName, jsonFilePath, formParameter); + + // 状态机元数据保存 + StateMachineMetadataOperation stateMachineMetadataOperation = new StateMachineMetadataOperation(); + stateMachineMetadataOperation.save(formDOM, formParameter, jsonFilePath, formMetadataFileName); + + // 表达式构造 + FormExpressionOperation formExpressionOperation = new FormExpressionOperation(); + TerminalType terminalType = formParameter.isMobile() ? TerminalType.MOBILE : TerminalType.PC; + formExpressionOperation.save(formDOM, formParameter, jsonFilePath, terminalType); + } + + /** + * 表单元数据保存操作 + * + * @param webDevPath + * @param formMetaDataFileName + * @param content + */ + private void save(String webDevPath, String formMetaDataFileName, String content) { + FormMetadataManager formMetadataManager = new FormMetadataManager(ExecuteEnvironment.Design, false); + formMetadataManager.saveMetadataFile(webDevPath, formMetaDataFileName.toLowerCase() + ".json", content); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/MetaDataOperationManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/MetaDataOperationManager.java new file mode 100644 index 00000000..4337cb99 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/MetaDataOperationManager.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormFormatParameter; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPage; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; + +public class MetaDataOperationManager { + public static void save(ZeroCodeFormParameter formParameter, String webDevPath, AdaptedPage adaptedPage) { + + // 保存表单元数据 + FormMetadataContentOperation formMetadataContentOperation = new FormMetadataContentOperation(); + formMetadataContentOperation.save(webDevPath, formParameter,adaptedPage); + + } + + public static void saveFormFormat(ZeroCodeFormParameter formParameter, ZeroCodeFormFormatParameter formFormatParameter, + String webDevPath, AdaptedPage adaptedPage) { + + // 保存表单元数据 + FormMetadataContentOperation formMetadataContentOperation = new FormMetadataContentOperation(); + formMetadataContentOperation.saveFormFormat(webDevPath, formParameter, formFormatParameter, adaptedPage); + + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/PageFlowMetadataOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/PageFlowMetadataOperation.java new file mode 100644 index 00000000..d7a61243 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/PageFlowMetadataOperation.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.common.JITEngineConstants; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPageFlowMetadataEntity; + +public class PageFlowMetadataOperation { + public void save(String webDevPath, AdaptedPageFlowMetadataEntity pageFlowMetadataEntity, String formMetadataName) { + String pageFlowContent = SerializeUtility.getInstance().serialize(pageFlowMetadataEntity); + FileUtility.writeFile(webDevPath, formMetadataName.toLowerCase() + JITEngineConstants.ProjectRouteFileExtension, pageFlowContent); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/StateMachineMetadataOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/StateMachineMetadataOperation.java new file mode 100644 index 00000000..09617294 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/StateMachineMetadataOperation.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.formmetadata.metadata.formdom.FormDOM; +import com.inspur.edp.web.jitengine.metadatamanager.StateMachineMetadataManager; +import com.inspur.edp.web.jitruntimebuild.api.entity.JitMetadataTypeEnum; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormRefMetadataParameter; + +import java.util.HashMap; + +public class StateMachineMetadataOperation { + /** + * 保存 + * + * @param formParameter + */ + public void save(FormDOM json, ZeroCodeFormParameter formParameter,String wevDevPath,String formMetadataFileName) { + if (json.getModule() != null && json.getModule().getStateMachines() != null && json.getModule().getStateMachines().size() > 0) { + StateMachineMetadataManager smManager = new StateMachineMetadataManager(ExecuteEnvironment.Design, false); + StringBuilder stateMachines = new StringBuilder(); + stateMachines.append("{"); + int index = 0; + for (HashMap o : json.getModule().getStateMachines()) { + if (index > 0) { + stateMachines.append(","); + } + String uri = o.get("uri").toString(); + + ZeroCodeFormRefMetadataParameter formRefMetadataParameter = formParameter.getSpecialFormRefMetaData(uri, JitMetadataTypeEnum.StateMachine); + if (formRefMetadataParameter != null) { + IMetadataContent obj = formRefMetadataParameter.getMetadata().getContent(); + String sm_json = smManager.serialize(obj); + String idStr = o.get("id").toString(); + stateMachines.append("\"").append(idStr).append("\":"); + stateMachines.append(sm_json); + index += 1; + } + + } + stateMachines.append("}"); + + // Save StateMachine + smManager.saveMetadataFile(wevDevPath, String.format("%1$s.sm.json", formMetadataFileName.toLowerCase()), stateMachines.toString()); + } + } + + +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManager.java new file mode 100644 index 00000000..3fd75bd4 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManager.java @@ -0,0 +1,173 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; +import com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate.SourceCodeManager; +import com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson.WebDevJsonManager; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.entity.PublishScriptRequest; +import com.inspur.edp.web.jitruntimebuild.scriptcache.api.service.ScriptCacheService; +import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerPathGenerator; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +public class ZeroCodeManager { + + ScriptCacheService scriptCacheServiceInstance; + + private ZeroCodeManager() { + this.scriptCacheServiceInstance = SpringBeanUtils.getBean(ScriptCacheService.class); + } + + public static ZeroCodeManager getInstance() { + return new ZeroCodeManager(); + } + + /** + * 保存零代码参数元数据到webdev文件目录 + * + * @param zeroCodeParameter + */ + public void saveZeroCodeParameterMetadataIntoJson(ZeroCodeParameter zeroCodeParameter) { + + // 保存webdevjson文件 + WebDevJsonManager.saveWebDevJson(zeroCodeParameter); + } + + public void build(ZeroCodeParameter zeroCodeParameter) { + // 如果存在pc表单 + if (zeroCodeParameter.hasFormParameter(TerminalType.PC)) { + // 执行 npm run build + JITEngineManager.buildFrontendProject(zeroCodeParameter.getAbsoluteBasePath(), ExecuteEnvironment.Runtime, TerminalType.PC); + } + + // 如果存在移动表单 + if (zeroCodeParameter.hasFormParameter(TerminalType.MOBILE)) { + JITEngineManager.buildFrontendProject(zeroCodeParameter.getAbsoluteBasePath(), ExecuteEnvironment.Runtime, TerminalType.MOBILE); + } + } + + public void generateSource(ZeroCodeParameter zeroCodeParameter) { + SourceCodeManager.generateSourceCode(zeroCodeParameter); + + } + + public void deploy(ZeroCodeParameter zeroCodeParameter) { + // pc 表单 + if (zeroCodeParameter.hasFormParameter(TerminalType.PC)) { + // 编译后的目标目录 + String distRollupPath = getAppDistRollupPath(zeroCodeParameter.getAbsoluteBasePath()); + + String deployPath = FileUtility.combine(zeroCodeParameter.getServerPath(), "web", zeroCodeParameter.getServiceUnitPath().toLowerCase(), "web"); + FileUtility.copyFolder(distRollupPath, deployPath); + if (FileUtility.exists(deployPath)) { + + //version.json + publishWithSingleFile(deployPath, zeroCodeParameter, "version.json"); + //index.html + publishWithSingleFile(deployPath, zeroCodeParameter, "index.html"); + //polyfills.js + publishWithSingleFile(deployPath, zeroCodeParameter, "polyfills.js"); + //main.js + publishWithSingleFile(deployPath, zeroCodeParameter, "main.js"); + + zeroCodeParameter.getFormParameters().stream().filter(t -> !t.isMobile()).forEach(t -> { + String strDeployPathWithProject = FileUtility.combine(deployPath, zeroCodeParameter.getProjectName().toLowerCase()); + PublishScriptRequest publishScriptRequest = new PublishScriptRequest(); + publishScriptRequest.setAbsoluteBaseDirectory(strDeployPathWithProject); + // 为了和设计时传参保持一致 将参数调整为小写形式 + publishScriptRequest.setProjectName(zeroCodeParameter.getProjectName().toLowerCase()); + publishScriptRequest.setFormCode(t.getCode()); + + String strLocalServerPath = LocalServerPathGenerator.getNewInstance(false).getLocalServerWebPath(); + String strRelativePath = FileUtility.getRelativePath(strLocalServerPath, strDeployPathWithProject, true); + publishScriptRequest.setProjectRelativePath(strRelativePath); + // 无需更新元数据版本 + //publishScriptRequest.setUpdateMetadataVersion(false); + // 由于零代码不存在对应的元数据 因此设置元数据为工程名称 作为一个临时参数值 + publishScriptRequest.setMetaDataId(t.getMetadata().getHeader().getId()); + this.scriptCacheServiceInstance.publishScriptWithSingleFileName(publishScriptRequest, t.getCode().toLowerCase(), null); + }); + + + } + } + // 移动表单 + if (zeroCodeParameter.hasFormParameter(TerminalType.MOBILE)) { + // 编译后的目标目录 + String distRollupPath = getMobileAppDistRollupPath(zeroCodeParameter.getAbsoluteBasePath()); + + String deployPath = FileUtility.combine(zeroCodeParameter.getServerPath(), "web", zeroCodeParameter.getServiceUnitPath().toLowerCase(), "mob"); + FileUtility.copyFolder(distRollupPath, deployPath); + + if (FileUtility.exists(deployPath)) { + + zeroCodeParameter.getFormParameters().stream().filter(ZeroCodeFormParameter::isMobile).forEach((zeroCodeFormParameter)->{ + String metaDataId = zeroCodeParameter.getProjectName().toLowerCase(); + if (zeroCodeFormParameter != null) { + metaDataId = zeroCodeFormParameter.getMetadata().getHeader().getId(); + } + + + String strDeployPathWithProject = FileUtility.combine(deployPath, zeroCodeParameter.getProjectName().toLowerCase()); + PublishScriptRequest publishScriptRequest = new PublishScriptRequest(); + publishScriptRequest.setAbsoluteBaseDirectory(strDeployPathWithProject); + // 为了和设计时传参保持一致 将参数调整为小写形式 + publishScriptRequest.setProjectName(zeroCodeParameter.getProjectName().toLowerCase()); + + String strLocalServerPath = LocalServerPathGenerator.getNewInstance(false).getLocalServerWebPath(); + String strRelativePath = FileUtility.getRelativePath(strLocalServerPath, strDeployPathWithProject, true); + publishScriptRequest.setProjectRelativePath(strRelativePath); + publishScriptRequest.setMetaDataId(metaDataId); + publishScriptRequest.setFormCode(zeroCodeFormParameter.getCode()); + publishScriptRequest.setZeroCodeMobileForm(true); + // 无需更新元数据版本 + //publishScriptRequest.setUpdateMetadataVersion(false); + this.scriptCacheServiceInstance.publishScriptWithDirectory(publishScriptRequest); + }); + + } + } + + } + + private void publishWithSingleFile(String deployPath, ZeroCodeParameter zeroCodeParameter, String fileName) { + String strDeployPathWithProject = FileUtility.combine(deployPath, zeroCodeParameter.getProjectName().toLowerCase()); + PublishScriptRequest publishScriptRequest = new PublishScriptRequest(); + publishScriptRequest.setAbsoluteBaseDirectory(strDeployPathWithProject); + // 为了和设计时传参保持一致 将参数调整为小写形式 + publishScriptRequest.setProjectName(zeroCodeParameter.getProjectName().toLowerCase()); + + String strLocalServerPath = LocalServerPathGenerator.getNewInstance(false).getLocalServerWebPath(); + String strRelativePath = FileUtility.getRelativePath(strLocalServerPath, strDeployPathWithProject, true); + publishScriptRequest.setProjectRelativePath(strRelativePath); + // 无需更新元数据版本 + //publishScriptRequest.setUpdateMetadataVersion(false); + // 由于零代码不存在对应的元数据 因此设置元数据为工程名称 作为一个临时参数值 + publishScriptRequest.setMetaDataId(zeroCodeParameter.getProjectName().toLowerCase()); + this.scriptCacheServiceInstance.publishScriptWithSingleFileName(publishScriptRequest, "", fileName); + } + + + /** + * 获取生成文件代码的路径 + * + * @param absolutePath + * @return + */ + private String getAppDistRollupPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "app", "dist-rollup")); + } + + /** + * 获取生成文件代码的路径 + * + * @param absolutePath + * @return + */ + private String getMobileAppDistRollupPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "mobileapp", "dist-rollup")); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/services/ServicePathGenerator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/services/ServicePathGenerator.java new file mode 100644 index 00000000..728a8f15 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/services/ServicePathGenerator.java @@ -0,0 +1,13 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.services; + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * @author liyz + * @date 2021/12/14 + */ +public class ServicePathGenerator { + public static String getServicesSourceDir(String webDevPath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(webDevPath, "services")); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/AbstractSourceCodeOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/AbstractSourceCodeOperation.java new file mode 100644 index 00000000..1cb651cc --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/AbstractSourceCodeOperation.java @@ -0,0 +1,10 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +public abstract class AbstractSourceCodeOperation implements ISourceCodeOperation { + + String getLowerCaseProjectName(ZeroCodeParameter parameter) { + return parameter.getProjectName().toLowerCase(); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/ISourceCodeOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/ISourceCodeOperation.java new file mode 100644 index 00000000..feab4b2c --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/ISourceCodeOperation.java @@ -0,0 +1,7 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +public interface ISourceCodeOperation { + void generate(ZeroCodeParameter zeroCodeParameter); +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeManager.java new file mode 100644 index 00000000..5083dfd9 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeManager.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +public class SourceCodeManager { + public static void generateSourceCode(ZeroCodeParameter zeroCodeParameter) { + + if (zeroCodeParameter.hasFormParameter(TerminalType.PC)) { + ISourceCodeOperation sourceCodePCOperation = new SourceCodePCOperation(); + sourceCodePCOperation.generate(zeroCodeParameter); + } + + if (zeroCodeParameter.hasFormParameter(TerminalType.MOBILE)) { + ISourceCodeOperation sourceCodeMobileOperation = new SourceCodeMobileOperation(); + sourceCodeMobileOperation.generate(zeroCodeParameter); + } + } + + public static String getSourcePath(ZeroCodeParameter zeroCodeParameter, TerminalType terminalType) { + return SourceCodePathGenerator.generate(zeroCodeParameter, terminalType); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeMobileOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeMobileOperation.java new file mode 100644 index 00000000..052446cd --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodeMobileOperation.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; +import com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson.WebDevJsonManager; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitengine.ProjectCompileContext; + +public class SourceCodeMobileOperation extends AbstractSourceCodeOperation implements ISourceCodeOperation { + @Override + public void generate(ZeroCodeParameter zeroCodeParameter) { + String webDevPath = WebDevJsonManager.getWebDevPath(zeroCodeParameter, TerminalType.MOBILE); + String sourceAppPath = SourceCodePathGenerator.generate(zeroCodeParameter, TerminalType.MOBILE); + if (!FileUtility.exists(webDevPath)) { + return; + } + String lowerCaseProjectName = getLowerCaseProjectName(zeroCodeParameter); + // 根据webdev json文件 + ProjectCompileContext projectCompileContext = new ProjectCompileContext(lowerCaseProjectName, + zeroCodeParameter.getRelyNodeModulesPath(), + "mobile", "vue", + webDevPath, + sourceAppPath, null, zeroCodeParameter.getServiceUnitPath(), ExecuteEnvironment.Runtime); + JITEngineManager.compileProject(projectCompileContext); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePCOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePCOperation.java new file mode 100644 index 00000000..2313c9bb --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePCOperation.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.environment.ExecuteEnvironment; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; +import com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson.WebDevJsonManager; +import com.inspur.edp.web.jitengine.JITEngineManager; +import com.inspur.edp.web.jitengine.ProjectCompileContext; + +public class SourceCodePCOperation extends AbstractSourceCodeOperation implements ISourceCodeOperation { + @Override + public void generate(ZeroCodeParameter zeroCodeParameter) { + String webDevPath = WebDevJsonManager.getWebDevPath(zeroCodeParameter, TerminalType.PC); + String sourceAppPath = SourceCodePathGenerator.generate(zeroCodeParameter, TerminalType.PC); + if (!FileUtility.exists(webDevPath)) { + return; + } + String lowerCaseProjectName = this.getLowerCaseProjectName(zeroCodeParameter); + // 根据webdev json文件 + ProjectCompileContext projectCompileContext = this.generateCompileContext(lowerCaseProjectName, webDevPath, sourceAppPath, zeroCodeParameter); + JITEngineManager.compileProject(projectCompileContext); + } + + /** + * 构造生成上下文参数 + * @param lowerCaseProjectName 小写形式的工程名称 + * @param webDevPath + * @param sourceAppPath + * @param zeroCodeParameter + * @return + */ + private ProjectCompileContext generateCompileContext(String lowerCaseProjectName, String webDevPath, String sourceAppPath, ZeroCodeParameter zeroCodeParameter) { + ProjectCompileContext projectCompileContext = new ProjectCompileContext(lowerCaseProjectName, + zeroCodeParameter.getRelyNodeModulesPath(), + "pc", "angular", + webDevPath, + sourceAppPath, null, zeroCodeParameter.getServiceUnitPath(), ExecuteEnvironment.Runtime); + projectCompileContext.setGenerateViewModel(true); + // 是否使用解析模式 + projectCompileContext.setJieXiForm(zeroCodeParameter.isUseJieXiMode()); + return projectCompileContext; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePathGenerator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePathGenerator.java new file mode 100644 index 00000000..264f75c5 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/sourcegenerate/SourceCodePathGenerator.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.sourcegenerate; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormFormatParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +public class SourceCodePathGenerator { + public static String generate(ZeroCodeParameter zeroCodeParameter, TerminalType terminalType) { + if (terminalType == TerminalType.MOBILE) { + return getMobileAppPath(zeroCodeParameter.getAbsoluteBasePath()); + } + return getAppPath(zeroCodeParameter.getAbsoluteBasePath()); + } + + public static String generateFormFormatSourcePath( + ZeroCodeParameter zeroCodeParameter, + ZeroCodeFormFormatParameter formFormatParameter, + TerminalType terminalType) { + String basePath = FileUtility.combine(zeroCodeParameter.getAbsoluteBasePath(), "form-format", formFormatParameter.getFormFormatConfigId()); + if (terminalType == TerminalType.MOBILE) { + return getMobileAppPath(basePath); + } + return getAppPath(basePath); + } + + /** + * 获取生成文件代码的路径 + * + * @param absolutePath + * @return + */ + private static String getAppPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "app")); + } + + /** + * 获取生成文件代码的路径 + * + * @param absolutePath + * @return + */ + private static String getMobileAppPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "mobileapp")); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/AbstractWebDevJsonOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/AbstractWebDevJsonOperation.java new file mode 100644 index 00000000..92930b4f --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/AbstractWebDevJsonOperation.java @@ -0,0 +1,51 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.operation.MetaDataOperationManager; +import com.inspur.edp.web.frontendproject.zerocode.operation.PageFlowMetadataOperation; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPage; +import com.inspur.edp.web.pageflow.metadata.entity.AdaptedPageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.entity.Project; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author guozhiqi + */ +public abstract class AbstractWebDevJsonOperation implements IWevDevJsonOperation { + + /** + * 保存json文件到指定目录 + * @param formParameterList + * @param webDevPath + * @param projectName + */ + protected void saveJson(ListformParameterList, String webDevPath,String projectName) { + AdaptedPageFlowMetadataEntity pageFlowMetadataEntity = new AdaptedPageFlowMetadataEntity(); + Project pageFlowProject = new Project(); + pageFlowProject.setName(projectName); + pageFlowMetadataEntity.setProject(pageFlowProject); + pageFlowMetadataEntity.setPages(new ArrayList<>()); + + + formParameterList.forEach(t -> { + List pageList = pageFlowMetadataEntity.getPages(); + + AdaptedPage adaptedPage = new AdaptedPage(); + MetaDataOperationManager.save(t, webDevPath, adaptedPage); + + pageList.add(adaptedPage); + + t.getFormFormatList().forEach(formFormatParam -> { + AdaptedPage adaptedFormatPage = new AdaptedPage(); + MetaDataOperationManager.saveFormFormat(t, formFormatParam, webDevPath, adaptedFormatPage); + pageList.add(adaptedFormatPage); + }); + }); + + // 保存页面流元数据 + PageFlowMetadataOperation pageFlowMetadataOperation = new PageFlowMetadataOperation(); + pageFlowMetadataOperation.save(webDevPath, pageFlowMetadataEntity, projectName); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/IWevDevJsonOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/IWevDevJsonOperation.java new file mode 100644 index 00000000..badceb36 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/IWevDevJsonOperation.java @@ -0,0 +1,11 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +/** + * webdev json文件操作 + */ +public interface IWevDevJsonOperation { + + void save(ZeroCodeParameter zeroCodeParameter); +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonManager.java new file mode 100644 index 00000000..0903d376 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonManager.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +public class WebDevJsonManager { + public static void saveWebDevJson(ZeroCodeParameter zeroCodeParameter) { + + if (zeroCodeParameter.hasFormParameter(TerminalType.PC)) { + IWevDevJsonOperation pcWebDevJsonOperation = getWebDevJsonOperationInstance(TerminalType.PC); + pcWebDevJsonOperation.save(zeroCodeParameter); + } + + if (zeroCodeParameter.hasFormParameter(TerminalType.MOBILE)) { + IWevDevJsonOperation mobileWebDevJsonOperation = getWebDevJsonOperationInstance(TerminalType.MOBILE); + mobileWebDevJsonOperation.save(zeroCodeParameter); + } + } + + public static String getWebDevPath(ZeroCodeParameter zeroCodeParameter, TerminalType terminalType) { + return WebDevJsonPathGenerator.generate(zeroCodeParameter, terminalType); + } + + + private static IWevDevJsonOperation getWebDevJsonOperationInstance(TerminalType terminalType) { + IWevDevJsonOperation wevDevJsonOperationInstance; + if (terminalType == TerminalType.MOBILE) { + wevDevJsonOperationInstance = new WebDevMobileJsonOperation(); + } else { + wevDevJsonOperationInstance = new WebDevPCJsonOperation(); + } + return wevDevJsonOperationInstance; + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonPathGenerator.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonPathGenerator.java new file mode 100644 index 00000000..9a70866c --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevJsonPathGenerator.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +/** + * webdev json文件路径生成 + */ +public class WebDevJsonPathGenerator { + public static String generate(ZeroCodeParameter zeroCodeParameter, TerminalType terminalType) { + if (terminalType == TerminalType.MOBILE) { + return getMobileWebDevPath(zeroCodeParameter.getAbsoluteBasePath()); + } + + return getPCWebDevPath(zeroCodeParameter.getAbsoluteBasePath()); + } + + /** + * 获取webdev文件目录 + * + * @param absolutePath + * @return + */ + private static String getPCWebDevPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "webdev")); + } + + /** + * 获取移动对应的webdev路径 + * + * @param absolutePath + * @return + */ + private static String getMobileWebDevPath(String absolutePath) { + return FileUtility.getPlatformIndependentPath(FileUtility.combine(absolutePath, "src", "mobiledev")); + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevMobileJsonOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevMobileJsonOperation.java new file mode 100644 index 00000000..a3b37d36 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevMobileJsonOperation.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +import java.util.List; +import java.util.stream.Collectors; + +public class WebDevMobileJsonOperation extends AbstractWebDevJsonOperation implements IWevDevJsonOperation { + @Override + public void save(ZeroCodeParameter zeroCodeParameter) { + String webDevPath = WebDevJsonPathGenerator.generate(zeroCodeParameter, TerminalType.MOBILE); + + List zeroCodeFormParameterList = zeroCodeParameter.getFormParameters().stream().filter(ZeroCodeFormParameter::isMobile).collect(Collectors.toList()); + + // 保存PC 表单元数据 + if (zeroCodeFormParameterList != null && zeroCodeFormParameterList.size() > 0) { + this.saveJson(zeroCodeFormParameterList, webDevPath, zeroCodeParameter.getProjectName()); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJson.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJson.java new file mode 100644 index 00000000..3ee4ac11 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJson.java @@ -0,0 +1,4 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +public class WebDevPCJson { +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJsonOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJsonOperation.java new file mode 100644 index 00000000..18c7e846 --- /dev/null +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/webdevjson/WebDevPCJsonOperation.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation.webdevjson; + +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; + +import java.util.List; +import java.util.stream.Collectors; + +public class WebDevPCJsonOperation extends AbstractWebDevJsonOperation implements IWevDevJsonOperation { + @Override + public void save(ZeroCodeParameter zeroCodeParameter) { + String webDevPath = WebDevJsonPathGenerator.generate(zeroCodeParameter, TerminalType.PC); + + List zeroCodeFormParameterList = zeroCodeParameter.getFormParameters().stream().filter(t -> !t.isMobile()).collect(Collectors.toList()); + + // 保存PC 表单元数据 + if (zeroCodeFormParameterList != null && zeroCodeFormParameterList.size() > 0) { + this.saveJson(zeroCodeFormParameterList, webDevPath, zeroCodeParameter.getProjectName()); + } + + } +} diff --git a/web-frontendproject/src/main/resources/META-INF/spring.factories b/web-frontendproject/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..5678cc68 --- /dev/null +++ b/web-frontendproject/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.frontendproject.config.FormMetadataDebugUriConfiguration,\ +com.inspur.edp.web.frontendproject.config.FrontendProjectConfiguration,\ +com.inspur.edp.web.frontendproject.config.ZeroCodeConfiguration diff --git a/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImplTest.java b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImplTest.java new file mode 100644 index 00000000..870c40e1 --- /dev/null +++ b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/changedetect/generate/stepexecute/MetadataChangeStepExecuteImplTest.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.*; + +/** + * @Title: MetadataChangeStepExecuteImplTest + * @Description: com.inspur.edp.web.frontendproject.changedetect.generate.stepexecute + * @Author: Noah + * @Version: V1.0 + * @Create: 2022/7/1 8:47 + */ +public class MetadataChangeStepExecuteImplTest { + @Test + public void testRegular() { + String filePath = "fff.frm.en-vht.Lres"; + + Pattern p = Pattern.compile(".frm.[a-zA-Z-_]+.lres", Pattern.COMMENTS | Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(filePath); + + Assert.assertEquals(m.find(), true); + + + // assertTrue(hasFlag); + } +} diff --git a/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImplTest.java b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImplTest.java new file mode 100644 index 00000000..7230a03c --- /dev/null +++ b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/ZeroCodeServiceImplTest.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.frontendproject.zerocode; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +class ZeroCodeServiceImplTest { + + @Test + void resolveMetadataAndGenerateSource() { + ZeroCodeParameter zeroCodeParameter=new ZeroCodeParameter(); + zeroCodeParameter.setProjectName("bo-guozhiqi"); + zeroCodeParameter.setAbsoluteBasePath("c:/projects/guozhiqi"); + zeroCodeParameter.setRelyNodeModulesPath("c:/projects/node_modules"); + zeroCodeParameter.setServiceUnitPath("scm/sd"); + + + ListformParameters=new ArrayList<>(); + ZeroCodeFormParameter formParameter=new ZeroCodeFormParameter(); + formParameter.setCode("formcode"); + formParameter.setName("formname"); + + ZeroCodeServiceImpl serviceImpl=new ZeroCodeServiceImpl(); + serviceImpl.resolveMetadataAndGenerateSource(zeroCodeParameter); + + } +} diff --git a/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManagerTest.java b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManagerTest.java new file mode 100644 index 00000000..bbe0cebf --- /dev/null +++ b/web-frontendproject/src/main/test/java/com/inspur/edp/web/frontendproject/zerocode/operation/ZeroCodeManagerTest.java @@ -0,0 +1,15 @@ +package com.inspur.edp.web.frontendproject.zerocode.operation; + +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeFormParameter; +import com.inspur.edp.web.frontendproject.zerocode.ZeroCodeParameter; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ZeroCodeManagerTest { + + @Test + void saveZeroCodeParameterMetadataIntoJson() { + + } +} diff --git a/web-ide-api/pom.xml b/web-ide-api/pom.xml new file mode 100644 index 00000000..220425d9 --- /dev/null +++ b/web-ide-api/pom.xml @@ -0,0 +1,16 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-ide-api + + + + diff --git a/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/PluginConfig.java b/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/PluginConfig.java new file mode 100644 index 00000000..8ca16b52 --- /dev/null +++ b/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/PluginConfig.java @@ -0,0 +1,6 @@ +package com.inspur.edp.web.ide.api; + +public class PluginConfig +{ + public String Config; +} \ No newline at end of file diff --git a/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/WebIDEService.java b/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/WebIDEService.java new file mode 100644 index 00000000..520f3ce9 --- /dev/null +++ b/web-ide-api/src/main/java/com/inspur/edp/web/ide/api/WebIDEService.java @@ -0,0 +1,10 @@ +package com.inspur.edp.web.ide.api; + +/** + * @deprecated 暂不使用 + * @author noah + */ +public interface WebIDEService +{ + String getIDEPluginConfig(); +} \ No newline at end of file diff --git a/web-ide-webapi/pom.xml b/web-ide-webapi/pom.xml new file mode 100644 index 00000000..17778460 --- /dev/null +++ b/web-ide-webapi/pom.xml @@ -0,0 +1,36 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + ide-config-webapi + + + io.iec.edp + caf-boot-commons-environment + + + com.fasterxml.jackson.core + jackson-databind + + + jakarta.ws.rs + jakarta.ws.rs-api + + + io.iec.edp + caf-boot-starter-rest-server + + + com.inspur.edp + web-jitengine-common + + + + diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/common/FileUtil.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/common/FileUtil.java new file mode 100644 index 00000000..529c1de5 --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/common/FileUtil.java @@ -0,0 +1,33 @@ +package com.inspur.edp.ide.config.webapi.common; + +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.FileInputStream; + +@Slf4j +public class FileUtil +{ + public static String readFile(String path) { + String encoding = "UTF-8"; + File file = new File(path); + long length = file.length(); + String fileContents = null; + try { + byte[] bytes = new byte[(int) length]; + FileInputStream in = new FileInputStream(file); + in.read(bytes); + in.close(); + + fileContents = new String(bytes, encoding); + // 处理utf-8 bom头 + if (fileContents.startsWith("\ufeff")) { + fileContents = fileContents.substring(1); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + e.printStackTrace(); + } + return fileContents; + } +} diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/config/WebIdeConfiguration.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/config/WebIdeConfiguration.java new file mode 100644 index 00000000..97f7e51a --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/config/WebIdeConfiguration.java @@ -0,0 +1,17 @@ +package com.inspur.edp.ide.config.webapi.config; + +import com.inspur.edp.ide.config.webapi.control.WebIDEServiceController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import io.iec.edp.caf.rest.RESTEndpoint; + +/** + * @author noah + */ +@Configuration("com.inspur.edp.web.ide.webapi.config.WebIdeConfiguration") +public class WebIdeConfiguration { + @Bean("com.inspur.edp.web.ide.webapi.config.WebIdeConfiguration.webIdeWebapiEndPoint") + public RESTEndpoint webIdeWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/getpluginconfig", new WebIDEServiceController()); + } +} diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/control/WebIDEServiceController.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/control/WebIDEServiceController.java new file mode 100644 index 00000000..927f702d --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/control/WebIDEServiceController.java @@ -0,0 +1,21 @@ +package com.inspur.edp.ide.config.webapi.control; + +import com.inspur.edp.ide.config.webapi.entity.PluginConfig; +import com.inspur.edp.ide.config.webapi.service.WebIDEService; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class WebIDEServiceController { + @Path("") + @GET + public final PluginConfig getPluginConfig() { + return WebIDEService.getInstance().getPluginConfig(); + } +} \ No newline at end of file diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelDescription.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelDescription.java new file mode 100644 index 00000000..19221aa1 --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelDescription.java @@ -0,0 +1,24 @@ +package com.inspur.edp.ide.config.webapi.entity; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class PanelDescription { + private String id; + + private String title; + + private String location; + + private String url; + + private Object modalOptions; + + private PanelStyle style = PanelStyle.Eager; + + private Object activationCommands; + + private Object editor; +} \ No newline at end of file diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelStyle.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelStyle.java new file mode 100644 index 00000000..5ee99b0a --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PanelStyle.java @@ -0,0 +1,10 @@ +package com.inspur.edp.ide.config.webapi.entity; + +/** + * panel样式 + */ +public enum PanelStyle { + Eager, + Lazy, + Editor +} \ No newline at end of file diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PluginConfig.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PluginConfig.java new file mode 100644 index 00000000..b1c0fbfd --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/entity/PluginConfig.java @@ -0,0 +1,20 @@ +package com.inspur.edp.ide.config.webapi.entity; + +import lombok.Getter; + +import java.util.ArrayList; + +@Getter +public class PluginConfig { + public PluginConfig() { + this.eager = new ArrayList<>(); + this.lazy = new ArrayList<>(); + this.editor = new ArrayList<>(); + } + + private final ArrayList eager; + + private final ArrayList lazy; + + private final ArrayList editor; +} \ No newline at end of file diff --git a/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/service/WebIDEService.java b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/service/WebIDEService.java new file mode 100644 index 00000000..bf6e1b86 --- /dev/null +++ b/web-ide-webapi/src/main/java/com/inspur/edp/ide/config/webapi/service/WebIDEService.java @@ -0,0 +1,127 @@ +package com.inspur.edp.ide.config.webapi.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.ide.config.webapi.common.FileUtil; +import com.inspur.edp.ide.config.webapi.entity.PanelDescription; +import com.inspur.edp.ide.config.webapi.entity.PanelStyle; +import com.inspur.edp.ide.config.webapi.entity.PluginConfig; +import com.inspur.edp.web.common.utility.StringUtility; +import io.iec.edp.caf.common.JSONSerializer; +import io.iec.edp.caf.common.environment.EnvironmentUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.configurationprocessor.json.JSONObject; + +import java.io.File; +import java.nio.file.Paths; + +/** + * ide service + * @author noah + */ +@Slf4j +public class WebIDEService { + private static WebIDEService instance; + private static PluginConfig pluginConfig; + + private WebIDEService() { + initPluginConfig(); + } + + public static WebIDEService getInstance() { + if (instance == null) { + instance = new WebIDEService(); + } + return instance; + } + + public final PluginConfig getPluginConfig() { + this.initPluginConfig(); + return pluginConfig; + } + + private void initPluginConfig() { + String devRootPath = EnvironmentUtil.getBasePath(); + String pluginsPath = Paths.get(devRootPath).resolve("web/platform/dev/main/web/webide/plugins".replace('/', File.separatorChar)).toString(); + if (!(new File(pluginsPath)).isDirectory()) { + return; + } + + PluginConfig config = new PluginConfig(); + String[] pluginDirs = (new File(pluginsPath)).list((ff, nn) -> ff.isDirectory()); + + for (String dir : pluginDirs) { + String fullPath = Paths.get(pluginsPath, dir).toString(); + PanelDescription panelDescription = getPluginDescription(getPluginPackageJson(fullPath)); + if (panelDescription == null) { + continue; + } + reviseUrlWithDir(panelDescription, dir); + switch (panelDescription.getStyle()) { + case Eager: + config.getEager().add(panelDescription); + break; + case Lazy: + config.getLazy().add(panelDescription); + break; + case Editor: + config.getEditor().add(panelDescription); + break; + default: + break; + } + } + pluginConfig = config; + } + + private String getPluginPackageJson(String path) { + String fullPath = Paths.get(path).resolve("plugin.conf.json").toString(); + + if (!(new File(fullPath)).isFile()) { + return null; + } + return FileUtil.readFile(fullPath); + } + + private PanelDescription getPluginDescription(String jsonStr) { + if (StringUtility.isNullOrEmpty(jsonStr)) { + return null; + } + try { + JSONSerializer.deserialize(jsonStr, JSONObject.class); + JsonNode jobj = JSONSerializer.deserialize(jsonStr, JsonNode.class); + // 获取插件视图注册信息 + PanelDescription result = jobj.get("panel") == null ? null : JSONSerializer.deserialize(jobj.get("panel").toString(), PanelDescription.class); + JsonNode activationCommands = jobj.get("activationCommands"); + JsonNode editorDescription = jobj.get("editor"); + if (result != null) { + if (activationCommands != null) { + result.setStyle(PanelStyle.Lazy); + result.setActivationCommands(activationCommands); + } else if (editorDescription != null) { + result.setStyle(PanelStyle.Editor); + result.setEditor(editorDescription); + } + } + return result; + } catch (RuntimeException e) { + log.error(e.getMessage(), e); + return null; + } + } + + /** + * 修正panelDescription的url路径 + * n版url不带index.html,server会自动跳转,j版server不行。 + * @param panelDescription + * @param dir + */ + private void reviseUrlWithDir(PanelDescription panelDescription, String dir) { + String url = panelDescription.getUrl(); + if (url != null && url.matches(".+(\\.html|\\.htm)(\\?.*)?$")) { + return; + } + + // url不符合要求,需要重新指定 + panelDescription.setUrl("/platform/dev/main/web/webide/plugins/" + dir + "/index.html"); + } +} diff --git a/web-ide-webapi/src/main/resources/META-INF/spring.factories b/web-ide-webapi/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..d75703ec --- /dev/null +++ b/web-ide-webapi/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.ide.config.webapi.config.WebIdeConfiguration diff --git a/web-npmpackage-api/pom.xml b/web-npmpackage-api/pom.xml new file mode 100644 index 00000000..77c7e49c --- /dev/null +++ b/web-npmpackage-api/pom.xml @@ -0,0 +1,29 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-npmpackage-api + + + + javax.ws.rs + javax.ws.rs-api + + + jakarta.ws.rs + jakarta.ws.rs-api + + + com.inspur.edp + web-jitengine-common + + + + diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java new file mode 100644 index 00000000..55fc08b7 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java @@ -0,0 +1,44 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +/** + * npm 安装包参数 + * @author noah + */ +public class NpmInstallPackageParameter { + /** + * 安装包名称 + */ + private String packageName; + /** + * 安装包版本 默认为latest + */ + private String version="latest"; + /** + * 安装包tag + */ + private String tag; + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java new file mode 100644 index 00000000..161adb3d --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java @@ -0,0 +1,184 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmUpdatePolicy; + +import java.util.ArrayList; +import java.util.List; + +/** + * npm 包参数 + * + * @author noah + */ +public class NpmInstallParameter { + + /** + * 执行npm install时的代理地址 + * 默认为官方源 + */ + private String registry = "https://registry.npmjs.org/"; + + /** + * npm 安装登录用户名 无默认值 + * 针对需要登录才可以install的源,那么必须首先进行登录 + */ + private String userName; + + /** + * npm 安装密码 无默认值 + * 针对需要登录才可以install的源,那么必须首先进行登录 + */ + private String password; + + /** + * 登录数据源登录需要输入的email + */ + private String email; + /** + * 使用生产模式进行install + * 使用该模式 不会安装devdependies的配置脚本 + */ + private boolean useProduction = false; + /** + * 是否使用离线模式 + * 默认情况下使用离线模式 即使用已经解压后的node_modules 离线包 + */ + private boolean offlineMode = true; + + /** + * 是否整体更新 + */ + private boolean updateAll = true; + + /** + * 是否强制更新 + */ + private boolean force = false; + + /** + * 是否是移动表单工程 + */ + private boolean isMobile = false; + + /** + * 更新策略 默认为手工更新 + */ + private String updatePolicy = NpmUpdatePolicy.manual; + + /** + * 运行位置 + * 默认为设计时 + */ + private ExecuteEnvironmentEnum executeEnvironment = ExecuteEnvironmentEnum.None; + + private List npmInstallPackageParameterList; + + public String getRegistry() { + // 确保获取到的地址 末尾不包含反斜线 + if (!StringUtility.isNullOrEmpty(this.registry) && + this.registry.lastIndexOf("/") == (this.registry.length() - 1)) { + this.registry = this.registry.substring(0, this.registry.length() - 1); + } + return registry; + } + + public void setRegistry(String registry) { + this.registry = registry; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isUseProduction() { + return useProduction; + } + + public void setUseProduction(boolean useProduction) { + this.useProduction = useProduction; + } + + public boolean isOfflineMode() { + return offlineMode; + } + + public void setOfflineMode(boolean offlineMode) { + this.offlineMode = offlineMode; + } + + public boolean isUpdateAll() { + return updateAll; + } + + public void setUpdateAll(boolean updateAll) { + this.updateAll = updateAll; + } + + public boolean isForce() { + return force; + } + + public void setForce(boolean force) { + this.force = force; + } + + public List getNpmInstallPackageParameterList() { + if (this.npmInstallPackageParameterList == null) { + this.npmInstallPackageParameterList = new ArrayList<>(); + } + return npmInstallPackageParameterList; + } + + public void setNpmInstallPackageParameterList(List npmInstallPackageParameterList) { + this.npmInstallPackageParameterList = npmInstallPackageParameterList; + } + + public ExecuteEnvironmentEnum getExecuteEnvironment() { + return executeEnvironment; + } + + public void setExecuteEnvironment(ExecuteEnvironmentEnum executeEnvironment) { + this.executeEnvironment = executeEnvironment; + } + + public boolean isMobile() { + return isMobile; + } + + public void setMobile(boolean mobile) { + isMobile = mobile; + } + + public String getUpdatePolicy() { + return updatePolicy; + } + + public void setUpdatePolicy(String updatePolicy) { + this.updatePolicy = updatePolicy; + } + + public String getEmail() { + if (StringUtility.isNullOrEmpty(this.email)) { + this.email = "guozhiqi21@163.com"; + } + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java new file mode 100644 index 00000000..fe4494ff --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; + +/** + * npm 包checkupdate 选项 + * @author noah + * */ +public class NpmPackageCheckUpdateOptions { + /** + * 是否在升级工具中执行 + */ + private boolean isUpgradeTool=false; + /** + * 执行环境 + */ + private ExecuteEnvironmentEnum executeEnvironment=ExecuteEnvironmentEnum.Design; + + /** + * 是否移动表单 + */ + private boolean isMobile=false; + + public boolean isUpgradeTool() { + return isUpgradeTool; + } + + public void setUpgradeTool(boolean upgradeTool) { + isUpgradeTool = upgradeTool; + } + + public ExecuteEnvironmentEnum getExecuteEnvironment() { + return executeEnvironment; + } + + public void setExecuteEnvironment(ExecuteEnvironmentEnum executeEnvironment) { + this.executeEnvironment = executeEnvironment; + } + + public boolean isMobile() { + return isMobile; + } + + public void setMobile(boolean mobile) { + isMobile = mobile; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java new file mode 100644 index 00000000..e3c42403 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +/** + * npm 包常量定义 + * + * @author noah + */ +public class NpmPackageConstants { + /** + * node_modules 常量 + */ + public static final String Node_ModulesName = "node_modules"; + + /** + * package.json 文件名称 + */ + public static final String PackageJsonName = "package.json"; + + /** + * package-lock.json 文件 + */ + public static final String PackageLockJsonName="package-lock.json"; + + /** + * 最新版本标识 + */ + public static final String LatestVersion = "latest"; + + /** + * npm 参数配置文件名称 + */ + public static final String NpmSettingFileName = "setting.json"; + + /** + * npm 参数配置文件相对于nodejs路径的路径名 + */ + public static final String NpmSettingPath = "npmsettings"; + + /** + * 标识npm正在安装过程中的标识 + */ + public static final String NpmInstallingTag = "npminstalling.log"; +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java new file mode 100644 index 00000000..b8876ba2 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +/** + * npm包安装响应 + * + * @author noah + */ +public class NpmPackageResponse { + /** + * 是否执行成功标识 + */ + private boolean success = true; + /** + * 执行失败 错误信息提示 + */ + private String errorMessage; + + private NpmPackageResponseLevel responseLevel = NpmPackageResponseLevel.Info; + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public NpmPackageResponseLevel getResponseLevel() { + return responseLevel; + } + + public Object getExtraData() { + return extraData; + } + + public void setExtraData(Object extraData) { + this.extraData = extraData; + } + + /** + * 额外的数据传递 + */ + public Object extraData; + + public void setResponseLevel(NpmPackageResponseLevel responseLevel) { + this.responseLevel = responseLevel; + } + + public static NpmPackageResponse create() { + return new NpmPackageResponse(); + } + public static NpmPackageResponse createError(String errorMessage) { + NpmPackageResponse npmPackageResponse=new NpmPackageResponse(); + npmPackageResponse.setErrorMessage(errorMessage); + npmPackageResponse.setSuccess(false); + npmPackageResponse.setResponseLevel(NpmPackageResponseLevel.Error); + return npmPackageResponse; + } + +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java new file mode 100644 index 00000000..f5be9e2a --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.npmpackage.api.entity; + +/** + * npm包响应级别 + * @author noah + * */ +public enum NpmPackageResponseLevel { + /** + * 错误 异常 + */ + Error, + /** + * 提示 + */ + Info +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java new file mode 100644 index 00000000..25e929c1 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.npmpackage.api.entity.packagejson; + +import com.inspur.edp.web.common.utility.StringUtility; + +public class NpmPackageJsonDependencyInfo { + private String key; + private String value; + + public NpmPackageJsonDependencyInfo(String key, String value) { + this.key = !StringUtility.isNullOrEmpty(key) ? key.trim() : ""; + this.value = !StringUtility.isNullOrEmpty(value) ? value.trim() : ""; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java new file mode 100644 index 00000000..e7355c95 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java @@ -0,0 +1,133 @@ +package com.inspur.edp.web.npmpackage.api.entity.packagejson; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * @author guozhiqi + */ +public class NpmPackageJsonInfo { + private String name; + private String version; + private String description; + private String author = "Noah"; + private String license; + private List dependencies; + private List devDependencies; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public List getDependencies() { + if (dependencies == null) { + this.dependencies = new ArrayList<>(); + } + return dependencies; + } + + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + } + + public List getDevDependencies() { + if (this.devDependencies == null) { + this.devDependencies = new ArrayList<>(); + } + return devDependencies; + } + + public void setDevDependencies(List devDependencies) { + this.devDependencies = devDependencies; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NpmPackageJsonInfo that = (NpmPackageJsonInfo) o; + if (this.getDependencies().size() != that.getDependencies().size() || this.getDevDependencies().size() != that.getDevDependencies().size()) { + return false; + } + + final boolean[] exists = {true}; + this.getDependencies().forEach(t -> { + if (exists[0]) { + String dependencyKey = t.getKey(); + String dependencyValue = t.getValue(); + exists[0] = that.getDependencies().stream().anyMatch(d -> d.getKey().equals(dependencyKey) && d.getValue().equals(dependencyValue)); + } + }); + if (!exists[0]) { + return false; + } + this.getDevDependencies().forEach(t -> { + if (exists[0]) { + String dependencyKey = t.getKey(); + String dependencyValue = t.getValue(); + exists[0] = that.getDevDependencies().stream().anyMatch(d -> d.getKey().equals(dependencyKey) && d.getValue().equals(dependencyValue)); + } + }); + if (!exists[0]) { + return false; + } + + + return this.version.equals(that.version); + } + + public boolean equalsInDependencies(String dependencyName, String version) { + return this.getDependencies().stream().anyMatch(d -> d.getKey().equals(dependencyName) && d.getValue().equals(version)); + } + + public boolean equalsInDevDependencies(String dependencyName, String version) { + return this.getDevDependencies().stream().anyMatch(d -> d.getKey().equals(dependencyName) && d.getValue().equals(version)); + } + + @Override + public int hashCode() { + return Objects.hash(name, version, description, author, license, dependencies, devDependencies); + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java new file mode 100644 index 00000000..e646fa04 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java @@ -0,0 +1,131 @@ +package com.inspur.edp.web.npmpackage.api.entity.settings; + +import com.inspur.edp.web.common.utility.StringUtility; + +/** + * npm 仓库配置 + * + * @author noah + */ +public class NpmRepository { + /** + * id 参数 + */ + private String id; + + /** + * 仓库名称 + */ + private String name; + + /** + * 仓库地址 + */ + private String url; + /** + * 配置登录用户名 + */ + private String userName; + /** + * 配置登录密码 + */ + private String password; + /** + * 更新策略 默认为手工更新 + */ + private String updatePolicy = NpmUpdatePolicy.beforeBuild; + + /** + * 最后更新时间 标识node_modules 的最后更新时间戳 + */ + private String lastUpdated; + + /** + * 是否需要登录 + */ + private boolean needLogin = false; + + /** + * 是否允许删除 默认值为true 即允许删除 + */ + private boolean canDelete=true; + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUserName() { + if (StringUtility.isNullOrEmpty(userName)) { + userName = ""; + } + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + if (StringUtility.isNullOrEmpty(password)) { + password = ""; + } + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getUpdatePolicy() { + return updatePolicy; + } + + public void setUpdatePolicy(String updatePolicy) { + this.updatePolicy = updatePolicy; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(String lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public boolean isNeedLogin() { + return needLogin; + } + + public void setNeedLogin(boolean needLogin) { + this.needLogin = needLogin; + } + + public boolean isCanDelete() { + return canDelete; + } + + public void setCanDelete(boolean canDelete) { + this.canDelete = canDelete; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java new file mode 100644 index 00000000..a6752e48 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.npmpackage.api.entity.settings; + +/** + * npm 参数配置 + * + * @author noah + */ +public class NpmSettingConfig { + + /** + * npm 仓库配置 + */ + private NpmRepository[] repositories = {}; + + /** + * 是否启用移动编译 + */ + private boolean enableMobileBuild=true; + + public NpmRepository[] getRepositories() { + return repositories; + } + + public void setRepositories(NpmRepository[] repositories) { + this.repositories = repositories; + } + + public boolean isEnableMobileBuild() { + return enableMobileBuild; + } + + public void setEnableMobileBuild(boolean enableMobileBuild) { + this.enableMobileBuild = enableMobileBuild; + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java new file mode 100644 index 00000000..06683d36 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.npmpackage.api.entity.settings; + + +/** + * npm 配置模式 + * @author noah + */ + +public class NpmSettingMode { + /** + * 生产 + */ + public static final String prod="prod"; + /** + * 开发 + */ + public static final String dev="dev"; + /** + * 临时 + */ + public static final String snapshot="snapshot"; +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java new file mode 100644 index 00000000..7b419b2c --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java @@ -0,0 +1,57 @@ +package com.inspur.edp.web.npmpackage.api.entity.settings; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * npm 配置 + * + * @author noah + */ +public class NpmSettings { + /** + * 离线模式 默认为true + */ + private boolean offline = true; + + private String settingMode; + private NpmSettingConfig settingConfig; + + + public boolean isOffline() { + return offline; + } + + public void setOffline(boolean offline) { + this.offline = offline; + } + + public String getSettingMode() { + return settingMode; + } + + public void setSettingMode(String settingMode) { + this.settingMode = settingMode; + } + + public NpmSettingConfig getSettingConfig() { + return settingConfig; + } + + public void setSettingConfig(NpmSettingConfig settingConfig) { + this.settingConfig = settingConfig; + } + + /** + * 更新当前更新的最后更新时间 + * + * @param lastUpdated + */ + public void setLastUpdated(String lastUpdated) { + List filterRepository = Arrays.stream(this.getSettingConfig().getRepositories()).filter(t -> t.getId().equals(this.getSettingMode())).collect(Collectors.toList()); + if (filterRepository != null && filterRepository.size() > 0) { + filterRepository.forEach(t -> t.setLastUpdated(lastUpdated)); + } + } +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java new file mode 100644 index 00000000..0173a646 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.npmpackage.api.entity.settings; + +/** + * npm 更新策略 + * + * @author noah + */ +public class NpmUpdatePolicy { + /** + * 手工更新 + */ + public static final String manual="manual"; + /** + * 编译前执行 + */ + public static final String beforeBuild="beforeBuild"; + + /** + * 从不执行 + */ + public static final String never="never"; + + +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java new file mode 100644 index 00000000..7eb2da87 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.npmpackage.api.webservice; + +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +/** + * npm 包安装webservice + * + * @author noah + */ +@Path("/") +public interface NpmPackageInstallWebService { + + /** + * npm install命令执行 + * @param installParameter install参数 + * @return 安装结果反馈 + */ + @POST + @Path("/npminstall") + NpmPackageResponse install(NpmSettings installParameter); + + /** + * npm install命令执行 使用默认的npm配置信息 + * @return 安装结果反馈 + */ + @GET + @Path("/npminstall") + NpmPackageResponse install(); + + /** + * npm install命令执行 + * @param installParameter install参数 + * @return 安装结果反馈 + */ + @POST + @Path("/npminstallcheck") + NpmPackageResponse installCheck(NpmSettings installParameter); + + +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java new file mode 100644 index 00000000..3df1e637 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java @@ -0,0 +1,8 @@ +package com.inspur.edp.web.npmpackage.api.webservice; + +/** + * npm 包发布webservice + * @author noah + */ +public interface NpmPackagePublishWebService { +} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java new file mode 100644 index 00000000..4b0839e9 --- /dev/null +++ b/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java @@ -0,0 +1,38 @@ +package com.inspur.edp.web.npmpackage.api.webservice; + +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +/** + * npm 包webservice + * + * @author noah + */ +@Path("/") +public interface NpmPackageWebService { + + /** + * 获取npm 配置参数 + * @return + */ + @GET + @Path("/npmsetting") + NpmSettings getNpmSetting(); + + /** + * 保存npm配置信息 + * @param npmSettings npm配置信息 + * @return + */ + @POST + @Path("/savenpmsetting") + NpmPackageResponse saveNpmSetting(NpmSettings npmSettings); + + @GET + @Path("/npmcheckupdate") + NpmPackageResponse checkUpdate(); +} diff --git a/web-npmpackage-core/pom.xml b/web-npmpackage-core/pom.xml new file mode 100644 index 00000000..598245ec --- /dev/null +++ b/web-npmpackage-core/pom.xml @@ -0,0 +1,32 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-npmpackage-core + + + + com.inspur.edp + web-npmpackage-api + + + org.springframework.boot + spring-boot-starter-test + + + io.iec.edp + caf-boot-starter-rest-server + + + com.inspur.edp + lcm-logging-service + + + diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java new file mode 100644 index 00000000..ab056cc4 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java @@ -0,0 +1,62 @@ +package com.inspur.edp.web.npmpackage.core.cacheclean; + +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; + + +public class NpmCacheCleanCommandExecutor { + /** + * 命令执行 + * + * @param npmInstallParameter + * @param npmName + */ + public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String npmName, String version) { + + // 构造install 命令参数 执行npm包安装操作 + + LoggerUtility.logToBrowser("执行离线包缓存清理", LoggerLevelEnum.Info); + boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment() == ExecuteEnvironmentEnum.UpgradeTool; + String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + + String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentWorkPath); + String npmInstallCommandExecuteWithPath = npmCommandExecuteWithPath + " cache clean --force"; + + String[] command = new String[2]; + // 盘符独立打开 + command[0] = npmInstallCommandExecuteWithPath; + command[1] = "exit"; + // 执行npm 包安装 + return runCommand(command, true); + } + + private static NpmPackageResponse runCommand(String[] commands, boolean isWait) { + String command = String.join(" && ", commands); + return runCommand(command, isWait); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + private static NpmPackageResponse runCommand(String command, boolean isWait) { + StringBuilder errorSB = new StringBuilder(); + String errorMessage = CommandLineUtility.executeCommand(command, errorSB); + if (!StringUtility.isNullOrEmpty(errorMessage)) { + LoggerUtility.log(errorMessage, LoggerLevelEnum.Info); + } + + return NpmPackageResponse.create(); + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java new file mode 100644 index 00000000..7507b286 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java @@ -0,0 +1,23 @@ +package com.inspur.edp.web.npmpackage.core.config; + +import com.inspur.edp.web.npmpackage.api.webservice.NpmPackageWebService; +import com.inspur.edp.web.npmpackage.core.webservice.NpmPacakgeWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author guozhiqi + */ +@Configuration +public class NpmPackageConfiguration { + @Bean + public NpmPackageWebService npmPackageWebService(){ + return new NpmPacakgeWebServiceImpl(); + } + + @Bean + public RESTEndpoint NpmPackageWebServiceEndpoint(){ + return new RESTEndpoint("/dev/main/web/v1.0/npmpackage", new NpmPacakgeWebServiceImpl()); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java new file mode 100644 index 00000000..dc8ea3c4 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.npmpackage.core.config; + +import com.inspur.edp.web.npmpackage.api.webservice.NpmPackageInstallWebService; +import com.inspur.edp.web.npmpackage.core.webservice.NpmPackageInstallWebServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class NpmPackageInstallConfiguration { + @Bean + public NpmPackageInstallWebService npmPackageInstallWebService(){ + return new NpmPackageInstallWebServiceImpl(); + } + + @Bean + public RESTEndpoint NpmPackageInstallWebServiceEndpoint(){ + return new RESTEndpoint("/dev/main/web/v1.0/npmpackageinstall", new NpmPackageInstallWebServiceImpl()); + } +} \ No newline at end of file diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java new file mode 100644 index 00000000..3c12da26 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java @@ -0,0 +1,71 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.npmpackage.api.entity.*; + +/** + * node_modules 路径构造 + * + * @author guozhiqi + */ +public class NodeModulesPathGenerator { + /** + * 根据入参获取node_modules 待安装路径 + * 针对设计时:如果传递projectPath,那么以projectPath为基础获取对应工作区;如果projectPath为空,那么使用当前启用工作区 + * 针对运行时定制:获取当前server及对应的node_modules + * 针对元数据部署工具:获取当前server及对应node_modules + * 针对移动:适应上述情况 + * + * @param npmInstallParameter + * @return + */ + public static String generate(NpmInstallParameter npmInstallParameter, String currentWorkPath) { + + String parentNodeModulesPath = generatePackageJsonPath(npmInstallParameter, currentWorkPath); + String node_modulesPath = FileUtility.combine(parentNodeModulesPath, NpmPackageConstants.Node_ModulesName); + return node_modulesPath; + } + + /** + * 获取对应package.json 对应目录 + * @param npmInstallParameter + * @param currentWorkPath + * @return + */ + public static String generatePackageJsonPath(NpmInstallParameter npmInstallParameter, String currentWorkPath) { + ExecuteEnvironmentEnum executeEnvironment = npmInstallParameter.getExecuteEnvironment(); + + String parentNode_modulesPath = ""; + + // 如果是运行时定制 + if (executeEnvironment.equals(ExecuteEnvironmentEnum.Runtime)) { + + String relativePath = FileUtility.combine("web", "runtime", "projects"); + // 移除移动单独的node_modules 文件目录 + //relativePath = npmInstallParameter.isMobile() ? FileUtility.combine(relativePath, "mobile") : relativePath; + // 获取到运行时定制下node_modules path + parentNode_modulesPath = FileUtility.combine(currentWorkPath, relativePath); + } + + // 设计时 + if (executeEnvironment.equals(ExecuteEnvironmentEnum.Design)) { + // 获取当前开发时工作空间绝对路径 + String currentDevRootPath = MetadataUtility.getInstance().getDevRootAbsolutePath(); + parentNode_modulesPath = currentDevRootPath; + + } + + // 如果是部署工具 + if (executeEnvironment.equals(ExecuteEnvironmentEnum.UpgradeTool)) { + String relativePath = FileUtility.combine("web", "runtime", "projects"); + // 移除移动独立的node_modules + //relativePath = npmInstallParameter.isMobile() ? FileUtility.combine(relativePath, "mobile") : relativePath; + // 获取到元数据部署工具下node_modules path + parentNode_modulesPath = FileUtility.combine(currentWorkPath, relativePath); + } + return parentNode_modulesPath; + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java new file mode 100644 index 00000000..c5daaaa2 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java @@ -0,0 +1,77 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.*; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import org.apache.commons.lang3.SystemUtils; + +/** + * npm install 命令执行 + * + * @author noah + */ +class NpmInstallCommandExecutor { + /** + * 命令执行 + * + * @param npmInstallParameter + * @param currentServerPath + */ + public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String currentServerPath, String parentNodeModulesPath) { + // 构造install 命令参数 执行npm包安装操作 + String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentServerPath); + + + String npmInstallCommand = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); + + + String[] command = new String[1]; + if (SystemUtils.IS_OS_WINDOWS) { + command = new String[4]; + // 盘符独立打开 + command[0] = FileUtility.getAbsolutePathHead(parentNodeModulesPath); + command[1] = "cd " + parentNodeModulesPath; + command[2] = npmCommandExecuteWithPath + " update " + npmInstallCommand; + command[3] = "exit"; + } else if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC_OSX) { + command = new String[3]; + command[0] = "cd " + parentNodeModulesPath; + command[1] = npmCommandExecuteWithPath + " update " + npmInstallCommand; + command[2] = "exit"; + } + // 执行npm 包安装 + return runCommand(command, true); + } + + private static NpmPackageResponse runCommand(String[] commands, boolean isWait) { + String command = String.join(" && ", commands); + return runCommand(command, isWait); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + private static NpmPackageResponse runCommand(String command, boolean isWait) { + StringBuilder errorSB = new StringBuilder(); + String errorMessage = CommandLineUtility.executeCommand(command, errorSB); + // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出 + if (!StringUtility.isNullOrEmpty(errorMessage)) { + return NpmPackageResponse.createError("npm install failed, the reason is " + errorMessage); + } + + // 如果存在输出异常 那么不再继续执行 + if (!StringUtility.isNullOrEmpty(errorSB.toString()) && errorSB.toString().toLowerCase().contains("npm err")) { + return NpmPackageResponse.createError(errorSB.toString()); + } + + return NpmPackageResponse.create(); + } + + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java new file mode 100644 index 00000000..75ad0086 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java @@ -0,0 +1,87 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallPackageParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +import java.util.List; + +/** + * npm 安装命令参数构造 + * + * @author noah + */ +class NpmInstallCommandParameterGenerator { + /** + * npm 安装命令参数构造 + * + * @param npmInstallParameter + * @return + */ + public static String generate(NpmInstallParameter npmInstallParameter) { + String args = ""; + if (!npmInstallParameter.isUpdateAll()) { + String npmInstallPackages = getNpmInstalledPackageList(npmInstallParameter.getNpmInstallPackageParameterList()); + if (!StringUtility.isNullOrEmpty(npmInstallPackages)) { + args += npmInstallPackages; + } + } + + if (npmInstallParameter.isUseProduction()) { + args += " --production=true "; + } + args += " --package-lock=false "; + args += " --audit=false "; + // 为了避免nodejs输出长时间的看着未响应 设置logvel级别 进行安装的日志输出 + args += " --loglevel=http "; + // 避免由于peer dependency 版本找不到问题 + args += " --legacy-peer-deps "; + // 某些环境由于某些软件原因 会导致启用ssl失败 默认禁用该属性 + args += " --strict-ssl=false "; + args += " --registry=" + npmInstallParameter.getRegistry(); + + // 为了避免某些依赖项无法安装 因此增加强制标识 + args += " --force"; + + return args; + } + + + /** + * 构造npm安装包列表 + * + * @param npmInstallPackageParameterList + * @return + */ + private static String getNpmInstalledPackageList(List npmInstallPackageParameterList) { + StringBuilder sb = new StringBuilder(); + npmInstallPackageParameterList.forEach(packageParameter -> { + String packageArgs = getNpmInstalledPackage(packageParameter); + if (!StringUtility.isNullOrEmpty(packageArgs)) { + sb.append(packageArgs); + } + }); + return sb.toString(); + } + + /** + * 构造npm 安装包参数及其对应的版本标识 + * + * @param npmInstallPackageParameter npm 安装包参数 + * @return + */ + private static String getNpmInstalledPackage(NpmInstallPackageParameter npmInstallPackageParameter) { + String args = ""; + // 获取对应的npm包名 + String npmInstallPackageName = npmInstallPackageParameter.getPackageName(); + if (StringUtility.isNullOrEmpty(npmInstallPackageName)) { + return args; + } + // 获取对应的npm包对应的版本 + String npmInstallPackageVersion = StringUtility.isNullOrEmpty(npmInstallPackageParameter.getVersion()) ? npmInstallPackageParameter.getVersion() : NpmPackageConstants.LatestVersion; + args += " " + npmInstallPackageName + "@" + npmInstallPackageVersion; + return args; + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java new file mode 100644 index 00000000..01ffe3f7 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java @@ -0,0 +1,14 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.io.FileUtility; + +/** + * npm 安装锁定文件 + * + * @author noah + */ +public class NpmInstallLockFilePathGenerator { + public static String generate(String parentPath) { + return FileUtility.combine(parentPath, ".jnpm.lock"); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java new file mode 100644 index 00000000..419a64d5 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java @@ -0,0 +1,279 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.packagejson.NpmPackageJsonInfo; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmUpdatePolicy; +import com.inspur.edp.web.npmpackage.core.npminstall.global.NpmInstallGlobalManager; +import com.inspur.edp.web.npmpackage.core.npmlogin.NpmLoginCommandExecutor; +import com.inspur.edp.web.npmpackage.core.npmlogout.NpmLogoutCommandExecutor; +import com.inspur.edp.web.npmpackage.core.npmpackagecheck.NpmPackageCheck; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingConvertor; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingManager; + +import java.io.File; +import java.util.Arrays; + + +/** + * npm 安装manager 进行npm安装的统一入口 + * + * @author noah + */ +public class NpmInstallManager { + private static final Object _lockObj = new Object(); + + /** + * 安装前检测是否可以安装 + * + * @param npmInstallParameter + * @return + */ + public static NpmPackageResponse npmInstallCheck(NpmInstallParameter npmInstallParameter) { + NpmPackageResponse npmPackageResponse = NpmInstallParameterValidator.validate(npmInstallParameter); + if (!npmPackageResponse.isSuccess()) { + return npmPackageResponse; + } + // 获取node_modules 要安装的路径 + boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment().equals(ExecuteEnvironmentEnum.UpgradeTool); + String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + + // 获取待执行安装的node_modules 路径 + String parentNode_ModulesPath = NodeModulesPathGenerator.generatePackageJsonPath(npmInstallParameter, currentWorkPath); + + // 设置对应权限,防止由于无权限而导致恩无法写入问题 + FileUtility.setPermission(parentNode_ModulesPath); + + String lockFilePath = NpmInstallLockFilePathGenerator.generate(parentNode_ModulesPath); + + // 根据server启动时间和当前创建时间来进行比较 如果比server创建时间新 那么自动删除 + long serverStartTime = CommonUtility.getServerStartTime(); + File lockFileInfo = new File(lockFilePath); + boolean needAutoDeleteLockFile = lockFileInfo.exists() && lockFileInfo.lastModified() <= serverStartTime; + + // 避免多线程同时访问造成 + synchronized (_lockObj) { + if (needAutoDeleteLockFile) { + FileUtility.deleteFile(lockFilePath); + } else { + if (FileUtility.exists(lockFilePath)) { + return NpmPackageResponse.createError("正在执行安装操作,请勿重复执行!"); + } + } + } + return NpmPackageResponse.create(); + } + + /** + * 执行默认的安装操作 + * + * @param isUpgradeTool + * @return + */ + public static NpmPackageResponse npmInstallWithDefault(boolean isUpgradeTool, boolean isRuntime, boolean isGlobal) { + NpmPackageResponse packageResponse; + if (!isGlobal) { + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(isUpgradeTool); + NpmInstallParameter packageParameter = NpmSettingConvertor.convertFromNpmSetting(npmSettings); + // 依据参数进行默认目录的安装 + if (isRuntime) { + packageParameter.setExecuteEnvironment(ExecuteEnvironmentEnum.Runtime); + } else { + packageParameter.setExecuteEnvironment(ExecuteEnvironmentEnum.Design); + } + + packageResponse = npmInstall(packageParameter, false); + } else { + packageResponse = NpmInstallGlobalManager.npmInstallWithDefault(isUpgradeTool); + } + if (!packageResponse.isSuccess()) { + LoggerUtility.logToBrowser(packageResponse.getErrorMessage(), LoggerLevelEnum.Info); + } + // 不再返回错误信息 如果遇到安装异常 进行提示 而不输出错误 + return NpmPackageResponse.create(); + } + + /** + * 执行npm 安装 + * + * @param npmInstallParameter + * @return + */ + public static NpmPackageResponse npmInstall(NpmInstallParameter npmInstallParameter, boolean enableForceUpdate) { + //LoggerUtility.log("开始执行npm install 参数校验", LoggerLevelEnum.Info, true); + NpmPackageResponse npmPackageResponse = NpmInstallParameterValidator.validate(npmInstallParameter); + if (!npmPackageResponse.isSuccess()) { + return npmPackageResponse; + } + if (!enableForceUpdate) { + if (npmInstallParameter.isOfflineMode()) { + LoggerUtility.logToBrowser("开启离线模式,自动更新离线包停止", LoggerLevelEnum.Info); + return npmPackageResponse; + } + if (npmInstallParameter.getUpdatePolicy().equals(NpmUpdatePolicy.manual)) { + LoggerUtility.logToBrowser("离线包更新策略为手工,自动更新离线包停止", LoggerLevelEnum.Info); + return npmPackageResponse; + } + if (npmInstallParameter.getUpdatePolicy().equals(NpmUpdatePolicy.never)) { + LoggerUtility.logToBrowser("离线包更新策略为Never,自动更新离线包停止", LoggerLevelEnum.Info); + return npmPackageResponse; + } + } + + // 获取node_modules 要安装的路径 + boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment() == ExecuteEnvironmentEnum.UpgradeTool; + String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + + // 获取待执行安装的node_modules 路径 + String parentNode_ModulesPath = NodeModulesPathGenerator.generatePackageJsonPath(npmInstallParameter, currentWorkPath); + + String lockFilePath = NpmInstallLockFilePathGenerator.generate(parentNode_ModulesPath); + + // 根据server启动时间和当前创建时间来进行比较 如果比server创建时间新 那么自动删除 + boolean reWithUnFinishedInstall = false; + long serverStartTime = CommonUtility.getServerStartTime(); + File lockFileInfo = new File(lockFilePath); + boolean needAutoDeleteLockFile = lockFileInfo.exists() && lockFileInfo.lastModified() <= serverStartTime; + if (needAutoDeleteLockFile) { + FileUtility.deleteFile(lockFilePath); + // 继续执行未完成的安装 + reWithUnFinishedInstall = true; + } + + // 避免多线程同时访问造成 + synchronized (_lockObj) { + if (FileUtility.exists(lockFilePath)) { + return NpmPackageResponse.createError("npm 正在安装,若需重新安装,请删除lock文件!"); + } + } + String packageJsonPathInServer = PackageJsonPathGenerator.generate(currentWorkPath, npmInstallParameter.isMobile()); + if (!FileUtility.exists(packageJsonPathInServer)) { + String errorMessage = "server不包含package.json 文件,server path is :" + packageJsonPathInServer; + LoggerUtility.logToBrowser(errorMessage, LoggerLevelEnum.Info); + return NpmPackageResponse.create(); + } + + + // node_modules 目录下的package.json 文件是否存在 + String packageJsonPathInNodeModules = FileUtility.combine(parentNode_ModulesPath, NpmPackageConstants.PackageJsonName); + String nodeModulesPath = FileUtility.combine(parentNode_ModulesPath, "node_modules"); + // 如果不是强制安装 只有在package.json 和node_modules 目录均存在的前提下才判断是否无需安装 + if (!reWithUnFinishedInstall && !enableForceUpdate && FileUtility.exists(packageJsonPathInNodeModules) && FileUtility.exists(nodeModulesPath)) { + String serverPackageJsonContent = FileUtility.readAsString(packageJsonPathInServer); + NpmPackageJsonInfo serverPackageJsonInfo = NpmPackageCheck.packageJsonInfoGenerate(serverPackageJsonContent); + + String nodeModulesPackageJsonContent = FileUtility.readAsString(packageJsonPathInNodeModules); + NpmPackageJsonInfo nodeModulesPackageJsonInfo = NpmPackageCheck.packageJsonInfoGenerate(nodeModulesPackageJsonContent); + + if (serverPackageJsonInfo.equals(nodeModulesPackageJsonInfo)) { + LoggerUtility.logToBrowser("离线包版本未发生变更,无需执行离线包安装", LoggerLevelEnum.Info); + deleteLockFile(lockFilePath); + return NpmPackageResponse.create(); + } + } + + + try { + + FileUtility.createFile(lockFilePath); + + // 删除package-lock.json 文件 + deletePackageLockJson(parentNode_ModulesPath); + + // 如果文件目录不存在 那么创建对应的文件目录 拷贝package.json 到目标文件目录 + if (!FileUtility.exists(parentNode_ModulesPath)) { + FileUtility.createDirectory(parentNode_ModulesPath); + } + LoggerUtility.logToBrowser("开始执行npm install 安装", LoggerLevelEnum.Info); + + LoggerUtility.logToBrowser("开始执行npm install 命令", LoggerLevelEnum.Info); + + + // 仅在帐号和密码都设置的前提下进行登录操作 + boolean needLogin = !StringUtility.isNullOrEmpty(npmInstallParameter.getUserName()) && !StringUtility.isNullOrEmpty(npmInstallParameter.getPassword()); + + if (needLogin) { + LoggerUtility.logToBrowser("执行npm登录操作", LoggerLevelEnum.Info); + NpmPackageResponse loginPackageResponse = NpmLoginCommandExecutor.execute(npmInstallParameter, currentWorkPath); + if (!loginPackageResponse.isSuccess()) { + deleteLockFile(lockFilePath); + return loginPackageResponse; + } + } + + // 执行package.json 文件复制 + NpmPackageResponse packageJsonCopyResponse = PackageJsonCopyManager.copy(npmInstallParameter, currentWorkPath, parentNode_ModulesPath); + if (!packageJsonCopyResponse.isSuccess()) { + deleteLockFile(lockFilePath); + return packageJsonCopyResponse; + } + + // npm install 命令执行 + NpmPackageResponse installPackageResponse = NpmInstallCommandExecutor.execute(npmInstallParameter, currentWorkPath, parentNode_ModulesPath); + if (!installPackageResponse.isSuccess()) { + deleteLockFile(lockFilePath); + // 如果安装失败 移除版本文件 + FileUtility.deleteFile(packageJsonPathInNodeModules); + return installPackageResponse; + } + + if (false) { + // 仅在需要登录的前提下执行登录退出操作 + LoggerUtility.logToBrowser("执行npm登出操作", LoggerLevelEnum.Info); + NpmPackageResponse logoutPackgaeResponse = NpmLogoutCommandExecutor.execute(npmInstallParameter, currentWorkPath); + if (!logoutPackgaeResponse.isSuccess()) { + deleteLockFile(lockFilePath); + return logoutPackgaeResponse; + } + } + } catch (Exception ex) { + deleteLockFile(lockFilePath); + } + + + deleteLockFile(lockFilePath); + + LoggerUtility.logToBrowser("npm install 执行完毕", LoggerLevelEnum.Info); + return NpmPackageResponse.create(); + } + + /** + * 删除锁定文件 + * + * @param lockFilePath + */ + private static void deleteLockFile(String lockFilePath) { + try { + if (FileUtility.exists(lockFilePath)) { + FileUtility.deleteFile(lockFilePath); + } + } catch (Exception ignored) { + } + } + + + /** + * 删除package-lock.json 文件 + * + * @param parentNode_ModulesPath + */ + private static void deletePackageLockJson(String parentNode_ModulesPath) { + String packageLockJsonPath = FileUtility.combine(parentNode_ModulesPath, NpmPackageConstants.PackageLockJsonName); + if (FileUtility.exists(packageLockJsonPath)) { + try { + FileUtility.deleteFile(packageLockJsonPath); + } catch (Exception ex) { + LoggerUtility.logToBrowser("delete package-lock.json failed, the path is " + packageLockJsonPath + " , the stack is " + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Info); + } + + } + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java new file mode 100644 index 00000000..849d13a5 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponseLevel; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmUpdatePolicy; + +/** + * npm安装参数验证 + * + * @author noah + */ +class NpmInstallParameterValidator { + /** + * 参数验证 + * + * @param npmInstallParameter + * @return + */ + public static NpmPackageResponse validate(NpmInstallParameter npmInstallParameter) { + ExecuteEnvironmentEnum executeEnvironment = npmInstallParameter.getExecuteEnvironment(); + if (executeEnvironment.equals(ExecuteEnvironmentEnum.None)) { + // 表示是设计时 + return NpmPackageResponse.createError("请设置npm install 运行位置参数:ExecuteEnvironment"); + } + + if (StringUtility.isNullOrEmpty(npmInstallParameter.getUserName()) && !StringUtility.isNullOrEmpty(npmInstallParameter.getPassword())) { + return NpmPackageResponse.createError("请设置帐号"); + } + if (StringUtility.isNullOrEmpty(npmInstallParameter.getPassword()) && !StringUtility.isNullOrEmpty(npmInstallParameter.getUserName())) { + return NpmPackageResponse.createError("请设置密码"); + } + + if (!npmInstallParameter.isUpdateAll() && npmInstallParameter.getNpmInstallPackageParameterList().size() == 0) { + return NpmPackageResponse.createError("请设置待更新的npm包及其版本,或设置全部更新"); + } + // 如果更新策略为never + if (npmInstallParameter.getUpdatePolicy().equals(NpmUpdatePolicy.never)) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setResponseLevel(NpmPackageResponseLevel.Info); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("当前为从不更新模式,无法在线执行install操作"); + return npmPackageResponse; + } + + // 如果为离线模式 那么无需执行任何安装 + if (npmInstallParameter.isOfflineMode()) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setResponseLevel(NpmPackageResponseLevel.Info); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("当前为离线模式,无需执行install操作"); + return npmPackageResponse; + } + return NpmPackageResponse.create(); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java new file mode 100644 index 00000000..49795e10 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; + +/** + * npm installing参数信息 + * + * @author noah + */ +public class NpmInstallingParameter { + private boolean installing = true; + + public boolean isInstalling() { + return installing; + } + + public void setInstalling(boolean installing) { + this.installing = installing; + } + + /** + * 创建npm安装参数 + * @return + */ + public static NpmInstallParameter createNew() { + return new NpmInstallParameter(); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java new file mode 100644 index 00000000..7b509c2c --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java @@ -0,0 +1,46 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +/** + * npm安装中标识管理 + * + * @author noah + */ +class NpmInstallingTagManager { + /** + * 写入npm 安装参数到标识文件 + * + * @param nodeModulePath + */ + public static void createTag(String nodeModulePath) { + String npmInstallingTagPath = getNpmInstallingTagPath(nodeModulePath); + if (!FileUtility.exists(npmInstallingTagPath)) { + FileUtility.createDirectory(nodeModulePath); + } + String content = SerializeUtility.getInstance().serialize(NpmInstallingParameter.createNew()); + FileUtility.writeFile(npmInstallingTagPath, content); + } + + /** + * 判断是否当前处于installing状态 + * @param nodeModulesPath + * @return + */ + public static boolean isInstalling(String nodeModulesPath) { + String npmInstallingTagPath = getNpmInstallingTagPath(nodeModulesPath); + return FileUtility.exists(npmInstallingTagPath); + } + + + /** + * 构造npm installing标识路径参数 + * * @param nodeModulesPath + * @return + */ + public static String getNpmInstallingTagPath(String nodeModulesPath) { + return FileUtility.combine(nodeModulesPath, NpmPackageConstants.NpmInstallingTag); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java new file mode 100644 index 00000000..7acb00e2 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import java.net.InetAddress; + +/** + * 执行对npm仓库的连接请求 + * + * @author noah + */ +public class NpmRepositoryConnection { + /** + * 进行连接测试 + * @param ipAddress + * @return + */ + public static boolean connectTest(String ipAddress) { + try { + int timeOut = 3000; //超时应该在3钞以上 + return InetAddress.getByName(ipAddress).isReachable(timeOut); + } catch (Exception e) { + return false; + } + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java new file mode 100644 index 00000000..c0da6256 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java @@ -0,0 +1,50 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; + +/** + * package.json 文件复制 + * @author noah + */ +class PackageJsonCopyManager { + /** + * package.json 文件从server复制到目标node_modules 目录下 + * @param npmInstallParameter npm install执行参数 + * @param currentWorkPath 当前工作server目录 + * @param node_ModulesPath node_modules 路径 + * @return + */ + public static NpmPackageResponse copy(NpmInstallParameter npmInstallParameter, String currentWorkPath, String node_ModulesPath) { + //从server拷贝package.json文件 + // 获取package.json 在server 目录下的存放位置 + String packageJsonPathInServer = PackageJsonPathGenerator.generate(currentWorkPath, npmInstallParameter.isMobile()); + boolean packageJsonExists = FileUtility.exists(packageJsonPathInServer); + // node_modules 目录下的package.json 文件是否存在 + String packageJsonPathInNodeModules = FileUtility.combine(node_ModulesPath, NpmPackageConstants.PackageJsonName); + boolean packageJsonInNodeModulesExists = FileUtility.exists(packageJsonPathInNodeModules); + if (!packageJsonExists && packageJsonInNodeModulesExists) { + // 如果server目录下放置的package.json 不存在 但node_modules 目录下的package.json 文件存在 + LoggerUtility.log("the package.json file in the server is not exists,server path is :" + packageJsonPathInServer + " , but the node_modules path has package.json . so use the node_modules package.json ", LoggerLevelEnum.Info); + } + + if (!packageJsonExists && !packageJsonInNodeModulesExists) { + // 如果均不存在 那么无法执行install 操作 + return NpmPackageResponse.createError("the package.json file is not exists in the server, the path is " + packageJsonPathInServer); + } + + if (packageJsonExists) { + // 复制server目录下的package.json文件至node_modules 下 保证package.json文件得以更新 + // 首先删除对应的目标文件 + FileUtility.deleteFile(packageJsonPathInNodeModules); + + FileUtility.copyFile(packageJsonPathInServer, packageJsonPathInNodeModules, true); + } + + return NpmPackageResponse.create(); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java new file mode 100644 index 00000000..6b1341fa --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java @@ -0,0 +1,37 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +/** + * package.json 服务端路径获取 + * + * @author noah + */ +public class PackageJsonPathGenerator { + /** + * 构造package.json 路径 + * + * @param isUpgradeTool 是否运行在元数据部署工具 + * @param isMobile 是否移动工程 + * @return + */ + public static String generate(boolean isUpgradeTool, boolean isMobile) { + String serverPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + return generate(serverPath, isMobile); + } + + /** + * 构造package。json文件路径 + * + * @param serverPath 服务端server路径 + * @param isMobile 是否移动工程 + * @return + */ + public static String generate(String serverPath, boolean isMobile) { + String nodejsPath = NodejsFunctionUtility.getNodeJsPathInServer(); + String packageJsonPath = FileUtility.combine(nodejsPath, "packagejson"); + return FileUtility.combine(packageJsonPath, NpmPackageConstants.PackageJsonName); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java new file mode 100644 index 00000000..2968e280 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java @@ -0,0 +1,42 @@ +package com.inspur.edp.web.npmpackage.core.npminstall.global; + +import com.inspur.edp.web.common.utility.OperatingSystemUtility; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * @author guozhiqi + */ +public class GlobalNpmDeployPathGenerator { + public static String getGlobalNpmPath() { + if (!OperatingSystemUtility.isWindows()) { + return ""; + } + Process p; + //test.bat中的命令是ipconfig/all + String cmd = "cmd.exe" + " /C" + " " + "npm config get prefix "; +// String cmd="jarsigner -verify -verbose -certs C:\\Users\\Administrator\\Desktop\\PandaClient.apk"; + String resultstr = null; + try { + //执行命令 + p = Runtime.getRuntime().exec(cmd); + //取得命令结果的输出流 + InputStream fis = p.getInputStream(); + //用一个读输出流类去读 + //用缓冲器读行 + BufferedReader br = new BufferedReader(new InputStreamReader(fis, "GB2312")); + String line = null; + //直到读完为止 + + while ((line = br.readLine()) != null) { + resultstr = line; + } + } catch (IOException e) { + e.printStackTrace(); + } + return resultstr; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java new file mode 100644 index 00000000..4c4ab1ab --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java @@ -0,0 +1,101 @@ +package com.inspur.edp.web.npmpackage.core.npminstall.global; + +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.*; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; + +import java.io.File; + +/** + * @author guozhiqi + */ +public class GlobalNpmInstallCommandExecutor { + /** + * 命令执行 + * + * @param npmInstallParameter + * @param npmName + */ + public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String npmName, String version) { + if (StringUtility.isNullOrEmpty(npmName)) { + return NpmPackageResponse.create(); + } + if (StringUtility.isNullOrEmpty(version)) { + version = "latest"; + } + // 构造install 命令参数 执行npm包安装操作 + + LoggerUtility.logToBrowser("执行全局离线包安装:" + npmName + "@" + version, LoggerLevelEnum.Info); + boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment() == ExecuteEnvironmentEnum.UpgradeTool; + String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + + String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentWorkPath); + String npmInstallCommandExecuteWithPath = "npm install " + npmName + "@" + version + " "; + + String npmInstallCommand = GlobalNpmInstallCommandParameterGenerator.generate(npmInstallParameter); + + + String[] command = new String[2]; + // 盘符独立打开 + command[0] = npmInstallCommandExecuteWithPath + npmInstallCommand; + command[1] = "exit"; + // 执行npm 包安装 + return runCommand(command, true); + } + + private static NpmPackageResponse runCommand(String[] commands, boolean isWait) { + String command = String.join(" && ", commands); + return runCommand(command, isWait); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + private static NpmPackageResponse runCommand(String command, boolean isWait) { + StringBuilder errorSB = new StringBuilder(); + String errorMessage = CommandLineUtility.executeCommand(command, errorSB); + // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出 + if (!StringUtility.isNullOrEmpty(errorMessage)) { + return NpmPackageResponse.createError("npm install failed, the reason is " + errorMessage); + } + + // 如果存在输出异常 那么不再继续执行 + if (!StringUtility.isNullOrEmpty(errorSB.toString()) && errorSB.toString().toLowerCase().contains("npm err")) { + // 如果是特殊的错误 表示在windows上依赖包版本不对,导致无法正确安装问题 + // 先将 + if (OperatingSystemUtility.isWindows() && errorSB.toString().toLowerCase().contains("npm ERR! Maximum call stack size exceeded".toLowerCase())) { + // 仅在windows下执行 + String globalNpmPath = GlobalNpmDeployPathGenerator.getGlobalNpmPath(); + if (!StringUtility.isNullOrEmpty(globalNpmPath)) { + File globalNpmPathFile = new File(globalNpmPath); + if (globalNpmPathFile.exists()) { + // 获取对应的jit 路径 + String globalJitPath = FileUtility.combine(globalNpmPath, "node_modules", "@farris"); + File globalJitPathFile = new File(globalJitPath); + if (globalJitPathFile.exists() && globalJitPathFile.isDirectory()) { + // 重命名文件目录 + String globalJitRenamedPath = FileUtility.combine(globalNpmPath, "node_modules", "@farris-autobackup"); + // 将源目录进行重命名 + FileUtility.reName(globalJitPath, globalJitRenamedPath); + FileUtility.deleteFolder(globalJitPath); + } + LoggerUtility.log("npm在线安装全局离线包出现版本依赖错误,系统自动修复,重新进行安装处理!", LoggerLevelEnum.Info); + return runCommand(command, isWait); + } + } + } + return NpmPackageResponse.createError(errorSB.toString()); + } + + return NpmPackageResponse.create(); + } + + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java new file mode 100644 index 00000000..dcdf0728 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java @@ -0,0 +1,77 @@ +package com.inspur.edp.web.npmpackage.core.npminstall.global; + + +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallPackageParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +import java.util.List; + +/** + * npm 安装命令参数构造 + * + * @author noah + */ +class GlobalNpmInstallCommandParameterGenerator { + /** + * npm 安装命令参数构造 + * + * @param npmInstallParameter + * @return + */ + public static String generate(NpmInstallParameter npmInstallParameter) { + String args = ""; + + if (npmInstallParameter.isUseProduction()) { + args += " --production=true "; + } + args += " -g "; + args += " --package-lock=false "; + args += " --audit=false "; + args += " --registry=" + npmInstallParameter.getRegistry(); + + // 为了避免某些依赖项无法安装 因此增加强制标识 + args += " --force"; + + return args; + } + + + /** + * 构造npm安装包列表 + * + * @param npmInstallPackageParameterList + * @return + */ + private static String getNpmInstalledPackageList(List npmInstallPackageParameterList) { + StringBuilder sb = new StringBuilder(); + npmInstallPackageParameterList.forEach(packageParameter -> { + String packageArgs = getNpmInstalledPackage(packageParameter); + if (!StringUtility.isNullOrEmpty(packageArgs)) { + sb.append(packageArgs); + } + }); + return sb.toString(); + } + + /** + * 构造npm 安装包参数及其对应的版本标识 + * + * @param npmInstallPackageParameter npm 安装包参数 + * @return + */ + private static String getNpmInstalledPackage(NpmInstallPackageParameter npmInstallPackageParameter) { + String args = ""; + // 获取对应的npm包名 + String npmInstallPackageName = npmInstallPackageParameter.getPackageName(); + if (StringUtility.isNullOrEmpty(npmInstallPackageName)) { + return args; + } + // 获取对应的npm包对应的版本 + String npmInstallPackageVersion = StringUtility.isNullOrEmpty(npmInstallPackageParameter.getVersion()) ? npmInstallPackageParameter.getVersion() : NpmPackageConstants.LatestVersion; + args += " " + npmInstallPackageName + "@" + npmInstallPackageVersion; + return args; + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java new file mode 100644 index 00000000..19bd30e2 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.npmpackage.core.npminstall.global; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +/** + * 获取对应的package.json 路径 + * + * @author guozhiqi + */ +public class GlobalPackageJsonPathGenerator { + + /** + * 构造package。json文件路径 + * + * @return + */ + public static String generate() { + String nodejsPath = NodejsFunctionUtility.getNodeJsPathInServer(); + String packageJsonPath = FileUtility.combine(nodejsPath, "packagejson", "global"); + return FileUtility.combine(packageJsonPath, NpmPackageConstants.PackageJsonName); + } + + /** + * 获取临时目录的packagejson 文件 + * + * @return + */ + public static String getPackageJsonFilePathInTmpDir() { + String packageJsonPath = getPackageJsonPathInTmpDir(); + return FileUtility.combine(packageJsonPath, NpmPackageConstants.PackageJsonName); + } + + + /** + * 获取临时目录的packagejson 文件 + * + * @return + */ + public static String getPackageJsonPathInTmpDir() { + String tmpDir = FileUtility.getTmpDir(); + return FileUtility.combine(tmpDir, "globaljitpackagejson"); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java new file mode 100644 index 00000000..0edac0ea --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java @@ -0,0 +1,186 @@ +package com.inspur.edp.web.npmpackage.core.npminstall.global; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.packagejson.NpmPackageJsonInfo; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmUpdatePolicy; +import com.inspur.edp.web.npmpackage.core.npminstall.NpmInstallLockFilePathGenerator; +import com.inspur.edp.web.npmpackage.core.npmlogin.NpmLoginCommandExecutor; +import com.inspur.edp.web.npmpackage.core.npmpackagecheck.NpmPackageCheck; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingConvertor; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingManager; + +import java.io.File; +import java.util.concurrent.atomic.AtomicReference; + +/** + * npm全局安装 + * + * @author noah + */ +public class NpmInstallGlobalManager { + private static final Object _lockObj = new Object(); + + /** + * 执行默认的安装操作 + * + * @param isUpgradeTool + * @return + */ + public static NpmPackageResponse npmInstallWithDefault(boolean isUpgradeTool) { + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(isUpgradeTool); + NpmInstallParameter packageParameter = NpmSettingConvertor.convertFromNpmSetting(npmSettings); + // 依据参数进行默认目录的安装 + + return npmInstall(packageParameter); + } + + /** + * 全局离线包执行安装 + * + * @param npmInstallParameter + * @return + */ + public static NpmPackageResponse npmInstall(NpmInstallParameter npmInstallParameter) { + if (npmInstallParameter.isOfflineMode()) { + String errorMessage = "开启离线模式,自动更新离线包停止"; + LoggerUtility.logToBrowser(errorMessage, LoggerLevelEnum.Info); + return NpmPackageResponse.create(); + } + if (npmInstallParameter.getUpdatePolicy().equals(NpmUpdatePolicy.manual)) { + String errorMessage = "离线包更新策略为手工,自动更新离线包停止"; + LoggerUtility.logToBrowser(errorMessage, LoggerLevelEnum.Info); + return NpmPackageResponse.create(); + } + if (npmInstallParameter.getUpdatePolicy().equals(NpmUpdatePolicy.never)) { + String errorMessage = "离线包更新策略为Never,自动更新离线包停止"; + LoggerUtility.logToBrowser(errorMessage, LoggerLevelEnum.Info); + return NpmPackageResponse.create(); + } + + boolean isUpgradeTool = npmInstallParameter.getExecuteEnvironment().equals(ExecuteEnvironmentEnum.UpgradeTool); + String tmpPackageJsonPath = GlobalPackageJsonPathGenerator.getPackageJsonPathInTmpDir(); + String serverPackageJsonPath = GlobalPackageJsonPathGenerator.generate(); + // 获取package.json 文件路径 + String tmpPackageJsonFilePath = GlobalPackageJsonPathGenerator.getPackageJsonFilePathInTmpDir(); + + String lockFilePath = NpmInstallLockFilePathGenerator.generate(tmpPackageJsonPath); + + + // 根据server启动时间和当前创建时间来进行比较 如果比server创建时间新 那么自动删除 + long serverStartTime = CommonUtility.getServerStartTime(); + File lockFileInfo = new File(lockFilePath); + boolean needAutoDeleteLockFile = lockFileInfo.exists() && lockFileInfo.lastModified() <= serverStartTime; + boolean reWithUnFinishInstall = false; + if (needAutoDeleteLockFile) { + FileUtility.deleteFile(lockFilePath); + reWithUnFinishInstall = true; + } + + synchronized (_lockObj) { + if (FileUtility.exists(lockFilePath)) { + LoggerUtility.logToBrowser("npm 正在全局安装,若需重新安装,请删除lock文件!", LoggerLevelEnum.Info); + return NpmPackageResponse.createError("npm 正在全局安装,若需重新安装,请删除lock文件!"); + } + } + + boolean needInstall = false; + boolean isSameCopiledFile = false; + + // 如果文件目录不存在 那么创建对应的文件目录 拷贝package.json 到目标文件目录 + if (!FileUtility.exists(tmpPackageJsonPath)) { + FileUtility.createDirectory(tmpPackageJsonPath); + } + + if (!FileUtility.exists(serverPackageJsonPath)) { + // 如果server中package.json 文件不存在 那么无需执行 + return NpmPackageResponse.create(); + } + + if (!FileUtility.exists(tmpPackageJsonFilePath) || reWithUnFinishInstall) { + // 如果目标文件不存在 那么直接进行拷贝 并且进行安装 + needInstall = true; + isSameCopiledFile = true; + } + + + // 如果不是直接拷贝 那么比较两个文件目录是否相同 + // 比较package.json + String serverPackageJsonContent = FileUtility.readAsString(serverPackageJsonPath); + + + NpmPackageJsonInfo serverPackageJsonInfo = NpmPackageCheck.packageJsonInfoGenerate(serverPackageJsonContent); + + NpmPackageJsonInfo tmpPackageJsonInfo = null; + if (!isSameCopiledFile) { + String tmpPackageJsonContent = FileUtility.readAsString(tmpPackageJsonFilePath); + tmpPackageJsonInfo = NpmPackageCheck.packageJsonInfoGenerate(tmpPackageJsonContent); + } + + if (!needInstall) { + // 取反 + needInstall = !serverPackageJsonInfo.equals(tmpPackageJsonInfo); + } + + // 逐个执行安装 + try { + if (needInstall && serverPackageJsonInfo != null) { + synchronized (_lockObj) { + FileUtility.createFile(lockFilePath); + } + LoggerUtility.logToBrowser("执行全局离线包安装", LoggerLevelEnum.Info); + LoggerUtility.logToBrowser("全局离线包临时文件路径为:" + tmpPackageJsonFilePath, LoggerLevelEnum.Info); + + NpmPackageJsonInfo finalNodeModulesPackageJsonInfo = tmpPackageJsonInfo; + boolean finalIsSameCopiledFile = isSameCopiledFile; + + boolean needLogin = !StringUtility.isNullOrEmpty(npmInstallParameter.getUserName()) && !StringUtility.isNullOrEmpty(npmInstallParameter.getPassword()); + if (needLogin) { + String currentWorkPath = FileUtility.getCurrentWorkPath(isUpgradeTool); + NpmLoginCommandExecutor.execute(npmInstallParameter, currentWorkPath); + } + + AtomicReference commandResponse = new AtomicReference<>(); + final boolean[] canContinue = {true}; + serverPackageJsonInfo.getDependencies().forEach(t -> { + if (canContinue[0]) { + // 如果是复制的文件 那么直接进行安装 + if (finalIsSameCopiledFile) { + commandResponse.set(GlobalNpmInstallCommandExecutor.execute(npmInstallParameter, t.getKey(), t.getValue())); + } else { + if (!finalNodeModulesPackageJsonInfo.equalsInDependencies(t.getKey(), t.getValue())) { + commandResponse.set(GlobalNpmInstallCommandExecutor.execute(npmInstallParameter, t.getKey(), t.getValue())); + } + } + if (commandResponse.get() != null && !commandResponse.get().isSuccess()) { + canContinue[0] = false; + } + } + }); + if (commandResponse.get() != null && !commandResponse.get().isSuccess()) { + String errorMessage = "全局离线包安装失败," + commandResponse.get().getErrorMessage(); + LoggerUtility.logToBrowser(errorMessage, LoggerLevelEnum.Info); + // 如果安装失败 下次要重新安装 + FileUtility.deleteFile(tmpPackageJsonFilePath); + return NpmPackageResponse.createError(errorMessage); + } + LoggerUtility.logToBrowser("全局离线包安装完成", LoggerLevelEnum.Info); + FileUtility.copyFile(serverPackageJsonPath, tmpPackageJsonFilePath, true); + } else { + LoggerUtility.logToBrowser("全局离线包版本未发生变更,无需执行全局离线包安装", LoggerLevelEnum.Info); + } + } finally { + if (FileUtility.exists(lockFilePath)) { + FileUtility.deleteFile(lockFilePath); + } + } + return NpmPackageResponse.create(); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java new file mode 100644 index 00000000..bccb147a --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java @@ -0,0 +1,192 @@ +package com.inspur.edp.web.npmpackage.core.npmlogin; + +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import org.apache.commons.lang3.SystemUtils; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + + +/** + * npm login 命令执行 + * + * @author guozhiqi + */ +public class NpmLoginCommandExecutor { + /** + * npm 登录命令执行 + * + * @param npmInstallParameter + * @param currentServerPath + */ + public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String currentServerPath) { + // 构造install 命令参数 执行npm包安装操作 + String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentServerPath); + String args = npmCommandExecuteWithPath; + + args += " login "; + + String npmLoginCommand = NpmLoginCommandParameterGenerator.generate(npmInstallParameter); + + if (!StringUtility.isNullOrEmpty(npmLoginCommand)) { + args += npmLoginCommand; + } + + String[] command = {args}; + + // 执行npm 包安装 + return runLoginCommand(command, npmInstallParameter.getUserName(), npmInstallParameter.getPassword(), npmInstallParameter.getEmail()); + + } + + public static NpmPackageResponse runLoginCommand(String[] commands, String userName, String password, String email) { + String command = String.join(" && ", commands); + return runLoginCommand(command, true, userName, password, email); + + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + public static NpmPackageResponse runLoginCommand(String command, boolean isWait, String userName, String password, String email) { + String errorMessage = ""; + BufferedReader bufferedReader = null; + Process process = null; + OutputStream outputStream = null; + InputStream errinputStream = null; + StringBuilder errorSB = new StringBuilder(); + try { + LoggerUtility.logToBrowser(command, LoggerLevelEnum.Info); + + String updateCommand = command; + if (SystemUtils.IS_OS_WINDOWS) { + updateCommand = "cmd.exe" + " /C" + " " + command; + process = Runtime.getRuntime().exec(updateCommand); + } else if (SystemUtils.IS_OS_UNIX) { + updateCommand = command; + process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", updateCommand}); + } + if (updateCommand == null) { + return NpmPackageResponse.createError("不支持的操作系统类型,请联系开发人员处理"); + } + + InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream()); + bufferedReader = new BufferedReader(inputStreamReader); + + outputStream = process.getOutputStream(); + errinputStream = process.getErrorStream(); + InputStreamReader errInputStreamReader = new InputStreamReader(errinputStream); + + StringBuilder sb = new StringBuilder(); + + int len = -1; + char[] c = new char[1024]; + //读取进程输入流中的内容 + while ((len = inputStreamReader.read(c)) != -1) { + String s = new String(c, 0, len); + + if (!StringUtility.isNullOrEmpty(s)) { + boolean canPrint = true; + if (s.trim().contains("Username:")) { + canPrint = false; + String strUserName = userName + "\n"; + outputStream.write(strUserName.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + } else if (s.trim().contains("Password:")) { + canPrint = false; + String strPassword = password + "\n"; + outputStream.write(strPassword.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + } else if (s.contains("Email:")) { + canPrint = false; + String strEmail = email + "\n"; + outputStream.write(strEmail.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + outputStream.close(); + } + if (canPrint) { + // 输出日志信息 + LoggerUtility.logToBrowser(s, LoggerLevelEnum.Info,false); + } + } + //判断是否存在错误描述 + if (CommandLineUtility.checkHasError(s)) { + if(s.contains("npm ERR! Unable to authenticate")){ + // npm登录失败 + errorMessage="npm登录失败,请查看网络是否正常连接"; + }else{ + errorMessage = s; + } + break; + } + } + + // 获取error输出流 + + while ((len = errInputStreamReader.read(c)) != -1) { + String s = new String(c, 0, len); + errorSB.append(s); + LoggerUtility.logToBrowser(s, LoggerLevelEnum.Info); + } + + process.waitFor(); + // 销毁线程 + //process.destroy(); + + } catch (Exception e) { + e.printStackTrace(); + LoggerUtility.logToBrowser(Arrays.toString(e.getStackTrace()), LoggerLevelEnum.Info); + errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace()); + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (Exception e) { + e.printStackTrace(); + errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace()); + } + } + } + // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出 + if (!StringUtility.isNullOrEmpty(errorMessage)) { + return NpmPackageResponse.createError("npm install executed failed!" + errorMessage); + } + + if (!StringUtility.isNullOrEmpty(errorSB.toString())) { + // 针对几种固定错误 进行提示 + String header="然后重新执行更新操作。"; + String strErrorMessage = errorSB.toString(); + if (strErrorMessage.contains("network This is a problem related to network connectivity")) { + errorMessage = "请检查Url地址是否正确或网络是否可以联通,"+header; + } else if (strErrorMessage.contains("401 Unauthorized") && strErrorMessage.contains("Bad username or password")) { + // 用户名或密码错误 + errorMessage = "用户名或密码错误,请修正后重新执行更新操作。"; + } else if (strErrorMessage.contains("404 Not Found - PUT") && strErrorMessage.contains("/user/org.couchdb.user")) { + errorMessage = "请检查Url地址是否正确或用户名是否存在,请修正后重新执行更新操作。"; + } else { + errorMessage = errorMessage + errorSB; + } + } + + if (!StringUtility.isNullOrEmpty(errorMessage) && errorSB.toString().contains("npm ERR!")) { + return NpmPackageResponse.createError(errorMessage); + } + + return NpmPackageResponse.create(); + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java new file mode 100644 index 00000000..4bf2f53c --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.npmpackage.core.npmlogin; + +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; + +/** + * npm login 命令参数构造 + * + * @author noah + */ +class NpmLoginCommandParameterGenerator { + public static String generate(NpmInstallParameter npmInstallParameter) { + String args = ""; + args += " --registry=" + npmInstallParameter.getRegistry(); + return args; + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java new file mode 100644 index 00000000..6a03144d --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java @@ -0,0 +1,133 @@ +package com.inspur.edp.web.npmpackage.core.npmlogout; + +import com.inspur.edp.web.common.entity.NodeJsCommandEnum; +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.utility.CommandLineUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import org.apache.commons.lang3.SystemUtils; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; + +/** + * npm 登出命令执行 + */ +public class NpmLogoutCommandExecutor { + /** + * npm登出命令执行 + * + * @param npmInstallParameter + * @param currentServerPath + */ + public static NpmPackageResponse execute(NpmInstallParameter npmInstallParameter, String currentServerPath) { + // 构造install 命令参数 执行npm包安装操作 + String npmCommandExecuteWithPath = NodejsFunctionUtility.getNodeJsCommandInServerWithOS(NodeJsCommandEnum.Npm, currentServerPath); + String args = npmCommandExecuteWithPath; + + args += " logout "; + + String npmLoginCommand = NpmLogoutCommandParameterGenerator.generate(npmInstallParameter); + + if (!StringUtility.isNullOrEmpty(npmLoginCommand)) { + args += npmLoginCommand; + } + + String[] command = {args}; + // 执行npm 包安装 + return runCommand(command, true); + + } + + public static NpmPackageResponse runCommand(String[] commands, boolean isWait) { + String command = String.join(" && ", commands); + return runCommand(command, isWait); + } + + /** + * 执行命令 + * + * @param command 待执行命令 + * @param isWait 是否等待返回结果 + */ + public static NpmPackageResponse runCommand(String command, boolean isWait) { + String errorMessage = ""; + BufferedReader bufferedReader = null; + InputStream errinputStream = null; + StringBuilder errorSB = new StringBuilder(); + try { + LoggerUtility.logToBrowser(command, LoggerLevelEnum.Info); + Process process = null; + + String updateCommand = command; + if (SystemUtils.IS_OS_WINDOWS) { + updateCommand = "cmd.exe" + " /C" + " " + command; + process = Runtime.getRuntime().exec(updateCommand); + } else if (SystemUtils.IS_OS_UNIX) { + updateCommand = command; + process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", updateCommand}); + } + if (updateCommand == null) { + return NpmPackageResponse.createError("不支持的操作系统类型,请联系开发人员处理!"); + } + + InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream()); + bufferedReader = new BufferedReader(inputStreamReader); + + errinputStream = process.getErrorStream(); + InputStreamReader errInputStreamReader = new InputStreamReader(errinputStream); + + StringBuilder sb = new StringBuilder(); + + int len = -1; + char[] c = new char[1024]; + //读取进程输入流中的内容 + while ((len = inputStreamReader.read(c)) != -1) { + String s = new String(c, 0, len); + LoggerUtility.logToBrowser(s, LoggerLevelEnum.Info); + //判断是否存在错误描述 + if (CommandLineUtility.checkHasError(s)) { + errorMessage = s; + break; + } + } + + // 获取error输出流 + + while ((len = errInputStreamReader.read(c)) != -1) { + String s = new String(c, 0, len); + errorSB.append(s); + LoggerUtility.logToBrowser(s, LoggerLevelEnum.Info); + } + + + } catch (Exception e) { + e.printStackTrace(); + errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace()); + } finally { + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (Exception e) { + e.printStackTrace(); + errorMessage = e.getMessage() + Arrays.toString(e.getStackTrace()); + } + } + } + // 如果出现编译错误 那么通过异常的方式将错误信息进行抛出 + if (!StringUtility.isNullOrEmpty(errorMessage)) { + return NpmPackageResponse.createError("npm logout failed,the message is " + errorMessage); + } + // 如果error信息不为空 + if (!StringUtility.isNullOrEmpty(errorSB.toString()) && errorSB.toString().contains("npm ERR!") && !errorSB.toString().contains("not logged in ")) { + return NpmPackageResponse.createError(errorSB.toString()); + } + return NpmPackageResponse.create(); + } + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java new file mode 100644 index 00000000..1acf07b5 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.npmpackage.core.npmlogout; + +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; + +/** + * npm 登录退出 + * @author noah + */ +public class NpmLogoutCommandParameterGenerator { + public static String generate(NpmInstallParameter npmInstallParameter) + { + String args = ""; + args += " --registry=" + npmInstallParameter.getRegistry(); + return args; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java new file mode 100644 index 00000000..60521903 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java @@ -0,0 +1,111 @@ +package com.inspur.edp.web.npmpackage.core.npmpackagecheck; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageCheckUpdateOptions; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; +import com.inspur.edp.web.npmpackage.api.entity.packagejson.NpmPackageJsonDependencyInfo; +import com.inspur.edp.web.npmpackage.api.entity.packagejson.NpmPackageJsonInfo; +import com.inspur.edp.web.npmpackage.core.npminstall.NodeModulesPathGenerator; +import com.inspur.edp.web.npmpackage.core.npminstall.PackageJsonPathGenerator; +import io.iec.edp.caf.common.JSONSerializer; + +import java.util.Iterator; +import java.util.Map; + +/** + * npm 设计时包版本检测 + * + * @author noah + */ +public class NpmPackageCheck { + /** + * npm 设计时包版本检测 + * + * @param checkUpdateOptions + * @return + */ + public static boolean check(NpmPackageCheckUpdateOptions checkUpdateOptions) { + // 获取package.json 在server的部署位置 + String currentServerPath = FileUtility.getCurrentWorkPath(checkUpdateOptions.isUpgradeTool()); + String serverPackageJsonPath = PackageJsonPathGenerator.generate(currentServerPath, checkUpdateOptions.isMobile()); + + NpmInstallParameter npmInstallParameter = new NpmInstallParameter(); + npmInstallParameter.setExecuteEnvironment(checkUpdateOptions.getExecuteEnvironment()); + npmInstallParameter.setMobile(checkUpdateOptions.isMobile()); + String parentNodeModulesPackageJsonPath = NodeModulesPathGenerator.generatePackageJsonPath(npmInstallParameter, currentServerPath); + String nodeModulesWithPackageJsonPath = FileUtility.combine(parentNodeModulesPackageJsonPath, NpmPackageConstants.PackageJsonName); + // 如果源文件不存在 那么无需进行比较 + if (!FileUtility.exists(serverPackageJsonPath)) { + return true; + } + // 如果目标不存在 那么直接认为需要更新 + if (!FileUtility.exists(nodeModulesWithPackageJsonPath)) { + return false; + } + + // 如果两个文件都存在 那么比较文件内容 + + String serverPackageJsonContent = FileUtility.readAsString(serverPackageJsonPath); + String nodeModulesPackageJsonContent = FileUtility.readAsString(nodeModulesWithPackageJsonPath); + + + NpmPackageJsonInfo serverPackageJsonInfo = packageJsonInfoGenerate(serverPackageJsonContent); + NpmPackageJsonInfo nodeModulesPackageJsonInfo = packageJsonInfoGenerate(nodeModulesPackageJsonContent); + + if (serverPackageJsonInfo == null || nodeModulesPackageJsonInfo == null) { + return false; + } + // 取反 + + return serverPackageJsonInfo.equals(nodeModulesPackageJsonInfo); + } + + public static NpmPackageJsonInfo packageJsonInfoGenerate(String serverPackageJsonContent) { + NpmPackageJsonInfo packageJsonInfo = new NpmPackageJsonInfo(); + + JsonNode jsonNode = JSONSerializer.deserialize(serverPackageJsonContent, JsonNode.class); + String packageJsonName = jsonNode.get("name").asText(); + packageJsonInfo.setName(packageJsonName); + + String packageJsonVersion = jsonNode.get("version").asText(); + packageJsonInfo.setVersion(packageJsonVersion); + + String packageJsonDescription = jsonNode.get("description").asText(); + packageJsonInfo.setDescription(packageJsonDescription); + + String packageJsonAuthor = jsonNode.get("author").textValue(); + packageJsonInfo.setAuthor(packageJsonAuthor); + + String packageJsonLicense = jsonNode.get("license").asText(); + packageJsonInfo.setLicense(packageJsonLicense); + + ObjectNode dependenciesObjNode = (ObjectNode) jsonNode.get("dependencies"); + ObjectNode devDependenciesObjNode = (ObjectNode) jsonNode.get("devDependencies"); + + if (dependenciesObjNode != null) { + Iterator> iterator = dependenciesObjNode.fields(); + while (iterator.hasNext()) { + Map.Entry field = iterator.next(); + if (field != null && !StringUtility.isNullOrEmpty(field.getKey()) && !StringUtility.isNullOrEmpty(field.getValue().textValue())) { + packageJsonInfo.getDependencies().add(new NpmPackageJsonDependencyInfo(field.getKey(), field.getValue().textValue())); + } + } + } + + if (devDependenciesObjNode != null) { + Iterator> iterator = devDependenciesObjNode.fields(); + while (iterator.hasNext()) { + Map.Entry field = iterator.next(); + if (field != null && !StringUtility.isNullOrEmpty(field.getKey()) && !StringUtility.isNullOrEmpty(field.getValue().textValue())) { + packageJsonInfo.getDevDependencies().add(new NpmPackageJsonDependencyInfo(field.getKey(), field.getValue().textValue())); + } + } + } + + return packageJsonInfo; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java new file mode 100644 index 00000000..c8ba84e1 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java @@ -0,0 +1,17 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +/** + * npm 参数配置常量 + * @author noah + */ +public class NpmSettingConstant { + /** + * npm 参数配置文件名称 + */ + public static final String SettingFileName="setting.json"; + + /** + * 相对于nodejs路径的目录名称 + */ + public static final String RelativePathWithNodeJs="npmsettings"; +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java new file mode 100644 index 00000000..1b2e6259 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java @@ -0,0 +1,42 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmRepository; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + + +/** + * npm setting 转换成npm install parameter + * + * @author guozhiqi + */ +public class NpmSettingConvertor { + public static NpmInstallParameter convertFromNpmSetting(NpmSettings npmSettings) { + NpmInstallParameter npmInstallParameter = new NpmInstallParameter(); + String currentNpmSettingMode = npmSettings.getSettingMode(); + NpmRepository[] repositories = npmSettings.getSettingConfig().getRepositories(); + + NpmRepository currentRepository = null; + for (NpmRepository repository : repositories) { + String tempSettingMode = repository.getId(); + if (tempSettingMode.equals(currentNpmSettingMode)) { + currentRepository = repository; + } + } + // 如果获取到的仓库实例为空 + if (currentRepository == null) { + throw new RuntimeException("未获取到npm配置仓库实例"); + } + + npmInstallParameter.setUserName(currentRepository.getUserName()); + npmInstallParameter.setPassword(currentRepository.getPassword()); + npmInstallParameter.setRegistry(currentRepository.getUrl()); + npmInstallParameter.setExecuteEnvironment(ExecuteEnvironmentEnum.Design); + npmInstallParameter.setUpdatePolicy(currentRepository.getUpdatePolicy()); + npmInstallParameter.setUpdateAll(true); + npmInstallParameter.setOfflineMode(npmSettings.isOffline()); + + return npmInstallParameter; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java new file mode 100644 index 00000000..1dc51eb2 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmRepository; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +public class NpmSettingEncryptService { + private static final NpmSettingEncryptService encryService = new NpmSettingEncryptService(); + + public static NpmSettingEncryptService getInstance() { + return encryService; + } + + public NpmSettings deEncrypt(NpmSettings npmSettings) { + NpmSettings deepCloneNpmSetting = SerializeUtility.getInstance().deserialize(SerializeUtility.getInstance().serialize(npmSettings), NpmSettings.class); + if (deepCloneNpmSetting != null && deepCloneNpmSetting.getSettingConfig() != null && deepCloneNpmSetting.getSettingConfig().getRepositories() != null) { + NpmRepository[] repositories = deepCloneNpmSetting.getSettingConfig().getRepositories(); + int offset = 3; + for (int i = 0; i < deepCloneNpmSetting.getSettingConfig().getRepositories().length; i++) { + NpmRepository repositoryItem = repositories[i]; + // 修正对应参数值 避免由于安全问题 暴露明文 + repositoryItem.setUserName(this.fromCharCode(offset, repositoryItem.getUserName(), false)); + repositoryItem.setPassword(this.fromCharCode(offset, repositoryItem.getPassword(), false)); + repositoryItem.setUrl(this.fromCharCode(offset, repositoryItem.getUrl(), false)); + } + } + return deepCloneNpmSetting; + } + + public NpmSettings encrypt(NpmSettings npmSettings) { + NpmSettings deepCloneNpmSetting = SerializeUtility.getInstance().deserialize(SerializeUtility.getInstance().serialize(npmSettings), NpmSettings.class); + if (deepCloneNpmSetting != null && deepCloneNpmSetting.getSettingConfig() != null && deepCloneNpmSetting.getSettingConfig().getRepositories() != null) { + NpmRepository[] repositories = deepCloneNpmSetting.getSettingConfig().getRepositories(); + int offset = 3; + for (int i = 0; i < deepCloneNpmSetting.getSettingConfig().getRepositories().length; i++) { + NpmRepository repositoryItem = repositories[i]; + // 修正对应参数值 避免由于安全问题 暴露明文 + repositoryItem.setUserName(this.fromCharCode(offset, repositoryItem.getUserName(), true)); + repositoryItem.setPassword(this.fromCharCode(offset, repositoryItem.getPassword(), true)); + repositoryItem.setUrl(this.fromCharCode(offset, repositoryItem.getUrl(), true)); + } + } + return deepCloneNpmSetting; + } + + + /** + * 加密加3 解密减3 + * + * @param offset + * @param source + * @param isEncrypt + * @return + */ + private String fromCharCode(int offset, String source, boolean isEncrypt) { + if (source == null || source.length() == 0) { + return ""; + } + char[] arrCharSource = source.toCharArray(); + StringBuilder builder = new StringBuilder(arrCharSource.length); + + for (char codePoint : arrCharSource) { + if (isEncrypt) { + builder.append((char) (codePoint + offset)); + } else { + builder.append((char) (codePoint - offset)); + } + + } + return builder.toString(); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java new file mode 100644 index 00000000..af05eef8 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java @@ -0,0 +1,47 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmRepository; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettingConfig; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettingMode; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +/** + * npm 参数配置初始化 + * + * @author noah + */ +class NpmSettingInitialization { + + /** + * 构造默认的npm配置参数 + * @return + */ + public static NpmSettings initialize() { + NpmSettings npmSettings = new NpmSettings(); + // 默认为离线模式 为停用 如果要启用必须手工开启 + npmSettings.setOffline(true); + npmSettings.setSettingMode(NpmSettingMode.prod); + + NpmSettingConfig settingConfig = new NpmSettingConfig(); + + // 构造三个默认的仓库 + NpmRepository[] repositories = new NpmRepository[1]; + + NpmRepository prodRepository = new NpmRepository(); + prodRepository.setId("prod"); + prodRepository.setName("npm-gsp"); + prodRepository.setUrl("https://repos.iec.io/repository/npm-gsp/"); + prodRepository.setUserName("igix-npm-common"); + prodRepository.setPassword("Pkjw8li9yDOcHQvB"); + prodRepository.setNeedLogin(true); + prodRepository.setCanDelete(false); + + repositories[0] = prodRepository; + + settingConfig.setRepositories(repositories); + + npmSettings.setSettingConfig(settingConfig); + + return npmSettings; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java new file mode 100644 index 00000000..7a0fa288 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java @@ -0,0 +1,68 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.io.NodejsFunctionUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmRepository; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +import java.util.UUID; + +/** + * npm 配置管理 + * + * @author noah + */ +public class NpmSettingManager { + + + /** + * 获取对应的npm配置文件内容 + * + * @param isUpgradeTool + * @return + */ + public static NpmSettings getNpmSetting(boolean isUpgradeTool) { + // 获取nodejs路径 + String nodeJsPath = NodejsFunctionUtility.getNodeJsPathInServer(); + // 从配置文件中读取对应的内容 + NpmSettings npmSettings = NpmSettingReader.read(nodeJsPath); + if (npmSettings == null) { + // 如果未成功读取到文件内容 那么取默认值 + npmSettings = NpmSettingInitialization.initialize(); + } + + return npmSettings; + } + + /** + * npm配置信息保存 + * + * @param npmSettings npm配置信息 + * @return + */ + public static NpmPackageResponse saveNpmSetting(NpmSettings npmSettings) { + + if (npmSettings == null) { + return NpmPackageResponse.createError("npm 配置信息为空,请设置"); + } + + // 针对保存 如果对应的id不存在 那么设置为随机数 并返回至前端 + for (NpmRepository npmRepository : npmSettings.getSettingConfig().getRepositories()) { + if (npmRepository.getId() == null || npmRepository.getId().length() == 0) { + UUID uuid = UUID.randomUUID(); + npmRepository.setId(uuid.toString()); + } + } + + String nodeJsPath = NodejsFunctionUtility.getNodeJsPathInServer(); + String serializedNpmSetting = SerializeUtility.getInstance().serialize(npmSettings, true); + // 参数保存至配置文件 + NpmSettingWriter.write(nodeJsPath, serializedNpmSetting); + NpmPackageResponse packageResponse = NpmPackageResponse.create(); + packageResponse.setExtraData(npmSettings); + return packageResponse; + } + + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java new file mode 100644 index 00000000..008048cc --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java @@ -0,0 +1,42 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageConstants; + +/** + * npm 配置文件路径manager + * + * @author noah + */ +class NpmSettingPathManager { + /** + * 根据nodejs目录获取npm配置文件路径 + * + * @param nodeJsPath nodejs 文件路径 + * @return + */ + public static String getNpmSettingFilePath(String nodeJsPath) { + String npmSettingPath = getNpmSettingPath(nodeJsPath); + return FileUtility.combine(npmSettingPath, NpmPackageConstants.NpmSettingFileName); + } + + /** + * 获取npm配置文件所在目录 + * * @param nodeJsPath + * + * @return + */ + public static String getNpmSettingPath(String nodeJsPath) { + return FileUtility.combine(nodeJsPath, NpmPackageConstants.NpmSettingPath); + } + + /** + * npm参数配置文件是否存在 + * + * @param npmSettingPath npm参数配置文件路径 + * @return + */ + public static boolean exists(String npmSettingPath) { + return FileUtility.exists(npmSettingPath); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java new file mode 100644 index 00000000..d7653d8a --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java @@ -0,0 +1,41 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; + +import java.util.Arrays; + +/** + * npm 配置参数读取 + * + * @author noah + */ +class NpmSettingReader { + /** + * 读取server下对应的npm配置参数 + * + * @param nodeJsPath nodejs路径 + * @return + */ + public static NpmSettings read(String nodeJsPath) { + String npmSettingFilePath = NpmSettingPathManager.getNpmSettingFilePath(nodeJsPath); + // 如果文件不存在 那么无需进行解析 + if (!NpmSettingPathManager.exists(npmSettingFilePath)) { + LoggerUtility.log("npm settings config file not exists, jit-engine will create with default content! the path is " + npmSettingFilePath, LoggerLevelEnum.Info); + return null; + } + + String strNpmSettings = FileUtility.readAsString(npmSettingFilePath); + + try { + // 如果转换失败 即读取到的文件内容无法转换成npm配置参数信息 + return SerializeUtility.getInstance().deserialize(strNpmSettings, NpmSettings.class); + } catch (Exception e) { + LoggerUtility.log("read npmsettings failed,please check! the path is :" + npmSettingFilePath + " , and the reason is " + Arrays.toString(e.getStackTrace()), LoggerLevelEnum.Info); + } + return null; + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java new file mode 100644 index 00000000..cd2c0624 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.npmpackage.core.npmsetting; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; + +import java.util.Arrays; + +/** + * npm 配置文件写入 + * + * @author noah + */ +class NpmSettingWriter { + /** + * 写入文件内容到npm配置文件 + * + * @param nodeJsPath nodejs文件路径 + * @param content npm配置文件内容 + */ + public static void write(String nodeJsPath, String content) { + String npmSettingFilePath = NpmSettingPathManager.getNpmSettingFilePath(nodeJsPath); + if (!NpmSettingPathManager.exists(npmSettingFilePath)) { + // 构造对应的目录 + String npmSettingPath = NpmSettingPathManager.getNpmSettingPath(nodeJsPath); + FileUtility.createDirectory(npmSettingPath); + } + try { + FileUtility.writeFile(npmSettingFilePath, content); + } catch (Exception ex) { + LoggerUtility.log("write to npmsetting file failed,please check! the path is " + npmSettingFilePath + " , and the reason is " + Arrays.toString(ex.getStackTrace()), LoggerLevelEnum.Info); + } + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json new file mode 100644 index 00000000..8e2af028 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json @@ -0,0 +1,216 @@ +{ + "name": "@farris/jit-engine", + "version": "0.0.1", + "description": "npm auto install", + "engines": { + "node": ">= 6.9.0", + "npm": ">= 3.0.0" + }, + "keywords": [ + "node_modules", + "jit" + ], + "author": "Noah", + "license": "ISC", + "dependencies": { + "@angular-devkit/core": "7.3.9", + "@angular/compiler-cli": "7.2.15", + "@angular/common": "7.2.13", + "@angular/core": "7.2.13", + "@angular/forms": "7.2.13", + "@angular/router": "7.2.13", + "@ant-design/icons-angular": "2.1.0", + "@ecp-caf/caf-common": "^2.0.5", + "@edp-aif/common-api": "^0.6.1", + "@edp-aif/runtime-api": "^0.6.0", + "@edp-bif/common-api": "^0.7.1", + "@edp-bif/runtime-api": "^0.7.2", + "@farris/bef": "0.0.12-20210428112135-dev", + "@farris/command-services": "0.0.12-20210508093120-dev", + "@farris/component-querycondition": "^0.1.46", + "@farris/devkit": "0.0.12-20210428112050-dev", + "@farris/discussion-group": "0.0.22", + "@farris/dynamic-control-group": "^0.1.11", + "@farris/extend-file-upload": "^0.1.9", + "@farris/extend-fileupload-adapt-unifile": "^0.1.4", + "@farris/farris-rollup": "1.0.80", + "@farris/header-group-editor": "0.0.15", + "@farris/ide-devkit": "^1.0.33", + "@farris/ide-enum-editor": "0.0.3", + "@farris/ide-publish-menu": "0.0.17", + "@farris/kendo-binding": "0.0.12-20210428112252-dev", + "@farris/mobile-bef": "0.0.6", + "@farris/mobile-business-ui": "0.0.27", + "@farris/mobile-cli": "latest", + "@farris/mobile-command-services": "0.0.16", + "@farris/mobile-devkit": "0.0.5", + "@farris/mobile-ui": "0.0.19", + "@farris/mobile-vue-adapter": "0.0.10", + "@farris/tags": "0.0.9", + "@farris/ui-area-response": "0.0.2", + "@farris/ui-avatar": "0.0.17", + "@farris/ui-batch-edit-dialog": "0.0.12", + "@farris/ui-button": "0.0.16", + "@farris/ui-calculator": "0.0.1", + "@farris/ui-calendar": "0.0.5", + "@farris/ui-combo-list": "^0.1.37", + "@farris/ui-combo-lookup": "^0.1.21", + "@farris/ui-common": "^0.2.6", + "@farris/ui-datagrid": "^0.8.21", + "@farris/ui-datagrid-editors": "^0.2.43", + "@farris/ui-datagrid-filter": "0.0.15", + "@farris/ui-datagrid-settings": "0.0.16", + "@farris/ui-datalist": "0.0.16", + "@farris/ui-datatable": "^0.1.25", + "@farris/ui-datepicker": "^0.3.7", + "@farris/ui-dialog": "0.0.13", + "@farris/ui-draggable": "0.0.4", + "@farris/ui-dropdown": "0.0.12", + "@farris/ui-editor": "0.0.10", + "@farris/ui-enum-editor": "0.0.3", + "@farris/ui-field-group": "0.0.21", + "@farris/ui-filter": "0.0.8", + "@farris/ui-filter-editor": "^0.1.15", + "@farris/ui-filter-panel": "0.0.10", + "@farris/ui-flex-layout": "0.0.3", + "@farris/ui-footer": "0.0.2", + "@farris/ui-forms": "0.0.35", + "@farris/ui-html-editor": "0.0.23", + "@farris/ui-input-group": "^0.2.5", + "@farris/ui-language-textbox": "^0.1.14", + "@farris/ui-layout": "0.0.6", + "@farris/ui-list-filter": "0.0.63", + "@farris/ui-list-nav": "0.0.12", + "@farris/ui-list-view": "0.0.26", + "@farris/ui-loading": "^0.1.9", + "@farris/ui-locale": "0.2.12", + "@farris/ui-lookup": "^0.4.7", + "@farris/ui-messager": "^0.2.10", + "@farris/ui-modal": "^0.1.3", + "@farris/ui-multi-select": "^0.2.1", + "@farris/ui-nav": "0.0.4", + "@farris/ui-notify": "^0.1.6", + "@farris/ui-number-spinner": "^0.2.32", + "@farris/ui-pagination": "^0.1.10", + "@farris/ui-panel": "0.0.4", + "@farris/ui-perfect-scrollbar": "0.0.7", + "@farris/ui-popover": "0.0.4", + "@farris/ui-progress": "0.0.2", + "@farris/ui-progress-step": "0.0.23", + "@farris/ui-property-panel": "0.0.7", + "@farris/ui-response-toolbar": "^0.1.15", + "@farris/ui-responsive": "0.0.2", + "@farris/ui-scrollspy": "0.0.24", + "@farris/ui-section": "^0.1.2", + "@farris/ui-shortcuts": "0.0.4", + "@farris/ui-sidebar": "^0.1.4", + "@farris/ui-sort-editor": "^0.1.7", + "@farris/ui-splitter": "0.0.2", + "@farris/ui-switch": "0.0.6", + "@farris/ui-tabs": "^0.2.12", + "@farris/ui-tag": "0.0.2", + "@farris/ui-text": "^0.1.28", + "@farris/ui-time-picker": "^0.1.4", + "@farris/ui-time-spinner": "0.0.9", + "@farris/ui-tooltip": "0.0.17", + "@farris/ui-tree": "0.0.4", + "@farris/ui-treetable": "^0.3.4", + "@farris/ui-verify-detail": "0.0.6", + "@farris/ui-view-change": "0.0.5", + "@farris/ui-wizard": "0.0.29", + "@gsp-aif/common-api": "0.0.10", + "@gsp-aif/runtime-api": "0.0.11", + "@gsp-bef/gsp-be-metadata": "0.0.25", + "@gsp-bef/gsp-cm-metadata": "0.0.22", + "@gsp-bef/gsp-udt-metadata": "0.0.13", + "@gsp-bef/gsp-vo-metadata": "0.0.17", + "@gsp-cmp/chgdr": "0.0.2", + "@gsp-cmp/querysolution": "^0.1.28", + "@gsp-cmp/webcommand": "0.0.15", + "@gsp-dip/data-imp-exp": "^1.1.48", + "@gsp-lcm/bo-dt-service": "0.0.7", + "@gsp-lcm/bo-rt-service": "0.0.7", + "@gsp-lcm/bo-tree": "0.0.26", + "@gsp-lcm/dbo-selector": "0.0.4", + "@gsp-lcm/dbo-selectrt": "0.0.1", + "@gsp-lcm/metadata-selector": "0.0.50", + "@gsp-lcm/metadatart-selector": "0.0.6", + "@gsp-lcm/metadatart-selector4biztype": "0.0.12", + "@gsp-svc/cloudprint": "^0.4.19", + "@gsp-svc/expression": "0.0.53", + "@gsp-svc/file-load": "0.0.1", + "@gsp-svc/file-viewer": "0.0.74", + "@gsp-svc/filtercondition": "0.0.30", + "@gsp-svc/formdoc-upload": "^0.1.8", + "@gsp-sys/rtf-apphelp": "^1.0.9", + "@gsp-sys/rtf-common": "^2.0.8", + "@gsp-sys/rtf-ui": "0.0.7", + "@gsp-sys/sysmgr-common": "0.0.8", + "@gsp-sys/sysmgr-ui": "0.0.94", + "@gsp-wf/rtdevkit": "^1.0.5", + "@gsp-wf/task-action-impl": "0.0.17", + "@gsp-wf/task-impl-api": "0.0.8", + "@gsp-wf/ui-comment": "^0.1.8", + "@gsp-wf/ui-flowchart": "^1.1.1", + "@gsp-wf/wf-approval-logs": "^0.2.0", + "@gsp-wf/wf-process-editor": "^0.1.8", + "@gsp-wf/wf-sign": "0.0.5", + "@gsp-wf/wf-task-handler": "0.0.26", + "@gspwidget/portlet": "^1.5.0", + "@gspwidget/util": "^1.5.0", + "@gspwidget/widget-core": "^1.5.0", + "@gspwidget/widget-devkit": "^1.5.0", + "@progress/kendo-angular-buttons": "^4.4.0", + "@progress/kendo-angular-dateinputs": "^3.7.3", + "@progress/kendo-angular-dropdowns": "^3.5.3", + "@progress/kendo-angular-grid": "^3.14.1", + "@progress/kendo-angular-inputs": "^4.2.1", + "@progress/kendo-angular-intl": "^1.7.0", + "@progress/kendo-angular-l10n": "^1.4.0", + "@progress/kendo-angular-label": "^1.3.0", + "@progress/kendo-angular-layout": "^3.3.0", + "@progress/kendo-angular-pdf-export": "^1.3.1", + "@progress/kendo-angular-resize-sensor": "^3.2.0", + "@progress/kendo-angular-treeview": "^3.1.1", + "@progress/kendo-data-query": "^1.5.1", + "@progress/kendo-drawing": "^1.5.11", + "@progress/kendo-theme-default": "^2.57.1", + "@progress/kendo-theme-bootstrap": "^2.14.2", + "@progress/kendo-angular-dialog": "3.12.0", + "@progress/kendo-angular-excel-export": "2.3.0", + "primeng": "9.0.0", + "@qdp/command-services": "0.0.1-0.0.16dev", + "@qdp/common": "0.0.1-0.0.37dev", + "@qdp/condition-schema": "0.0.1-0.0.14dev", + "@qdp/echarts": "0.0.1-0.0.18dev", + "@qdp/formular": "0.0.1-0.0.19dev", + "@qdp/ide-cmp": "0.0.1-0.0.44dev", + "@qdp/localize": "0.0.1-0.0.14dev", + "@qdp/query-framework": "0.0.1-0.0.27dev", + "@qdp/search-join": "0.0.1-0.0.20dev", + "@qdp/spread": "0.0.1-0.0.34dev", + "bignumber.js": "^9.0.1", + "ngx-cookie-service": "^2.2.0", + "chalk": "2.4.2", + "date-fns": "2.6.0", + "lodash": "^4.17.10", + "moment": "^2.29.1", + "moment-timezone": "^0.5.33", + "prettier": "^1.18.2", + "rxjs": "~6.3.3", + "signature_pad": "^3.0.0-beta.4", + "dayjs": "1.10.3", + "vant": "3.0.3", + "vue": "3.0.5", + "vue-router": "4.0.3", + "reflect-metadata": "0.1.13", + "typescript": "3.2.4", + "tslib": "1.9.3" + }, + "devDependencies": { + "@babel/core": "^7.12.9", + "@babel/preset-env": "^7.12.7", + "@babel/preset-typescript": "^7.12.7", + "cross-env": "^7.0.3" + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallService.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallService.java new file mode 100644 index 00000000..6ac6df54 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallService.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.npmpackage.core.service; + +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.core.npminstall.NpmInstallManager; + +/** + * npm 包安装service + * + * @author guozhiqi + */ +public class NpmPackageInstallService { + /** + * 对外公共 npm包install + * + * @param npmInstallParameter + * @return + */ + public static NpmPackageResponse install(NpmInstallParameter npmInstallParameter) { + return NpmInstallManager.npmInstall(npmInstallParameter, true); + } + + public static NpmPackageResponse installCheck(NpmInstallParameter npmInstallParameter) { + return NpmInstallManager.npmInstallCheck(npmInstallParameter); + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageService.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageService.java new file mode 100644 index 00000000..750c651c --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageService.java @@ -0,0 +1,59 @@ +package com.inspur.edp.web.npmpackage.core.service; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.utility.LoggerLevelEnum; +import com.inspur.edp.web.common.utility.LoggerUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageCheckUpdateOptions; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.core.npminstall.NodeModulesPathGenerator; +import com.inspur.edp.web.npmpackage.core.npmpackagecheck.NpmPackageCheck; + +/** + * npm 包 manager service + * + * @author guozhiqi + */ +public class NpmPackageService { + /** + * 执行npm 版本检测 + * + * @param checkUpdateOptions + * @return + */ + public static NpmPackageResponse checkUpdate(NpmPackageCheckUpdateOptions checkUpdateOptions) { + + // 升级工具中不进行检测 + if (checkUpdateOptions.isUpgradeTool()) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("升级工具执行,npm包版本不进行检测"); + return npmPackageResponse; + } + + String currentServerPath = FileUtility.getCurrentWorkPath(checkUpdateOptions.isUpgradeTool()); + + + // 判断是否存在node_modules 避免被误删除的情况 + NpmInstallParameter npmInstallParameter = new NpmInstallParameter(); + npmInstallParameter.setExecuteEnvironment(checkUpdateOptions.getExecuteEnvironment()); + npmInstallParameter.setMobile(checkUpdateOptions.isMobile()); + String nodeModulesPath = NodeModulesPathGenerator.generatePackageJsonPath(npmInstallParameter, currentServerPath); + nodeModulesPath = FileUtility.combine(nodeModulesPath, "node_modules"); + if (!FileUtility.exists(nodeModulesPath) || FileUtility.isEmptyFolder(nodeModulesPath)) { + String tip = "未配置编译依赖node_modules,请在 Npm包管理进行在线安装。node_modules路径为:" + nodeModulesPath; + LoggerUtility.logToBrowser(tip, LoggerLevelEnum.Info); + return NpmPackageResponse.createError(tip); + } + + // 是否需要update标识 + boolean npmCheckFlag = NpmPackageCheck.check(checkUpdateOptions); + + + if (npmCheckFlag) { + return NpmPackageResponse.create(); + } else { + return NpmPackageResponse.createError("npm包版本存在更新,为保证最终脚本运行正确,需先进行更新。\r\n请在选项->设置->Npm包管理进行更新!"); + } + } +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImpl.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImpl.java new file mode 100644 index 00000000..11fc8777 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPacakgeWebServiceImpl.java @@ -0,0 +1,90 @@ +package com.inspur.edp.web.npmpackage.core.webservice; + +import com.inspur.edp.web.common.environment.ExecuteEnvironmentEnum; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageCheckUpdateOptions; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmRepository; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmUpdatePolicy; +import com.inspur.edp.web.npmpackage.api.webservice.NpmPackageWebService; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingEncryptService; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingManager; +import com.inspur.edp.web.npmpackage.core.service.NpmPackageService; + +/** + * npm 包webservice + * + * @author noah + */ +public class NpmPacakgeWebServiceImpl implements NpmPackageWebService { + @Override + public NpmSettings getNpmSetting() { + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(false); + + npmSettings = NpmSettingEncryptService.getInstance().encrypt(npmSettings); + + return npmSettings; + } + + + /** + * 保存npm配置信息 + * + * @param npmSettings npm配置信息 + * @return + */ + @Override + public NpmPackageResponse saveNpmSetting(NpmSettings npmSettings) { + npmSettings=NpmSettingEncryptService.getInstance().deEncrypt(npmSettings); + + return NpmSettingManager.saveNpmSetting(npmSettings); + } + + @Override + public NpmPackageResponse checkUpdate() { + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(false); + // 如果为离线模式 + if (npmSettings.isOffline()) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("离线模式下无法执行在线install"); + return npmPackageResponse; + } + + NpmRepository currentRepository = null; + NpmRepository[] repositories = npmSettings.getSettingConfig().getRepositories(); + for (NpmRepository repository : repositories) { + String tempSettingMode = repository.getId(); + if (tempSettingMode.equals(npmSettings.getSettingMode())) { + currentRepository = repository; + } + } + if (currentRepository == null) { + // 如果未找到当前配置的仓库 + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("未获取到当前配置npm仓库"); + return npmPackageResponse; + } + + // 如果配置策略为手工或从不 + if (NpmUpdatePolicy.never.equals(currentRepository.getUpdatePolicy())) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setSuccess(true); + npmPackageResponse.setErrorMessage("当前配置策略不是自动更新,无法执行在线install操作。"); + return npmPackageResponse; + } + + if (NpmUpdatePolicy.manual.equals(currentRepository.getUpdatePolicy())) { + NpmPackageCheckUpdateOptions checkUpdateOptions = new NpmPackageCheckUpdateOptions(); + checkUpdateOptions.setExecuteEnvironment(ExecuteEnvironmentEnum.Design); + checkUpdateOptions.setUpgradeTool(false); + return NpmPackageService.checkUpdate(checkUpdateOptions); + } +// 如果为编译前 那么自动执行无需提示 + return NpmPackageResponse.create(); + + } + + +} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java new file mode 100644 index 00000000..59052161 --- /dev/null +++ b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java @@ -0,0 +1,81 @@ +package com.inspur.edp.web.npmpackage.core.webservice; + +import com.inspur.edp.web.common.utility.CommonUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponse; +import com.inspur.edp.web.npmpackage.api.entity.NpmPackageResponseLevel; +import com.inspur.edp.web.npmpackage.api.entity.settings.NpmSettings; +import com.inspur.edp.web.npmpackage.api.webservice.NpmPackageInstallWebService; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingConvertor; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingEncryptService; +import com.inspur.edp.web.npmpackage.core.npmsetting.NpmSettingManager; +import com.inspur.edp.web.npmpackage.core.service.NpmPackageInstallService; + +/** + * npm 包安装webservice + * + * @author guozhiqi + */ +public class NpmPackageInstallWebServiceImpl implements NpmPackageInstallWebService { + @Override + public NpmPackageResponse install(NpmSettings npmSettings) { + if (npmSettings == null) { + throw new RuntimeException("npm 安装参数不能为空"); + } + npmSettings = NpmSettingEncryptService.getInstance().deEncrypt(npmSettings); + + // 执行参数转换 + try { + NpmInstallParameter npmInstallParameter = NpmSettingConvertor.convertFromNpmSetting(npmSettings); + + // 执行npm 安装 + NpmPackageResponse npmPackageResponse = NpmPackageInstallService.install(npmInstallParameter); + + try { + // 保存最后的更新时间 + npmSettings.setLastUpdated(CommonUtility.getCurrentDateString()); + NpmSettingManager.saveNpmSetting(npmSettings); + } catch (Exception ignored) { + + } + + return npmPackageResponse; + } catch (Exception e) { + NpmPackageResponse npmPackageResponse = new NpmPackageResponse(); + npmPackageResponse.setResponseLevel(NpmPackageResponseLevel.Error); + npmPackageResponse.setSuccess(false); + npmPackageResponse.setErrorMessage("npm install failed, 请检查配置或联系管理员!"); + return npmPackageResponse; + } + } + + /** + * npm install命令执行 使用默认的npm配置信息 + * + * @return 安装结果反馈 + */ + @Override + public NpmPackageResponse install() { + // 获取默认的npm 仓库配置 + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(false); + // 使用默认配置进行在线install + return install(npmSettings); + } + + /** + * npm install命令执行 + * + * @param installParameter install参数 + * @return 安装结果反馈 + */ + @Override + public NpmPackageResponse installCheck(NpmSettings installParameter) { + installParameter=NpmSettingEncryptService.getInstance().deEncrypt(installParameter); + + // 获取默认的npm 仓库配置 + NpmSettings npmSettings = NpmSettingManager.getNpmSetting(false); + NpmInstallParameter npmInstallParameter = NpmSettingConvertor.convertFromNpmSetting(npmSettings); + // 使用默认配置进行在线install + return NpmPackageInstallService.installCheck(npmInstallParameter); + } +} diff --git a/web-npmpackage-core/src/main/resources/META-INF/spring.factories b/web-npmpackage-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..212dd7dc --- /dev/null +++ b/web-npmpackage-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.npmpackage.core.config.NpmPackageConfiguration,com.inspur.edp.web.npmpackage.core.config.NpmPackageInstallConfiguration diff --git a/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java b/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java new file mode 100644 index 00000000..918813ed --- /dev/null +++ b/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java @@ -0,0 +1,52 @@ +package com.inspur.edp.web.npmpackage.core.npminstall; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallPackageParameter; +import com.inspur.edp.web.npmpackage.api.entity.NpmInstallParameter; +import com.inspur.edp.web.npmpackage.api.entity.packagejson.NpmPackageJsonInfo; +import com.inspur.edp.web.npmpackage.core.npmpackagecheck.NpmPackageCheck; +import junit.framework.TestCase; + + +public class NpmInstallCommandParameterGeneratorTest extends TestCase { + + public void testGenerate() { +// NpmInstallParameter npmInstallParameter = new NpmInstallParameter(); +// String result = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); +// System.out.println(result); +// +// npmInstallParameter.setUseProduction(false); +// result = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); +// System.out.println(result); +// +// npmInstallParameter.setUpdateAll(false); +// result = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); +// System.out.println(result); +// +// npmInstallParameter.setUpdateAll(false); +// npmInstallParameter.setUseProduction(true); +// result = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); +// System.out.println(result); +// +// NpmInstallPackageParameter npmInstallPackageParameter = new NpmInstallPackageParameter(); +// npmInstallPackageParameter.setPackageName("@farris/jit-engine"); +// npmInstallParameter.getNpmInstallPackageParameterList().add(npmInstallPackageParameter); +// result = NpmInstallCommandParameterGenerator.generate(npmInstallParameter); +// System.out.println(result); + + + } + + public void testSerialize() { +// String source = "C:\\wwwwwwprojects/package.json"; +// String jsonStr = FileUtility.readAsString(source); +// +// NpmPackageJsonInfo packageInfo1= NpmPackageCheck.packageJsonInfoGenerate(jsonStr); +// NpmPackageJsonInfo packageJsonInfo2= NpmPackageCheck.packageJsonInfoGenerate(jsonStr); +// +// +// +// System.out.println(packageInfo1.equals(packageJsonInfo2)); + + } +} diff --git a/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java b/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java new file mode 100644 index 00000000..90eebbd4 --- /dev/null +++ b/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java @@ -0,0 +1,19 @@ +package com.inspur.edp.web.npmpackage.core.npmpackagecheck; + +import junit.framework.TestCase; + +public class NpmPackageCheckTest extends TestCase { + + public void testCheck() { + System.out.println(System.getenv("nUMBER_OF_PROCESSORS")); + } + + public void testPackageJsonInfoGenerate() { + + } + + public void getProcessor(){ + + } + +} diff --git a/web-npmpackage-patch/pom.xml b/web-npmpackage-patch/pom.xml new file mode 100644 index 00000000..0353a040 --- /dev/null +++ b/web-npmpackage-patch/pom.xml @@ -0,0 +1,25 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-npmpackage-patch + + + com.fasterxml.jackson.core + jackson-databind + + + + + 8 + 8 + + + diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java new file mode 100644 index 00000000..87f7a643 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java @@ -0,0 +1,175 @@ +package com.inspur.edp.web.npmpackagepatch; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +public class FileOperation { + private static final String ENCODING = "UTF-8"; + private static final String UTF8_BOM_HEADER = "\ufeff"; + + /** + * Read file content as string + * + * @param path the full file path + * @return the string + * @description 根据文件的完整路径,读取文件内容(UTF-8编码) + */ + public static String readAsString(String path) { + File file = new File(path); + long fileLength = file.length(); + byte[] fileContent = new byte[(int) fileLength]; + try { + FileInputStream in = new FileInputStream(file); + in.read(fileContent); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("readAsString failed", e); + } + + try { + // 判断有没有utf-8 bom头, 有则去除。 + String fileContents = new String(fileContent, ENCODING); + if (fileContents.startsWith(UTF8_BOM_HEADER)) { + fileContents = fileContents.substring(1); + } + return fileContents; + } catch (UnsupportedEncodingException e) { + System.err.println("The OS does not support " + ENCODING); + e.printStackTrace(); + return null; + } + } + + public static void copyFile(String sourcePath, String targetPath) { + try { + File sourceFile = new File(sourcePath); + File targetFile = new File(targetPath); + copyFile(sourceFile, targetFile); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static void copyFile(File sourcePath, File targetPath) { + try { + if (!sourcePath.exists()) { + return; + } + sourcePath.setExecutable(true); + sourcePath.setReadable(true); + sourcePath.setWritable(true); + Files.copy(sourcePath.toPath(), targetPath.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * 将文本写入指定文件; 如果文件不存在先创建文件,再执行写入操作; 如果文件存在,删除后重新创建并写入。 + * + * @param fileNameAndPath 目标文件路径 + * @param contents 写入文件的内容 + */ + public static void writeFile(String fileNameAndPath, String contents) { + // 如果文件路径不存在 那么创建对应的文件目录 + File file = new File(fileNameAndPath); + + File fileParent = file.getParentFile(); + if (!fileParent.exists()) { + fileParent.mkdirs(); + } + + if (exists(file)) { + clear(file); + } else { + createFile(file); + } + // 如果写入的内容为null 那么转换成空字符串写入 + if (contents == null) { + contents = ""; + } + updateFile(fileNameAndPath, contents); + } + + /** + * 检测文件或目录是否存在 + * + * @param fileHandler 文件或目录句柄 + * @return + */ + private static boolean exists(File fileHandler) { + return fileHandler.exists(); + } + + /** + * 清空文件中内容 + * + * @param file 待清空文件句柄 + */ + private static void clear(File file) { + try { + if (file.exists()) { + file.setWritable(true); + file.setReadable(true); + file.setExecutable(true); + } + FileWriter fileWriter = new FileWriter(file); + fileWriter.write(""); + fileWriter.flush(); + fileWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 创建文件 + * + * @param path 待创建文件路径 + */ + public static void createFile(String path) { + try { + File file = new File(path); + if (!exists(file)) { + file.createNewFile(); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + /** + * 创建文件 + * + * @param file 待创建文件句柄 + */ + private static boolean createFile(File file) { + try { + file.createNewFile(); + return true; + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + } + + /** + * 更新文件 + * + * @param fullPath + * @param content + */ + public static void updateFile(String fullPath, String content) { + try { + byte[] buffer = content.getBytes(StandardCharsets.UTF_8); + FileOutputStream fos = new FileOutputStream(fullPath, true); + fos.write(buffer); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java new file mode 100644 index 00000000..337aa25b --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.npmpackagepatch; + +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.cfg.MapperConfig; +import com.fasterxml.jackson.databind.introspect.AnnotatedField; +import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; + +public class MyPropertyNamingStrategy extends PropertyNamingStrategy { + @Override + public String nameForField(MapperConfig< ? > config, AnnotatedField field, String defaultName) { + return convert(defaultName); + } + + @Override + public String nameForGetterMethod(MapperConfig< ? > config, AnnotatedMethod method, String defaultName) { + return convert(defaultName); + } + + @Override + public String nameForSetterMethod(MapperConfig< ? > config, AnnotatedMethod method, String defaultName) { + return convert(defaultName); + } + + private String convert(String input) { + return input; + } +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java new file mode 100644 index 00000000..b339a12a --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java @@ -0,0 +1,130 @@ +package com.inspur.edp.web.npmpackagepatch; + +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonInfo; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * npm包集成补丁工具 + * + * @author noah + */ +public class NpmPackagePatchService { + /** + * 补丁工具调用入口 + * + * @param param + */ + public void Update(HashMap param) { + System.out.println("开始执行npm包版本更新"); + if (param == null) { + throw new RuntimeException("npm包安装入参param 为空"); + } + String patchPKG = param.get("PatchPkg"); + String serverPath = param.get("ServerPath"); + + // 补丁路径为空或serverPath 为空都是不允许的 + if (patchPKG == null || patchPKG.length() == 0) { + throw new RuntimeException("npm包安装入参,补丁路径参数PatchPKG 为空"); + } + if (serverPath == null || serverPath.length() == 0) { + throw new RuntimeException("npm包安装入参,安装环境路径参数ServerPath 为空"); + } + + File patchFile = new File(patchPKG); + // 如果目录不存在 那么不需要执行任何操作 + if (!patchFile.exists()) { + return; + } + + // 从server读取package.json 作为临时文件 + Path serverPackageJsonPath; + // 如果server目录不存在 那么认为是包含jstack目录 + if (new File(Paths.get(serverPath).resolve("server").toString()).exists()) { + serverPackageJsonPath = Paths.get(serverPath).resolve("server").resolve("runtime").resolve("nodejs").resolve("packagejson"); + } else { + serverPackageJsonPath = Paths.get(serverPath).resolve("jstack").resolve("runtime").resolve("nodejs").resolve("packagejson"); + } + + File serverPackageJsonFilePath = new File(serverPackageJsonPath.resolve(PatchConstants.PackageJsonFileName).toString()); + if (!serverPackageJsonFilePath.exists()) { + System.out.println("server不存在package.json,不更新npm包版本"); + return; + } + + // 读取补丁文件中特定路径下的json文件 + Path packageJsonPath = Paths.get(patchPKG, "root", "server", "var", "npmpackage"); + File packageJsonPathFileInfo = new File(packageJsonPath.toString()); + // 如果没有包含json文件 那么不需要任何操作 + if (!packageJsonPathFileInfo.exists()) { + return; + } + File tempPackageJsonFilePath = null; + try { + // 创造一个临时目录文件 + tempPackageJsonFilePath = copyTempPackageJsonFile(serverPackageJsonPath, serverPackageJsonFilePath); + String packageJsonInfoContent = FileOperation.readAsString(tempPackageJsonFilePath.getPath()); + PackageJsonInfo packageJsonInfo = SerializePackageJson.getInstance().deserialize(packageJsonInfoContent); + // 版本加1 + packageJsonInfo.versionPlus(); + + //读取目录下所有的json文件 + List fileList = new ArrayList<>(); + RescureReadFiles.getFiles(packageJsonPath.toString(), fileList); + + // 只读取server/var/npmpackage 目录下的json文件内容 + // 只读取json文件 + // 判断是否需要更新源文件 + if (fileList.size() > 0) { + fileList.forEach(t -> { + if (t.getName().contains(".json")) { + executeSpecialJsonFile(packageJsonInfo, t); + } + }); + } + PackageJsonFileManager.write(packageJsonInfo, tempPackageJsonFilePath.getPath()); + + FileOperation.copyFile(tempPackageJsonFilePath, serverPackageJsonFilePath); + + + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException(ex.getMessage(), ex); + } finally { + // 临时文件删除 + if (tempPackageJsonFilePath != null && tempPackageJsonFilePath.exists()) { + tempPackageJsonFilePath.delete(); + } + System.out.println("npm包版本更新完毕"); + } + } + + /** + * 处理具体的json文件 + * + * @param packageJsonInfo + * @param t + */ + private void executeSpecialJsonFile(PackageJsonInfo packageJsonInfo, File t) { + String patchJsonContent = FileOperation.readAsString(t.getPath()); + PackageJsonInfo specialPackageJsonInfo = SerializePackageJson.getInstance().deserialize(patchJsonContent); + PackageJsonFileManager.merge(packageJsonInfo, specialPackageJsonInfo); + } + + private File copyTempPackageJsonFile(Path serverPackageJsonPath, File serverPackageJsonFilePath) { + File tempPackageJsonFilePath = new File(serverPackageJsonPath.resolve(PatchConstants.TempPackageJsonFileName).toString()); + + FileOperation.copyFile(serverPackageJsonFilePath, tempPackageJsonFilePath); + if (!tempPackageJsonFilePath.exists()) { + tempPackageJsonFilePath = serverPackageJsonFilePath; + } + return tempPackageJsonFilePath; + } + + +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java new file mode 100644 index 00000000..3fdc52ad --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java @@ -0,0 +1,93 @@ +package com.inspur.edp.web.npmpackagepatch; + +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonDependencyInfo; +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonInfo; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * package.json 文件操作 + * + * @author noah + */ +public class PackageJsonFileManager { + + + public static PackageJsonInfo read(String path) { + String packageJsonContent = FileOperation.readAsString(path); + // 将字符串转换称为实体 + return SerializePackageJson.getInstance().deserialize(packageJsonContent); + } + + public static void write(PackageJsonInfo packageJsonInfo, String path) { + String packageJsonInfoContent = SerializePackageJson.getInstance().serialize(packageJsonInfo); + FileOperation.writeFile(path, packageJsonInfoContent); + } + + /** + * 将目标依赖合并到源package.json 中 + * + * @param sourcePackageJsonInfo + * @param targetPackageJsonInfo + */ + public static void merge(PackageJsonInfo sourcePackageJsonInfo, PackageJsonInfo targetPackageJsonInfo) { + if (sourcePackageJsonInfo == null || targetPackageJsonInfo == null) { + return; + } + // 获取依赖配置 + if (targetPackageJsonInfo.getDependencies() != null && targetPackageJsonInfo.getDependencies().size() > 0) { + targetPackageJsonInfo.getDependencies().forEach(t -> { + // + if (t.getKey() != null && t.getValue() != null) { + updatePackageJsonInfoDependency(sourcePackageJsonInfo, t.getKey(), t.getValue(), false); + } + }); + } + + // 获取dev 依赖配置 + if (targetPackageJsonInfo.getDevDependencies() != null && targetPackageJsonInfo.getDevDependencies().size() > 0) { + targetPackageJsonInfo.getDevDependencies().forEach(t -> { + if (t.getKey() != null && t.getValue() != null) { + updatePackageJsonInfoDependency(sourcePackageJsonInfo, t.getKey(), t.getValue(), true); + } + }); + } + } + + + /** + * 更新依赖项 + * @param packageJsonInfo + * @param key + * @param value + * @param isDevDependency + */ + private static void updatePackageJsonInfoDependency(PackageJsonInfo packageJsonInfo, String key, String value, boolean isDevDependency) { + List dependencyInfoList = null; + if (isDevDependency) { + dependencyInfoList = packageJsonInfo.getDevDependencies(); + } else { + dependencyInfoList = packageJsonInfo.getDependencies(); + } + List dependencyInfos = dependencyInfoList.stream().filter(t -> t.getKey().trim().equals(key.trim())).collect(Collectors.toList()); + // 表示不存在 + if (dependencyInfos == null || dependencyInfos.size() == 0) { + dependencyInfoList.add(new PackageJsonDependencyInfo(key, value)); + } else { + List finalDependencyInfoList = dependencyInfoList; + dependencyInfos.forEach(dependencyInfo -> { + if (dependencyInfo.getKey() != null) { + if (dependencyInfo.getKey().trim().equals(key.trim())) { + if ("delete".equalsIgnoreCase(value.trim())) { + finalDependencyInfoList.remove(dependencyInfo); + } else { + dependencyInfo.setValue(value); + } + } + } + }); + } + } + +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java new file mode 100644 index 00000000..7fdb2541 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java @@ -0,0 +1,6 @@ +package com.inspur.edp.web.npmpackagepatch; + +public class PatchConstants { + public static final String PackageJsonFileName = "package.json"; + public static final String TempPackageJsonFileName = "temp-package.json"; +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md new file mode 100644 index 00000000..bec421f4 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md @@ -0,0 +1,2 @@ +补丁工具集成npm包安装,不依赖其他包,作为独立的jar包部署到补丁工具中。 + diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java new file mode 100644 index 00000000..fe20bf9c --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.npmpackagepatch; + +import java.io.File; +import java.util.List; + +/** + * 递归读取目录下的所有文件列表 + * + * @author noah + */ +public class RescureReadFiles { + /** + * 获取文件目录下所有文件列表 + * @param path + * @param fileList + */ + public static void getFiles(String path, List fileList) { + File file = new File(path); + File[] array = file.listFiles(); + for (File value : array) { + if (value.isFile()) { + fileList.add(value); + } else if (value.isDirectory()) { + getFiles(value.getPath(), fileList); + } + } + } +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java new file mode 100644 index 00000000..b85d21d7 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java @@ -0,0 +1,184 @@ +package com.inspur.edp.web.npmpackagepatch; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonDependencyInfo; +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonInfo; +import com.inspur.edp.web.npmpackagepatch.packagejson.SerializedPackageJson; + +import java.util.*; + +public class SerializePackageJson { + private final ObjectMapper defaultObjectMapper; + + private SerializePackageJson() { + defaultObjectMapper = this.createDefaultObjectMapper(); + } + + private static SerializePackageJson serializeUtilityInstance = null; + + public static SerializePackageJson getInstance() { + if (Objects.isNull(serializeUtilityInstance)) { + synchronized (SerializePackageJson.class) { + if (Objects.isNull(serializeUtilityInstance)) { + serializeUtilityInstance = new SerializePackageJson(); + } + } + } + + return serializeUtilityInstance; + } + + private ObjectMapper createDefaultObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.setPropertyNamingStrategy(new MyPropertyNamingStrategy()); + PropertyNamingStrategy currentNameStrategy = mapper.getPropertyNamingStrategy(); + mapper.setPropertyNamingStrategy(currentNameStrategy); + return mapper; + } + + + /** + * Deserialize string to an object. + * 将一个对象字符串反序列化成对象 + * + * @param contentString the content string + * @return the t + * @description Json反序列化 + */ + public PackageJsonInfo deserialize(String contentString) { + try { + return packageJsonInfoGenerate(contentString); + } catch (Exception ex) { + throw new RuntimeException(ex.getMessage(), ex); + } + } + + public PackageJsonInfo packageJsonInfoGenerate(String serverPackageJsonContent) { + PackageJsonInfo packageJsonInfo = new PackageJsonInfo(); + try { + JsonNode jsonNode = this.defaultObjectMapper.readTree(serverPackageJsonContent); + String packageJsonName = jsonNode.get("name").asText(); + packageJsonInfo.setName(packageJsonName); + + String packageJsonVersion = jsonNode.get("version").asText(); + packageJsonInfo.setVersion(packageJsonVersion); + + String packageJsonDescription = jsonNode.get("description").asText(); + packageJsonInfo.setDescription(packageJsonDescription); + + String packageJsonAuthor = jsonNode.get("author").textValue(); + packageJsonInfo.setAuthor(packageJsonAuthor); + + String packageJsonLicense = jsonNode.get("license").asText(); + packageJsonInfo.setLicense(packageJsonLicense); + + ObjectNode dependenciesObjNode = (ObjectNode) jsonNode.get("dependencies"); + ObjectNode devDependenciesObjNode = (ObjectNode) jsonNode.get("devDependencies"); + + if (dependenciesObjNode != null) { + Iterator> iterator = dependenciesObjNode.fields(); + while (iterator.hasNext()) { + Map.Entry field = iterator.next(); + if (field != null && field.getKey() != null && field.getValue() != null && field.getValue().textValue() != null) { + packageJsonInfo.getDependencies().add(new PackageJsonDependencyInfo(field.getKey(), field.getValue().textValue())); + } + } + } + + if (devDependenciesObjNode != null) { + Iterator> iterator = devDependenciesObjNode.fields(); + while (iterator.hasNext()) { + Map.Entry field = iterator.next(); + if (field != null && field.getKey() != null && field.getValue() != null && field.getValue().textValue() != null) { + packageJsonInfo.getDevDependencies().add(new PackageJsonDependencyInfo(field.getKey(), field.getValue().textValue())); + } + } + } + } catch (Exception e) { + System.out.println("Npm 在线安装出现异常:" + e.getMessage() + Arrays.toString(e.getStackTrace())); + throw new RuntimeException(e.getMessage(),e); + } + + + return packageJsonInfo; + } + + /** + * Serialize an object to string. + * 保持属性名称一致 + * + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(PackageJsonInfo entity) { + SerializedPackageJson serializedPackageJson = convertToSerializedPackageJson(entity); + + String result = serialize(this.defaultObjectMapper, serializedPackageJson, true); + return result; + } + + private SerializedPackageJson convertToSerializedPackageJson(PackageJsonInfo entity) { + SerializedPackageJson serializedPackageJson = new SerializedPackageJson(); + serializedPackageJson.setName(entity.getName()); + + LinkedHashMap dependencyMap = new LinkedHashMap<>(); + entity.getDependencies().forEach(t -> dependencyMap.put(t.getKey(), t.getValue())); + serializedPackageJson.setDependencies(dependencyMap); + + serializedPackageJson.setAuthor(entity.getAuthor()); + serializedPackageJson.setDescription(entity.getDescription()); + serializedPackageJson.setKeywords(entity.getKeywords()); + serializedPackageJson.setLicense(entity.getLicense()); + serializedPackageJson.setVersion(entity.getVersion()); + + LinkedHashMap devDependencyMap = new LinkedHashMap<>(); + entity.getDevDependencies().forEach(t -> devDependencyMap.put(t.getKey(), t.getValue())); + serializedPackageJson.setDevDependencies(devDependencyMap); + return serializedPackageJson; + } + + + /** + * Serialize an object to string. + * + * @param objectMapper the objectMapper + * @param entity the entity + * @return the string instance + * @description Json序列化 + */ + public String serialize(ObjectMapper objectMapper, Object entity, boolean usePretty) { + if (entity == null) { + return null; + } + + String serializeStr = null; + + try { + if (!usePretty) { + serializeStr = objectMapper.writeValueAsString(entity); + } else { + serializeStr = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(entity); + } + + return serializeStr; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + // endregion + + // region 自定义配置 + +} + + + diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java new file mode 100644 index 00000000..bb6412f5 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.npmpackagepatch.packagejson; + +public class PackageJsonDependencyInfo { + private String key; + private String value; + + public PackageJsonDependencyInfo(String key, String value) { + this.key = key != null ? key.trim() : ""; + this.value = key != null ? value.trim() : ""; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java new file mode 100644 index 00000000..5e7dffc9 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java @@ -0,0 +1,107 @@ +package com.inspur.edp.web.npmpackagepatch.packagejson; + +import com.inspur.edp.web.npmpackagepatch.packagejson.PackageJsonDependencyInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * 补丁文件更新 + * + * @author noah + */ +public class PackageJsonInfo { + private String name; + private String version; + private String description; + + private String[] keywords; + private String author = "Noah"; + private String license; + private List dependencies; + private List devDependencies; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String[] getKeywords() { + return keywords; + } + + public void setKeywords(String[] keywords) { + this.keywords = keywords; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public List getDependencies() { + if (dependencies == null) { + dependencies = new ArrayList<>(); + } + return dependencies; + } + + public void setDependencies(List dependencies) { + this.dependencies = dependencies; + } + + public List getDevDependencies() { + if (devDependencies == null) { + devDependencies = new ArrayList<>(); + } + return devDependencies; + } + + public void setDevDependencies(List devDependencies) { + this.devDependencies = devDependencies; + } + + /** + * 执行version自增加 + */ + public void versionPlus() { + if (this.version == null) { + this.version = "0.0.1"; + } + int lastQuoteIndex = this.version.lastIndexOf("."); + String lastVersion = this.version.substring(lastQuoteIndex + 1); + long lastVersionLang = Long.parseLong(lastVersion) + 1; + this.version = this.version.substring(0, lastQuoteIndex+1) + lastVersionLang; + } + +} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java new file mode 100644 index 00000000..36aab1d6 --- /dev/null +++ b/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java @@ -0,0 +1,85 @@ +package com.inspur.edp.web.npmpackagepatch.packagejson; + +import java.util.HashMap; + +/** + * 可序列化成固定格式的实体结构 + */ +public class SerializedPackageJson { + private String name; + private String version; + private String description; + + private String[] keywords; + private String author = "Noah"; + private String license; + private HashMap dependencies; + private HashMap devDependencies; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String[] getKeywords() { + if (keywords == null) { + keywords = new String[0]; + } + return keywords; + } + + public void setKeywords(String[] keywords) { + this.keywords = keywords; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public HashMap getDependencies() { + return dependencies; + } + + public void setDependencies(HashMap dependencies) { + this.dependencies = dependencies; + } + + public HashMap getDevDependencies() { + return devDependencies; + } + + public void setDevDependencies(HashMap devDependencies) { + this.devDependencies = devDependencies; + } +} diff --git a/web-pageflow-metadata/pom.xml b/web-pageflow-metadata/pom.xml new file mode 100644 index 00000000..9dab0b7d --- /dev/null +++ b/web-pageflow-metadata/pom.xml @@ -0,0 +1,40 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-pageflow-metadata + + + + com.inspur.edp + web-jitengine-common + + + com.inspur.edp + web-appconfig-core + + + io.iec.edp + caf-i18n-framework-api + + + com.inspur.edp + i18n-resource-api + + + com.inspur.edp + formserver-viewmodel + + + com.inspur.edp + lcm-metadata-spi + + + diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java new file mode 100644 index 00000000..c1b1a821 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 页面--面向生成器的实体结构 + * @author noah + */ +@Getter +@Setter +public class AdaptedPage { + private String id; + private String code; + private String name; + private String fileName; + private String relativePath; + /** + * 表单Uri,替换对relativePath的依赖 + */ + private String formUri; + private String routeUri; + private List routeParams; + private List children; +} \ No newline at end of file diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java new file mode 100644 index 00000000..fda226bf --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java @@ -0,0 +1,35 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * @author noah + */ +@Getter +@Setter +public class AdaptedPageFlowMetadataEntity extends AbstractMetadataContent { + private String id; + private Project project; + private List pages; + private String entry; + /** + * 关联应用code + */ + private String appCode; + /** + * 关联应用name + */ + private String appName; + + private Listpublishes; + + @Override + public AdaptedPageFlowMetadataEntity clone() { + String json = AdaptedPageFlowMetadataEntityService.serialize(this); + return AdaptedPageFlowMetadataEntityService.deserialize(json); + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java new file mode 100644 index 00000000..75f7721f --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java @@ -0,0 +1,131 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +import java.util.ArrayList; +import java.util.List; + +/** + * 页面流实体转换service + * @author noah + */ +public class AdaptedPageFlowMetadataEntityService { + /** + * 基于 PageFlowMetadataEntity 实例生成 AdaptedPageFlowMetadataEntity 实例 + */ + public static AdaptedPageFlowMetadataEntity generateAdaptedPageFlowMetadataEntity(PageFlowMetadataEntity pageFlowMetadataEntity) { + if (pageFlowMetadataEntity == null) { + return null; + } + AdaptedPageFlowMetadataEntity adaptedPageFlowMetadataEntity = new AdaptedPageFlowMetadataEntity(); + adaptedPageFlowMetadataEntity.setId(pageFlowMetadataEntity.getId()); + adaptedPageFlowMetadataEntity.setProject(pageFlowMetadataEntity.getProject()); + adaptedPageFlowMetadataEntity.setPages(generateAdaptedPage(pageFlowMetadataEntity)); + adaptedPageFlowMetadataEntity.setEntry(pageFlowMetadataEntity.getEntry()); + adaptedPageFlowMetadataEntity.setAppCode(pageFlowMetadataEntity.getAppCode()); + adaptedPageFlowMetadataEntity.setAppName(pageFlowMetadataEntity.getAppName()); + adaptedPageFlowMetadataEntity.setPublishes(pageFlowMetadataEntity.getPublishes()); + + return adaptedPageFlowMetadataEntity; + } + + private static ArrayList generateAdaptedPage(PageFlowMetadataEntity pageFlowMetadataEntity) { + if (pageFlowMetadataEntity == null || pageFlowMetadataEntity.getPages() == null || pageFlowMetadataEntity.getPages().length == 0) { + return null; + } + + ArrayList adaptedPageCollection = new ArrayList<>(); + for (Page page : pageFlowMetadataEntity.getPages()) { + AdaptedPage adaptedPage = new AdaptedPage(); + adaptedPage.setId(page.getId()); + adaptedPage.setCode(page.getCode()); + adaptedPage.setName(page.getName()); + adaptedPage.setFileName(page.getFileName()); + adaptedPage.setRelativePath(page.getRelativePath()); + adaptedPage.setFormUri(page.getFormUri()); + adaptedPage.setRouteUri(page.getRouteUri()); + adaptedPage.setRouteParams(cloneRouteParams(page.getRouteParams())); + adaptedPage.setChildren(generateRouteChildren(page.getId(), pageFlowMetadataEntity)); + + adaptedPageCollection.add(adaptedPage); + } + return adaptedPageCollection; + } + + private static List cloneRouteParams(List curretnRouteParams) { + if (curretnRouteParams == null || curretnRouteParams.size() == 0) { + return null; + } + + return new ArrayList<>(curretnRouteParams); + } + + private static List generateRouteChildren(String targetPageId, PageFlowMetadataEntity pageFlowMetadataEntity) { + + if (pageFlowMetadataEntity == null || StringUtility.isNullOrEmpty(targetPageId)) { + return null; + } + + List routeCollection = pageFlowMetadataEntity.getRoutes(); + Page[] pageCollection = pageFlowMetadataEntity.getPages(); + if (routeCollection == null || routeCollection.size() == 0) { + return null; + } + + ArrayList adaptedRouteList = new ArrayList<>(); + + for (Route route : routeCollection) { + if (route.getFrom().equals(targetPageId)) { + AdaptedRoute adaptedRoute = new AdaptedRoute(); + + adaptedRoute.setTo(route.getTo()); + Page childPage = getPage(route.getTo(), pageCollection); + if (childPage != null) { + adaptedRoute.setCode(childPage.getCode()); + } + adaptedRoute.setRouteUri(route.getRouteUri()); + adaptedRoute.setRouteParams(cloneRouteParams(route.getRouteParams())); + adaptedRoute.setImportRouteModule(route.isImportRouteModule()); + adaptedRouteList.add(adaptedRoute); + } + } + + return adaptedRouteList; + } + + private static Page getPage(String pageId, Page[] pageCollection) { + Page page = null; + + for (Page value : pageCollection) { + if (value.getId().equals(pageId)) { + page = value; + break; + } + } + + return page; + } + + public static String serialize(AdaptedPageFlowMetadataEntity pageFlowMetadataEntity) { + String pageFlowMetadataEntityStr = ""; + if (pageFlowMetadataEntity == null) { + return pageFlowMetadataEntityStr; + } + + pageFlowMetadataEntityStr = SerializeUtility.getInstance().serialize(pageFlowMetadataEntity); + + return pageFlowMetadataEntityStr; + } + + public static AdaptedPageFlowMetadataEntity deserialize(String pageFlowMetadataEntityStr) { + AdaptedPageFlowMetadataEntity pageFlowMetadataEntity = null; + if (StringUtility.isNullOrEmpty(pageFlowMetadataEntityStr)) { + return null; + } + + pageFlowMetadataEntity = SerializeUtility.getInstance().deserialize(pageFlowMetadataEntityStr, AdaptedPageFlowMetadataEntity.class); + + return pageFlowMetadataEntity; + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java new file mode 100644 index 00000000..ef587623 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 路由 -- 面向生成器 + * @author noah + */ +@Getter +@Setter +public class AdaptedRoute { + private String to; + private String code; + private String routeUri; + private List routeParams; + private boolean importRouteModule; +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java new file mode 100644 index 00000000..8e25bac9 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java @@ -0,0 +1,31 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 页面--对应设计器的表单 + */ +@Getter +@Setter +public class Page { + private String id; + private String code; + private String name; + private String fileName; + private String relativePath; + /** + * 表单Uri,替换对relativePath的依赖 + */ + private String formUri; + private String routeUri; + private List routeParams; + /** + * 是否强制使用解析模式 + */ + @JsonIgnore + private boolean isForceDynamicForm; +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java new file mode 100644 index 00000000..81561fb0 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java @@ -0,0 +1,105 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.serializer.PageFlowMetadataTransferSerializer; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 页面流定义实体 + */ +//TODO N转J N版存在[Serializable]注解 +@Getter +@Setter +public class PageFlowMetadataEntity extends AbstractMetadataContent { + /** + * ID + */ + private String id; + + /** + * 工程配置信息 + */ + private Project project; + + /** + * 页面集合 + */ + private Page[] pages; + + + /** + * 工程入口 + */ + private String entry; + private List routes; + + /** + * 关联应用code + */ + private String appCode; + /** + * 关联应用name + */ + private String appName; + + private Listpublishes; + + @Override + public PageFlowMetadataEntity clone() { + PageFlowMetadataTransferSerializer serializer = new PageFlowMetadataTransferSerializer(); + String json = serializer.serialize(this); + return serializer.deserialize(json); + } + + public static String Serialize(PageFlowMetadataEntity pageFlowMetadataEntity) { + String pageFlowMetadataEntityStr = ""; + if (pageFlowMetadataEntity == null) { + return pageFlowMetadataEntityStr; + } + + pageFlowMetadataEntityStr = SerializeUtility.getInstance().serialize(pageFlowMetadataEntity,false); + + return pageFlowMetadataEntityStr; + } + + public static PageFlowMetadataEntity Deserialize(String pageFlowMetadataEntityStr) { + PageFlowMetadataEntity pageFlowMetadataEntity = null; + if (StringUtility.isNullOrEmpty(pageFlowMetadataEntityStr)) { + return pageFlowMetadataEntity; + } + + pageFlowMetadataEntity = SerializeUtility.getInstance().deserialize(pageFlowMetadataEntityStr, PageFlowMetadataEntity.class); + + return pageFlowMetadataEntity; + } + + /** + * 基于pageId,获取对应的route uri + * + * @param pageFlowMetadataEntity + * @param pageId + * @return + */ + public static String GetPageRouteUri(PageFlowMetadataEntity pageFlowMetadataEntity, String pageId) { + String routeUri = ""; + + if (pageFlowMetadataEntity == null) { + return routeUri; + } + + Page[] pages = pageFlowMetadataEntity.getPages(); + for (Page page : pages) { + if (page.getId().equals(pageId)) { + routeUri = page.getRouteUri(); + break; + } + } + + return routeUri; + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java new file mode 100644 index 00000000..0c8bf073 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java @@ -0,0 +1,66 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; + +/** + * 页面流元数据 + */ +public class PageFlowMetadataEntityManager { + /** + * 页面流元数据实体序列化 + * + * @param pageFlowMetadataEntity + * @return + */ + public static String serialize(PageFlowMetadataEntity pageFlowMetadataEntity) { + String pageFlowMetadataEntityStr = ""; + if (pageFlowMetadataEntity == null) { + return pageFlowMetadataEntityStr; + } + + pageFlowMetadataEntityStr = SerializeUtility.getInstance().serialize(pageFlowMetadataEntity); + + return pageFlowMetadataEntityStr; + } + + /** + * 页面流元数据反序列化 + * + * @param pageFlowMetadataEntityStr + * @return + */ + public static PageFlowMetadataEntity deserialize(String pageFlowMetadataEntityStr) { + if (StringUtility.isNullOrEmpty(pageFlowMetadataEntityStr)) { + return null; + } + + return SerializeUtility.getInstance().deserialize(pageFlowMetadataEntityStr, PageFlowMetadataEntity.class); + } + + /** + * 基于pageId,获取对应的route uri + * + * @param pageFlowMetadataEntity + * @param pageId + * @return + */ + public static String getPageRouteUri(PageFlowMetadataEntity pageFlowMetadataEntity, String pageId) { + String routeUri = ""; + + if (pageFlowMetadataEntity == null) { + return routeUri; + } + + com.inspur.edp.web.pageflow.metadata.entity.Page[] pages = pageFlowMetadataEntity.getPages(); + + for (Page page : pages) { + if (page.getId().equals(pageId)) { + routeUri = page.getRouteUri(); + break; + } + } + + return routeUri; + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java new file mode 100644 index 00000000..5c7df296 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java @@ -0,0 +1,22 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +public class PagePublish { + private String id; + private String entry; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getEntry() { + return entry; + } + + public void setEntry(String entry) { + this.entry = entry; + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java new file mode 100644 index 00000000..bb96af99 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java @@ -0,0 +1,10 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Project { + private String name; +} \ No newline at end of file diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java new file mode 100644 index 00000000..ec971eff --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java @@ -0,0 +1,60 @@ +package com.inspur.edp.web.pageflow.metadata.entity; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * 路由 + */ +@Getter +@Setter +public class Route { + private String from; + private String to; + private String routeUri; + private List routeParams; + + private boolean importRouteModule; + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getRouteUri() { + return routeUri; + } + + public void setRouteUri(String routeUri) { + this.routeUri = routeUri; + } + + public List getRouteParams() { + return routeParams; + } + + public void setRouteParams(List routeParams) { + this.routeParams = routeParams; + } + + public boolean isImportRouteModule() { + return importRouteModule; + } + + public void setImportRouteModule(boolean importRouteModule) { + this.importRouteModule = importRouteModule; + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java new file mode 100644 index 00000000..8b24fc6d --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java @@ -0,0 +1,84 @@ +package com.inspur.edp.web.pageflow.metadata.listener; + +import com.inspur.edp.lcm.metadata.spi.event.MetadataCreateEventListener; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventListener; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; +import com.inspur.edp.web.common.constant.MetadataConstant; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.service.PageFlowMetadataUpdateService; + +public class PageFlowMetadataEventListener implements MetadataEventListener, MetadataCreateEventListener { + + @Override + public void fireMetadataSavingEvent(MetadataEventArgs metadataEventArgs) { + + } + + + /** + * 业务实体元数据保存后事件 + */ + @Override + public void fireMetadataSavedEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + + // 类型判断(避免对其他元数据产生影响) + if (metadataEventArgs.getMetadata().getContent() instanceof PageFlowMetadataEntity) { + pageFlowMetadataSaved(metadataEventArgs); + } + } + + @Override + public void fireMetadataDeletingEvent(MetadataEventArgs metadataEventArgs) { + + } + + @Override + public void fireMetadataDeletedEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + PageFlowMetadataUpdateService.getInstance().syncPageFlowMetadataAfterFormDeleted(metadataEventArgs); + } + + @Override + public void fireMetadataCreatingEvent(MetadataEventArgs metadataEventArgs) { + + } + + @Override + public void fireMetadataCreatedEvent(MetadataEventArgs metadataEventArgs) { + if (metadataEventArgs == null || metadataEventArgs.getMetadata() == null || metadataEventArgs.getMetadata().getHeader() == null) { + return; + } + + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType()) + || MetadataConstant.MOBILE_FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + PageFlowMetadataUpdateService.getInstance().updatePageFlowMetadata(metadataEventArgs); + } + } + + private void pageFlowMetadataSaved(MetadataEventArgs metadataEventArgs) { + // 获取页面流元数据ID + String pageFlowMetaDataID = metadataEventArgs.getMetadata().getHeader().getId(); + if (StringUtility.isNullOrEmpty(pageFlowMetaDataID)) { + return; + } + + // 获取页面流元数据文件名称 + String pageFlowMetadataFileName = metadataEventArgs.getMetadata().getHeader().getFileName(); + if (StringUtility.isNullOrEmpty(pageFlowMetadataFileName)) { + return; + } + + // 获取页面流元数据路径 + String pageFlowMetadataFullPath = metadataEventArgs.getPath(); + + // TODO:迁移到AppConfig中处理 + GspAppConfigService.getCurrent().updateAppConfigFileWhenPageFlowFileCreated(pageFlowMetaDataID, pageFlowMetadataFileName, pageFlowMetadataFullPath); + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java new file mode 100644 index 00000000..4436e731 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.pageflow.metadata.manager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.spi.MetadataContentManager; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.service.RouteMetataService; + +public class PageFlowMetadataEntityManager implements MetadataContentManager { + @Override + public void build(GspMetadata metadata) { + if (metadata == null) { + return; + } + + PageFlowMetadataEntity pageFlowMetadataEntity = new PageFlowMetadataEntity(); + + if (metadata.getHeader() != null && !StringUtility.isNullOrEmpty(metadata.getHeader().getId())) { + pageFlowMetadataEntity.setId(metadata.getHeader().getId()); + metadata.setContent(pageFlowMetadataEntity); + } + } + + /** + * @deprecated 没有找到使用者 + * @param pageFlowMetadataEntity + * @param pageId + * @return + */ + public static String getCurrentPageRouteUri(PageFlowMetadataEntity pageFlowMetadataEntity, String pageId) { + return RouteMetataService.getcurrentpagerouteuri(pageFlowMetadataEntity, pageId); + } + +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java new file mode 100644 index 00000000..cf907635 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.pageflow.metadata.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; + +public class PageFlowMetadataEntitySerializer implements MetadataContentSerializer { + /** + * JSON 字符串反序列化 + * + * @param matadataContent 元数据内容 + * @return + */ + @Override + public IMetadataContent DeSerialize(JsonNode matadataContent) { + if (matadataContent == null) { + return null; + } + + return SerializeUtility.getInstance().toObject(matadataContent, PageFlowMetadataEntity.class); + } + + /** + * JSON 字符串序列化 + * + * @param metadataContent 元数据内容 + * @return + */ + @Override + public JsonNode Serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } + + PageFlowMetadataEntity metadata = (PageFlowMetadataEntity) ((metadataContent instanceof PageFlowMetadataEntity) ? metadataContent : null); + + String metadataString = SerializeUtility.getInstance().serialize(metadata); + return SerializeUtility.getInstance().toJsonNode(metadataString); + } + +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java new file mode 100644 index 00000000..fa7a50aa --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java @@ -0,0 +1,45 @@ +package com.inspur.edp.web.pageflow.metadata.serializer; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import io.iec.edp.caf.common.JSONSerializer; + +/** + * @deprecated 元数据扩展里面不再需要TransferSerializer + */ +@Deprecated() +public class PageFlowMetadataTransferSerializer implements MetadataTransferSerializer { + /** + * Json反序列化接口 + * + * @param contentString + * @return + */ + @Override + public PageFlowMetadataEntity deserialize(String contentString) { + if (StringUtility.isNullOrEmpty(contentString)) { + return null; + } else { + return JSONSerializer.deserialize(contentString, PageFlowMetadataEntity.class); + } + } + + /** + * Json序列化接口 + * + * @param metadataContent + * @return + */ + @Override + public String serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } else { + PageFlowMetadataEntity metadata = (PageFlowMetadataEntity) ((metadataContent instanceof PageFlowMetadataEntity) ? metadataContent : null); + return JSONSerializer.serialize(metadata); + } + } + +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java new file mode 100644 index 00000000..b4ca1b8b --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java @@ -0,0 +1,398 @@ +package com.inspur.edp.web.pageflow.metadata.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.web.appconfig.api.entity.GspAppConfig; +import com.inspur.edp.web.appconfig.core.service.GspAppConfigService; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.common.constant.MetadataConstant; +import com.inspur.edp.web.common.entity.TerminalType; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.entity.Page; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.entity.Project; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 元数据事件扩展的处理类。 + * 用于当元数据扩展事件被触发时对页面流元数据进行更新。 + * 从Listener里拆出 + */ +@Slf4j +public class PageFlowMetadataUpdateService { + private static PageFlowMetadataUpdateService instance; + + public static PageFlowMetadataUpdateService getInstance() { + if (instance == null) { + instance = new PageFlowMetadataUpdateService(); + } + return instance; + } + + /** + * 自动更新页面流文件 + * + * @param metadataEventArgs + */ + public void updatePageFlowMetadata(MetadataEventArgs metadataEventArgs) { + if (!metadataEventArgs.getMetadata().getHeader().getType().equals(MetadataConstant.FORM_METADATA_TYPE) && !metadataEventArgs.getMetadata().getHeader().getType().equals(MetadataConstant.MOBILE_FORM_METADATA_TYPE)) { + return; + } + + // (1) 获取当前工程使用的页面流 + GspAppConfig appConfigInfo = getOrCreateGspAppConfig(metadataEventArgs.getMetadata().getRelativePath()); + if (appConfigInfo == null) { + return; + } + PageFlowMetadataEntity pageFlowMetadataEntity = getPageFlowMetadataEntity(metadataEventArgs, appConfigInfo); + if (pageFlowMetadataEntity == null) { + return; + } + + // (2) 更新页面流元数据 + updatePageFlowMetadataEntity(metadataEventArgs, pageFlowMetadataEntity); + // 更新页面流元数据入口 + if (pageFlowMetadataEntity.getPages().length == 0) { + pageFlowMetadataEntity.setEntry(""); + } else { + pageFlowMetadataEntity.setEntry(pageFlowMetadataEntity.getPages()[0].getCode()); + } + + // (3) 更新页面流元数据 + saveRouteMetadataContent(metadataEventArgs, pageFlowMetadataEntity, appConfigInfo); + } + + /** + * 删除表单时同步页面流元数据 + * + * @param metadataEventArgs + */ + public void syncPageFlowMetadataAfterFormDeleted(MetadataEventArgs metadataEventArgs) { + log.debug("Debug_PageFlowMetadataDeleteEventListener_SyncPageFlowMetadata: Sync PageFlow Metadata When Having Deleted Form metadatas."); + // 监听表单元数据删除。当删除表单元数据,同步页面流元数据 + if (!MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + return; + } + + // (1) 获取当前工程使用的页面流 + GspAppConfig appConfigInfo = getGspAppConfigInfoByMetadata(metadataEventArgs.getMetadata().getRelativePath()); + if (appConfigInfo == null) { + return; + } + + String projectPath = MetadataUtility.getInstance().getMetadataProjectPath(metadataEventArgs.getMetadata().getRelativePath()); + + PageFlowMetadataEntity pageFlowMetadataEntity = RouteMetataService.getRouteMetadataContentWithMetadataIdAndProjectPath(appConfigInfo.getPageFlowMetadataID(), appConfigInfo.getPageFlowMetadataFileName(), projectPath); + if (pageFlowMetadataEntity == null) { + log.debug(String.format("Current Project %1$s's PageFlowMetadata %2$s Content is Null.", metadataEventArgs.getMetadata().getRelativePath(), appConfigInfo.getPageFlowMetadataFileName())); + return; + } + + // (2) 从页面流中同步删除该表单元数据的记录 + log.debug("Current PageFlowMetadataEntity Pages Number is:" + pageFlowMetadataEntity.getPages().length); + Page[] updatePages = null; + for (int i = 0; i < pageFlowMetadataEntity.getPages().length; i++) { + // 检测到该表单元数据存在页面流中 + if (pageFlowMetadataEntity.getPages()[i].getId().equals(metadataEventArgs.getMetadata().getHeader().getId())) { + ArrayList tempArrayList = new ArrayList(Arrays.asList(pageFlowMetadataEntity.getPages())); + tempArrayList.remove(i); + updatePages = tempArrayList.toArray(new Page[0]); + + break; + } + } + + if (updatePages == null) { + return; + } + pageFlowMetadataEntity.setPages(updatePages); + log.debug("Updated Pages Number is:" + updatePages.length); + + if (pageFlowMetadataEntity.getPages().length == 0) { + pageFlowMetadataEntity.setEntry(""); + } else { + // 设置入口 + pageFlowMetadataEntity.setEntry(pageFlowMetadataEntity.getPages()[0].getCode()); + } + + // (3) 更新页面流元数据 + RouteMetataService.saveRouteMetadataContent(pageFlowMetadataEntity, appConfigInfo.getPageFlowMetadataID(), metadataEventArgs.getMetadata().getRelativePath()); + log.debug("Debug_PageFlowMetadataDeleteEventListener_SyncPageFlowMetadata: Done."); + } + + private GspAppConfig getOrCreateGspAppConfig(String metadataRelativePath) { + GspAppConfig appConfigInfo = null; + String currentProjectRelativePath = getProjectRelativePathByMetadata(metadataRelativePath); + if (StringUtility.isNullOrEmpty(currentProjectRelativePath)) { + return null; + } + appConfigInfo = GspAppConfigService.getCurrent().getOrCreateAppConfig(currentProjectRelativePath); + + return appConfigInfo; + } + + private GspAppConfig getGspAppConfigInfoByMetadata(String metadataRelativePath) { + GspAppConfig appConfigInfo = null; + String currentProjectRelativePath = getProjectRelativePathByMetadata(metadataRelativePath); + if (StringUtility.isNullOrEmpty(currentProjectRelativePath)) { + return null; + } + System.out.println("MetadataProject Instance's Relative Path is: " + currentProjectRelativePath); + + appConfigInfo = GspAppConfigService.getCurrent().getGspAppConfigInfo(currentProjectRelativePath); + + return appConfigInfo; + } + + private String getProjectRelativePathByMetadata(String metadataRelativePath) { + if (StringUtility.isNullOrEmpty(metadataRelativePath)) { + return null; + } + + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProjectInfo = metadataProjectService.getMetadataProjInfo(metadataRelativePath); + // 返回元数据工程的路径,包含metadata这层路径。工程、元数据工程,mistery。。 + return metadataProjectInfo.getProjectPath(); + } + + + private PageFlowMetadataEntity getPageFlowMetadataEntity(MetadataEventArgs metadataEventArgs, GspAppConfig appConfigInfo) { + PageFlowMetadataEntity pageFlowMetadataEntity = null; + + String pageFlowMetadataId = ""; + String pageFlowMetadataName = ""; + TerminalType terminalType = TerminalType.PC; + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + pageFlowMetadataId = appConfigInfo.getPageFlowMetadataID(); + pageFlowMetadataName = appConfigInfo.getPageFlowMetadataFileName(); + terminalType = TerminalType.PC; + } + if (MetadataConstant.MOBILE_FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + pageFlowMetadataId = appConfigInfo.getMobilePageFlowMetadataID(); + pageFlowMetadataName = appConfigInfo.getMobilePageFlowMetadataFileName(); + terminalType = TerminalType.MOBILE; + } + String projectPath = MetadataUtility.getInstance().getMetadataProjectPath(metadataEventArgs.getMetadata().getRelativePath()); + + // 表示关联的页面流id为空 可以认为当前不存在对应的页面流 + if (StringUtility.isNullOrEmpty(pageFlowMetadataId)) { + // 此时需要创建对应的页面流 并写入到appconfig.json 中 + GspMetadata pageFlowMetadata = createRouteMetadataInMemory(projectPath, terminalType); + PageFlowMetadataEntity createdPageFlowMetadataEntity = (PageFlowMetadataEntity) pageFlowMetadata.getContent(); + if (createdPageFlowMetadataEntity.getPages().length == 0) { + return null; + } + + // (2) 持久化页面流元数据 + String routeMetadataRelativePath = PageFlowMetadataUpdateService.getInstance().createRouteMetadataInDisk(pageFlowMetadata); + + // (3) 回写appconfigInfo + GspAppConfigService.getCurrent().updateAppConfigFile(terminalType, pageFlowMetadata.getHeader().getId(), pageFlowMetadata.getHeader().getFileName(), routeMetadataRelativePath); + + pageFlowMetadataId = pageFlowMetadata.getHeader().getId(); + pageFlowMetadataName = pageFlowMetadata.getHeader().getName(); + } + + pageFlowMetadataEntity = RouteMetataService.getRouteMetadataContentWithMetadataIdAndProjectPath(pageFlowMetadataId, pageFlowMetadataName, projectPath); + + return pageFlowMetadataEntity; + } + + private void updatePageFlowMetadataEntity(MetadataEventArgs metadataEventArgs, PageFlowMetadataEntity pageFlowMetadataEntity) { + boolean existSamePage = checkIfExistsSamePage(metadataEventArgs.getMetadata().getHeader().getId(), pageFlowMetadataEntity); + if (existSamePage) { + return; + } + + Page[] updatePages = null; + Page page = createPage(metadataEventArgs.getMetadata()); + List tempArrayList = pageFlowMetadataEntity.getPages() == null ? new ArrayList<>() : new ArrayList<>(Arrays.asList(pageFlowMetadataEntity.getPages())); + tempArrayList.add(page); + updatePages = tempArrayList.toArray(new Page[0]); + pageFlowMetadataEntity.setPages(updatePages); + } + + private boolean checkIfExistsSamePage(String pageId, PageFlowMetadataEntity pageFlowMetadataEntity) { + // 默认不存在 + boolean existSamePage = false; + + for (int i = 0; i < pageFlowMetadataEntity.getPages().length; i++) { + if (pageFlowMetadataEntity.getPages()[i].getId().equals(pageId)) { + existSamePage = true; + break; + } + } + + return existSamePage; + } + + private Page createPage(GspMetadata metadata) { + Page page = new Page(); + + page.setId(metadata.getHeader().getId()); + page.setCode(metadata.getHeader().getCode()); + page.setName(metadata.getHeader().getName()); + page.setFileName(metadata.getHeader().getFileName()); + page.setRelativePath(metadata.getRelativePath()); + page.setFormUri(metadata.getHeader().getId()); + page.setRouteUri(metadata.getHeader().getCode()); + + return page; + } + + private void saveRouteMetadataContent(MetadataEventArgs metadataEventArgs, PageFlowMetadataEntity pageFlowMetadataEntity, GspAppConfig appConfigInfo) { + if (MetadataConstant.FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + RouteMetataService.saveRouteMetadataContent(pageFlowMetadataEntity, appConfigInfo.getPageFlowMetadataID(), metadataEventArgs.getMetadata().getRelativePath()); + } else if (MetadataConstant.MOBILE_FORM_METADATA_TYPE.equals(metadataEventArgs.getMetadata().getHeader().getType())) { + RouteMetataService.saveRouteMetadataContent(pageFlowMetadataEntity, appConfigInfo.getMobilePageFlowMetadataID(), metadataEventArgs.getMetadata().getRelativePath()); + } + } + + /** + * 创建默认的页面流实体 + * 将当前指定类型的表单填充 + * + * @param pageFlowMetadataEntityId + * @param projectPath + * @param metadataSuffix + * @return + */ + public PageFlowMetadataEntity createPageFlowMetadataEntity(String pageFlowMetadataEntityId, String projectPath, String metadataSuffix) { + PageFlowMetadataEntity localPageFlowMetadataEntity = new PageFlowMetadataEntity(); + // (1) 创建元数据ID + localPageFlowMetadataEntity.setId(pageFlowMetadataEntityId); + // (2) 创建project属性 + localPageFlowMetadataEntity.setProject(new Project()); + localPageFlowMetadataEntity.getProject().setName(MetadataUtility.getInstance().getProjectName(projectPath)); + // (3) 获取当前工程的所有表单元数据 + List formMetataList = MetadataUtility.getInstance().getMetadataListInProject(projectPath, metadataSuffix); + // (4) 将表单元数据填充到页面流元数据中 + localPageFlowMetadataEntity.setPages((Page[]) java.lang.reflect.Array.newInstance(Page.class, formMetataList.size())); + + for (int i = 0; i < formMetataList.size(); i++) { + Page page = new Page(); + GspMetadata currentGspMetadata = formMetataList.get(i); + page.setId(currentGspMetadata.getHeader().getId()); + page.setCode(currentGspMetadata.getHeader().getCode()); + page.setName(currentGspMetadata.getHeader().getName()); + page.setFileName(currentGspMetadata.getHeader().getFileName()); + + page.setRelativePath(removeDevRootPathPrefix(currentGspMetadata.getRelativePath())); + // 设置routeUri + page.setRouteUri(currentGspMetadata.getHeader().getCode()); + localPageFlowMetadataEntity.getPages()[i] = page; + } + + if (localPageFlowMetadataEntity.getPages().length > 0) { + localPageFlowMetadataEntity.setEntry(localPageFlowMetadataEntity.getPages()[0].getCode()); + } + + return localPageFlowMetadataEntity; + } + + /** + * 移除工作空间前缀 + * + * @param metadataRelativePath + * @return + */ + private String removeDevRootPathPrefix(String metadataRelativePath) { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + String independentRelativePath = FileUtility.getPlatformIndependentPath(metadataRelativePath); + boolean startWithDevRootPrefix = StringUtility.startWith(independentRelativePath, FileUtility.getPlatformIndependentPath(devRootPath)); + + // 如果二者有其一是绝对路径 那么不能进行前缀处理 + if (FileUtility.isAbsolute(devRootPath) != FileUtility.isAbsolute(independentRelativePath)) { + startWithDevRootPrefix = false; + } + + if (startWithDevRootPrefix) { + // 如果以工作空间路径开头 那么移除 方便工作空间迁移时可以正常 + independentRelativePath = independentRelativePath.substring(devRootPath.length()); + } + if (independentRelativePath.startsWith("/")) { + independentRelativePath = independentRelativePath.substring(1); + } + return independentRelativePath; + } + + public GspMetadata createRouteMetadataInMemory(String projectPath, TerminalType terminalType) { + // 1. 创建元数据并执行初始化 + GspMetadata routeMetadata = new GspMetadata(); + routeMetadata.setHeader(new MetadataHeader()); + + GspProject gspProject = GspProjectUtil.getGspProject(projectPath); + routeMetadata.getHeader().setNameSpace(gspProject.getProjectNameSpace()); + routeMetadata.getHeader().setBizobjectID(gspProject.getBizobjectID()); + + updateRouteMetadataHeader(routeMetadata.getHeader(), terminalType); + + String relativePath = ""; + String routeMetadataBaseDirectory = "/route"; + routeMetadata.setRelativePath(projectPath + routeMetadataBaseDirectory); + + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + metadataService.initializeMetadataEntity(routeMetadata); + + // 2. 创建页面流元数据实体 + PageFlowMetadataEntity localPageFlowMetadataEntity = createPageFlowMetadataEntity(routeMetadata.getHeader().getId(), projectPath, terminalType.getFormMetadataSuffix()); + + // 3. 向页面流元数据回填内容 + // 如何写入内容,保证能读取数据 + routeMetadata.setContent(localPageFlowMetadataEntity); + + return routeMetadata; + } + + public String createRouteMetadataInDisk(GspMetadata routeMetadata) { + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + boolean isPathExists = FileUtility.exists(routeMetadata.getRelativePath()); + if (!isPathExists) { + FileUtility.createDirectory(routeMetadata.getRelativePath()); + } + + String routeMetadataRelativePath = routeMetadata.getRelativePath(); + + routeMetadata.setRelativePath(""); + // 如果页面流文件已经存在 那么删除当前元数据 重新创建 之所以重新创建 是因为routemetadta不一致 + if (metadataService.isMetadataExist(routeMetadataRelativePath, routeMetadata.getHeader().getFileName())) { + metadataService.deleteMetadata(routeMetadataRelativePath, routeMetadata.getHeader().getFileName()); + } + metadataService.createMetadata(routeMetadataRelativePath, routeMetadata); + return routeMetadataRelativePath; + } + + private void updateRouteMetadataHeader(MetadataHeader routeMetadataHeader, TerminalType terminalType) { + String routeMetadataCode = ""; + switch (terminalType) { + case PC: + routeMetadataCode = "predefinePageflow"; + routeMetadataHeader.setFileName(routeMetadataCode + ".pf"); + routeMetadataHeader.setType("PageFlowMetadata"); + break; + case MOBILE: + routeMetadataCode = "predefineMobilePageflow"; + routeMetadataHeader.setFileName(routeMetadataCode + ".mpf"); + routeMetadataHeader.setType("MobilePageFlowMetadata"); + break; + default: + throw new GSPException("Web_UpdateRouteMetadataHeader", "未识别的终端类型,请联系管理员处理。当前终端类型是:" + terminalType); + } + + routeMetadataHeader.setCode(routeMetadataCode); + routeMetadataHeader.setName(routeMetadataCode); + } +} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetataService.java b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetataService.java new file mode 100644 index 00000000..06607de5 --- /dev/null +++ b/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetataService.java @@ -0,0 +1,83 @@ +package com.inspur.edp.web.pageflow.metadata.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.common.GSPException; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntity; +import com.inspur.edp.web.pageflow.metadata.entity.PageFlowMetadataEntityManager; +import io.iec.edp.caf.commons.exception.ExceptionLevel; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +public class RouteMetataService { + + /** + * 获取路由元数据内容 + * + * @param routeMetadataId 页面流元数据id + * @param projectPath 基于开发根目录的路径 + * @return + */ + public static PageFlowMetadataEntity getRouteMetadataContentWithMetadataIdAndProjectPath(String routeMetadataId, String routeMetadataFileName, String projectPath) { + + if (StringUtility.isNullOrEmpty(routeMetadataId)) { + return null; + } + + // 如果对应元数据不存在 + if (!StringUtility.isNullOrEmpty(routeMetadataFileName) && !MetadataUtility.getInstance().isMetaDataExistsWithMetadataIDAndPath(projectPath, routeMetadataId)) { + return null; + } + + GspMetadata routeMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(routeMetadataId, projectPath); + if (routeMetadata == null) { + return null; + } + + return (PageFlowMetadataEntity) routeMetadata.getContent(); + } + + /** + * 保存路由元数据内容 + * + * @param pageFlowMetadataEntity 待保存元数据内容 + * @param routeMetadataId 页面流元数据id + * @param projectPath 基于开发根目录的路径 + */ + public static void saveRouteMetadataContent(PageFlowMetadataEntity pageFlowMetadataEntity, String routeMetadataId, String projectPath) { + if (StringUtility.isNullOrEmpty(routeMetadataId) || StringUtility.isNullOrEmpty(projectPath)) { + return; + } + + GspMetadata routeMetadata = MetadataUtility.getInstance().getMetadataWithIdAndPath(routeMetadataId, projectPath); + if (routeMetadata == null) { + log.debug("Save Route Metadata Content Operation is Stopped Because Target Route Metadata is NULL."); + return; + } + + routeMetadata.setContent(pageFlowMetadataEntity); + + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + + metadataService.saveMetadata(routeMetadata, routeMetadata.getRelativePath() + FileUtility.DIRECTORY_SEPARATOR_CHAR + routeMetadata.getHeader().getFileName()); + } + + /** + * 通过表单ID,查找对应的RouteUri + * + * @param pageFlowMetadataEntity + * @return + */ + public static String getcurrentpagerouteuri(PageFlowMetadataEntity pageFlowMetadataEntity, String pageId) { + if (pageFlowMetadataEntity == null || StringUtility.isNullOrEmpty(pageId)) { + throw new GSPException("WEB_GetCurrentPageRouteUri", "Current Route Metadata Content is Null or the Page id is Nulll or Empty.", null, ExceptionLevel.Warning); + } + + return PageFlowMetadataEntityManager.getPageRouteUri(pageFlowMetadataEntity, pageId); + } +} diff --git a/web-sourcecode-metadata/pom.xml b/web-sourcecode-metadata/pom.xml new file mode 100644 index 00000000..fb98594c --- /dev/null +++ b/web-sourcecode-metadata/pom.xml @@ -0,0 +1,40 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-sourcecode-metadata + + + + com.inspur.edp + web-jitengine-common + + + io.iec.edp + caf-i18n-framework-api + + + com.inspur.edp + i18n-resource-api + + + com.inspur.edp + formserver-viewmodel + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + lcm-metadata-spi + + + diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java new file mode 100644 index 00000000..cc20e51b --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java @@ -0,0 +1,21 @@ +package com.inspur.edp.web.sourcecode.metadata.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * 相对路径枚举值 + * + */ +public enum RelativePathEnumEntity { + /** + * 工作区 + */ + @JsonProperty("workspace") + WorkSpace, + /** + * 工程 + */ + @JsonProperty("project") + Project + +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java new file mode 100644 index 00000000..45e3e8d6 --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java @@ -0,0 +1,72 @@ +package com.inspur.edp.web.sourcecode.metadata.entity; + +/** + * 自定义web构件具体项 + * + */ +public class SourceCodeItemEntity { + /** + * 具体源文件项id + */ + private String id; + + /** + * 源文件路径 仅支持相对路径 + */ + private String sourcePath; + + /** + * 目标文件路径 仅支持相对路径 默认和源文件路径相同 + */ + private String targetPath; + + /** + * 相对路径枚举 + */ + private String relativePathEnum; + + /** + * 源文件内容 + */ + private String sourceFileContent; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getSourcePath() { + return sourcePath; + } + + public void setSourcePath(String sourcePath) { + this.sourcePath = sourcePath; + } + + public String getTargetPath() { + return targetPath; + } + + public void setTargetPath(String targetPath) { + this.targetPath = targetPath; + } + + public String getRelativePathEnum() { + return relativePathEnum; + } + + public void setRelativePathEnum(String relativePathEnum) { + this.relativePathEnum = relativePathEnum; + } + + public String getSourceFileContent() { + return sourceFileContent; + } + + public void setSourceFileContent(String sourceFileContent) { + this.sourceFileContent = sourceFileContent; + } +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java new file mode 100644 index 00000000..67008d97 --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.sourcecode.metadata.entity; + +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import com.inspur.edp.web.sourcecode.metadata.serializer.SourceCodeMetadataTransferSerializer; +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 自定义web代码 + */ +@Getter +@Setter +public class SourceCodeMetadataEntity extends AbstractMetadataContent { + public SourceCodeMetadataEntity() { + if (this.getItems() == null) { + this.items = new ArrayList<>(); + } + } + + /** + * 自定义web代码对应id + */ + private String id; + + /** + * 编码 + */ + private String code; + + /** + * 名称 + */ + private String name; + + /** + * 元数据所在路径 + */ + private String path; + + /** + * 工程名称 + */ + private String project; + + /** + * 自定义web代码包含的具体文件项 + */ + private List items; + + /** + * 描述信息 + */ + private String description; + + @Override + public Object clone() { + SourceCodeMetadataTransferSerializer serializer = new SourceCodeMetadataTransferSerializer(); + String json = serializer.serialize(this); + return serializer.deserialize(json); + } +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java new file mode 100644 index 00000000..7043b9d5 --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java @@ -0,0 +1,49 @@ +package com.inspur.edp.web.sourcecode.metadata.listener; + +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventArgs; +import com.inspur.edp.lcm.metadata.spi.event.MetadataEventListener; +import com.inspur.edp.web.common.GspProjectUtil; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; +import com.inspur.edp.web.sourcecode.metadata.utility.SourceCodeMetadataUtility; +import io.iec.edp.caf.commons.exception.CAFRuntimeException; + +/** + * 自定义web构建事件监听 + */ +public class SourceCodeMetadataEventListener implements MetadataEventListener { + + + @Override + public void fireMetadataSavingEvent(MetadataEventArgs e) { + if (e.getMetadata() != null && e.getMetadata().getContent() != null && e.getMetadata().getContent() instanceof SourceCodeMetadataEntity) { + String path = e.getMetadata().getRelativePath(); + GspProject project = GspProjectUtil.getGspProject(path); + if (project == null) { + throw new CAFRuntimeException("", "NoFrontendProjectFound", "找不到前端工程,参考路径是" + path, null); + } + String projectName = project.getMetadataProjectName(); + + SourceCodeMetadataEntity sourceCodeMetadataEntity = (SourceCodeMetadataEntity) e.getMetadata().getContent(); + // 根据源文件路径获取对应文件的内容 + SourceCodeMetadataUtility.sourceCodeItemsAddFileContent(sourceCodeMetadataEntity, projectName); + // 重新填充元数据内容 + e.getMetadata().setContent(sourceCodeMetadataEntity); + } + } + + @Override + public void fireMetadataSavedEvent(MetadataEventArgs metadataEventArgs) { + //N版方法为空 + } + + @Override + public void fireMetadataDeletingEvent(MetadataEventArgs metadataEventArgs) { + //N版方法为空 + } + + @Override + public void fireMetadataDeletedEvent(MetadataEventArgs metadataEventArgs) { + //N版方法为空 + } +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java new file mode 100644 index 00000000..2661f092 --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java @@ -0,0 +1,34 @@ +package com.inspur.edp.web.sourcecode.metadata.manager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.spi.MetadataContentManager; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; + +/** + * 自定义web构建 manager + */ +public class SourceCodeMetadataManager implements MetadataContentManager { + /** + * 创建默认的自定义web构件内容 + * + * @param metadata + */ + @Override + public void build(GspMetadata metadata) { + if (metadata == null) { + return; + } + + SourceCodeMetadataEntity sourceCodeMetadataEntity = new SourceCodeMetadataEntity(); + + if (metadata.getHeader() != null && !StringUtility.isNullOrEmpty(metadata.getHeader().getId())) { + sourceCodeMetadataEntity.setId(metadata.getHeader().getId()); + sourceCodeMetadataEntity.setCode(metadata.getHeader().getCode()); + sourceCodeMetadataEntity.setName(metadata.getHeader().getName()); + sourceCodeMetadataEntity.setPath(metadata.getRelativePath()); + metadata.setContent(sourceCodeMetadataEntity); + } + } + +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java new file mode 100644 index 00000000..5507fa2b --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java @@ -0,0 +1,28 @@ +package com.inspur.edp.web.sourcecode.metadata.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; + +/** + * 自定义web构建序列化实现 + */ +public class SourceCodeMetadataEntitySerializer implements MetadataContentSerializer { + + @Override + public IMetadataContent DeSerialize(JsonNode jsonNode) { + return SerializeUtility.getInstance().toObject(jsonNode, SourceCodeMetadataEntity.class); + } + + @Override + public JsonNode Serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } + + SourceCodeMetadataEntity metadata = (SourceCodeMetadataEntity) ((metadataContent instanceof SourceCodeMetadataEntity) ? metadataContent : null); + return SerializeUtility.getInstance().toJsonNode(SerializeUtility.getInstance().serialize(metadata,false)); + } +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java new file mode 100644 index 00000000..927b8333 --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java @@ -0,0 +1,29 @@ +package com.inspur.edp.web.sourcecode.metadata.serializer; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; +import io.iec.edp.caf.common.JSONSerializer; + +public class SourceCodeMetadataTransferSerializer implements MetadataTransferSerializer { + + @Override + public String serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } else { + SourceCodeMetadataEntity metadata = (SourceCodeMetadataEntity) ((metadataContent instanceof SourceCodeMetadataEntity) ? metadataContent : null); + return JSONSerializer.serialize(metadata); + } + } + + @Override + public IMetadataContent deserialize(String contentString) { + if (StringUtility.isNullOrEmpty(contentString)) { + return null; + } else { + return JSONSerializer.deserialize(contentString, SourceCodeMetadataEntity.class); + } + } +} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java new file mode 100644 index 00000000..d27b7dfb --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java @@ -0,0 +1,48 @@ +package com.inspur.edp.web.sourcecode.metadata.utility; + +import java.util.*; + +/** + * 文件操作扩展名 + * @author noah + */ +public class FileOperationExtensions +{ + // 注:实例必须有 volatile 关键字修饰,其保证初始化完全。 + private volatile static FileOperationExtensions instance = null; + + public static FileOperationExtensions getInstance() + { + if (instance == null) + { + synchronized (FileOperationExtensions.class) + { + if (instance == null) + { + instance = new FileOperationExtensions(); + } + } + } + return instance; + } + + private FileOperationExtensions() + { + this.extensions = new ArrayList<>(); + this.getExtensions().add("ts"); + this.getExtensions().add("html"); + this.getExtensions().add("css"); + this.getExtensions().add("scss"); + this.getExtensions().add("sass"); + } + + + /** + 可以进行操作的文件扩展名 + */ + private final ArrayList extensions; + public final ArrayList getExtensions() + { + return extensions; + } +} \ No newline at end of file diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileUtility.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileUtility.java new file mode 100644 index 00000000..1000cbbb --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileUtility.java @@ -0,0 +1,24 @@ +package com.inspur.edp.web.sourcecode.metadata.utility; + +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeItemEntity; + +/** + * 文件操作 + */ +public class FileUtility { + /** + * 读取文件内容 + * + * @param sourceCodeItemEntity + * @return + */ + public static String readFileContent(SourceCodeItemEntity sourceCodeItemEntity) { + //N版逻辑如此 + if (sourceCodeItemEntity != null) { + String strRelativeEnum = sourceCodeItemEntity.getRelativePathEnum(); + String sourcePath = sourceCodeItemEntity.getSourcePath(); + + } + return ""; + } +} \ No newline at end of file diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java new file mode 100644 index 00000000..6a6cab6a --- /dev/null +++ b/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java @@ -0,0 +1,79 @@ +package com.inspur.edp.web.sourcecode.metadata.utility; + +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.web.common.encrypt.EncryptUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeItemEntity; +import com.inspur.edp.web.sourcecode.metadata.entity.SourceCodeMetadataEntity; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import lombok.extern.slf4j.Slf4j; +import com.inspur.edp.web.common.io.FileUtility; + +@Slf4j +public class SourceCodeMetadataUtility { + /** + * 自定义web构件 项增加文件内容作为填充 + */ + public static void sourceCodeItemsAddFileContent(SourceCodeMetadataEntity sourceCodeMetadataEntity, String projectName) { + String strDevRootPath = getAbsoluteDevRootPath(); + strDevRootPath = getMetadataProjectPath(sourceCodeMetadataEntity.getPath()); + final String fstrDevRootPath = FileUtility.combine(strDevRootPath, "src", "app"); + if (sourceCodeMetadataEntity.getItems() != null && !sourceCodeMetadataEntity.getItems().isEmpty()) { + sourceCodeMetadataEntity.getItems().forEach((item) -> + sourceCodeItemAddFileContent(item, fstrDevRootPath, projectName)); + } + } + + /** + * 针对文件路径 填充文件内容 + */ + private static void sourceCodeItemAddFileContent(SourceCodeItemEntity item, String strDevRootPath, String projectName) { + String strSourcePath = replaceProjectName(item.getSourcePath(), projectName); + String absolutePath = StringUtility.contactByRemovingRepeat(strDevRootPath, strSourcePath); + if (FileUtility.exists(absolutePath)) { + try { + String strFileContent = FileUtility.readAsString(absolutePath); + String strBase64Encoding = EncryptUtility.getInstance().Base64Encode(strFileContent); + + + item.setSourceFileContent(strBase64Encoding); + } catch (RuntimeException ex) { + log.error("sourceCodeMetadata saving," + ex.getMessage(), ex); + } + } else { + System.out.println("自定义web构件,文件不存在,对应路径路径:" + absolutePath); + } + } + + private static String replaceProjectName(String source, String projectName) { + return source.replace("{{projectname}}", projectName); + } + + /** + * 获取当前元数据所在工程路径 + */ + private static String getMetadataProjectPath(String metadataFullPath) { + String currentProjectPath = metadataFullPath; + if (currentProjectPath.contains(MetadataUtility.getInstance().getDevRootPath())) { + return currentProjectPath; + } else { + MetadataProjectService bean = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject metadataProject = bean.getMetadataProjInfo(metadataFullPath); + + return java.nio.file.Paths.get(MetadataUtility.getInstance().getDevRootPath()).resolve(metadataProject.getProjectPath()).toString(); + } + } + + /** + * 获取开发时绝对路径 + */ + private static String getAbsoluteDevRootPath() { + String devRootPath = MetadataUtility.getInstance().getDevRootPath(); + if (!FileUtility.isAbsolute(devRootPath)) { + devRootPath = FileUtility.getAbsolutePathHead(devRootPath) + devRootPath; + } + return devRootPath; + } +} diff --git a/web-statemachine/pom.xml b/web-statemachine/pom.xml new file mode 100644 index 00000000..e305e751 --- /dev/null +++ b/web-statemachine/pom.xml @@ -0,0 +1,33 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-statemachine-metadata + + + + com.inspur.edp + web-jitengine-common + + + com.fasterxml.jackson.core + jackson-databind + + + com.inspur.edp + lcm-metadata-api + + + com.inspur.edp + lcm-metadata-spi + + + + diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java new file mode 100644 index 00000000..df6c88c4 --- /dev/null +++ b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java @@ -0,0 +1,16 @@ +package com.inspur.edp.web.statemachine.manager; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.spi.MetadataContentManager; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.statemachine.metadata.StateMachineMetadataContent; + +public class StateMachineMetadataManager implements MetadataContentManager { + @Override + public final void build(GspMetadata metadata) { + StateMachineMetadataContent content = new StateMachineMetadataContent(); + if (metadata != null && metadata.getHeader() != null && !StringUtility.isNullOrEmpty(metadata.getHeader().getId())) { + metadata.setContent(content); + } + } +} diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java new file mode 100644 index 00000000..637bbc3c --- /dev/null +++ b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java @@ -0,0 +1,74 @@ +package com.inspur.edp.web.statemachine.metadata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.inspur.edp.lcm.metadata.api.AbstractMetadataContent; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.web.statemachine.serializer.StateMachineTransferSerializer; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.HashMap; +import java.util.LinkedList; + +@Data +@EqualsAndHashCode(callSuper = true) +public class StateMachineMetadataContent extends AbstractMetadataContent { + + @JsonProperty("renderState") + private HashMap renderState; + + @JsonProperty("state") + private LinkedList state; + + @JsonProperty("initialState") + private String initialState; + + @JsonProperty("action") + private HashMap action; + + public final HashMap getRenderState() { + return renderState; + } + + public final void setRenderState(HashMap value) { + renderState = value; + } + + + public final LinkedList getState() { + return state; + } + + public final void setState(LinkedList value) { + state = value; + } + + public final String getInitialState() { + return initialState; + } + + public final void setInitialState(String value) { + initialState = value; + } + + public final HashMap getAction() { + return action; + } + + public final void setAction(HashMap value) { + action = value; + } + + @Override + public Object clone() { + StateMachineTransferSerializer serializer = new StateMachineTransferSerializer(); + String json = serializer.serialize(this); + IMetadataContent obj = serializer.deserialize(json); + return obj; + } + + public final String toJson() { + StateMachineTransferSerializer serializer = new StateMachineTransferSerializer(); + return serializer.serialize(this); + } +} diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java new file mode 100644 index 00000000..412d66a6 --- /dev/null +++ b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java @@ -0,0 +1,32 @@ +package com.inspur.edp.web.statemachine.serializer; + +import com.fasterxml.jackson.databind.JsonNode; +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataContentSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.statemachine.metadata.StateMachineMetadataContent; + +public class StateMachineSerializer implements MetadataContentSerializer { + + @Override + public final IMetadataContent DeSerialize(JsonNode contentJObject) { + if (contentJObject != null) { + StateMachineMetadataContent stateMachineMetadataContent = SerializeUtility.getInstance().deserialize(contentJObject.toString(), StateMachineMetadataContent.class); + return stateMachineMetadataContent; + } else { + return null; + } + } + + @Override + public final JsonNode Serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } + + StateMachineMetadataContent metadata = (StateMachineMetadataContent) ((metadataContent instanceof StateMachineMetadataContent) ? metadataContent : null); + JsonNode jsonNode = SerializeUtility.getInstance().toJsonNode(SerializeUtility.getInstance().serialize(metadata)); + return jsonNode; + } + +} diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java new file mode 100644 index 00000000..0e8a72e4 --- /dev/null +++ b/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.statemachine.serializer; + +import com.inspur.edp.lcm.metadata.api.IMetadataContent; +import com.inspur.edp.lcm.metadata.spi.MetadataTransferSerializer; +import com.inspur.edp.web.common.serialize.SerializeUtility; +import com.inspur.edp.web.common.utility.StringUtility; +import com.inspur.edp.web.statemachine.metadata.StateMachineMetadataContent; + +public class StateMachineTransferSerializer implements MetadataTransferSerializer { + @Override + public final IMetadataContent deserialize(String contentString) { + if (StringUtility.isNullOrEmpty(contentString)) { + return null; + } + return SerializeUtility.getInstance().deserialize(contentString, StateMachineMetadataContent.class); + } + + @Override + public final String serialize(IMetadataContent metadataContent) { + if (metadataContent == null) { + return null; + } else { + StateMachineMetadataContent metadata = (StateMachineMetadataContent) ((metadataContent instanceof StateMachineMetadataContent) ? metadataContent : null); + return SerializeUtility.getInstance().serialize(metadata); + } + } +} diff --git a/web-tsfile-api/pom.xml b/web-tsfile-api/pom.xml new file mode 100644 index 00000000..3ca9054e --- /dev/null +++ b/web-tsfile-api/pom.xml @@ -0,0 +1,27 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-tsfile-api + + + + + jakarta.ws.rs + jakarta.ws.rs-api + + + com.inspur.edp + web-jitengine-common + + + + + diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java new file mode 100644 index 00000000..284afffb --- /dev/null +++ b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java @@ -0,0 +1,9 @@ +package com.inspur.edp.web.tsfile.api.entity; + +/** + * 文件对象实体定义 + * @author noah + */ +public class FileObject { + public String content; +} diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java new file mode 100644 index 00000000..591d7ce6 --- /dev/null +++ b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java @@ -0,0 +1,64 @@ +package com.inspur.edp.web.tsfile.api.service; + +import java.util.ArrayList; + +/* +ts文件对外暴露service + */ +public interface TsFileService { + + /** + * 保存TS文件,包括新增和修改 + * + * @param fullPath 文件相对于开发根目录的路径,包含文件名和扩展名 + * @param content 文件内容 + */ + void saveTsFile(String fullPath, String content); + + /** + * 获取TS文件内容 + * + * @param fullPath 文件相对于开发根目录的路径,包含文件名和扩展名 + */ + String loadTsFileContent(String fullPath); + + /** + * 根据web构件获取对应TS文件内容 + * + * @param formRelativePath 所属表单的相对路径 + * @param webCmpId + * @return + */ + String loadTsFileContentByWebCmp(String formRelativePath, String webCmpId); + + /** + * 删除指定的TS文件 + * + * @param fullPath 文件相对于开发根目录的路径,包含文件名和扩展名 + */ + void deleteTsFile(String fullPath); + + /** + * 重命名指定的文件 + * + * @param fullPath 文件相对于开发根目录的路径,包含文件名和扩展名 + * @param newName 新文件名 + */ + void renameTsFile(String fullPath, String newName); + + /** + * 获取指定目录下的所有TS文件名 + * + * @param path 文件相对于开发根目录的路径,不含文件名 + */ + ArrayList getTsFileList(String path); + + + /** + * 判断指定文件是否存在 + * + * @param fullPath 文件相对于开发根目录的路径,包含文件名和扩展名 + * @return + */ + boolean isTsFileExist(String fullPath); +} diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java new file mode 100644 index 00000000..003beb89 --- /dev/null +++ b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java @@ -0,0 +1,30 @@ +package com.inspur.edp.web.tsfile.api.webservice; + +import com.inspur.edp.web.tsfile.api.entity.FileObject; + +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; + +/** + * description: + * + * @author Noah Guo + * @date 2021/01/19 + */ +@Path("/") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface TsFileWebService { + @Path("get") + @GET + Object loadTsFileContent(@QueryParam("path") String path); + + @Path("save") + @POST + void saveTsFile(@QueryParam("path") String path, FileObject fileObject); + + + @Path("create") + @POST + void createTypescriptFile(@QueryParam("path") String path); +} diff --git a/web-tsfile-core/pom.xml b/web-tsfile-core/pom.xml new file mode 100644 index 00000000..8610ddff --- /dev/null +++ b/web-tsfile-core/pom.xml @@ -0,0 +1,41 @@ + + + + web + com.inspur.edp + ${custom.version} + + 4.0.0 + + web-tsfile-core + + + com.inspur.edp + web-tsfile-api + + + commons-io + commons-io + + + io.iec.edp + caf-boot-commons-utils + 0.3.5 + + + com.inspur.edp + lcm-metadata-api + + + io.iec.edp + caf-boot-starter-rest-server + + + com.inspur.edp + web-jitengine-common + + + + diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java new file mode 100644 index 00000000..7fbfd330 --- /dev/null +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java @@ -0,0 +1,43 @@ +package com.inspur.edp.web.tsfile.core; + +import com.inspur.edp.web.tsfile.api.entity.FileObject; +import com.inspur.edp.web.tsfile.api.webservice.TsFileWebService; +import com.inspur.edp.web.tsfile.core.service.TsFileService4WebApi; + +import java.util.HashMap; +import java.util.Map; + +/** + * description: ts文件的操作 + * 提供加载ts文件、创建ts文件及保存ts文件的操作 + * + * @author Noah Guo + * @date 2021/01/19 + */ +public class TsFileWebServiceImpl implements TsFileWebService { + + + @Override + public Object loadTsFileContent(String path) { + + TsFileService4WebApi service = new TsFileService4WebApi(); + + Map map = new HashMap<>(); + map.put("success", true); + map.put("content", service.loadTsFile(path)); + return map; + } + + @Override + public void saveTsFile(String path, FileObject fileObject) { + TsFileService4WebApi service = new TsFileService4WebApi(); + service.saveTsFile(path, fileObject.content); + } + + @Override + public void createTypescriptFile(String path) { + TsFileService4WebApi service = new TsFileService4WebApi(); + service.createTypescriptFile(path); + } + +} diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java new file mode 100644 index 00000000..3dd61697 --- /dev/null +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java @@ -0,0 +1,27 @@ +package com.inspur.edp.web.tsfile.core.config; + +import com.inspur.edp.web.tsfile.api.service.TsFileService; +import com.inspur.edp.web.tsfile.core.TsFileWebServiceImpl; +import com.inspur.edp.web.tsfile.core.service.TsFileServiceImpl; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * description: 定义ts文件定义的自定义restful url地址 + * + * @author Noah Guo + * @date 2021/01/19 + */ +@Configuration("com.inspur.edp.web.tsfile.core.config.TsFileConfiguration") +public class TsFileConfiguration { + @Bean + public TsFileService tsFileService() { + return TsFileServiceImpl.getNewInstance(); + } + + @Bean() + public RESTEndpoint tsFileWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/tsfile", new TsFileWebServiceImpl()); + } +} diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java new file mode 100644 index 00000000..afa5c731 --- /dev/null +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java @@ -0,0 +1,58 @@ +package com.inspur.edp.web.tsfile.core.service; + +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.tsfile.api.service.TsFileService; +import com.inspur.edp.web.tsfile.core.util.NameUtil; +import org.apache.commons.io.FilenameUtils; + +import java.util.ArrayList; + +public class TsFileService4WebApi { + private final TsFileService service = TsFileServiceImpl.getNewInstance(); + + public final void deleteTsFile(String fullPath) { + service.deleteTsFile(fullPath); + } + + public final ArrayList getTsFileList(String path) { + return service.getTsFileList(path); + } + + public final boolean isTsFileExist(String path, String fileName) { + String filePathAndName = FileUtility.combine(path, fileName); + return service.isTsFileExist(filePathAndName); + } + + public final boolean isTsFileExist(String fullPath) { + return service.isTsFileExist(fullPath); + } + + public final String loadTsFile(String fullPath) { + return service.loadTsFileContent(fullPath); + } + + public final String loadTsFileByWebCmp(String formRelativePath, String webCmpId) { + return service.loadTsFileContentByWebCmp(formRelativePath, webCmpId); + } + + public final void renameTsFile(String fullPath, String newName) { + service.renameTsFile(fullPath, newName); + } + + public final void saveTsFile(String fullPath, String content) { + service.saveTsFile(fullPath, content); + } + + public final void createTypescriptFile(String fullPath) { + // 抽取文件名 + String fileName = FilenameUtils.getBaseName(fullPath); + String normalized = NameUtil.getPascal(fileName); + + String contentSB = "import { Injectable } from '@angular/core';" + "\r\n" + + "\r\n@Injectable()" + "\r\n" + + "export class " + normalized + "Service {" + "\r\n" + + " constructor() {}" + "\r\n" + + "}" + "\r\n"; + service.saveTsFile(fullPath, contentSB); + } +} diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java new file mode 100644 index 00000000..9b3d58e1 --- /dev/null +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java @@ -0,0 +1,103 @@ +package com.inspur.edp.web.tsfile.core.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; +import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.common.io.FileUtility; +import com.inspur.edp.web.common.metadata.MetadataUtility; +import com.inspur.edp.web.tsfile.api.service.TsFileService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +/** + * ts文件服务实现 + * */ +public class TsFileServiceImpl implements TsFileService { + + /** + * 私有构造函数 避免外部私自实例化 提供统一返回实例方法 + * */ + private TsFileServiceImpl() { + + } + + public static TsFileServiceImpl getNewInstance() { + return new TsFileServiceImpl(); + } + + @Override + public final void deleteTsFile(String fullPath) { + FileUtility.deleteFile(fullPath); + } + + @Override + public final ArrayList getTsFileList(String path) { + throw new UnsupportedOperationException(); + } + + @Override + public final boolean isTsFileExist(String fullPath) { + throw new UnsupportedOperationException(); + } + + @Override + public final String loadTsFileContent(String fullPath) { + String filePath = getAbsolutePath(fullPath); + return FileUtility.readAsString(filePath); + } + + @Override + public final String loadTsFileContentByWebCmp(String formRelativePath, String webCmpId) { + String fileStr = ""; + MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); + MetadataProject projInfo = metadataProjectService.getMetadataProjInfo(formRelativePath); + MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); + List metadataList = metadataService.getMetadataList(projInfo.getProjectPath()); + + GspMetadata webcmpMeta = null; + for (GspMetadata item : metadataList) { + if (webCmpId.equals(item.getHeader().getId())) { + webcmpMeta = item; + break; + } + } + + if (webcmpMeta == null) { + throw new RuntimeException(String.format("没有找到表单对应的web构件。表单路径:{%1$s},web构件id:{%2$s}", formRelativePath, webCmpId)); + } + + String fileName = webcmpMeta.getHeader().getFileName(); + String fullPath = webcmpMeta.getRelativePath() + "/" + fileName.substring(0, fileName.lastIndexOf(".")) + ".ts"; + return loadTsFileContent(fullPath); + } + + @Override + public final void renameTsFile(String fullPath, String newName) { + throw new UnsupportedOperationException(); + } + + @Override + public final void saveTsFile(String fullPath, String content) { + String absolutePath = getAbsolutePath(fullPath); + FileUtility.writeFile(absolutePath, content); + } + + /** + * 获取绝对路径 + * + * @param path + * @return + */ + private String getAbsolutePath(String path) { + String unifiedPath = FileUtility.getPlatformIndependentPath(path); + + String devRootPath = FileUtility.getPlatformIndependentPath(MetadataUtility.getInstance().getDevRootPath()); + + return unifiedPath.startsWith(devRootPath) ? unifiedPath : Paths.get(devRootPath).resolve((unifiedPath.startsWith("/") ? unifiedPath.substring(1) : unifiedPath)).toString(); + } + +} diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java new file mode 100644 index 00000000..31541df3 --- /dev/null +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java @@ -0,0 +1,26 @@ +package com.inspur.edp.web.tsfile.core.util; + +public class NameUtil { + public static String getPascal(String name) { + if (name.contains("-")) { + name = name.replace('-', '_'); + } + String[] parts = name.split("[_]", -1); + StringBuilder sb = new StringBuilder(); + for (String part : parts) { + sb.append(getCapitalized(part)); + } + + return sb.toString(); + } + + /** + * 首字母大写 + * + * @param name + * @return + */ + public static String getCapitalized(String name) { + return name.substring(0, 1).toUpperCase() + name.substring(1); + } +} diff --git a/web-tsfile-core/src/main/resources/META-INF/spring.factories b/web-tsfile-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..68a5998f --- /dev/null +++ b/web-tsfile-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.inspur.edp.web.tsfile.core.config.TsFileConfiguration diff --git a/xpath0.1.bat b/xpath0.1.bat new file mode 100644 index 00000000..630822c9 --- /dev/null +++ b/xpath0.1.bat @@ -0,0 +1,122 @@ +@if (@X)==(@Y) @end /* JScript comment + @echo off + + set "file=%~f1" + set "xpath=%~2" + set "option=%~3" + set "node=%~4" + + if "%~2" equ "" ( + goto :printHelp + ) + + for %%# in ("-h" "-help" "/h" "/help" "") do ( + if /i "%~1" equ %%# ( + goto :printHelp + ) + ) + + if exist "%file%\" ( + echo file "%~1" does not exist + exit /b 3 + ) + if not exist "%file%" ( + echo file "%~1" does not exist + exit /b 4 + ) + + + cscript //E:JScript //nologo "%~f0" /file:"%file%" /xpath:"%xpath%" /option:"%option%" /node:%node% + + exit /b %errorlevel% + + :printHelp + echo %~nx0 prints the value (or list of values) + echo of xml attribute/node in xml by given xpath expression + echo( + echo Usage: + echo( + echo call %~nx0 "filePath" "xpathExpression" + exit /b %errorlevel% + +@if (@X)==(@Y) @end JScript comment */ + +if (WScript.Arguments.length<2) +{ + WScript.Echo("Not enough arguments"); + WScript.Quit(3); +} + + +function escapeRegExp(str) { + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); +} + +function replaceAll(str, find, replace) { + return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); +} + +var xp=WScript.Arguments.Named.Item("xpath"); +xp=replaceAll(xp,"'",'"'); + +var option=WScript.Arguments.Named.Item("option"); +var node_n=parseInt(WScript.Arguments.Named.Item("node")); + + +var objDoc; +var objNodes; +var loaded; + +try { + objDoc = WScript.CreateObject("MSXML.DOMDocument"); + loaded=objDoc.load(WScript.Arguments.Named.Item("file")); +} catch (err){ + WScript.Echo("Error while parsing the xml"); + WScript.Echo(err.message); + WScript.Quit(1); +} + +if(!loaded){ + WScript.Echo("Error while parsing the xml"); + WScript.Echo(""); + WScript.Echo("Error Code:"+objDoc.parseError.errorCode); + WScript.Echo(""); + WScript.Echo("Line:"+objDoc.parseError.line+" Posotion:"+objDoc.parseError.filepos); + WScript.Echo(""); + WScript.Echo("Reason:"+objDoc.parseError.reason); + WScript.Echo(""); + WScript.Echo("URL:"+objDoc.parseError.url); + WScript.Echo(""); + WScript.Echo(objDoc.parseError.srcText); + WScript.Quit(5); +} + +try { + var objNodes = objDoc.selectNodes(xp); +} catch (err){ + WScript.Echo("invalid xpath expression"); + WScript.Echo(err.message); + WScript.Quit(2); +} + +if(!isNaN(node_n)) { + if(node_n>=objNodes.length){ + WScript.Echo("Out of nodes range"); + WScript.Echo("Nodes length is: "+objNodes.length); + WScript.Quit(35); + } + if(option.toLowerCase()=="xml"){ + WScript.Echo(objNodes.item(node_n).xml); + } else { + WScript.Echo(objNodes.item(node_n).text); + } +} else { + for (var i=0;i Date: Mon, 26 Dec 2022 03:51:32 +0000 Subject: [PATCH 03/18] =?UTF-8?q?=E9=80=82=E5=BA=94=E5=A4=9A=E7=BA=BF?= =?UTF-8?q?=E7=A8=8B=E5=B9=B6=E5=8F=91=E8=B0=83=E6=95=B4=20*=20Merge=20bra?= =?UTF-8?q?nch=20'master'=20of=20gitee.com:ubml/ui-model=20into=20master?= =?UTF-8?q?=20*=20!2=20=E5=A4=9A=E7=BA=BF=E7=A8=8B=E5=8D=95=E4=BE=8B?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=EF=BC=8C=E5=8F=98=E9=87=8F=E5=8F=AF?= =?UTF-8?q?=E8=A7=81=E6=80=A7=E8=B0=83=E6=95=B4=20*=20=E5=8D=95=E4=BE=8B?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=A2=9E=E5=8A=A0volatile=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=A4=9A=E7=BA=BF=E7=A8=8B=20=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E5=86=85=E5=AD=98=E4=B8=8D=E5=8F=AF=E8=A7=81=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20*=20=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E7=89=88=E6=9C=AC=E4=B8=BA1.8=20*=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4api=E8=BF=94=E5=9B=9E=E5=80=BC=E7=BB=93=E6=9E=84=20*?= =?UTF-8?q?=20=E9=80=89=E4=BA=BA=E7=BB=84=E4=BB=B6=E5=92=8C=E9=80=89?= =?UTF-8?q?=E7=BB=84=E7=BB=87=E7=BB=84=E4=BB=B6=E6=8F=90=E5=8F=96title=20*?= =?UTF-8?q?=20=E8=B0=83=E6=95=B4pom=20*=20=E4=B8=8D=E5=BD=B1=E5=93=8D?= =?UTF-8?q?=E6=AD=A3=E5=B8=B8=E5=8A=9F=E8=83=BD=E8=BF=90=E8=A1=8C=E7=9A=84?= =?UTF-8?q?=E5=89=8D=E6=8F=90=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20*=20=E4=B8=8D=E5=BD=B1=E5=93=8D=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E5=8A=9F=E8=83=BD=E8=BF=90=E8=A1=8C=E7=9A=84=E5=89=8D?= =?UTF-8?q?=E6=8F=90=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20=E4=B8=8D=E5=BD=B1=E5=93=8D=E6=AD=A3=E5=B8=B8?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=BF=90=E8=A1=8C=E7=9A=84=E5=89=8D=E6=8F=90?= =?UTF-8?q?=E4=B8=8B=E8=BF=9B=E8=A1=8C=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20*=20=E4=B8=8D=E5=BD=B1=E5=93=8D=E6=AD=A3=E5=B8=B8=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E8=BF=90=E8=A1=8C=E7=9A=84=E5=89=8D=E6=8F=90=E4=B8=8B?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96=20*=20?= =?UTF-8?q?=E9=99=84=E4=BB=B6=E4=B8=8A=E4=BC=A0=E9=A2=84=E8=A7=88=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=80=BC=E6=94=AF=E6=8C=81=E5=9B=BD=E9=99=85=E5=8C=96?= =?UTF-8?q?=20*=20=E5=B8=AE=E5=8A=A9=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20=E5=B8=AE=E5=8A=A9=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=20*=20=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E8=BE=93=E5=87=BA=E7=AC=A6=E5=90=88=E8=A7=84=E8=8C=83=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=8F=90=E5=8F=96=E8=B7=AF=E5=BE=84=20*=20?= =?UTF-8?q?=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6=E5=8F=98=E6=9B=B4=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=A7=BB=E5=8A=A8=E8=A1=A8=E5=8D=95=20*=20=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E6=96=87=E4=BB=B6=E5=8F=98=E6=9B=B4=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E8=A1=A8=E5=8D=95=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=9B=BD=E9=99=85=E5=8C=96=E5=8F=82=E6=95=B0=E6=8F=90=E5=8F=96?= =?UTF-8?q?=20*=20=E5=90=88=E5=B9=B6=E4=BB=A3=E7=A0=81=20*=20Merge=20branc?= =?UTF-8?q?h=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4=E5=85=B3?= =?UTF-8?q?=E8=81=94=E5=85=83=E6=95=B0=E6=8D=AE=E5=90=8C=E6=AD=A5=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20*=20npm=20=20install=20=E5=A2=9E=E5=8A=A0legacy-pee?= =?UTF-8?q?r-dependency=20=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branc?= =?UTF-8?q?h=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96?= =?UTF-8?q?=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E9=80=82=E5=BA=94=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=20*=20Merge=20branch=20'Branch=5Fdev=5F?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B?= =?UTF-8?q?'=20into=20'dev'=20*=20=E8=AE=BE=E8=AE=A1=E6=97=B6=E9=9B=86?= =?UTF-8?q?=E6=88=90=E6=8E=88=E6=9D=83=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B'=20into=20'dev'=20*=20=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8E=88=E6=9D=83=E6=8E=A7=E5=88=B6=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20Merg?= =?UTF-8?q?e=20branch=20'dev'=20into=20Branch=5Fdev=5F=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B=20*=20Merge=20bra?= =?UTF-8?q?nch=20'dev-maf-authority'=20into=20'dev'=20*=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E8=A1=A8=E5=8D=95=E9=83=A8=E7=BD=B2=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E4=BA=A4=E4=BB=98=E7=89=A9=20*=20=E4=BF=9D=E5=AD=98=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=20*=20=E4=BF=AE=E6=94=B9pom=20*=20=E4=BB=85=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=20*=20Merge=20remote-tracking=20branch=20'origin'=20into=20dev?= =?UTF-8?q?-multiTenantMaf=20*=20=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=A4=9A=E7=A7=9F=E6=88=B7=20*=20=E5=90=88=E5=B9=B6=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E6=A0=BC=E5=BC=8F=E4=BB=A3=E7=A0=81=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=86=B2=E7=AA=81=20*=20insuite=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E6=97=B6=E7=A9=BA=E6=8C=87?= =?UTF-8?q?=E9=92=88=20*=20Merge=20branch=20'Branch=5Fdev=5F=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80=E6=B5=8B'=20into?= =?UTF-8?q?=20'dev'=20*=20=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=A1=A8=E8=BE=BE=E5=BC=8F=E9=83=A8=E7=BD=B2=20*=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E8=B0=83=E8=AF=95=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=A1=A8=E8=BE=BE=E5=BC=8F=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=AF=B9=E5=BA=94=E7=9A=84su=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=8E=A5=E5=8F=A3=20*=20=E6=97=A0=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=B5=81=E7=9B=B4=E6=8E=A5=E5=8F=91=E5=B8=83=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=20*=20=E5=88=A0=E9=99=A4we?= =?UTF-8?q?b=E6=9E=84=E4=BB=B6=EF=BC=8C=E7=BA=A7=E8=81=94=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=AF=B9=E5=BA=94=E7=9A=84ts=E6=96=87=E4=BB=B6=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=8E=AF=E5=A2=83=E6=A3=80=E6=9F=A5=20*=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?node=5Fmodules=E6=A3=80=E6=B5=8B=20*=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E6=A3=80=E6=9F=A5=20*=20Merge=20branch=20'Br?= =?UTF-8?q?anch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96?= =?UTF-8?q?=E6=A3=80=E6=B5=8B'=20into=20'dev'=20*=20Merge=20branch=20'dev'?= =?UTF-8?q?=20into=20Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B=20*=20=E6=9B=B4=E6=94=B9=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=85=83=E6=95=B0=E6=8D=AE=E4=BE=9D=E8=B5=96=E7=89=88?= =?UTF-8?q?=E6=9C=AC=20*=20typescipt=E4=BD=BF=E7=94=A8=E5=86=85=E7=BD=AE?= =?UTF-8?q?=20*=20Merge=20branch=20'bizfieldnew'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=8E=9F=E7=94=9F=E5=AD=97=E6=AE=B5=E9=80=82=E9=85=8D=20*=20ty?= =?UTF-8?q?pescript=E5=91=BD=E4=BB=A4=E5=86=85=E7=BD=AEserver=20*=20?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=B5=8C=E5=A5=97udt=20*=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20*=20=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=98=A0=E5=B0=84=E5=85=B3=E7=B3=BB=E6=94=B9?= =?UTF-8?q?=E9=80=A0=20*=20=E8=87=AA=E5=AE=9A=E4=B9=89=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=98=A0=E5=B0=84=E5=85=B3=E7=B3=BB=E6=94=B9?= =?UTF-8?q?=E9=80=A0=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E7=A7=BB=E9=99=A4Re?= =?UTF-8?q?fElementId=E5=AD=97=E6=AE=B5=20*=20Merge=20branch=20'Branch=5Fd?= =?UTF-8?q?ev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98=E5=8C=96=E6=A3=80?= =?UTF-8?q?=E6=B5=8B'=20into=20'dev'=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20'Branch=5Fdev=5F=E5=85=83=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E5=8C=96=E6=A3=80=E6=B5=8B'=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20?= =?UTF-8?q?=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20*=20=E4=BF=AE=E6=AD=A3=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E6=8D=95=E8=8E=B7=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=B5=81=E5=85=83=E6=95=B0=E6=8D=AE=E6=89=BE=E4=B8=8D?= =?UTF-8?q?=E5=88=B0=E5=BC=82=E5=B8=B8=EF=BC=8C=E4=BB=8E=E8=80=8C=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=88=9B=E5=BB=BA=E8=AF=A5=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E6=A3=80=E6=B5=8B=20*=20=E5=8F=98=E6=9B=B4=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20*=20=E4=BF=AE=E6=AD=A3=E7=89=88=E6=9C=AC=20*=20Merg?= =?UTF-8?q?e=20branch=20'bizfieldnew'=20into=20'dev'=20*=20pom,lib?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=20*=20Merge=20branch=20'Branch=5FBranch=5Fde?= =?UTF-8?q?v=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=8D=95=E8=8E=B7=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=BC=82=E5=B8=B8=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=8B=E5=A5=BD=E7=9A=84=E5=BC=82=E5=B8=B8=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5FBranch=5Fdev=5F=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A7=A3=E6=9E=90'=20into=20'dev'=20*=20=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E5=88=9D=E5=A7=8B=E7=8A=B6=E6=80=81=20*=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0pom=E7=89=88=E6=9C=AC=20*=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=88=A0=E9=99=A4=E7=9A=84=E9=A1=BA=E5=BA=8F?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5FBranch=5Fdev=5F=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A7=A3=E6=9E=90'=20into=20'dev'=20*=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9D=83=E9=99=90=E8=B0=83=E6=95=B4=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3?= =?UTF-8?q?=E6=9E=90'=20into=20'dev'=20*=20=E6=9B=B4=E6=96=B0pom=E7=89=88?= =?UTF-8?q?=E6=9C=AC=20*=20=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E7=9A=84=E8=BD=AC=E6=8D=A2=E6=88=90=E5=B0=8F=E5=86=99=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E6=88=96=E5=A4=A7=E5=86=99=E5=BD=A2=E5=BC=8F=E7=9A=84?= =?UTF-8?q?method=20*=20Merge=20branch=20'bizfieldnew'=20into=20'dev'=20*?= =?UTF-8?q?=20=E4=BC=98=E5=8C=96=E7=94=9F=E6=88=90id=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=98=A0=E5=B0=84=20*=20Merge=20branch=20'web=5Fmafsu=5Fpatch'?= =?UTF-8?q?=20into=20web=5Fapproveformat=5Fpatch0817=20*=20Merge=20branch?= =?UTF-8?q?=20'BizFieldPatchFile'=20into=20'dev'=20*=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=AD=97=E6=AE=B5=E6=98=A0=E5=B0=84=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=9B=B8=E5=90=8C?= =?UTF-8?q?=E6=AF=94=E8=BE=83=E7=9A=84=E6=96=B9=E6=B3=95=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E8=8E=B7=E5=8F=96=E8=BF=90=E8=A1=8C=E6=97=B6=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=9A=84=E6=96=B9=E6=B3=95=20*=20Merge=20bra?= =?UTF-8?q?nch=20'BizFieldPatchFile'=20into=20'dev'=20*=20=E8=A7=A3?= =?UTF-8?q?=E5=86=B3bug=EF=BC=9A=E9=9B=B6=E4=BB=A3=E7=A0=81=5F=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E8=AE=BE=E7=BD=AE=5F=E9=80=89=E6=8B=A9=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E5=AD=97=E6=AE=B5=E5=90=8E=E5=86=8D=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=BC=96=E5=8F=B7=EF=BC=8C=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E5=85=B3=E8=81=94=E5=AD=97=E6=AE=B5=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=20*=20=E8=A7=A3=E6=9E=90=E8=A1=A8=E5=8D=95=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E8=B7=AF=E5=BE=84=E8=B0=83=E6=95=B4=20*=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E8=A1=A8=E5=8D=95=E8=B0=83=E6=95=B4=20*=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E8=A1=A8=E5=8D=95=E8=B0=83=E6=95=B4=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A7=A3=E6=9E=90=E8=B0=83=E6=95=B4=20*=20=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E6=94=B9=E4=B8=BAinfo=E7=BA=A7=E5=88=AB=20*=20?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=8E=A5=E5=8F=A3=E7=9A=84=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=94=B9=E4=B8=BAinfo=E7=BA=A7=E5=88=AB=20*=20Merge=20branch?= =?UTF-8?q?=20'BizFieldPatchFile'=20into=20'dev'=20*=20=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E4=B8=9A=E5=8A=A1=E5=AD=97=E6=AE=B5=EF=BC=8Cvo?= =?UTF-8?q?=E8=BD=ACschema=20*=20Merge=20branch=20'dev'=20into=20Branch=5F?= =?UTF-8?q?Branch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0web-logger=E6=97=A5=E5=BF=97=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0web-logger=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E9=80=89=E9=A1=B9=20*=20=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=85=B1lo?= =?UTF-8?q?gger=20*=20=E9=9B=86=E6=88=90=E8=BF=87=E6=BB=A4=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=8F=96=E6=95=B0=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20Branch=5FBranch=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=20*=20Merge=20branch=20'Fix=5Fliyz'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=8E=A7=E5=88=B6=E5=8F=B0=E6=89=93=E5=8D=B0?= =?UTF-8?q?=20*=20=E8=B0=83=E6=95=B4=E8=84=9A=E6=9C=AC=E4=B8=8B=E8=BD=BDrp?= =?UTF-8?q?c=E6=9C=8D=E5=8A=A1=E5=BE=97applicationname=20*=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=88=86SU=E9=83=A8=E7=BD=B2=20*=20=E5=AF=B9eapi?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=5Fmaf=E5=90=8E=E7=BC=80=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E6=B5=8F=E8=A7=88=E5=99=A8=E6=97=A5=E5=BF=97=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20*=20=E7=9B=AE=E6=A0=87=E5=90=8D=E7=A7=B0=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E6=88=90=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch=5Fdev=5F?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E6=9B=B4=E6=96=B0rp?= =?UTF-8?q?c=20*=20=E6=9B=B4=E6=96=B0formurl=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E4=B8=8B=E8=BD=BDjs=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E6=8E=A5=E5=8F=A3=20*=20=E9=A2=84=E8=A7=88=E6=97=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0gspapprovalformat=E8=A1=A8=E7=9A=84formurl?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=20*=20=E7=BC=93=E5=AD=98=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20*=20scriptcache=E5=A2=9E=E5=8A=A0rpc?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E6=9C=8D=E5=8A=A1=20*=20html=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=E5=8F=82=E6=95=B0=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6-=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=8F=90=E5=8F=96=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=98=AF=E8=A7=A3=E6=9E=90-=E6=9E=84=E9=80=A0namespace?= =?UTF-8?q?=E5=92=8Cjit=E4=B8=80=E8=87=B4=20*=20=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E7=BB=84=E5=90=88=E8=A1=A8=E5=8D=95=E7=9A=84namespace=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20=E6=B8=85=E9=99=A4=E6=97=A0=E7=94=A8=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=20*=20=E4=BF=AE=E6=AD=A3=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=BF=94=E5=9B=9E=E5=80=BC=E7=BB=93=E6=9E=84=E4=B8=8D?= =?UTF-8?q?=E4=B8=80=E8=87=B4=E9=97=AE=E9=A2=98=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20npm=E9=85=8D=E7=BD=AE=E5=8F=82=E6=95=B0=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=A4=84=E7=90=86=20*=20=E5=B0=86=E6=98=8E=E6=96=87?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93=20*=20?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E6=96=B9=E6=A1=88=E5=8F=82=E6=95=B0=E6=8F=90?= =?UTF-8?q?=E5=8F=96=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch?= =?UTF-8?q?=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=8F=90=E5=8F=96=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=20*=20Merge=20remote-tracking=20branch=20'origin/approvalforma?= =?UTF-8?q?t-1224'=20into=20web=5Fapp=E2=80=A6=20*=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E4=BB=A5=E5=8F=8A=E5=BC=82=E5=B8=B8=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=20*=20Merge=20branch=20'dev'=20into=20Branch=5FBranch?= =?UTF-8?q?=5Fdev=5F=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E6=8F=90=E4=BE=9B=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E6=98=AF=E5=90=A6=E4=B8=BA=E8=A7=A3=E6=9E=90=E5=9E=8B?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E7=9A=84API=20*=20Merge=20remote-tracking=20?= =?UTF-8?q?branch=20'origin/dev'=20into=20dev=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E6=8F=90=E4=BE=9B=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E4=B8=BA=E8=A7=A3=E6=9E=90=E5=9E=8B=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=9A=84API=20*=20=E7=BB=84=E5=90=88=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E7=AB=8B=E5=8A=A0=E8=BD=BDjs=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E7=94=9F=E6=88=90=E5=AF=B9=E5=BA=94service=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20*=20=E7=A7=BB=E9=99=A4html=E6=A8=A1=E6=9D=BF?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=BC=95=E5=8F=B7=20*=20Merge=20branch=20'de?= =?UTF-8?q?v-nocode-ts'=20into=20'dev'=20*=20=E4=B8=9A=E5=8A=A1=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=B7=BB=E5=8A=A0=E5=A4=9A=E9=80=89=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=EF=BC=9B=E6=94=AF=E6=8C=81=E5=BC=95=E7=94=A8web=E6=9E=84?= =?UTF-8?q?=E4=BB=B6=E5=86=85ts=E4=BB=A3=E7=A0=81=20*=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?pom=20*=20=E7=BB=9F=E4=B8=80=E8=B0=83=E6=95=B4=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E7=89=88=E6=9C=AC=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E5=90=88=E5=B9=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20*=20=E5=85=83=E6=95=B0=E6=8D=AE=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=B8=85=E7=90=86=E4=BC=98=E5=8C=96=20*=20=E8=BF=98=E5=8E=9Fsq?= =?UTF-8?q?l=E4=BB=A3=E7=A0=81=20*=20=E8=BF=98=E5=8E=9Fapi=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20*=20=E5=88=A0=E9=99=A4=E6=A0=BC=E5=BC=8F=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=AE=8C=E5=96=84=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E8=A1=A8=E5=8D=95--=E8=B4=9F=E8=BD=BD=E5=9D=87?= =?UTF-8?q?=E8=A1=A1=E9=85=8D=E7=BD=AE=20*=20=E6=8F=90=E4=BA=A4=E4=BE=9D?= =?UTF-8?q?=E8=B5=96jar=E5=8C=85=20*=20Merge=20branch=20'Branch=5Fdev=5Fnp?= =?UTF-8?q?m'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=20*=20=E4=BF=AE=E6=AD=A3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=8C=B9=E9=85=8D=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20=E6=9B=B4=E6=96=B0pom?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E5=91=BD=E4=BB=A4=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=A0=E9=99=A4=E8=B0=83=E6=95=B4=20*=20Merge=20bra?= =?UTF-8?q?nch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0dbo=E7=BC=93=E5=AD=98=E6=B8=85=E7=90=86=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E8=B0=83=E6=95=B4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81url=E5=9C=B0=E5=9D=80=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=A2=9E=E5=8A=A0=E8=B4=9F=E8=BD=BD=E5=9D=87=E8=A1=A1?= =?UTF-8?q?=20*=20=E6=89=8B=E5=B7=A5vo=E4=B8=8D=E4=BF=AE=E6=94=B9viewmodel?= =?UTF-8?q?=E8=A1=A8=20*=20Merge=20branch=20'dev-lyz'=20into=20'dev'=20*?= =?UTF-8?q?=20=E6=B8=85=E7=90=86=E5=A4=9A=E4=BD=99=E7=9A=84=E8=BE=93?= =?UTF-8?q?=E5=87=BA=20*=20Merge=20branch=20'dev-jiwt-lookup'=20into=20'de?= =?UTF-8?q?v'=20*=20Merge=20branch=20'dev'=20into=20dev-jiwt-lookup=20*=20?= =?UTF-8?q?=E4=BA=BA=E5=91=98=E9=80=89=E6=8B=A9=E5=92=8C=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E7=BB=84=E4=BB=B6=E6=94=AF=E6=8C=81=E5=90=91?= =?UTF-8?q?VO=E5=90=8C=E6=AD=A5=E5=B8=AE=E5=8A=A9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E3=80=82=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20=E4=BF=AE=E6=AD=A3=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E4=B8=AD=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E7=9B=B8?= =?UTF-8?q?=E5=AF=B9=E8=B7=AF=E5=BE=84=E5=9C=B0=E5=9D=80=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20udt=E6=89=A9=E5=B1=95=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=88=B0schema=EF=BC=9A=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B5=8C=E5=A5=97udt=20*=20=E6=8F=90=E5=8F=96udt=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=BF=A1=E6=81=AF=EF=BC=8C=E7=94=9F=E6=88=90=E5=88=B0?= =?UTF-8?q?=E8=A1=A8=E5=8D=95schema=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E7=A7=BB=E9=99=A4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81bean=E9=85=8D=E7=BD=AE=E4=BB=A3=E7=A0=81=20*=20'?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=81=E7=A8=8B=E4=B8=AD=E5=BF=83=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E7=9A=84=E8=A1=A8=E5=8D=95=E7=9A=84=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=B5=81=E6=95=B0=E6=8D=AE'=20*=20Merge=20branch=20'Branch=5Fd?= =?UTF-8?q?ev=5Fnpm'=20into=20'dev'=20*=20=E5=A2=9E=E5=8A=A0listener?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=20*=20Merge=20branch=20'nocode/approve-forma?= =?UTF-8?q?t'=20into=20'dev'=20*=20PC=E8=A1=A8=E5=8D=95=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E9=85=8D=E7=BD=AE=E7=94=9F?= =?UTF-8?q?=E6=88=90=E4=BB=A3=E7=A0=81=E5=B9=B6=E7=BC=96=E8=AF=91=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge?= =?UTF-8?q?=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=E5=8F=82?= =?UTF-8?q?=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20=E5=A2=9E=E5=8A=A0=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E6=BA=90=E4=BB=A3=E7=A0=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E6=81=A2=E5=A4=8D=E6=96=B9=E6=B3=95=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=82=E6=95=B0=20*=20=E7=A7=BB=E9=99=A4=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BE=9D=E8=B5=96node=5Fmodules=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=EF=BC=8Cbabel=E7=BC=96=E8=AF=91=E5=A2=9E=E5=8A=A0isBabelCompil?= =?UTF-8?q?e=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'?= =?UTF-8?q?=20into=20'dev'=20*=20=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Br?= =?UTF-8?q?anch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E=E5=8A=A0=E5=8F=82=E6=95=B0?= =?UTF-8?q?=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=8F=82=E6=95=B0=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E4=BF=AE=E6=AD=A3=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E4=BE=9D=E8=B5=96=E5=A4=A7=E5=B0=8F=E5=86=99=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge?= =?UTF-8?q?=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=94=AF=E6=8C=81npm=E5=AE=89=E8=A3=85=20*?= =?UTF-8?q?=20Merge=20branch=20'nocode/isRuntime'=20into=20'dev'=20*=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9B=B6=E4=BB=A3=E7=A0=81=E8=8E=B7=E5=8F=96?= =?UTF-8?q?udt=E5=85=83=E6=95=B0=E6=8D=AE=E9=97=AE=E9=A2=98=EF=BC=9B?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9B=B6=E4=BB=A3=E7=A0=81schemaChangeListen?= =?UTF-8?q?er=20*=20=E5=88=9B=E5=BB=BAschema=E6=94=AF=E6=8C=81=E4=BC=A0?= =?UTF-8?q?=E9=80=92isRuntime=E5=8F=82=E6=95=B0=20*=20=E9=9B=B6=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=94=AF=E6=8C=81npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20=E5=85=BC=E5=AE=B9=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E7=BB=9D=E5=AF=B9=E8=B7=AF=E5=BE=84=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=20*=20=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A1=A8=E5=8D=95=E8=A7=A3=E6=9E=90=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4?= =?UTF-8?q?=20=E7=BA=A7=E8=81=94=E5=88=A0=E9=99=A4=20*=20Merge=20branch=20?= =?UTF-8?q?'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=A7=86=E5=9B=BE=E5=AF=B9=E8=B1=A1=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=20*=20pom?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=E7=BB=9F=E4=B8=80=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=20*=20=E5=A2=9E=E5=8A=A0=E7=A7=BB=E5=8A=A8npm?= =?UTF-8?q?=E5=8C=85=E5=88=A4=E6=96=AD=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20=E5=AF=B9=E5=85=B6dev=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=20*=20=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=85=B3=E9=97=AD=20*=20eapi=E5=8F=96=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E5=BC=80=E6=94=BEvoID=E5=8F=96=E6=95=B0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=20*=20vo=E5=8F=98=E5=8C=96=E5=90=8C=E6=AD=A5=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E8=A1=A8=E5=8D=95=20*=20npm=E5=8C=85=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=9B=B4=E6=96=B0=E8=A1=A5=E4=B8=81-=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9D=83=E9=99=90=E8=AE=BE=E7=BD=AE=20*=20web=20*=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=A1=A5=E4=B8=81=E9=9B=86=E6=88=90=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=20*=20=E5=A2=9E=E5=8A=A0=E5=A4=8D=E5=88=B6package.jso?= =?UTF-8?q?n=20=E6=93=8D=E4=BD=9C=20*=20Merge=20branch=20'Branch=5Fdev=5Fn?= =?UTF-8?q?pm'=20into=20'dev'=20*=20Merge=20branch=20'nocode/approve-forma?= =?UTF-8?q?t'=20into=20'dev'=20*=20=E5=85=A8=E5=B1=80=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E9=9B=86=E6=88=90=E8=87=AA=E5=8A=A8=E5=AE=89=E8=A3=85=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20?= =?UTF-8?q?'dev'=20*=20linux=20=E5=91=BD=E4=BB=A4=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90=20*=20linux=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E7=9B=AE=E5=BD=95=E5=A2=9E=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=20*=20=E4=BF=AE=E6=AD=A3npm=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=97=B6=E4=BC=9A=E5=87=BA=E7=8E=B0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=EF=BC=8C=E5=AF=BC=E8=87=B4=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=90=8D=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=8E=AF=E5=A2=83=E5=BC=82=E5=B8=B8=E9=80=80=E5=87=BA?= =?UTF-8?q?=E6=97=B6=E7=BB=A7=E7=BB=AD=E5=AE=89=E8=A3=85=20*=20npm?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0=E9=9B=86=E6=88=90=E8=A1=A5?= =?UTF-8?q?=E4=B8=81=E5=B7=A5=E5=85=B7=20*=20=E5=85=A8=E5=B1=80=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E4=BD=BF=E7=94=A8=E7=B3=BB=E7=BB=9F=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=20*=20=E6=8C=89=E5=AE=A1=E6=89=B9=E6=A0=BC=E5=BC=8F=E7=94=9F?= =?UTF-8?q?=E6=88=90=E3=80=81=E7=BC=96=E8=AF=91=E3=80=81=E9=83=A8=E7=BD=B2?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20br?= =?UTF-8?q?anch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'Branch=5Fde?= =?UTF-8?q?v=5Fnpm'=20into=20'dev'=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20npm=E5=AE=89=E8=A3=85=E6=8F=90=E4=BA=A4=20*=20M?= =?UTF-8?q?erge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20npm?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=AE=89=E8=A3=85pom?= =?UTF-8?q?=20*=20Merge=20branch=20'Branch=5Fdev=5F=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F'=20into=20'dev'=20*=20=E8=A1=A8=E8=BE=BE=E5=BC=8F?= =?UTF-8?q?=E6=8F=90=E5=8F=96=20*=20Merge=20branch=20'Branch=5F=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81'=20into=20'dev'=20*=20npm=20run=20command=20?= =?UTF-8?q?*=20Merge=20branch=20'Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81'=20i?= =?UTF-8?q?nto=20'dev'=20*=20Merge=20branch=20'dev'=20into=20Branch=5F?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E5=A2=9E=E5=8A=A0header?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=9B=BD=E9=99=85=E5=8C=96=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=8F=90=E5=8F=96=20*=20=E8=A1=A8=E8=BE=BE=E5=BC=8F=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E9=9B=86=E6=88=90=E5=A2=9E=E5=8A=A0messagetype?= =?UTF-8?q?=E3=80=81id=20*=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into?= =?UTF-8?q?=20'dev'=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Me?= =?UTF-8?q?rge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2ng=20build=E4=B8=BA=20npm=20run=20build=20*?= =?UTF-8?q?=20=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20Merge=20branch=20'Branch?= =?UTF-8?q?=5F=E9=9B=B6=E4=BB=A3=E7=A0=81'=20into=20'dev'=20*=20Merge=20br?= =?UTF-8?q?anch=20'dev'=20into=20Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81=20*?= =?UTF-8?q?=20Merge=20branch=20'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20M?= =?UTF-8?q?erge=20branch=20'Branch=5Fdev=5Fnpm'=20of=20https://git.iec.io/?= =?UTF-8?q?webadp/web=20into=20Br=E2=80=A6=20*=20Merge=20branch=20'dev'=20?= =?UTF-8?q?into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20'Branch=5Fdev=5Fnpm'=20*=20Merge=20branch=20'webdev0421'=20i?= =?UTF-8?q?nto=20'dev'=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=20*=20=E7=AC=AC=E4=B8=80=E7=BB=B4=E5=BA=A6=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E7=AC=AC=E4=BA=8C=E7=BB=B4=E5=BA=A6=E4=B8=8D=E4=B8=BA=E7=A9=BA?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=BF=94=E5=9B=9E=E5=85=AC=E6=9C=89=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81=E5=BC=80=E5=8F=91?= =?UTF-8?q?=20*=20FormProcessService=20*=20Merge=20branch=20'dev'=20into?= =?UTF-8?q?=20Branch=5F=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20npm=E5=AE=89=E8=A3=85=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=8C=85=E7=89=88=E6=9C=AC=E6=A3=80=E6=B5=8B=20*=20np?= =?UTF-8?q?m=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=B7=A8=E7=9B=98=E7=AC=A6=20*=20Merge=20bra?= =?UTF-8?q?nch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20?= =?UTF-8?q?'Branch=5Fdev=5Fnpm'=20into=20'dev'=20*=20Merge=20branch=20'dev?= =?UTF-8?q?'=20into=20Branch=5Fdev=5Fnpm=20*=20Merge=20branch=20'dev'=20in?= =?UTF-8?q?to=20'Branch=5Fdev=5Fnpm'=20*=20Merge=20branch=20'webdev0421'?= =?UTF-8?q?=20into=20'dev'=20*=20=E6=9F=A5=E6=89=BE=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BC=98=E5=8C=96=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20of=20ssh://git.iec.io:6060/webadp/web=20into=20webdev0421?= =?UTF-8?q?=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20Merge=20br?= =?UTF-8?q?anch=20'form-process'=20into=20'dev'=20*=20=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=8E=A8=E9=80=81=E5=88=B0=E6=B5=81=E7=A8=8B=EF=BC=88=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=A0=BC=E5=BC=8F=EF=BC=89=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E7=BB=93=E6=9E=84=E8=B0=83=E6=95=B4=20*=20jit?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B0=83=E6=95=B4=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'dev'=20of=20ssh://gi?= =?UTF-8?q?t.iec.io:6060/webadp/web=20into=20webdev0421=20*=20npm=E5=8C=85?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=9B=86=E6=88=90=E8=A1=A5=E4=B8=81=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=20*=20=E6=B3=A8=E9=87=8A=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20*=20=E4=BF=AE=E6=AD=A3=E8=B7=AF=E7=94=B1=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84=E6=96=87=E4=BB=B6=E5=90=8D=E7=A7=B0=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E9=85=8D=E7=BD=AE=20*=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=85=8D=E7=BD=AEconfiguration=20*=20?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=20*=20=E9=9B=B6=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=80=81=E7=BC=96=E8=AF=91=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E7=A7=BB=E5=8A=A8=E7=8B=AC=E7=AB=8B=E7=9A=84node=5Fmo?= =?UTF-8?q?dules=20*=20npm=20install=20=E5=A4=9A=E7=BA=BF=E7=A8=8B?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20*=20npm=E5=9C=A8=E7=BA=BF=E5=AE=89?= =?UTF-8?q?=E8=A3=85=20*=20package.json=E6=96=87=E4=BB=B6=20*=20Merge=20br?= =?UTF-8?q?anch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E5=AE=89=E8=A3=85=E5=8C=85=20*=20=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E7=94=9F=E6=88=90UDT=20schema=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=97=B6=EF=BC=8CTypeContext=E9=83=BD=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E4=B8=BAisRuntime:true=20*=20=E6=9F=A5=E8=AF=A2sql=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20scriptcache=E6=94=AF=E6=8C=81oracle=2010g=20*?= =?UTF-8?q?=20Merge=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*=20?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=89=A7=E8=A1=8Ccommand=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=8E=B7=E5=8F=96=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E8=B7=AF=E5=BE=84=E5=8F=8D=E6=96=9C=E7=BA=BF=20*=20Me?= =?UTF-8?q?rge=20branch=20'dev'=20of=20ssh://git.iec.io:6060/webadp/web=20?= =?UTF-8?q?into=20webdev0421=20*=20npm=20install=20=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=88=90=E4=B8=BA=E5=8D=95=E7=8B=AC=E7=9A=84?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=89=A7=E8=A1=8C=20*=20=E6=94=AF=E6=8C=81np?= =?UTF-8?q?m=E5=8C=85=E5=AE=89=E8=A3=85=20*=20npm=20install=20*=20npm=20?= =?UTF-8?q?=E9=9B=86=E6=88=90=E5=AE=89=E8=A3=85=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20Branch=5Fdev=5Fnpm=20*=20npm=E5=9C=A8=E7=BA=BF?= =?UTF-8?q?=E5=AE=89=E8=A3=85=20*=20=E8=AE=BE=E8=AE=A1=E6=97=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81linux=E9=83=A8=E7=BD=B2=20*=20Merge=20branch=20'dev'?= =?UTF-8?q?=20of=20ssh://git.iec.io:6060/webadp/web=20into=20webdev0421=20?= =?UTF-8?q?*=20=E8=B0=83=E6=95=B4command=E6=89=A7=E8=A1=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BD=8D=E7=BD=AE=E8=87=B3common=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=20*=20Merge=20branch=20'dev'=20into=20Branch=5Fdev=5Fnpm=20*?= =?UTF-8?q?=20npm=E5=AE=89=E8=A3=85=20*=20=E6=97=A0=E6=95=88=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=96=87=E4=BB=B6=E6=B8=85=E7=90=86=20*=20=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=E6=94=AF=E6=8C=81linux=20=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F=20*=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E3=80=81=E9=A2=84=E8=A7=88url=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E8=BD=AC=E5=B0=8F=E5=86=99=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6?= =?UTF-8?q?=E5=AE=9A=E5=88=B6=E7=8A=B6=E6=80=81=E6=9C=BA=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20*=20=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=B7=A5=E5=85=B7=E7=9B=AE=E5=BD=95=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E6=94=AF=E6=8C=81=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E5=B7=A5=E5=85=B7=E8=B7=AF=E5=BE=84=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20pom=E8=B0=83=E6=95=B4=20*=20=E8=AF=BB=E5=8F=96=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=B8=BA=E7=A9=BA=E6=97=B6=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=BC=82=E5=B8=B8=E6=8A=9B=E5=87=BA=EF=BC=8C=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E5=AF=B9=E5=90=8E=E7=BB=AD=E6=93=8D=E4=BD=9C=E7=9A=84?= =?UTF-8?q?=E5=BD=B1=E5=93=8D=20*=20pom=E6=8F=90=E4=BA=A4jar=E5=8C=85?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E8=B0=83=E6=95=B4=20*=20=E8=B0=83=E6=95=B4ap?= =?UTF-8?q?i=E7=BC=96=E8=BE=91=E7=9A=84jar=E5=8C=85version=EF=BC=8C?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E7=9A=84jar=E5=8C=85=E7=A7=BB=E9=99=A4snapsh?= =?UTF-8?q?ot=20*=20=E4=BB=A3=E7=A0=81=E6=97=A0=E6=95=88=E5=BC=95=E5=85=A5?= =?UTF-8?q?=E6=B8=85=E9=99=A4=20*=20Merge=20branch=20'dev'=20of=20ssh://gi?= =?UTF-8?q?t.iec.io:6060/webadp/web=20into=20webdev0421=20*=20=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6service?= =?UTF-8?q?=E6=8B=B7=E8=B4=9D=20*=20Merge=20branch=20'dev'=20into=20'maste?= =?UTF-8?q?r'=20*=20=E8=B5=84=E6=BA=90=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E7=AD=96=E7=95=A5=20*=20=E8=8E=B7=E5=8F=96=E5=A4=9A=E8=AF=AD?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=8F=96=E6=B6=88=E5=BC=82=E5=B8=B8=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=EF=BC=8C=E7=9B=B4=E6=8E=A5=E6=8A=9B=E5=87=BA=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E4=BF=A1=E6=81=AF=20*=20bindingField=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=B8=BAnull=E5=88=A4=E6=96=AD=20*=20=E5=B0=86?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=A7=A3=E6=9E=90=E8=B0=83=E6=95=B4=E6=88=90?= =?UTF-8?q?code=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=20*=20Merge=20branch=20'dev'=20of?= =?UTF-8?q?=20https://git.iec.io/webadp/web=20into=20dev=20*=20=E8=BF=90?= =?UTF-8?q?=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E6=94=AF=E6=8C=81babel?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20=E5=88=9B=E5=BB=BAbindingField?= =?UTF-8?q?=E6=97=B6=E6=A3=80=E6=9F=A5=E4=B8=8A=E7=BA=A7bindingField?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20of=20https://git.iec.io/webadp/web=20into=20dev=20*=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6?= =?UTF-8?q?=E5=AE=8C=E5=96=84=20*=20j=E7=89=88=E5=BC=82=E5=B8=B8=E6=8D=95?= =?UTF-8?q?=E8=8E=B7=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E6=95=88=E4=BB=A3=E7=A0=81=20*=20=E4=BF=AE=E6=AD=A3java?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=B8=8D=E7=AC=A6=E5=90=88=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E5=86=99=E9=97=AE=E9=A2=98=20*=20Merge=20bra?= =?UTF-8?q?nch=20'dev'=20of=20https://git.iec.io/webadp/web=20into=20dev?= =?UTF-8?q?=20*=20j=E7=89=88=E4=BB=A3=E7=A0=81=E6=96=B9=E6=B3=95=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=86=99=E8=B0=83=E6=95=B4=20*=20Merge=20branch=20'de?= =?UTF-8?q?v'=20into=20'master'=20*=20fieldbuilder=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E5=B0=8F=E5=86=99=E5=BD=A2=E5=BC=8F?= =?UTF-8?q?=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E7=94=9F=E6=88=90UDT=20schem?= =?UTF-8?q?a=E4=BF=A1=E6=81=AF=E6=97=B6=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E8=8E=B7=E5=8F=96=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=8E=A5=E5=8F=A3=20*=20utility=20=20commit=20*=20bas?= =?UTF-8?q?e64=E5=8A=A0=E5=AF=86=E6=B5=8B=E8=AF=95=20*=20Merge=20branch=20?= =?UTF-8?q?'master'=20of=20ssh://git.iec.io:6060/webadp/web=20*=20base64?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0utf8=E8=AE=BE=E7=BD=AE=20*=20=E9=80=82?= =?UTF-8?q?=E5=BA=94localhost=E6=9B=B4=E6=94=B9=20*=20eapi=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E8=B0=83=E6=95=B4=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=88=90=E4=B8=BA=E9=A6=96=E5=AD=97=E6=AF=8D=E5=A4=A7=E5=86=99?= =?UTF-8?q?=E5=BD=A2=E5=BC=8F=20*=20=E8=A1=A8=E5=8D=95=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20=E5=A2=9E=E5=8A=A0=E7=BC=BA=E5=A4=B1class=20*=20?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=A7=84=E8=8C=83=E8=B0=83=E6=95=B4=20*=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6master=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9docker=E9=83=A8=E7=BD=B2=EF=BC=8Cformurl=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=B0=83=E6=95=B4=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9docker=E9=83=A8=E7=BD=B2=E7=9B=B8=E5=85=B3=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=9A=E5=B7=A5=E7=A8=8B=E5=90=8D=EF=BC=8C=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=96=87=E4=BB=B6=E5=90=8D=E6=9B=B4=E6=94=B9=20*=20Me?= =?UTF-8?q?rge=20branch=20'master'=20of=20https://git.iec.io/webadp/web=20?= =?UTF-8?q?*=20=E8=A1=A8=E5=8D=95=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9A=E8=AF=AD=20*=20=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=94=AF=E6=8C=81docker=E9=83=A8=E7=BD=B2=20*=20Merge=20branch?= =?UTF-8?q?=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20*=20?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9=E6=94=AF=E6=8C=81docker=20?= =?UTF-8?q?*=20Merge=20branch=20'b3580'=20into=20'master'=20*=20ts?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=AF=BB=E5=8F=96=E8=B7=AF=E5=BE=84=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20ts=E6=96=87=E4=BB=B6=E4=B9=B1=E7=A0=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=A4=84=E7=90=86=20*=20=E8=A1=A8=E5=8D=95module?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E5=A2=9E=E5=8A=A0=20*=20Merge=20branch=20'ma?= =?UTF-8?q?ster'=20of=20https://git.iec.io/webadp/web=20*=20ts=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86?= =?UTF-8?q?=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81=E7=A7=BB=E9=99=A4=E7=BB=9D?= =?UTF-8?q?=E5=AF=B9=E8=B7=AF=E5=BE=84=20*=20Merge=20branch=20'master'=20o?= =?UTF-8?q?f=20ssh://git.iec.io:6060/webadp/web=20into=20b3580=20*=20?= =?UTF-8?q?=E7=BB=B4=E5=BA=A6=E7=BC=96=E5=8F=B7=E8=BD=AC=E6=8D=A2=E4=B8=BA?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20Merge=20branch=20'master'=20of=20ssh://git.iec.io:60?= =?UTF-8?q?60/webadp/web=20into=20b3580=20*=20=E8=8E=B7=E5=8F=96=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81=E8=B7=A8SU=20*=20?= =?UTF-8?q?Merge=20branch=20'b3580'=20into=20'master'=20*=20=E5=B8=AE?= =?UTF-8?q?=E5=8A=A9=E6=9B=B4=E6=96=B0vo=20=20helpid=E5=8F=8C=E5=BC=95?= =?UTF-8?q?=E5=8F=B7=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86=20*=20Merge=20bra?= =?UTF-8?q?nch=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20into?= =?UTF-8?q?=20b3580=20*=20toout.bat=E4=BF=AE=E6=94=B9=20*=20=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E5=AE=A1=E6=89=B9=E9=A2=84=E8=A7=88=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E8=A1=A5=E5=85=A8=20*=20=E7=A7=BB=E5=8A=A8=E5=AE=A1=E6=89=B9po?= =?UTF-8?q?pm=E4=BF=AE=E6=94=B9=20*=20Merge=20branch=20'master'=20of=20htt?= =?UTF-8?q?ps://git.iec.io/webadp/web=20*=20schema=20=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20*=20Merge=20branch=20'b3580'=20into=20'mas?= =?UTF-8?q?ter'=20*=20=E8=B0=83=E6=95=B4=E4=BE=9D=E8=B5=96=20*=20Merge=20b?= =?UTF-8?q?ranch=20'master'=20of=20ssh://git.iec.io:6060/webadp/web=20into?= =?UTF-8?q?=20b3580=20*=20=E7=AD=BE=E5=85=A5=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E5=B7=A5=E7=A8=8B=20*=20Merge=20branch=20'F=5FWeb=5FF?= =?UTF-8?q?ormDel'=20into=20'master'=20*=20=E5=88=A0=E9=99=A4=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9B=B4=E6=96=B0=E9=A1=B5=E9=9D=A2=E6=B5=81=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=9F=A5=E6=89=BE=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E8=B7=AF=E5=BE=84=E7=9A=84=E6=96=B9=E6=B3=95?= =?UTF-8?q?=20*=20=E6=9B=B4=E6=96=B0=E7=BC=93=E5=AD=98code=20*=20=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E4=BF=AE=E6=94=B9=20*=20=E5=90=8C=E6=AD=A5sc?= =?UTF-8?q?hema=E6=9B=B4=E6=94=B9=20*=20Merge=20branch=20'webdev'=20into?= =?UTF-8?q?=20'master'=20*=20=E8=8E=B7=E5=8F=96=E6=96=87=E4=BB=B6=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=92=8C=E6=96=87=E4=BB=B6=E5=90=8D=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E8=8E=B7=E5=8F=96=E5=AE=89=E8=A3=85=E7=9B=98=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E9=97=AE=E9=A2=98=E4=BF=AE=E6=AD=A3=20*=20=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BC=A0=E8=BE=93=E5=BA=8F=E5=88=97=E5=8C=96?= =?UTF-8?q?=E5=99=A8=E8=B0=83=E6=95=B4=20*=20=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B1=9E=E6=80=A7=E6=A0=87=E8=AF=86=20*=20j?= =?UTF-8?q?=E7=89=88=E8=A1=A8=E5=8D=95schema=E5=90=8C=E6=AD=A5=20*=20Merge?= =?UTF-8?q?=20branch=20'webdev'=20into=20'master'=20*=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E8=8E=B7=E5=8F=96VO=E5=85=83=E6=95=B0=E6=8D=AE=E5=92=8C?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E5=85=83=E6=95=B0=E6=8D=AE=E7=9A=84?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E3=80=82=20*=20=E8=A1=A8=E5=8D=95=E5=8F=A6?= =?UTF-8?q?=E5=AD=98=E4=B8=BA=20*=20Merge=20branch=20'webdev'=20into=20'ma?= =?UTF-8?q?ster'=20*=20Merge=20branch=20'master'=20into=20'webdev'=20*=201?= =?UTF-8?q?.stateMachineId=202.TypeScriptFile=20Path=20*=201.stateMachineI?= =?UTF-8?q?d=202.TypeScriptFile=20Path=20*=201.stateMachineId=202.TypeScri?= =?UTF-8?q?ptFile=20Path=20*=20N=E8=BD=ACJ=E5=90=8C=E6=AD=A5=20*=201.?= =?UTF-8?q?=E8=A1=A8=E5=8D=95=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=202.=E5=85=83=E6=95=B0=E6=8D=AE=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E6=89=A9=E5=B1=95=203.=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E9=A2=84=E8=A7=88=E7=BC=96=E8=AF=91=E6=8C=87=E5=AE=9A=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=20*=20=E4=B8=AD=E6=96=87=E8=B5=84=E6=BA=90=E9=A1=B9?= =?UTF-8?q?=E7=94=9F=E6=88=90=20*=20=E8=A1=A8=E5=8D=95=E9=A2=84=E8=A7=88--?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E9=83=A8=E7=BD=B2=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20*=20=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A=E5=88=B6=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E6=8F=90=E4=BA=A4=20*=20=E5=90=91=E5=AF=BC?= =?UTF-8?q?=E5=88=9B=E5=BB=BAschema=20=20editor=E5=B1=9E=E6=80=A7=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E5=A2=9E=E5=8A=A0=E7=A7=BB=E5=8A=A8=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E9=A2=84=E8=A7=88=E5=B7=A5=E7=A8=8B=20*=20n=E8=BD=ACj?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=20*=20N=E8=BD=ACJ=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=20*=20=E8=B7=AF=E5=BE=84=E4=BF=AE=E6=94=B9=20*=20java=E7=BC=96?= =?UTF-8?q?=E8=AF=91=20*=20Merge=20branch=20'master'=20of=20https://git.ie?= =?UTF-8?q?c.io/zhangweiqing/web=20*=20jar=E5=8C=85=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20*=20Merge=20branch=20'master'=20of=20https?= =?UTF-8?q?://git.iec.io/zhangweiqing/web=20into=20master=20*=20=E5=8E=BB?= =?UTF-8?q?=E6=8E=89System.out.println=20*=20j=E7=89=88=E7=BC=96=E8=AF=91?= =?UTF-8?q?=20*=20Merge=20branch=20'master'=20of=20https://git.iec.io/zhan?= =?UTF-8?q?gweiqing/web=20*=20=E7=BC=96=E8=AF=91=E6=8F=90=E4=BA=A4=20*=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0spring.factories=E6=96=87=E4=BB=B6=20*=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3ide=E6=8F=92=E4=BB=B6=E7=9A=84url=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=EF=BC=8C=E7=BC=BA=E5=B0=91index.html=E7=9A=84?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E7=94=A8=E6=89=80=E5=9C=A8=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E6=8B=BC=E8=A3=85=E8=B7=AF=E5=BE=84=20*=20N=E8=BD=ACJ=E8=B0=83?= =?UTF-8?q?=E8=AF=95&=E5=91=BD=E5=90=8D=E8=B0=83=E6=95=B4=20*=20Merge=20br?= =?UTF-8?q?anch=20'master'=20of=20https://git.iec.io/zhangweiqing/web=20*?= =?UTF-8?q?=20=E8=BF=81=E7=A7=BB=E8=BF=90=E8=A1=8C=E6=97=B6=E5=AE=9A?= =?UTF-8?q?=E5=88=B6java=20*=20sourcecode=20metadata=20serializer=20*=20?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9C=BA=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=EF=BC=9B=E5=85=AC=E5=85=B1?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=B7=A5=E5=85=B7=20*=20ide?= =?UTF-8?q?=E8=AF=BB=E6=96=87=E4=BB=B6=EF=BC=9B=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E3=80=81=E9=A1=B5=E9=9D=A2=E6=B5=81=20*=20pom=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=8F=90=E4=BA=A4=20*=20appconfig=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20=E7=BC=96=E8=AF=91=E6=8F=90=E4=BA=A4=20*=20Merg?= =?UTF-8?q?e=20branch=20'master'=20of=20https://git.iec.io/zhangweiqing/we?= =?UTF-8?q?b=20*=20=E4=BF=AE=E6=94=B9=20*=20=E7=8A=B6=E6=80=81=E6=9C=BA?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E3=80=81ide=E5=91=BD=E5=90=8D?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=E6=94=B9=E5=90=8D=20*=20IDE=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E3=80=81TS=E4=BB=A3=E7=A0=81=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=AB=AF=E3=80=81=E7=8A=B6=E6=80=81=E6=9C=BA=E5=85=83?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=20*=20Merge=20branch=20'master'=20of=20https?= =?UTF-8?q?://git.iec.io/zhangweiqing/web=20*=20=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20=E6=B7=BB=E5=8A=A0toout.bat=20*=20pom?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=8F=90=E4=BA=A4=20*=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=20*=20common=E7=BC=96=E8=AF=91=20*=20common=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E7=BC=96=E8=AF=91=20*=20common=E5=B7=A5=E7=A8=8B=E8=B0=83?= =?UTF-8?q?=E6=95=B4=20*=20common=E5=B7=A5=E7=A8=8B=E7=BC=96=E8=AF=91=20*?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A=20*=20N=E7=89=88?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E8=BD=ACJ=E7=89=88=20*=20add=20restproject?= =?UTF-8?q?=20*=20form=20i18n=20*=20add=20web-form-jitengine=20*=20add=20w?= =?UTF-8?q?eb-frontendproject=20*=20add=20web-appconfig=20*=20add=20web-pa?= =?UTF-8?q?geflow-metadata=20*=20add=20web-sourcecode-metadata=20*=20?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8Dformmetadata=20*=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0webcomponent-api=20*=20init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inspur/edp/web/common/serialize/SerializeUtility.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java index 1613b45c..4219f71e 100644 --- a/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java +++ b/web-common/src/main/java/com/inspur/edp/web/common/serialize/SerializeUtility.java @@ -24,7 +24,10 @@ public class SerializeUtility { defaultObjectMapper = this.createDefaultObjectMapper(); } - private static SerializeUtility serializeUtilityInstance = null; + /** + * 增加volatile的作用是为了避免多线程访问时,导致变量不一致问题 + */ + private volatile static SerializeUtility serializeUtilityInstance = null; public static SerializeUtility getInstance() { if (Objects.isNull(serializeUtilityInstance)) { -- Gitee From 9b8e3984189f4b1bd44a6dfa73f585e41b50bdbf Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Sun, 1 Jan 2023 08:03:11 +0000 Subject: [PATCH 04/18] =?UTF-8?q?web=E5=91=BD=E4=BB=A4npm=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=E5=99=A8=EF=BC=8C=E9=81=BF=E5=85=8D=E5=91=BD=E4=BB=A4=E6=89=80?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E7=A8=8B=E5=BC=82=E5=B8=B8=E7=BB=88=E6=AD=A2?= =?UTF-8?q?=20*=20=E5=BC=82=E5=B8=B8=E6=8D=95=E8=8E=B7=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E8=BE=93=E5=87=BA=20*=20web=20npm=E5=91=BD=E4=BB=A4=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E5=A2=9E=E5=8A=A0=E5=BC=82=E5=B8=B8=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edp/web/common/entity/ResultCode.java | 17 ++++++++++++++++ .../web/common/entity/ResultMessageData.java | 12 +++++++++++ .../common/utility/CommandLineUtility.java | 5 +++++ .../WebThreadUncaughtExceptionHandler.java | 20 +++++++++++++++++++ .../FrontendProjectManager.java | 2 +- 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessageData.java create mode 100644 web-common/src/main/java/com/inspur/edp/web/common/utility/WebThreadUncaughtExceptionHandler.java diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java index d7237d40..96146aaf 100644 --- a/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultCode.java @@ -32,15 +32,32 @@ public class ResultCode { return FailureCode; } + /** + * 不包含data参数 只有一个成功标识 + * @return + * @param + */ public static ResultMessage success() { return new ResultMessage<>(SuccessCode, ""); } + public static ResultMessage success(T data) { + return new ResultMessage<>(SuccessCode, "", data); + } + public static ResultMessage failure(String errorMessage) { return new ResultMessage<>(FailureCode, errorMessage); } + public static ResultMessage failure(String errorMessage, T data) { + return new ResultMessage<>(FailureCode, errorMessage, data); + } + public static ResultMessage custom(Integer code, String errorMessage) { return new ResultMessage<>(code, errorMessage); } + + public static ResultMessage custom(Integer code, String errorMessage, T data) { + return new ResultMessage<>(code, errorMessage, data); + } } diff --git a/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessageData.java b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessageData.java new file mode 100644 index 00000000..3304192a --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/entity/ResultMessageData.java @@ -0,0 +1,12 @@ +package com.inspur.edp.web.common.entity; + +import java.io.Serializable; + +/** + * 响应参数值定义 可以根据需要继承该类来实现数据的基类定义 + * 主要是为了避免返回值数据无共同基类情况 + */ +public class ResultMessageData implements Serializable { + private static final long serialVersionUID = 1L; + +} diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java index a7871741..9016e50a 100644 --- a/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/CommandLineUtility.java @@ -93,6 +93,11 @@ public class CommandLineUtility { CommandExecuteInterceptor errorCommandInterceptor = new CommandExecuteInterceptor(process.getErrorStream(), errorSB, true); CommandExecuteInterceptor inputCommandInterceptor = new CommandExecuteInterceptor(process.getInputStream(), errorSB, false); + + // 设置配置子线程的异常捕获器 不能进行全局线程异常捕获,会影响其他线程的异常抛出,只限定当前启动的线程异常信息 + errorCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler()); + inputCommandInterceptor.setUncaughtExceptionHandler(new WebThreadUncaughtExceptionHandler()); + errorCommandInterceptor.start(); inputCommandInterceptor.start(); diff --git a/web-common/src/main/java/com/inspur/edp/web/common/utility/WebThreadUncaughtExceptionHandler.java b/web-common/src/main/java/com/inspur/edp/web/common/utility/WebThreadUncaughtExceptionHandler.java new file mode 100644 index 00000000..18ade45b --- /dev/null +++ b/web-common/src/main/java/com/inspur/edp/web/common/utility/WebThreadUncaughtExceptionHandler.java @@ -0,0 +1,20 @@ +package com.inspur.edp.web.common.utility; + +import com.inspur.edp.web.common.logger.WebLogger; + +import java.util.Arrays; + +/** + * 配置web自定义线程异常捕获 避免出现未知未捕获异常导致线程终止 + * 子线程捕获到异常,写入到日志文件,不再对外抛出异常 + * + * @author guozhiqi + */ +public class WebThreadUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + if (thread != null && throwable != null) { + WebLogger.Instance.error("Web命令执行出现异常,对应线程名称" + thread.getName() +"异常信息"+ throwable.getMessage() + Arrays.toString(throwable.getStackTrace()), this.getClass().getName()); + } + } +} diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java index acdbadf1..98a14705 100644 --- a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/FrontendProjectManager.java @@ -62,7 +62,7 @@ public class FrontendProjectManager { // 执行代码编译 FrontendProjectBuild.buildFrontendProject(projectPath, false); - return ResultCode.success(); + return ResultCode.success(); } -- Gitee From c006e190992baafd434591d4b34aedf839df046e Mon Sep 17 00:00:00 2001 From: Sagi Date: Mon, 9 Jan 2023 15:38:36 +0000 Subject: [PATCH 05/18] add LICENSE. Signed-off-by: Sagi --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..29f81d81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -- Gitee From 1066aed384399695f7f8aa7ac82615a2610cc1ef Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 12 Jan 2023 06:49:11 +0000 Subject: [PATCH 06/18] update README.md. Signed-off-by: guozhiqi --- README.md | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e03e2235..cf13806a 100644 --- a/README.md +++ b/README.md @@ -3,35 +3,7 @@ #### 介绍 前端UI模型。 -#### 软件架构 -软件架构说明 +支撑设计器的后端交互; +支持脚本负载同步; -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) -- Gitee From fb3ade8d2be176154c1a755ad9c397b37f0fbf80 Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 16 Feb 2023 02:19:20 +0000 Subject: [PATCH 07/18] add LICENSE. Signed-off-by: guozhiqi --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..29f81d81 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -- Gitee From 7e54a60030800b6a5607bbe6756ebc589f76b59f Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 16 Feb 2023 09:21:00 +0000 Subject: [PATCH 08/18] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20we?= =?UTF-8?q?b-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/?= =?UTF-8?q?package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edp/web/common/io/sourcefile/package.json | 212 ------------------ 1 file changed, 212 deletions(-) delete mode 100644 web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json diff --git a/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json b/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json deleted file mode 100644 index d74c41ca..00000000 --- a/web-common/src/test/java/com/inspur/edp/web/common/io/sourcefile/package.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "name": "@farris/jit-engine", - "version": "0.0.1", - "description": "npm auto install", - "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" - }, - "keywords": [ - "node_modules" - ], - "author": "Noah", - "license": "ISC1", - "dependencies": { - "@angular-devkit/core": "7.3.9", - "@angular/compiler-cli": "7.2.15", - "@angular/common": "7.2.13", - "@angular/core": "7.2.13", - "@angular/forms": "7.2.13", - "@angular/router": "7.2.13", - "@ant-design/icons-angular": "2.1.0", - "@ecp-caf/caf-common": "^2.0.5", - "@edp-aif/common-api": "^0.6.1", - "@edp-aif/runtime-api": "^0.6.0", - "@edp-bif/common-api": "^0.7.1", - "@edp-bif/runtime-api": "^0.7.2", - "@farris/bef": "0.0.12-20210428112135-dev", - "@farris/command-services": "0.0.12-20210508093120-dev", - "@farris/component-querycondition": "^0.1.46", - "@farris/devkit": "0.0.12-20210428112050-dev", - "@farris/discussion-group": "0.0.22", - "@farris/dynamic-control-group": "^0.1.11", - "@farris/extend-file-upload": "^0.1.9", - "@farris/extend-fileupload-adapt-unifile": "^0.1.4", - "@farris/farris-rollup": "^1.0.80", - "@farris/header-group-editor": "0.0.15", - "@farris/ide-devkit": "^1.0.33", - "@farris/ide-enum-editor": "0.0.3", - "@farris/ide-publish-menu": "0.0.17", - "@farris/kendo-binding": "0.0.12-20210428112252-dev", - "@farris/mobile-bef": "0.0.6", - "@farris/mobile-business-ui": "0.0.27", - "@farris/mobile-cli": "latest", - "@farris/mobile-command-services": "0.0.16", - "@farris/mobile-devkit": "0.0.5", - "@farris/mobile-ui": "0.0.19", - "@farris/mobile-vue-adapter": "0.0.10", - "@farris/tags": "0.0.9", - "@farris/ui-area-response": "0.0.2", - "@farris/ui-avatar": "0.0.17", - "@farris/ui-batch-edit-dialog": "0.0.12", - "@farris/ui-button": "0.0.16", - "@farris/ui-calculator": "0.0.1", - "@farris/ui-calendar": "0.0.5", - "@farris/ui-combo-list": "^0.1.37", - "@farris/ui-combo-lookup": "^0.1.21", - "@farris/ui-common": "^0.2.6", - "@farris/ui-datagrid": "^0.8.21", - "@farris/ui-datagrid-editors": "^0.2.43", - "@farris/ui-datagrid-filter": "0.0.15", - "@farris/ui-datagrid-settings": "0.0.16", - "@farris/ui-datalist": "0.0.16", - "@farris/ui-datatable": "^0.1.25", - "@farris/ui-datepicker": "^0.3.7", - "@farris/ui-dialog": "0.0.13", - "@farris/ui-draggable": "0.0.4", - "@farris/ui-dropdown": "0.0.12", - "@farris/ui-editor": "0.0.10", - "@farris/ui-enum-editor": "0.0.3", - "@farris/ui-field-group": "0.0.21", - "@farris/ui-filter": "0.0.8", - "@farris/ui-filter-editor": "^0.1.15", - "@farris/ui-filter-panel": "0.0.10", - "@farris/ui-flex-layout": "0.0.3", - "@farris/ui-footer": "0.0.2", - "@farris/ui-forms": "0.0.35", - "@farris/ui-html-editor": "0.0.23", - "@farris/ui-input-group": "^0.2.5", - "@farris/ui-language-textbox": "^0.1.14", - "@farris/ui-layout": "0.0.6", - "@farris/ui-list-filter": "0.0.63", - "@farris/ui-list-nav": "0.0.12", - "@farris/ui-list-view": "0.0.26", - "@farris/ui-loading": "^0.1.9", - "@farris/ui-locale": "0.2.12", - "@farris/ui-lookup": "^0.4.7", - "@farris/ui-messager": "^0.2.10", - "@farris/ui-modal": "^0.1.3", - "@farris/ui-multi-select": "^0.2.1", - "@farris/ui-nav": "0.0.4", - "@farris/ui-notify": "^0.1.6", - "@farris/ui-number-spinner": "^0.2.32", - "@farris/ui-pagination": "^0.1.10", - "@farris/ui-panel": "0.0.4", - "@farris/ui-perfect-scrollbar": "0.0.7", - "@farris/ui-popover": "0.0.4", - "@farris/ui-progress": "0.0.2", - "@farris/ui-progress-step": "0.0.23", - "@farris/ui-property-panel": "0.0.7", - "@farris/ui-response-toolbar": "^0.1.15", - "@farris/ui-responsive": "0.0.2", - "@farris/ui-scrollspy": "0.0.24", - "@farris/ui-section": "^0.1.2", - "@farris/ui-shortcuts": "0.0.4", - "@farris/ui-sidebar": "^0.1.4", - "@farris/ui-sort-editor": "^0.1.7", - "@farris/ui-splitter": "0.0.2", - "@farris/ui-switch": "0.0.6", - "@farris/ui-tabs": "^0.2.12", - "@farris/ui-tag": "0.0.2", - "@farris/ui-text": "^0.1.28", - "@farris/ui-time-picker": "^0.1.4", - "@farris/ui-time-spinner": "0.0.9", - "@farris/ui-tooltip": "0.0.17", - "@farris/ui-tree": "0.0.4", - "@farris/ui-treetable": "^0.3.4", - "@farris/ui-verify-detail": "0.0.6", - "@farris/ui-view-change": "0.0.5", - "@farris/ui-wizard": "0.0.29", - "@gsp-aif/common-api": "0.0.10", - "@gsp-aif/runtime-api": "0.0.11", - "@gsp-bef/gsp-be-metadata": "0.0.25", - "@gsp-bef/gsp-cm-metadata": "0.0.22", - "@gsp-bef/gsp-udt-metadata": "0.0.13", - "@gsp-bef/gsp-vo-metadata": "0.0.17", - "@gsp-cmp/chgdr": "0.0.2", - "@gsp-cmp/querysolution": "^0.1.28", - "@gsp-cmp/webcommand": "0.0.15", - "@gsp-dip/data-imp-exp": "^1.1.48", - "@gsp-lcm/bo-dt-service": "0.0.7", - "@gsp-lcm/bo-rt-service": "0.0.7", - "@gsp-lcm/bo-tree": "0.0.26", - "@gsp-lcm/dbo-selector": "0.0.4", - "@gsp-lcm/dbo-selectrt": "0.0.1", - "@gsp-lcm/metadata-selector": "0.0.50", - "@gsp-lcm/metadatart-selector": "0.0.6", - "@gsp-lcm/metadatart-selector4biztype": "0.0.12", - "@gsp-svc/cloudprint": "^0.4.19", - "@gsp-svc/expression": "0.0.53", - "@gsp-svc/file-load": "0.0.1", - "@gsp-svc/file-viewer": "0.0.74", - "@gsp-svc/filtercondition": "0.0.30", - "@gsp-svc/formdoc-upload": "^0.1.8", - "@gsp-sys/rtf-apphelp": "^1.0.9", - "@gsp-sys/rtf-common": "^2.0.8", - "@gsp-sys/rtf-ui": "0.0.7", - "@gsp-sys/sysmgr-common": "0.0.8", - "@gsp-sys/sysmgr-ui": "0.0.94", - "@gsp-wf/rtdevkit": "^1.0.5", - "@gsp-wf/task-action-impl": "0.0.17", - "@gsp-wf/task-impl-api": "0.0.8", - "@gsp-wf/ui-comment": "^0.1.8", - "@gsp-wf/ui-flowchart": "^1.1.1", - "@gsp-wf/wf-approval-logs": "^0.2.0", - "@gsp-wf/wf-process-editor": "^0.1.8", - "@gsp-wf/wf-sign": "0.0.5", - "@gsp-wf/wf-task-handler": "0.0.26", - "@gspwidget/portlet": "^1.5.0", - "@gspwidget/util": "^1.5.0", - "@gspwidget/widget-core": "^1.5.0", - "@gspwidget/widget-devkit": "^1.5.0", - "@progress/kendo-angular-buttons": "^4.4.0", - "@progress/kendo-angular-dateinputs": "^3.7.3", - "@progress/kendo-angular-dropdowns": "^3.5.3", - "@progress/kendo-angular-grid": "^3.14.1", - "@progress/kendo-angular-inputs": "^4.2.1", - "@progress/kendo-angular-intl": "^1.7.0", - "@progress/kendo-angular-l10n": "^1.4.0", - "@progress/kendo-angular-label": "^1.3.0", - "@progress/kendo-angular-layout": "^3.3.0", - "@progress/kendo-angular-pdf-export": "^1.3.1", - "@progress/kendo-angular-resize-sensor": "^3.2.0", - "@progress/kendo-angular-treeview": "^3.1.1", - "@progress/kendo-data-query": "^1.5.1", - "@progress/kendo-drawing": "^1.5.11", - "@progress/kendo-theme-default": "^2.57.1", - "@progress/kendo-theme-bootstrap": "^2.14.2", - "@progress/kendo-angular-dialog": "3.12.0", - "@qdp/command-services": "0.0.1-0.0.16dev", - "@qdp/common": "0.0.1-0.0.37dev", - "@qdp/condition-schema": "0.0.1-0.0.14dev", - "@qdp/echarts": "0.0.1-0.0.18dev", - "@qdp/formular": "0.0.1-0.0.19dev", - "@qdp/ide-cmp": "0.0.1-0.0.44dev", - "@qdp/localize": "0.0.1-0.0.14dev", - "@qdp/query-framework": "0.0.1-0.0.27dev", - "@qdp/search-join": "0.0.1-0.0.20dev", - "@qdp/spread": "0.0.1-0.0.34dev", - "bignumber.js": "^9.0.1", - "chalk": "2.4.2", - "date-fns": "2.6.0", - "lodash": "^4.17.10", - "moment": "^2.29.1", - "moment-timezone": "^0.5.33", - "prettier": "^1.18.2", - "rxjs": "~6.3.3", - "signature_pad": "^3.0.0-beta.4", - "dayjs": "1.10.3", - "vant": "3.0.3", - "vue": "3.0.5", - "vue-router": "4.0.3", - "reflect-metadata": "0.1.13", - "typescript": "3.2.4", - "tslib": "1.9.3" - }, - "devDependencies": { - "@babel/core": "^7.12.9", - "@babel/preset-env": "^7.12.7", - "@babel/preset-typescript": "^7.12.7", - "cross-env": "^7.0.3" - } -} \ No newline at end of file -- Gitee From d3e507540967c362d9907f876a616169d304df0e Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 16 Feb 2023 09:21:23 +0000 Subject: [PATCH 09/18] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20we?= =?UTF-8?q?b-common/src/test/java/com/inspur/edp/web/common/io/targetfile/?= =?UTF-8?q?package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edp/web/common/io/targetfile/package.json | 212 ------------------ 1 file changed, 212 deletions(-) delete mode 100644 web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json diff --git a/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json b/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json deleted file mode 100644 index d74c41ca..00000000 --- a/web-common/src/test/java/com/inspur/edp/web/common/io/targetfile/package.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "name": "@farris/jit-engine", - "version": "0.0.1", - "description": "npm auto install", - "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" - }, - "keywords": [ - "node_modules" - ], - "author": "Noah", - "license": "ISC1", - "dependencies": { - "@angular-devkit/core": "7.3.9", - "@angular/compiler-cli": "7.2.15", - "@angular/common": "7.2.13", - "@angular/core": "7.2.13", - "@angular/forms": "7.2.13", - "@angular/router": "7.2.13", - "@ant-design/icons-angular": "2.1.0", - "@ecp-caf/caf-common": "^2.0.5", - "@edp-aif/common-api": "^0.6.1", - "@edp-aif/runtime-api": "^0.6.0", - "@edp-bif/common-api": "^0.7.1", - "@edp-bif/runtime-api": "^0.7.2", - "@farris/bef": "0.0.12-20210428112135-dev", - "@farris/command-services": "0.0.12-20210508093120-dev", - "@farris/component-querycondition": "^0.1.46", - "@farris/devkit": "0.0.12-20210428112050-dev", - "@farris/discussion-group": "0.0.22", - "@farris/dynamic-control-group": "^0.1.11", - "@farris/extend-file-upload": "^0.1.9", - "@farris/extend-fileupload-adapt-unifile": "^0.1.4", - "@farris/farris-rollup": "^1.0.80", - "@farris/header-group-editor": "0.0.15", - "@farris/ide-devkit": "^1.0.33", - "@farris/ide-enum-editor": "0.0.3", - "@farris/ide-publish-menu": "0.0.17", - "@farris/kendo-binding": "0.0.12-20210428112252-dev", - "@farris/mobile-bef": "0.0.6", - "@farris/mobile-business-ui": "0.0.27", - "@farris/mobile-cli": "latest", - "@farris/mobile-command-services": "0.0.16", - "@farris/mobile-devkit": "0.0.5", - "@farris/mobile-ui": "0.0.19", - "@farris/mobile-vue-adapter": "0.0.10", - "@farris/tags": "0.0.9", - "@farris/ui-area-response": "0.0.2", - "@farris/ui-avatar": "0.0.17", - "@farris/ui-batch-edit-dialog": "0.0.12", - "@farris/ui-button": "0.0.16", - "@farris/ui-calculator": "0.0.1", - "@farris/ui-calendar": "0.0.5", - "@farris/ui-combo-list": "^0.1.37", - "@farris/ui-combo-lookup": "^0.1.21", - "@farris/ui-common": "^0.2.6", - "@farris/ui-datagrid": "^0.8.21", - "@farris/ui-datagrid-editors": "^0.2.43", - "@farris/ui-datagrid-filter": "0.0.15", - "@farris/ui-datagrid-settings": "0.0.16", - "@farris/ui-datalist": "0.0.16", - "@farris/ui-datatable": "^0.1.25", - "@farris/ui-datepicker": "^0.3.7", - "@farris/ui-dialog": "0.0.13", - "@farris/ui-draggable": "0.0.4", - "@farris/ui-dropdown": "0.0.12", - "@farris/ui-editor": "0.0.10", - "@farris/ui-enum-editor": "0.0.3", - "@farris/ui-field-group": "0.0.21", - "@farris/ui-filter": "0.0.8", - "@farris/ui-filter-editor": "^0.1.15", - "@farris/ui-filter-panel": "0.0.10", - "@farris/ui-flex-layout": "0.0.3", - "@farris/ui-footer": "0.0.2", - "@farris/ui-forms": "0.0.35", - "@farris/ui-html-editor": "0.0.23", - "@farris/ui-input-group": "^0.2.5", - "@farris/ui-language-textbox": "^0.1.14", - "@farris/ui-layout": "0.0.6", - "@farris/ui-list-filter": "0.0.63", - "@farris/ui-list-nav": "0.0.12", - "@farris/ui-list-view": "0.0.26", - "@farris/ui-loading": "^0.1.9", - "@farris/ui-locale": "0.2.12", - "@farris/ui-lookup": "^0.4.7", - "@farris/ui-messager": "^0.2.10", - "@farris/ui-modal": "^0.1.3", - "@farris/ui-multi-select": "^0.2.1", - "@farris/ui-nav": "0.0.4", - "@farris/ui-notify": "^0.1.6", - "@farris/ui-number-spinner": "^0.2.32", - "@farris/ui-pagination": "^0.1.10", - "@farris/ui-panel": "0.0.4", - "@farris/ui-perfect-scrollbar": "0.0.7", - "@farris/ui-popover": "0.0.4", - "@farris/ui-progress": "0.0.2", - "@farris/ui-progress-step": "0.0.23", - "@farris/ui-property-panel": "0.0.7", - "@farris/ui-response-toolbar": "^0.1.15", - "@farris/ui-responsive": "0.0.2", - "@farris/ui-scrollspy": "0.0.24", - "@farris/ui-section": "^0.1.2", - "@farris/ui-shortcuts": "0.0.4", - "@farris/ui-sidebar": "^0.1.4", - "@farris/ui-sort-editor": "^0.1.7", - "@farris/ui-splitter": "0.0.2", - "@farris/ui-switch": "0.0.6", - "@farris/ui-tabs": "^0.2.12", - "@farris/ui-tag": "0.0.2", - "@farris/ui-text": "^0.1.28", - "@farris/ui-time-picker": "^0.1.4", - "@farris/ui-time-spinner": "0.0.9", - "@farris/ui-tooltip": "0.0.17", - "@farris/ui-tree": "0.0.4", - "@farris/ui-treetable": "^0.3.4", - "@farris/ui-verify-detail": "0.0.6", - "@farris/ui-view-change": "0.0.5", - "@farris/ui-wizard": "0.0.29", - "@gsp-aif/common-api": "0.0.10", - "@gsp-aif/runtime-api": "0.0.11", - "@gsp-bef/gsp-be-metadata": "0.0.25", - "@gsp-bef/gsp-cm-metadata": "0.0.22", - "@gsp-bef/gsp-udt-metadata": "0.0.13", - "@gsp-bef/gsp-vo-metadata": "0.0.17", - "@gsp-cmp/chgdr": "0.0.2", - "@gsp-cmp/querysolution": "^0.1.28", - "@gsp-cmp/webcommand": "0.0.15", - "@gsp-dip/data-imp-exp": "^1.1.48", - "@gsp-lcm/bo-dt-service": "0.0.7", - "@gsp-lcm/bo-rt-service": "0.0.7", - "@gsp-lcm/bo-tree": "0.0.26", - "@gsp-lcm/dbo-selector": "0.0.4", - "@gsp-lcm/dbo-selectrt": "0.0.1", - "@gsp-lcm/metadata-selector": "0.0.50", - "@gsp-lcm/metadatart-selector": "0.0.6", - "@gsp-lcm/metadatart-selector4biztype": "0.0.12", - "@gsp-svc/cloudprint": "^0.4.19", - "@gsp-svc/expression": "0.0.53", - "@gsp-svc/file-load": "0.0.1", - "@gsp-svc/file-viewer": "0.0.74", - "@gsp-svc/filtercondition": "0.0.30", - "@gsp-svc/formdoc-upload": "^0.1.8", - "@gsp-sys/rtf-apphelp": "^1.0.9", - "@gsp-sys/rtf-common": "^2.0.8", - "@gsp-sys/rtf-ui": "0.0.7", - "@gsp-sys/sysmgr-common": "0.0.8", - "@gsp-sys/sysmgr-ui": "0.0.94", - "@gsp-wf/rtdevkit": "^1.0.5", - "@gsp-wf/task-action-impl": "0.0.17", - "@gsp-wf/task-impl-api": "0.0.8", - "@gsp-wf/ui-comment": "^0.1.8", - "@gsp-wf/ui-flowchart": "^1.1.1", - "@gsp-wf/wf-approval-logs": "^0.2.0", - "@gsp-wf/wf-process-editor": "^0.1.8", - "@gsp-wf/wf-sign": "0.0.5", - "@gsp-wf/wf-task-handler": "0.0.26", - "@gspwidget/portlet": "^1.5.0", - "@gspwidget/util": "^1.5.0", - "@gspwidget/widget-core": "^1.5.0", - "@gspwidget/widget-devkit": "^1.5.0", - "@progress/kendo-angular-buttons": "^4.4.0", - "@progress/kendo-angular-dateinputs": "^3.7.3", - "@progress/kendo-angular-dropdowns": "^3.5.3", - "@progress/kendo-angular-grid": "^3.14.1", - "@progress/kendo-angular-inputs": "^4.2.1", - "@progress/kendo-angular-intl": "^1.7.0", - "@progress/kendo-angular-l10n": "^1.4.0", - "@progress/kendo-angular-label": "^1.3.0", - "@progress/kendo-angular-layout": "^3.3.0", - "@progress/kendo-angular-pdf-export": "^1.3.1", - "@progress/kendo-angular-resize-sensor": "^3.2.0", - "@progress/kendo-angular-treeview": "^3.1.1", - "@progress/kendo-data-query": "^1.5.1", - "@progress/kendo-drawing": "^1.5.11", - "@progress/kendo-theme-default": "^2.57.1", - "@progress/kendo-theme-bootstrap": "^2.14.2", - "@progress/kendo-angular-dialog": "3.12.0", - "@qdp/command-services": "0.0.1-0.0.16dev", - "@qdp/common": "0.0.1-0.0.37dev", - "@qdp/condition-schema": "0.0.1-0.0.14dev", - "@qdp/echarts": "0.0.1-0.0.18dev", - "@qdp/formular": "0.0.1-0.0.19dev", - "@qdp/ide-cmp": "0.0.1-0.0.44dev", - "@qdp/localize": "0.0.1-0.0.14dev", - "@qdp/query-framework": "0.0.1-0.0.27dev", - "@qdp/search-join": "0.0.1-0.0.20dev", - "@qdp/spread": "0.0.1-0.0.34dev", - "bignumber.js": "^9.0.1", - "chalk": "2.4.2", - "date-fns": "2.6.0", - "lodash": "^4.17.10", - "moment": "^2.29.1", - "moment-timezone": "^0.5.33", - "prettier": "^1.18.2", - "rxjs": "~6.3.3", - "signature_pad": "^3.0.0-beta.4", - "dayjs": "1.10.3", - "vant": "3.0.3", - "vue": "3.0.5", - "vue-router": "4.0.3", - "reflect-metadata": "0.1.13", - "typescript": "3.2.4", - "tslib": "1.9.3" - }, - "devDependencies": { - "@babel/core": "^7.12.9", - "@babel/preset-env": "^7.12.7", - "@babel/preset-typescript": "^7.12.7", - "cross-env": "^7.0.3" - } -} \ No newline at end of file -- Gitee From af51e26177d61a64022cc8dae4dd1bb7ee0e8a59 Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 16 Feb 2023 09:24:40 +0000 Subject: [PATCH 10/18] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20we?= =?UTF-8?q?b-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/c?= =?UTF-8?q?ore/packagejsonfile/package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/packagejsonfile/package.json | 216 ------------------ 1 file changed, 216 deletions(-) delete mode 100644 web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json b/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json deleted file mode 100644 index 8e2af028..00000000 --- a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "name": "@farris/jit-engine", - "version": "0.0.1", - "description": "npm auto install", - "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" - }, - "keywords": [ - "node_modules", - "jit" - ], - "author": "Noah", - "license": "ISC", - "dependencies": { - "@angular-devkit/core": "7.3.9", - "@angular/compiler-cli": "7.2.15", - "@angular/common": "7.2.13", - "@angular/core": "7.2.13", - "@angular/forms": "7.2.13", - "@angular/router": "7.2.13", - "@ant-design/icons-angular": "2.1.0", - "@ecp-caf/caf-common": "^2.0.5", - "@edp-aif/common-api": "^0.6.1", - "@edp-aif/runtime-api": "^0.6.0", - "@edp-bif/common-api": "^0.7.1", - "@edp-bif/runtime-api": "^0.7.2", - "@farris/bef": "0.0.12-20210428112135-dev", - "@farris/command-services": "0.0.12-20210508093120-dev", - "@farris/component-querycondition": "^0.1.46", - "@farris/devkit": "0.0.12-20210428112050-dev", - "@farris/discussion-group": "0.0.22", - "@farris/dynamic-control-group": "^0.1.11", - "@farris/extend-file-upload": "^0.1.9", - "@farris/extend-fileupload-adapt-unifile": "^0.1.4", - "@farris/farris-rollup": "1.0.80", - "@farris/header-group-editor": "0.0.15", - "@farris/ide-devkit": "^1.0.33", - "@farris/ide-enum-editor": "0.0.3", - "@farris/ide-publish-menu": "0.0.17", - "@farris/kendo-binding": "0.0.12-20210428112252-dev", - "@farris/mobile-bef": "0.0.6", - "@farris/mobile-business-ui": "0.0.27", - "@farris/mobile-cli": "latest", - "@farris/mobile-command-services": "0.0.16", - "@farris/mobile-devkit": "0.0.5", - "@farris/mobile-ui": "0.0.19", - "@farris/mobile-vue-adapter": "0.0.10", - "@farris/tags": "0.0.9", - "@farris/ui-area-response": "0.0.2", - "@farris/ui-avatar": "0.0.17", - "@farris/ui-batch-edit-dialog": "0.0.12", - "@farris/ui-button": "0.0.16", - "@farris/ui-calculator": "0.0.1", - "@farris/ui-calendar": "0.0.5", - "@farris/ui-combo-list": "^0.1.37", - "@farris/ui-combo-lookup": "^0.1.21", - "@farris/ui-common": "^0.2.6", - "@farris/ui-datagrid": "^0.8.21", - "@farris/ui-datagrid-editors": "^0.2.43", - "@farris/ui-datagrid-filter": "0.0.15", - "@farris/ui-datagrid-settings": "0.0.16", - "@farris/ui-datalist": "0.0.16", - "@farris/ui-datatable": "^0.1.25", - "@farris/ui-datepicker": "^0.3.7", - "@farris/ui-dialog": "0.0.13", - "@farris/ui-draggable": "0.0.4", - "@farris/ui-dropdown": "0.0.12", - "@farris/ui-editor": "0.0.10", - "@farris/ui-enum-editor": "0.0.3", - "@farris/ui-field-group": "0.0.21", - "@farris/ui-filter": "0.0.8", - "@farris/ui-filter-editor": "^0.1.15", - "@farris/ui-filter-panel": "0.0.10", - "@farris/ui-flex-layout": "0.0.3", - "@farris/ui-footer": "0.0.2", - "@farris/ui-forms": "0.0.35", - "@farris/ui-html-editor": "0.0.23", - "@farris/ui-input-group": "^0.2.5", - "@farris/ui-language-textbox": "^0.1.14", - "@farris/ui-layout": "0.0.6", - "@farris/ui-list-filter": "0.0.63", - "@farris/ui-list-nav": "0.0.12", - "@farris/ui-list-view": "0.0.26", - "@farris/ui-loading": "^0.1.9", - "@farris/ui-locale": "0.2.12", - "@farris/ui-lookup": "^0.4.7", - "@farris/ui-messager": "^0.2.10", - "@farris/ui-modal": "^0.1.3", - "@farris/ui-multi-select": "^0.2.1", - "@farris/ui-nav": "0.0.4", - "@farris/ui-notify": "^0.1.6", - "@farris/ui-number-spinner": "^0.2.32", - "@farris/ui-pagination": "^0.1.10", - "@farris/ui-panel": "0.0.4", - "@farris/ui-perfect-scrollbar": "0.0.7", - "@farris/ui-popover": "0.0.4", - "@farris/ui-progress": "0.0.2", - "@farris/ui-progress-step": "0.0.23", - "@farris/ui-property-panel": "0.0.7", - "@farris/ui-response-toolbar": "^0.1.15", - "@farris/ui-responsive": "0.0.2", - "@farris/ui-scrollspy": "0.0.24", - "@farris/ui-section": "^0.1.2", - "@farris/ui-shortcuts": "0.0.4", - "@farris/ui-sidebar": "^0.1.4", - "@farris/ui-sort-editor": "^0.1.7", - "@farris/ui-splitter": "0.0.2", - "@farris/ui-switch": "0.0.6", - "@farris/ui-tabs": "^0.2.12", - "@farris/ui-tag": "0.0.2", - "@farris/ui-text": "^0.1.28", - "@farris/ui-time-picker": "^0.1.4", - "@farris/ui-time-spinner": "0.0.9", - "@farris/ui-tooltip": "0.0.17", - "@farris/ui-tree": "0.0.4", - "@farris/ui-treetable": "^0.3.4", - "@farris/ui-verify-detail": "0.0.6", - "@farris/ui-view-change": "0.0.5", - "@farris/ui-wizard": "0.0.29", - "@gsp-aif/common-api": "0.0.10", - "@gsp-aif/runtime-api": "0.0.11", - "@gsp-bef/gsp-be-metadata": "0.0.25", - "@gsp-bef/gsp-cm-metadata": "0.0.22", - "@gsp-bef/gsp-udt-metadata": "0.0.13", - "@gsp-bef/gsp-vo-metadata": "0.0.17", - "@gsp-cmp/chgdr": "0.0.2", - "@gsp-cmp/querysolution": "^0.1.28", - "@gsp-cmp/webcommand": "0.0.15", - "@gsp-dip/data-imp-exp": "^1.1.48", - "@gsp-lcm/bo-dt-service": "0.0.7", - "@gsp-lcm/bo-rt-service": "0.0.7", - "@gsp-lcm/bo-tree": "0.0.26", - "@gsp-lcm/dbo-selector": "0.0.4", - "@gsp-lcm/dbo-selectrt": "0.0.1", - "@gsp-lcm/metadata-selector": "0.0.50", - "@gsp-lcm/metadatart-selector": "0.0.6", - "@gsp-lcm/metadatart-selector4biztype": "0.0.12", - "@gsp-svc/cloudprint": "^0.4.19", - "@gsp-svc/expression": "0.0.53", - "@gsp-svc/file-load": "0.0.1", - "@gsp-svc/file-viewer": "0.0.74", - "@gsp-svc/filtercondition": "0.0.30", - "@gsp-svc/formdoc-upload": "^0.1.8", - "@gsp-sys/rtf-apphelp": "^1.0.9", - "@gsp-sys/rtf-common": "^2.0.8", - "@gsp-sys/rtf-ui": "0.0.7", - "@gsp-sys/sysmgr-common": "0.0.8", - "@gsp-sys/sysmgr-ui": "0.0.94", - "@gsp-wf/rtdevkit": "^1.0.5", - "@gsp-wf/task-action-impl": "0.0.17", - "@gsp-wf/task-impl-api": "0.0.8", - "@gsp-wf/ui-comment": "^0.1.8", - "@gsp-wf/ui-flowchart": "^1.1.1", - "@gsp-wf/wf-approval-logs": "^0.2.0", - "@gsp-wf/wf-process-editor": "^0.1.8", - "@gsp-wf/wf-sign": "0.0.5", - "@gsp-wf/wf-task-handler": "0.0.26", - "@gspwidget/portlet": "^1.5.0", - "@gspwidget/util": "^1.5.0", - "@gspwidget/widget-core": "^1.5.0", - "@gspwidget/widget-devkit": "^1.5.0", - "@progress/kendo-angular-buttons": "^4.4.0", - "@progress/kendo-angular-dateinputs": "^3.7.3", - "@progress/kendo-angular-dropdowns": "^3.5.3", - "@progress/kendo-angular-grid": "^3.14.1", - "@progress/kendo-angular-inputs": "^4.2.1", - "@progress/kendo-angular-intl": "^1.7.0", - "@progress/kendo-angular-l10n": "^1.4.0", - "@progress/kendo-angular-label": "^1.3.0", - "@progress/kendo-angular-layout": "^3.3.0", - "@progress/kendo-angular-pdf-export": "^1.3.1", - "@progress/kendo-angular-resize-sensor": "^3.2.0", - "@progress/kendo-angular-treeview": "^3.1.1", - "@progress/kendo-data-query": "^1.5.1", - "@progress/kendo-drawing": "^1.5.11", - "@progress/kendo-theme-default": "^2.57.1", - "@progress/kendo-theme-bootstrap": "^2.14.2", - "@progress/kendo-angular-dialog": "3.12.0", - "@progress/kendo-angular-excel-export": "2.3.0", - "primeng": "9.0.0", - "@qdp/command-services": "0.0.1-0.0.16dev", - "@qdp/common": "0.0.1-0.0.37dev", - "@qdp/condition-schema": "0.0.1-0.0.14dev", - "@qdp/echarts": "0.0.1-0.0.18dev", - "@qdp/formular": "0.0.1-0.0.19dev", - "@qdp/ide-cmp": "0.0.1-0.0.44dev", - "@qdp/localize": "0.0.1-0.0.14dev", - "@qdp/query-framework": "0.0.1-0.0.27dev", - "@qdp/search-join": "0.0.1-0.0.20dev", - "@qdp/spread": "0.0.1-0.0.34dev", - "bignumber.js": "^9.0.1", - "ngx-cookie-service": "^2.2.0", - "chalk": "2.4.2", - "date-fns": "2.6.0", - "lodash": "^4.17.10", - "moment": "^2.29.1", - "moment-timezone": "^0.5.33", - "prettier": "^1.18.2", - "rxjs": "~6.3.3", - "signature_pad": "^3.0.0-beta.4", - "dayjs": "1.10.3", - "vant": "3.0.3", - "vue": "3.0.5", - "vue-router": "4.0.3", - "reflect-metadata": "0.1.13", - "typescript": "3.2.4", - "tslib": "1.9.3" - }, - "devDependencies": { - "@babel/core": "^7.12.9", - "@babel/preset-env": "^7.12.7", - "@babel/preset-typescript": "^7.12.7", - "cross-env": "^7.0.3" - } -} -- Gitee From 63a2860249e426b8eccf0dc17a8f152e4f05619c Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Thu, 2 Mar 2023 06:20:50 +0000 Subject: [PATCH 11/18] update notice Signed-off-by: guozhiqi --- NOTICE | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 NOTICE diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..b308bda5 --- /dev/null +++ b/NOTICE @@ -0,0 +1,8 @@ +OPEN SOURCE SOFTWARE NOTICE + +Please note we provide an open source software notice for the third party open source software along with this software and/or this software component (in the following just “this SOFTWARE”). The open source software licenses are granted by the respective right holders. + +Warranty Disclaimer +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +Copyright Notice and License Texts \ No newline at end of file -- Gitee From 52c09de52952b01c090724d5330e7077277b08fe Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 09:37:54 +0800 Subject: [PATCH 12/18] =?UTF-8?q?=E8=B0=83=E6=95=B4form-process=20?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- form-process/pom.xml | 5 +- form-process/web-form-process-api/pom.xml | 32 --- .../api/service/FormProcessService.java | 21 -- .../config/FormProcessConfiguration.java | 51 ++--- ...rviceImpl.java => FormProcessManager.java} | 215 +++++++----------- .../service/FormProcessWebService.java | 14 ++ .../deploy/AbstractDeployOperation.java | 4 +- .../web/tsfile/core/TsFileWebServiceImpl.java | 1 - 8 files changed, 112 insertions(+), 231 deletions(-) delete mode 100644 form-process/web-form-process-api/pom.xml delete mode 100644 form-process/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java mode change 100644 => 100755 form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java rename form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/{FormProcessServiceImpl.java => FormProcessManager.java} (44%) mode change 100644 => 100755 create mode 100755 form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessWebService.java diff --git a/form-process/pom.xml b/form-process/pom.xml index 7e3ac472..45d4cc99 100644 --- a/form-process/pom.xml +++ b/form-process/pom.xml @@ -13,9 +13,6 @@ form-process pom ${custom.version} - - web-form-process - web-form-process-api - + \ No newline at end of file diff --git a/form-process/web-form-process-api/pom.xml b/form-process/web-form-process-api/pom.xml deleted file mode 100644 index 472d0f74..00000000 --- a/form-process/web-form-process-api/pom.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - form-process - com.inspur.edp - ${custom.version} - - 4.0.0 - - web-form-process-api - jar - ${custom.version} - - \ No newline at end of file diff --git a/form-process/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java b/form-process/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java deleted file mode 100644 index 72cb0644..00000000 --- a/form-process/web-form-process-api/src/main/java/com/inspur/edp/web/form/process/api/service/FormProcessService.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.inspur.edp.web.form.process.api.service; - -public interface FormProcessService { - void publishFormFormatForNoCode(String formId, String boId, String microAppCode, String deviceType); -} diff --git a/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java old mode 100644 new mode 100755 index 24a3ed4e..42c62ec8 --- a/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java +++ b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/config/FormProcessConfiguration.java @@ -1,36 +1,15 @@ -/* - * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.inspur.edp.web.form.process.config; - -import com.inspur.edp.web.form.process.service.FormProcessServiceImpl; -import com.inspur.edp.web.form.process.service.FormProcessWebService; -import io.iec.edp.caf.rest.RESTEndpoint; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration("com.inspur.ed.web.form.process.config.FormProcessConfiguration") -public class FormProcessConfiguration { - @Bean - public RESTEndpoint formProcessWebapiEndPoint() { - return new RESTEndpoint("/dev/main/v1.0/form/form-process", new FormProcessWebService()); - } - - @Bean - public FormProcessServiceImpl getFormProcessService() { - return new FormProcessServiceImpl(); - } -} +package com.inspur.edp.web.form.process.config; + +import com.inspur.edp.web.form.process.service.FormProcessWebService; +import io.iec.edp.caf.rest.RESTEndpoint; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration("com.inspur.ed.web.form.process.config.FormProcessConfiguration") +public class FormProcessConfiguration { + @Bean + public RESTEndpoint formProcessWebapiEndPoint() { + return new RESTEndpoint("/dev/main/v1.0/form/form-process", new Object[]{new FormProcessWebService()}); + } +} + diff --git a/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessManager.java old mode 100644 new mode 100755 similarity index 44% rename from form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java rename to form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessManager.java index 152f1eaf..1123ae3b --- a/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessServiceImpl.java +++ b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessManager.java @@ -1,135 +1,80 @@ -/* - * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.inspur.edp.web.form.process.service; - -import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; -import com.inspur.edp.lcm.metadata.api.entity.GspProject; -import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; -import com.inspur.edp.lcm.metadata.api.service.MetadataService; -import com.inspur.edp.lcm.metadata.api.service.NoCodeService; -import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService; -import com.inspur.edp.web.form.process.api.service.FormProcessService; -import com.inspur.edp.wf.bizprocess.entity.FormFormat; -import com.inspur.edp.wf.bizprocess.entity.UrlParameter; -import com.inspur.edp.wf.bizprocess.service.FormFormatRpcService; -import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo; -import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService; -import io.iec.edp.caf.commons.utils.SpringBeanUtils; -import io.iec.edp.caf.rpc.client.RpcClassHolder; - -import java.util.Arrays; -import java.util.List; - -public class FormProcessServiceImpl implements FormProcessService { - - private static class LazyHolder { - private static final FormProcessServiceImpl INSTANCE = new FormProcessServiceImpl(); - } - public FormProcessServiceImpl() {} - - public static final FormProcessServiceImpl getInstance() { - return LazyHolder.INSTANCE; - } - - public void publishFormFormat(String formId, String formPath) { - if (formPath == null || formPath.equals("")) { - throw new RuntimeException("参数path不允许为空。"); - } - - String unifiedPath = formPath.replace('\\', '/'); - if (unifiedPath.startsWith("/")) { - unifiedPath = unifiedPath.substring(1); // 去掉开头的/ - } - - MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); - - List mdList = metadataService.getMetadataList(unifiedPath); - GspMetadata md = mdList.stream().filter(item -> item.getHeader().getId().equals(formId)).findFirst().orElse(null); - if (md == null) { - throw new RuntimeException("找不到表单元数据: " + formId + "。文件路径:" + unifiedPath + "。"); - } - MetadataHeader header = md.getHeader(); - GspProject project = metadataService.getGspProjectInfo(unifiedPath); - String deploymentPath = project.getSuDeploymentPath(); - String projectName = project.getMetadataProjectName().toLowerCase(); - String url = "/" + deploymentPath + "/web/" + projectName + "/" + "index.html#/" + header.getCode(); - String boId = project.getBizobjectID(); - - pushFormFormat(formId, md, url, boId); - } - - @Override - public void publishFormFormatForNoCode(String formId, String boId, String microAppCode, String deviceType) { - - - // 获取表单 - NoCodeService noCodeService =SpringBeanUtils.getBean(NoCodeService.class); - GspMetadata formMetadata = noCodeService.getMetadata(formId); - - // 根据bo获取app/su路径 - DevBasicInfoService devBasicInfoService = SpringBeanUtils.getBean(DevBasicInfoService.class); - DevBasicBoInfo boInfo = devBasicInfoService.getDevBasicBoInfo(boId); - String deploymentPath = boInfo.getAppCode() + "/" + boInfo.getSuCode(); - - // \web\apps\scm\sd\web\bo-salesorder2103front - String devicePath = "mobile".equals(deviceType) ? "mob" : "web"; - String url = "/" + deploymentPath + "/" + devicePath + "/" + microAppCode + "/" + "index.html#/" + formMetadata.getHeader().getCode(); - - pushFormFormat(formId, formMetadata, url, boId); - } - - private void pushFormFormat(String formId, GspMetadata formMetadta, String url, String boId) { - // 组织参数,调用工作流接口。 - FormFormat ff = new FormFormat(); - ff.setId(formId); - ff.setCode(formMetadta.getHeader().getCode()); - ff.setName(formMetadta.getHeader().getName()); - ff.setUrlType("url"); - ff.setFormUrl(url); - - UrlParameter actionParam = new UrlParameter(); - actionParam.setCode("action"); - actionParam.setName("动作"); - actionParam.setValue("LoadAndView1"); - UrlParameter idParam = new UrlParameter(); - idParam.setCode("id"); - idParam.setName("内码"); - idParam.setValue("{\"expr\":\"DefaultFunction.GetContextParameter(\\\"dataId\\\")\",\"sexpr\":\"\"}\n"); - List list = Arrays.asList(actionParam, idParam); - // UrlParameter param1 = new UrlParameter(); - // param1.setCode("expr"); - // param1.setValue("DefaultFunction.GetContextParameter(\\\"dataId\\\")"); - // UrlParameter param2 = new UrlParameter(); - // param2.setCode("sexpr"); - // param2.setValue(""); - // List list = Arrays.asList(param1, param2); - ff.setUrlParameters(list); - ff.setFormatType("wf"); - - ff.setBizCategory(getBizTypeId(boId)); - - RpcClassHolder rpcHelper = SpringBeanUtils.getBean(RpcClassHolder.class); - FormFormatRpcService service = rpcHelper.getRpcClass(FormFormatRpcService.class); - service.addFormFormat(ff); - } - - private String getBizTypeId(String bizObjectId) { - MdBizTypeMappingService service = SpringBeanUtils.getBean(MdBizTypeMappingService.class); - List bizTypeIds = service.getBizTypeIdsByBoId(bizObjectId); - return bizTypeIds == null || bizTypeIds.size() == 0 ? "" : bizTypeIds.get(0); - } -} +package com.inspur.edp.web.form.process.service; + +import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; +import com.inspur.edp.lcm.metadata.api.entity.GspProject; +import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader; +import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.metadata.businesstype.api.MdBizTypeMappingService; +import com.inspur.edp.wf.bizprocess.entity.FormFormat; +import com.inspur.edp.wf.bizprocess.entity.UrlParameter; +import com.inspur.edp.wf.bizprocess.service.FormFormatRpcService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; +import io.iec.edp.caf.rpc.client.RpcClassHolder; + +import java.util.Arrays; +import java.util.List; + +public class FormProcessManager { + private static class LazyHolder { + private static final FormProcessManager INSTANCE = new FormProcessManager(); + } + + private FormProcessManager() { + } + + public static final FormProcessManager getInstance() { + /* 25 */ + return LazyHolder.INSTANCE; + } + + public void publishFormFormat(String formId, String formPath) { + if (formPath == null || formPath.equals("")) { + throw new RuntimeException("参数path不允许为空。"); + } + String unifiedPath = formPath.replace('\\', '/'); + if (unifiedPath.startsWith("/")) { + unifiedPath = unifiedPath.substring(1); + } + MetadataService metadataService = (MetadataService) SpringBeanUtils.getBean(MetadataService.class); + List mdList = metadataService.getMetadataList(unifiedPath); + GspMetadata md = mdList.stream().filter(item -> item.getHeader().getId().equals(formId)).findFirst().orElse(null); + if (md == null) { + throw new RuntimeException("找不到表单元数据: " + formId + "。文件路径:" + unifiedPath + "。"); + } + MetadataHeader header = md.getHeader(); + GspProject project = metadataService.getGspProjectInfo(unifiedPath); + String deploymentPath = project.getSuDeploymentPath(); + String projectName = project.getMetadataProjectName().toLowerCase(); + String url = "/" + deploymentPath + "/web/" + projectName + "/index.html#/" + header.getCode(); + FormFormat ff = new FormFormat(); + ff.setId(formId); + ff.setCode(header.getCode()); + ff.setName(header.getName()); + ff.setUrlType("url"); + ff.setFormUrl(url); + UrlParameter actionParam = new UrlParameter(); + actionParam.setCode("action"); + actionParam.setName("动作"); + actionParam.setValue("LoadAndView1"); + UrlParameter idParam = new UrlParameter(); + idParam.setCode("id"); + idParam.setName("内码"); + idParam.setValue("{\"expr\":\"DefaultFunction.GetContextParameter(\\\"dataId\\\")\",\"sexpr\":\"\"}\n"); + List list = Arrays.asList(new UrlParameter[]{actionParam, idParam}); + ff.setUrlParameters(list); + ff.setFormatType("wf"); + String boId = project.getBizobjectID(); + ff.setBizCategory(getBizTypeId(boId)); + ff.setTerminal("PC"); + RpcClassHolder rpcHelper = (RpcClassHolder) SpringBeanUtils.getBean(RpcClassHolder.class); + FormFormatRpcService service = (FormFormatRpcService) rpcHelper.getRpcClass(FormFormatRpcService.class); + service.addFormFormat(ff); + } + + private String getBizTypeId(String bizObjectId) { + MdBizTypeMappingService service = (MdBizTypeMappingService) SpringBeanUtils.getBean(MdBizTypeMappingService.class); + List bizTypeIds = service.getBizTypeIdsByBoId(bizObjectId); + return (bizTypeIds == null || bizTypeIds.size() == 0) ? "" : bizTypeIds.get(0); + } +} + diff --git a/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessWebService.java b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessWebService.java new file mode 100755 index 00000000..9fe63fda --- /dev/null +++ b/form-process/web-form-process/src/main/java/com/inspur/edp/web/form/process/service/FormProcessWebService.java @@ -0,0 +1,14 @@ + package com.inspur.edp.web.form.process.service; + import javax.ws.rs.*; + + @Path("/") + @Consumes({"application/json"}) + @Produces({"application/json"}) + public class FormProcessWebService { + @Path("/form-format") + @PUT + public void publishFormFormat(@QueryParam("id") String formId, @QueryParam("path") String path) { + FormProcessManager.getInstance().publishFormFormat(formId, path); + } + } + diff --git a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/deploy/AbstractDeployOperation.java b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/deploy/AbstractDeployOperation.java index 680928bb..546e7b98 100644 --- a/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/deploy/AbstractDeployOperation.java +++ b/web-frontendproject/src/main/java/com/inspur/edp/web/frontendproject/zerocode/operation/deploy/AbstractDeployOperation.java @@ -25,11 +25,11 @@ import com.inspur.edp.web.jitruntimebuild.scriptcache.api.service.ScriptCacheSer import com.inspur.edp.web.jitruntimebuild.scriptcache.localserver.LocalServerPathGenerator; import io.iec.edp.caf.commons.utils.SpringBeanUtils; - abstract class AbstractDeployOperation implements IDeployOperation { +abstract class AbstractDeployOperation implements IDeployOperation { private final TerminalType terminalType; private final ScriptCacheService scriptCacheServiceInstance; - public AbstractDeployOperation(TerminalType terminalType) { + AbstractDeployOperation(TerminalType terminalType) { this.terminalType = terminalType; this.scriptCacheServiceInstance = SpringBeanUtils.getBean(ScriptCacheService.class); } diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java index c87f0c3e..ba0e1ec1 100644 --- a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java @@ -32,7 +32,6 @@ import java.util.Map; */ public class TsFileWebServiceImpl implements TsFileWebService { - @Override public Object loadTsFileContent(String path) { -- Gitee From b7fb0e1edceb0b7a4f919e9cf68d06a634b2d8da Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:00:17 +0800 Subject: [PATCH 13/18] =?UTF-8?q?=E8=B0=83=E6=95=B4form-process=20?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- form-process/pom.xml | 4 +++- form-process/web-form-process/pom.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/form-process/pom.xml b/form-process/pom.xml index 45d4cc99..f333cbdc 100644 --- a/form-process/pom.xml +++ b/form-process/pom.xml @@ -13,6 +13,8 @@ form-process pom ${custom.version} - + + web-form-process + \ No newline at end of file diff --git a/form-process/web-form-process/pom.xml b/form-process/web-form-process/pom.xml index 8678da14..18ba3de6 100644 --- a/form-process/web-form-process/pom.xml +++ b/form-process/web-form-process/pom.xml @@ -58,7 +58,7 @@ com.inspur.edp wf-bizprocess-api - 0.1.9 + 0.3.2 io.iec.edp -- Gitee From fdb869090833438b3194c5ba3db8aabd4467578e Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:18:53 +0800 Subject: [PATCH 14/18] =?UTF-8?q?=E8=B0=83=E6=95=B4npm-package=E5=B7=A5?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- npmpackage/pom.xml | 22 +++++++++++++++++++ .../web-npmpackage-api}/pom.xml | 2 +- .../entity/NpmInstallPackageParameter.java | 0 .../api/entity/NpmInstallParameter.java | 0 .../entity/NpmPackageCheckUpdateOptions.java | 0 .../api/entity/NpmPackageConstants.java | 0 .../api/entity/NpmPackageResponse.java | 0 .../api/entity/NpmPackageResponseLevel.java | 0 .../NpmPackageJsonDependencyInfo.java | 0 .../packagejson/NpmPackageJsonInfo.java | 0 .../api/entity/settings/NpmRepository.java | 0 .../api/entity/settings/NpmSettingConfig.java | 0 .../api/entity/settings/NpmSettingMode.java | 0 .../api/entity/settings/NpmSettings.java | 0 .../api/entity/settings/NpmUpdatePolicy.java | 0 .../api/service/NpmPackageInstallService.java | 0 .../api/service/NpmPackageService.java | 0 .../NpmPackageInstallWebService.java | 0 .../NpmPackagePublishWebService.java | 0 .../api/webservice/NpmPackageWebService.java | 0 .../web-npmpackage-core}/pom.xml | 2 +- .../NpmCacheCleanCommandExecutor.java | 0 .../core/config/NpmPackageConfiguration.java | 0 .../NpmPackageInstallConfiguration.java | 0 .../npminstall/NodeModulesPathGenerator.java | 0 .../npminstall/NpmInstallCommandExecutor.java | 0 .../NpmInstallCommandParameterGenerator.java | 0 .../NpmInstallLockFilePathGenerator.java | 0 .../core/npminstall/NpmInstallManager.java | 0 .../NpmInstallParameterValidator.java | 0 .../npminstall/NpmInstallingParameter.java | 0 .../npminstall/NpmInstallingTagManager.java | 0 .../npminstall/NpmRepositoryConnection.java | 0 .../npminstall/PackageJsonCopyManager.java | 0 .../npminstall/PackageJsonPathGenerator.java | 0 .../global/GlobalNpmDeployPathGenerator.java | 0 .../GlobalNpmInstallCommandExecutor.java | 0 ...alNpmInstallCommandParameterGenerator.java | 0 .../GlobalPackageJsonPathGenerator.java | 0 .../global/NpmInstallGlobalManager.java | 0 .../npmlogin/NpmLoginCommandExecutor.java | 0 .../NpmLoginCommandParameterGenerator.java | 0 .../npmlogout/NpmLogoutCommandExecutor.java | 0 .../NpmLogoutCommandParameterGenerator.java | 0 .../core/npmpackagecheck/NpmPackageCheck.java | 0 .../core/npmsetting/NpmSettingConstant.java | 0 .../core/npmsetting/NpmSettingConvertor.java | 0 .../npmsetting/NpmSettingEncryptService.java | 0 .../npmsetting/NpmSettingInitialization.java | 0 .../core/npmsetting/NpmSettingManager.java | 0 .../npmsetting/NpmSettingPathManager.java | 0 .../core/npmsetting/NpmSettingReader.java | 0 .../core/npmsetting/NpmSettingWriter.java | 0 .../core/packagejsonfile/package.json | 0 .../service/NpmPackageInstallServiceImpl.java | 0 .../core/service/NpmPackageServiceImpl.java | 0 .../NpmPackageInstallWebServiceImpl.java | 0 .../webservice/NpmPackageWebServiceImpl.java | 0 .../main/resources/META-INF/spring.factories | 0 ...mInstallCommandParameterGeneratorTest.java | 0 .../npmpackagecheck/NpmPackageCheckTest.java | 0 .../web-npmpackage-patch}/pom.xml | 2 +- .../web/npmpackagepatch/FileOperation.java | 0 .../MyPropertyNamingStrategy.java | 0 .../NpmPackagePatchService.java | 0 .../PackageJsonFileManager.java | 0 .../web/npmpackagepatch/PatchConstants.java | 0 .../inspur/edp/web/npmpackagepatch/README.md | 0 .../web/npmpackagepatch/RescureReadFiles.java | 0 .../npmpackagepatch/SerializePackageJson.java | 0 .../PackageJsonDependencyInfo.java | 0 .../packagejson/PackageJsonInfo.java | 0 .../packagejson/SerializedPackageJson.java | 0 pom.xml | 5 ++--- 74 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 npmpackage/pom.xml rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/pom.xml (97%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageInstallService.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageService.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java (100%) rename {web-npmpackage-api => npmpackage/web-npmpackage-api}/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/pom.xml (97%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallServiceImpl.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageServiceImpl.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageWebServiceImpl.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/main/resources/META-INF/spring.factories (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java (100%) rename {web-npmpackage-core => npmpackage/web-npmpackage-core}/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/pom.xml (96%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java (100%) rename {web-npmpackage-patch => npmpackage/web-npmpackage-patch}/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java (100%) diff --git a/npmpackage/pom.xml b/npmpackage/pom.xml new file mode 100644 index 00000000..beafd794 --- /dev/null +++ b/npmpackage/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + com.inspur.edp + web + ${custom.version} + + + npmpackage + pom + ${custom.version} + + + web-npmpackage-api + web-npmpackage-core + web-npmpackage-patch + + + \ No newline at end of file diff --git a/web-npmpackage-api/pom.xml b/npmpackage/web-npmpackage-api/pom.xml similarity index 97% rename from web-npmpackage-api/pom.xml rename to npmpackage/web-npmpackage-api/pom.xml index abf57fbe..7067fc86 100644 --- a/web-npmpackage-api/pom.xml +++ b/npmpackage/web-npmpackage-api/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + npmpackage com.inspur.edp ${custom.version} diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallPackageParameter.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmInstallParameter.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageCheckUpdateOptions.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageConstants.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponse.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/NpmPackageResponseLevel.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonDependencyInfo.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/packagejson/NpmPackageJsonInfo.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmRepository.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingConfig.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettingMode.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmSettings.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/entity/settings/NpmUpdatePolicy.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageInstallService.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageInstallService.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageInstallService.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageInstallService.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageService.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageService.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageService.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/service/NpmPackageService.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageInstallWebService.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackagePublishWebService.java diff --git a/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java b/npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java similarity index 100% rename from web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java rename to npmpackage/web-npmpackage-api/src/main/java/com/inspur/edp/web/npmpackage/api/webservice/NpmPackageWebService.java diff --git a/web-npmpackage-core/pom.xml b/npmpackage/web-npmpackage-core/pom.xml similarity index 97% rename from web-npmpackage-core/pom.xml rename to npmpackage/web-npmpackage-core/pom.xml index eee153a0..fc752b6a 100644 --- a/web-npmpackage-core/pom.xml +++ b/npmpackage/web-npmpackage-core/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + npmpackage com.inspur.edp ${custom.version} diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/cacheclean/NpmCacheCleanCommandExecutor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageConfiguration.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/config/NpmPackageInstallConfiguration.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NodeModulesPathGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandExecutor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallLockFilePathGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallParameterValidator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingParameter.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallingTagManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/NpmRepositoryConnection.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonCopyManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/PackageJsonPathGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmDeployPathGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandExecutor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalNpmInstallCommandParameterGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/GlobalPackageJsonPathGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npminstall/global/NpmInstallGlobalManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandExecutor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogin/NpmLoginCommandParameterGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandExecutor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmlogout/NpmLogoutCommandParameterGenerator.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheck.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConstant.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingConvertor.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingEncryptService.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingInitialization.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingPathManager.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingReader.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/npmsetting/NpmSettingWriter.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/packagejsonfile/package.json diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallServiceImpl.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallServiceImpl.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallServiceImpl.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageInstallServiceImpl.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageServiceImpl.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageServiceImpl.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageServiceImpl.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/service/NpmPackageServiceImpl.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageInstallWebServiceImpl.java diff --git a/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageWebServiceImpl.java b/npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageWebServiceImpl.java similarity index 100% rename from web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageWebServiceImpl.java rename to npmpackage/web-npmpackage-core/src/main/java/com/inspur/edp/web/npmpackage/core/webservice/NpmPackageWebServiceImpl.java diff --git a/web-npmpackage-core/src/main/resources/META-INF/spring.factories b/npmpackage/web-npmpackage-core/src/main/resources/META-INF/spring.factories similarity index 100% rename from web-npmpackage-core/src/main/resources/META-INF/spring.factories rename to npmpackage/web-npmpackage-core/src/main/resources/META-INF/spring.factories diff --git a/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java b/npmpackage/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java similarity index 100% rename from web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java rename to npmpackage/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npminstall/NpmInstallCommandParameterGeneratorTest.java diff --git a/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java b/npmpackage/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java similarity index 100% rename from web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java rename to npmpackage/web-npmpackage-core/src/test/com/inspur/edp/web/npmpackage/core/npmpackagecheck/NpmPackageCheckTest.java diff --git a/web-npmpackage-patch/pom.xml b/npmpackage/web-npmpackage-patch/pom.xml similarity index 96% rename from web-npmpackage-patch/pom.xml rename to npmpackage/web-npmpackage-patch/pom.xml index 9e86df9c..390d01ab 100644 --- a/web-npmpackage-patch/pom.xml +++ b/npmpackage/web-npmpackage-patch/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + npmpackage com.inspur.edp ${custom.version} diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/FileOperation.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/MyPropertyNamingStrategy.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/NpmPackagePatchService.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PackageJsonFileManager.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/PatchConstants.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/README.md diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/RescureReadFiles.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/SerializePackageJson.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonDependencyInfo.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/PackageJsonInfo.java diff --git a/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java b/npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java similarity index 100% rename from web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java rename to npmpackage/web-npmpackage-patch/src/main/java/com/inspur/edp/web/npmpackagepatch/packagejson/SerializedPackageJson.java diff --git a/pom.xml b/pom.xml index bc7d1da2..95dd6d7a 100644 --- a/pom.xml +++ b/pom.xml @@ -38,9 +38,6 @@ jitengine-web-api jitengine-web-core - web-npmpackage-core - web-npmpackage-api - web-npmpackage-patch web-dynamic-form-api web-dynamic-form-core web-formconfig-api @@ -49,6 +46,8 @@ scriptcache appconfig approval-format + npmpackage + form-process -- Gitee From 836d97899efc7b5574c1d483a32f9db12319e8ea Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:21:30 +0800 Subject: [PATCH 15/18] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- metadata/pom.xml | 22 +++++++++++++++++++ .../web-pageflow-metadata}/pom.xml | 2 +- .../pageflow/metadata/entity/AdaptedPage.java | 0 .../entity/AdaptedPageFlowMetadataEntity.java | 0 .../AdaptedPageFlowMetadataEntityService.java | 0 .../metadata/entity/AdaptedRoute.java | 0 .../web/pageflow/metadata/entity/Page.java | 0 .../entity/PageFlowMetadataEntity.java | 0 .../entity/PageFlowMetadataEntityManager.java | 0 .../pageflow/metadata/entity/PagePublish.java | 0 .../web/pageflow/metadata/entity/Project.java | 0 .../web/pageflow/metadata/entity/Route.java | 0 .../PageFlowMetadataEventListener.java | 0 .../PageFlowMetadataEntityManager.java | 0 .../PageFlowMetadataEntitySerializer.java | 0 .../PageFlowMetadataTransferSerializer.java | 0 .../PageFlowMetadataUpdateService.java | 0 .../service/RouteMetadataService.java | 0 .../entity/PageFlowMetadataEntityTest.java | 0 .../web-sourcecode-metadata}/pom.xml | 2 +- .../entity/RelativePathEnumEntity.java | 0 .../metadata/entity/SourceCodeItemEntity.java | 0 .../entity/SourceCodeMetadataEntity.java | 0 .../SourceCodeMetadataEventListener.java | 0 .../manager/SourceCodeMetadataManager.java | 0 .../SourceCodeMetadataEntitySerializer.java | 0 .../SourceCodeMetadataTransferSerializer.java | 0 .../utility/FileOperationExtensions.java | 0 .../utility/SourceCodeMetadataUtility.java | 0 .../web-statemachine}/pom.xml | 2 +- .../manager/StateMachineMetadataManager.java | 0 .../metadata/StateMachineMetadataContent.java | 0 .../serializer/StateMachineSerializer.java | 0 .../StateMachineTransferSerializer.java | 0 .../StateMachineMetadataContentTest.java | 0 pom.xml | 5 ++--- 36 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 metadata/pom.xml rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/pom.xml (97%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetadataService.java (100%) rename {web-pageflow-metadata => metadata/web-pageflow-metadata}/src/test/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityTest.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/pom.xml (97%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java (100%) rename {web-sourcecode-metadata => metadata/web-sourcecode-metadata}/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java (100%) rename {web-statemachine => metadata/web-statemachine}/pom.xml (97%) rename {web-statemachine => metadata/web-statemachine}/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java (100%) rename {web-statemachine => metadata/web-statemachine}/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java (100%) rename {web-statemachine => metadata/web-statemachine}/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java (100%) rename {web-statemachine => metadata/web-statemachine}/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java (100%) rename {web-statemachine => metadata/web-statemachine}/src/test/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContentTest.java (100%) diff --git a/metadata/pom.xml b/metadata/pom.xml new file mode 100644 index 00000000..2c93a6a9 --- /dev/null +++ b/metadata/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + com.inspur.edp + web + 0.1.9-SNAPSHOT + + + metadata + pom + ${custom.version} + + + web-pageflow-metadata + web-sourcecode-metadata + web-statemachine + + + \ No newline at end of file diff --git a/web-pageflow-metadata/pom.xml b/metadata/web-pageflow-metadata/pom.xml similarity index 97% rename from web-pageflow-metadata/pom.xml rename to metadata/web-pageflow-metadata/pom.xml index de910635..bdedf19a 100644 --- a/web-pageflow-metadata/pom.xml +++ b/metadata/web-pageflow-metadata/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + metadata com.inspur.edp ${custom.version} diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPage.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntity.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedPageFlowMetadataEntityService.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/AdaptedRoute.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Page.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntity.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityManager.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/PagePublish.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Project.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/entity/Route.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/listener/PageFlowMetadataEventListener.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/manager/PageFlowMetadataEntityManager.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataEntitySerializer.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/serializer/PageFlowMetadataTransferSerializer.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/PageFlowMetadataUpdateService.java diff --git a/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetadataService.java b/metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetadataService.java similarity index 100% rename from web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetadataService.java rename to metadata/web-pageflow-metadata/src/main/java/com/inspur/edp/web/pageflow/metadata/service/RouteMetadataService.java diff --git a/web-pageflow-metadata/src/test/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityTest.java b/metadata/web-pageflow-metadata/src/test/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityTest.java similarity index 100% rename from web-pageflow-metadata/src/test/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityTest.java rename to metadata/web-pageflow-metadata/src/test/java/com/inspur/edp/web/pageflow/metadata/entity/PageFlowMetadataEntityTest.java diff --git a/web-sourcecode-metadata/pom.xml b/metadata/web-sourcecode-metadata/pom.xml similarity index 97% rename from web-sourcecode-metadata/pom.xml rename to metadata/web-sourcecode-metadata/pom.xml index 377db5ab..16afe908 100644 --- a/web-sourcecode-metadata/pom.xml +++ b/metadata/web-sourcecode-metadata/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + metadata com.inspur.edp ${custom.version} diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/RelativePathEnumEntity.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeItemEntity.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/entity/SourceCodeMetadataEntity.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/listener/SourceCodeMetadataEventListener.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/manager/SourceCodeMetadataManager.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataEntitySerializer.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/serializer/SourceCodeMetadataTransferSerializer.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/FileOperationExtensions.java diff --git a/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java b/metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java similarity index 100% rename from web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java rename to metadata/web-sourcecode-metadata/src/main/java/com/inspur/edp/web/sourcecode/metadata/utility/SourceCodeMetadataUtility.java diff --git a/web-statemachine/pom.xml b/metadata/web-statemachine/pom.xml similarity index 97% rename from web-statemachine/pom.xml rename to metadata/web-statemachine/pom.xml index 2a4ee129..09fa7a4e 100644 --- a/web-statemachine/pom.xml +++ b/metadata/web-statemachine/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + metadata com.inspur.edp ${custom.version} diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java b/metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java similarity index 100% rename from web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java rename to metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/manager/StateMachineMetadataManager.java diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java b/metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java similarity index 100% rename from web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java rename to metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContent.java diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java b/metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java similarity index 100% rename from web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java rename to metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineSerializer.java diff --git a/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java b/metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java similarity index 100% rename from web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java rename to metadata/web-statemachine/src/main/java/com/inspur/edp/web/statemachine/serializer/StateMachineTransferSerializer.java diff --git a/web-statemachine/src/test/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContentTest.java b/metadata/web-statemachine/src/test/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContentTest.java similarity index 100% rename from web-statemachine/src/test/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContentTest.java rename to metadata/web-statemachine/src/test/java/com/inspur/edp/web/statemachine/metadata/StateMachineMetadataContentTest.java diff --git a/pom.xml b/pom.xml index 95dd6d7a..0a21ca00 100644 --- a/pom.xml +++ b/pom.xml @@ -22,15 +22,13 @@ web-common web-form-metadata-api web-form-metadata - web-sourcecode-metadata - web-pageflow-metadata web-frontendproject web-frontendproject-api web-form-jitengine web-designschema web-designschema-api - web-statemachine + web-tsfile-api web-tsfile-core web-ide-api @@ -48,6 +46,7 @@ approval-format npmpackage form-process + metadata -- Gitee From 0d1bad5da1a5d2800c0acfb656834d8828699e5f Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:42:55 +0800 Subject: [PATCH 16/18] =?UTF-8?q?=E8=B0=83=E6=95=B4tsfile-service=EF=BC=8C?= =?UTF-8?q?=E9=80=82=E9=85=8Dspring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/tsfile/api/service/TsFileService.java | 10 +++-- .../web/tsfile/core/TsFileWebServiceImpl.java | 20 +++++----- .../core/config/TsFileConfiguration.java | 8 +++- ...4WebApi.java => TsFileManagerService.java} | 14 +++++-- .../core/service/TsFileServiceImpl.java | 38 ++++++------------- 5 files changed, 44 insertions(+), 46 deletions(-) rename web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/{TsFileService4WebApi.java => TsFileManagerService.java} (90%) diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java index 63c3d761..387cbe92 100644 --- a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java +++ b/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java @@ -17,9 +17,12 @@ package com.inspur.edp.web.tsfile.api.service; import java.util.ArrayList; +import java.util.List; -/* -ts文件对外暴露service +/** + * ts文件对外暴露service + * + * @author noah */ public interface TsFileService { @@ -49,6 +52,7 @@ public interface TsFileService { /** * 依据ts文件路径构造对应的ts 中class名称 + * * @param tsFilePath * @return */ @@ -74,7 +78,7 @@ public interface TsFileService { * * @param path 文件相对于开发根目录的路径,不含文件名 */ - ArrayList getTsFileList(String path); + List getTsFileList(String path); /** diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java index ba0e1ec1..7126efc3 100644 --- a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java @@ -18,8 +18,9 @@ package com.inspur.edp.web.tsfile.core; import com.inspur.edp.web.tsfile.api.entity.FileObject; import com.inspur.edp.web.tsfile.api.webservice.TsFileWebService; -import com.inspur.edp.web.tsfile.core.service.TsFileService4WebApi; +import com.inspur.edp.web.tsfile.core.service.TsFileManagerService; +import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; @@ -32,33 +33,30 @@ import java.util.Map; */ public class TsFileWebServiceImpl implements TsFileWebService { + @Resource + private TsFileManagerService tsFileManagerService; + @Override public Object loadTsFileContent(String path) { - - TsFileService4WebApi service = new TsFileService4WebApi(); - Map map = new HashMap<>(); map.put("success", true); - map.put("content", service.loadTsFile(path)); + map.put("content", this.tsFileManagerService.loadTsFile(path)); return map; } @Override public void saveTsFile(String path, FileObject fileObject) { - TsFileService4WebApi service = new TsFileService4WebApi(); - service.saveTsFile(path, fileObject.content); + this.tsFileManagerService.saveTsFile(path, fileObject.content); } @Override public void createTypescriptFile(String path) { - TsFileService4WebApi service = new TsFileService4WebApi(); - service.createTypescriptFile(path); + this.tsFileManagerService.createTypescriptFile(path); } @Override public void createMobileTsFile(String path) { - TsFileService4WebApi service = new TsFileService4WebApi(); - service.createMobileTsFile(path); + this.tsFileManagerService.createMobileTsFile(path); } } diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java index b752ae86..c2386bae 100644 --- a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java @@ -18,6 +18,7 @@ package com.inspur.edp.web.tsfile.core.config; import com.inspur.edp.web.tsfile.api.service.TsFileService; import com.inspur.edp.web.tsfile.core.TsFileWebServiceImpl; +import com.inspur.edp.web.tsfile.core.service.TsFileManagerService; import com.inspur.edp.web.tsfile.core.service.TsFileServiceImpl; import io.iec.edp.caf.rest.RESTEndpoint; import org.springframework.context.annotation.Bean; @@ -33,7 +34,12 @@ import org.springframework.context.annotation.Configuration; public class TsFileConfiguration { @Bean public TsFileService tsFileService() { - return TsFileServiceImpl.getNewInstance(); + return new TsFileServiceImpl(); + } + + @Bean + public TsFileManagerService tsFileManagerService() { + return new TsFileManagerService(); } @Bean() diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java similarity index 90% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java rename to web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java index af2295f8..6e8f9b0d 100644 --- a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileService4WebApi.java +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java @@ -18,20 +18,26 @@ package com.inspur.edp.web.tsfile.core.service; import com.inspur.edp.web.common.io.FileUtility; import com.inspur.edp.web.tsfile.api.service.TsFileService; +import io.iec.edp.caf.commons.utils.SpringBeanUtils; -import java.util.ArrayList; +import javax.annotation.Resource; +import java.util.List; /** * @author guozhiqi */ -public class TsFileService4WebApi { - private final TsFileService service = TsFileServiceImpl.getNewInstance(); +public class TsFileManagerService { + /** + * 注入TsFileService + */ + @Resource + private TsFileService service; public final void deleteTsFile(String fullPath) { service.deleteTsFile(fullPath); } - public final ArrayList getTsFileList(String path) { + public final List getTsFileList(String path) { return service.getTsFileList(path); } diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java index 91598253..9158bbc6 100644 --- a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java +++ b/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java @@ -20,6 +20,7 @@ import com.inspur.edp.lcm.metadata.api.entity.GspMetadata; import com.inspur.edp.lcm.metadata.api.entity.MetadataProject; import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService; import com.inspur.edp.lcm.metadata.api.service.MetadataService; +import com.inspur.edp.web.common.customexception.WebCustomException; import com.inspur.edp.web.common.io.FileUtility; import com.inspur.edp.web.common.metadata.MetadataUtility; import com.inspur.edp.web.tsfile.api.service.TsFileService; @@ -30,6 +31,7 @@ import org.apache.commons.io.FilenameUtils; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Optional; /** * ts文件服务实现 @@ -38,16 +40,6 @@ import java.util.List; */ public class TsFileServiceImpl implements TsFileService { - /** - * 私有构造函数 避免外部私自实例化 提供统一返回实例方法 - */ - private TsFileServiceImpl() { - - } - - public static TsFileServiceImpl getNewInstance() { - return new TsFileServiceImpl(); - } @Override public final void deleteTsFile(String fullPath) { @@ -55,7 +47,7 @@ public class TsFileServiceImpl implements TsFileService { } @Override - public final ArrayList getTsFileList(String path) { + public final List getTsFileList(String path) { throw new UnsupportedOperationException(); } @@ -72,26 +64,18 @@ public class TsFileServiceImpl implements TsFileService { @Override public final String loadTsFileContentByWebCmp(String formRelativePath, String webCmpId) { - String fileStr = ""; - MetadataProjectService metadataProjectService = SpringBeanUtils.getBean(MetadataProjectService.class); - MetadataProject projInfo = metadataProjectService.getMetadataProjInfo(formRelativePath); - MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class); - List metadataList = metadataService.getMetadataList(projInfo.getProjectPath()); - - GspMetadata webcmpMeta = null; - for (GspMetadata item : metadataList) { - if (webCmpId.equals(item.getHeader().getId())) { - webcmpMeta = item; - break; - } + Optional optionalProjInfo = MetadataUtility.getInstance().getMetadataProject(formRelativePath); + if (!optionalProjInfo.isPresent()) { + throw new WebCustomException("获取工程路径信息为空,对应工程路径为:" + formRelativePath); } + List metadataList = MetadataUtility.getInstance().getMetadataListWithDesign(optionalProjInfo.get().getProjectPath()); + + GspMetadata webcmpMeta = metadataList.stream().filter(item -> webCmpId.equals(item.getHeader().getId())).findFirst() + .orElseThrow(() -> new WebCustomException(String.format("没有找到表单对应的web构件。表单路径:{%1$s},web构件id:{%2$s}", formRelativePath, webCmpId))); - if (webcmpMeta == null) { - throw new RuntimeException(String.format("没有找到表单对应的web构件。表单路径:{%1$s},web构件id:{%2$s}", formRelativePath, webCmpId)); - } String fileName = webcmpMeta.getHeader().getFileName(); - String fullPath = webcmpMeta.getRelativePath() + "/" + fileName.substring(0, fileName.lastIndexOf(".")) + ".ts"; + String fullPath = FileUtility.combine(webcmpMeta.getRelativePath(), fileName.substring(0, fileName.lastIndexOf(".")) + ".ts"); return loadTsFileContent(fullPath); } -- Gitee From e3514d1818e1cd3236663b93896868e7e9acd8f3 Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:50:46 +0800 Subject: [PATCH 17/18] =?UTF-8?q?=E8=B0=83=E6=95=B4tsfile-service=EF=BC=8C?= =?UTF-8?q?=E9=80=82=E9=85=8Dspring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 3 +-- tsfile/pom.xml | 20 +++++++++++++++++++ .../web-tsfile-api}/pom.xml | 2 +- .../edp/web/tsfile/api/entity/FileObject.java | 0 .../web/tsfile/api/service/TsFileService.java | 0 .../api/webservice/TsFileWebService.java | 0 .../web-tsfile-core}/pom.xml | 2 +- .../web/tsfile/core/TsFileWebServiceImpl.java | 0 .../core/config/TsFileConfiguration.java | 0 .../core/service/TsFileManagerService.java | 0 .../core/service/TsFileServiceImpl.java | 0 .../edp/web/tsfile/core/util/NameUtil.java | 0 .../main/resources/META-INF/spring.factories | 0 .../core/service/TsFileServiceImplTest.java | 0 14 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tsfile/pom.xml rename {web-tsfile-api => tsfile/web-tsfile-api}/pom.xml (97%) rename {web-tsfile-api => tsfile/web-tsfile-api}/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java (100%) rename {web-tsfile-api => tsfile/web-tsfile-api}/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java (100%) rename {web-tsfile-api => tsfile/web-tsfile-api}/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/pom.xml (98%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/main/resources/META-INF/spring.factories (100%) rename {web-tsfile-core => tsfile/web-tsfile-core}/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java (100%) diff --git a/pom.xml b/pom.xml index 0a21ca00..5108f457 100644 --- a/pom.xml +++ b/pom.xml @@ -29,8 +29,6 @@ web-designschema web-designschema-api - web-tsfile-api - web-tsfile-core web-ide-api web-ide-webapi @@ -47,6 +45,7 @@ npmpackage form-process metadata + tsfile diff --git a/tsfile/pom.xml b/tsfile/pom.xml new file mode 100644 index 00000000..778f9184 --- /dev/null +++ b/tsfile/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + com.inspur.edp + web + ${custom.version} + + + tsfile + pom + ${custom.version} + + web-tsfile-api + web-tsfile-core + + + \ No newline at end of file diff --git a/web-tsfile-api/pom.xml b/tsfile/web-tsfile-api/pom.xml similarity index 97% rename from web-tsfile-api/pom.xml rename to tsfile/web-tsfile-api/pom.xml index a949eaa6..0ce2e32f 100644 --- a/web-tsfile-api/pom.xml +++ b/tsfile/web-tsfile-api/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + tsfile com.inspur.edp ${custom.version} diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java b/tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java similarity index 100% rename from web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java rename to tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/entity/FileObject.java diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java b/tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java similarity index 100% rename from web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java rename to tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/service/TsFileService.java diff --git a/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java b/tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java similarity index 100% rename from web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java rename to tsfile/web-tsfile-api/src/main/java/com/inspur/edp/web/tsfile/api/webservice/TsFileWebService.java diff --git a/web-tsfile-core/pom.xml b/tsfile/web-tsfile-core/pom.xml similarity index 98% rename from web-tsfile-core/pom.xml rename to tsfile/web-tsfile-core/pom.xml index d0f68a05..7eabcd8c 100644 --- a/web-tsfile-core/pom.xml +++ b/tsfile/web-tsfile-core/pom.xml @@ -19,7 +19,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - web + tsfile com.inspur.edp ${custom.version} diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java b/tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java similarity index 100% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java rename to tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/TsFileWebServiceImpl.java diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java b/tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java similarity index 100% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java rename to tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/config/TsFileConfiguration.java diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java b/tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java similarity index 100% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java rename to tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileManagerService.java diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java b/tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java similarity index 100% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java rename to tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImpl.java diff --git a/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java b/tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java similarity index 100% rename from web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java rename to tsfile/web-tsfile-core/src/main/java/com/inspur/edp/web/tsfile/core/util/NameUtil.java diff --git a/web-tsfile-core/src/main/resources/META-INF/spring.factories b/tsfile/web-tsfile-core/src/main/resources/META-INF/spring.factories similarity index 100% rename from web-tsfile-core/src/main/resources/META-INF/spring.factories rename to tsfile/web-tsfile-core/src/main/resources/META-INF/spring.factories diff --git a/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java b/tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java similarity index 100% rename from web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java rename to tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java -- Gitee From 39e9e562321d4b89b0a6746611a27c84dad69415 Mon Sep 17 00:00:00 2001 From: guozhiqi Date: Wed, 19 Jul 2023 10:51:47 +0800 Subject: [PATCH 18/18] =?UTF-8?q?=E8=B0=83=E6=95=B4tsfile-service=EF=BC=8C?= =?UTF-8?q?=E9=80=82=E9=85=8Dspring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edp/web/tsfile/core/service/TsFileServiceImplTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java b/tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java index 3bdb20d5..9ff93af4 100644 --- a/tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java +++ b/tsfile/web-tsfile-core/src/test/java/com/inspur/edp/web/tsfile/core/service/TsFileServiceImplTest.java @@ -25,14 +25,14 @@ public class TsFileServiceImplTest { @Test public void testClassName() { - TsFileService tsFileService = TsFileServiceImpl.getNewInstance(); + TsFileService tsFileService = new TsFileServiceImpl(); String tsClassName = tsFileService.getTsClassNameByPath("ddd.ts"); System.out.printf(tsClassName); } @Test public void replaceTsClassName() { - TsFileService tsFileService = TsFileServiceImpl.getNewInstance(); + TsFileService tsFileService = new TsFileServiceImpl(); String oldTsClassName = tsFileService.getTsClassNameByPath("ddd.ts"); assertEquals(oldTsClassName, "DddService"); -- Gitee

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 z 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%0AcEuNHD6HJ4|hc5k*02=6eLw>X`;r9{~hQ1vb{$o zXPQJmJ93MhIL6iRX&rzSCc$zGMNSMnCxAL9+els*K->8|(NjC-=8!c68f+n>aGXfe zA|^q9KxLSb?-20mNT&Ypn5^HR!T(<->vu2UHc5$+jeI*~B`6Bavy&!0 z3x9ZT{&bdY?c}}RQ~L{64bFx}VbNK(;s_(48$;}FVTduJiK@jMDC$J)A=FeRL9%wB z4S1zT8$vCdGZtM>RVwdy*6y_nn5EukNK!vKhOrVa$zt$%tNsH;VFFVaOK+Q8uq}H9MMv7I? z;4U<9VAG;PmF#y~#!0FpEi`v0%ZU-xQKU)5Zq{ojWm7`yNU`OccSL5GUqlz8Qy`w? z`1H*xd(;vz)PtkkH{H(|tm9f9H@Nd^PR=BoLJ>$x10*9`Iv6_yIU~UWTg^PDIHy2-D z85azU1wpmw;i(?3$L2C&U9qvIF0LQvx21W9cz(ux6i0^7pk}_Sml~uCtBNnpj&6PO z)L_bXY$l$4@!W_0PpoEW2$X%rA!vp{unJNQ$y>xv~S*pimchQiNP}4 zwsmgO6dH91XGNw^pw1U;J8|2@HUmyoa%X)>i0J~64Bo@)_<>`LKANpuA44dGCl6N#6DMT-YR&&8A_)NQ0rQT1!!cOCi_9N{ zi!=0=Dt4Kk{uY^Z^v>YM9zv!BkNAf*Z~;~SOaR;qP?*ODgcf80fc{V2O5n;hMjUdJ z^h&u~76DT7J5SjN1`6Dg#SaCp;zyVeW#I$?EoqU;aPJ%7-N1SDna`K-gE{V3{_dl6 zDG@kJRT2Dr;`HU^xpCK|p4i}dEgfa`nOC=EU&v3?Ipqikd41G6Dm_i{EG-)W@-kPE zz%vD&M_|)Hz7}PR{Ra&75l-#^RIRJoYpCr(_0#?pju@}gJI=V-lEYtPuf91AnO%af z{`?n2rA}wO+cNXevV)3vkVRQ1y0f`P0E)1@Se~rKERT?|AK8fIqBo0AJrF1gw7>8Q z@*vUFrcZr>k1IU=OMUPvsNlTAes`;6BU)D!y6$DgYxupH?+EjcM;esbyYM5zupl!B zFtfP&Cr`f?gL%wLRWNf*U@z87(jO@+67tHf39c{75ZM#TdTrO7s9at0%%HTPf#l|^ z4uHZ6@7n`~#P>Pm3~NGB>WktN3xI*++et4zXd|&|u?OPEbuW(oi{AAwJDNQN=HV7p z0072su`ADiw2c4Tn*E=tV}^DIrz_=t9A;^0Ro z%82B}osvwvQ6UQXXlGKfbAU_k^8$}|ySGYIJ~Is8f;6fPhR#9BHyI|`x}-eGs3I-xPILa34&Mdurh!9I zuh!mCig$CEUfP@LecigS{kU^X*i6Dn8{TI&OHIl?4`rZI*Ytqwz0Ge2iCkJdJ^C3~ zJh%zxqA>O`=KVc2k7kckVUOks7+g+oK5^&PBx5BP4-aPhyIatCw}LSG``aNfzwKS= z^vUz)W(5~VlGQcLbCYo`1Uu-F@eC%YC^d#Q^cME8^wmXPyyt(A~M*gjXp#TTpf ztiS}+J`0U**Anh#!f4LpC6=ZZuzuSdT-`Z=@;2gG6e~!UFs^}%4Wqqf1%g#XIGalw zd+5b51|Fnt3KZMu5aOH%LJBM>wv~~8!I@x=e;sz?t1(Si;n$!jUJLWe*5%^4Veu1Gc zr&#OCE@lP)@n`%FtE{ax8-44Km@j(axX^I5+1^ZNMh?e zHmMS?E5#}-+A&6)(;syDTzVy)bWh&8qcA{LHnOeC=@S-c>YcX|k%T)CqQE(IX0T=v z-WN8;-MH^zlh+ikeF{s1uaT_y@<&O+>^n3gk> z$(W6^GqUbBn=4*eSSS>o*DgAzYR(zNKP|a>iUKi4$b)mf{H%+XsHp9sbrGV>a~O|! z@m~C7lZAN6nhDptho=3nlCdM2lMb-X4NN@9$X>!BWp(E$D1LRvYGT5U2t~BrHxgI6 zYeAId8B}d?@tf4f`4PEF`%u)ok$MtP&uke9*CD^swo7;Rmr*4ekuPXk63AsV#ukJ4 zX^iwp7VEhX&7Yt=+$W+m_h#Q$1V@$E30vZD7|O^Szb%DjPECKw^K$+2>=feeFTe|f z1Fu+i%(8S`7t#)@gAEWh4DKv-ux2PcjCHeHddoj57UNOGIVd+G+2^6^ z7LRrEAgL0m&D6D@klb+PcQUEq2yi%lA-%g%O`h2BQQy+92%9r6r_6!RMoa*<7Po ziBV9%j=N+y@ltQ3R6$KGIvy2lkzX*4meg%r+pQ+kpVDV}#p+((m6qKe zUdiz8THF*ccoa)&d5|UBnQTdar0NQ_y>dt~xvy?qJKQ*>O0rMehoihs-lxO-LA_;m z57#}k+acQ>cEkG0*S&L?GrtE&*-bK(R zzGZyB@?sc-p8(e(`^m*`b6<2S0FQ8vcW{wT73@4}dT|!-WU{|_c z0;X?vkGK7^yWViN=(qG({PoYhg_UQ&kLhQ3{+FNKcuVd*8t0a!uX+26i29^s9_f-ZbJAqG^6cr2 zF?5VC{$o3b<}#mXH>_t|?I0k(@mrg|*0C=qEBtnBd(Jo5n+%2zrz=W6;hQ~~n{p9=VZ3}}7pFaRCy@TTg6H0S=BP>i1CP$5t@l`~4 z!(FFcNPkb9y<_?sEnYc;ZIw#W-&5b?mi2|jPS88X9|*~ONA|_7F)qOslkrU27HGEA z9Ma=ddKmJ#*=a5NI-`F3^Ty}>=7bXvdrg#WxjhF7e>9ME zlNEmjTXk`+!849pip3vaT81jH4{#X{dVFLgfe%Xa1O*N6n#XjA$ETpsLyBX)4ggQG ziMlEb^%xI?sTALvV=c=XXzSI;xrr8Co+oviLmS4l)mLR-uCe{g?W~ZQ3Z2~`3uYI! z|6JJr(#k#n5s6r5zstZ#pA&Ip{opW;#--chtXEp*qi_}hmaR|Ri~1sU6~c)|0Cgfw zy$VRha{gw!@_am#)cS(TidygzAWqFQHwvoBl8Wm9;2x})KC*0W*zByKap;vI4MGDR z&`9|Yun!bq#Loa{QBhgrqxH(jOwZmsEq&J*R@UF*1NUN$>C56i1NZ0c3+Y&4x9Qg{ z%r~40J?q^mva_3fNH~%^0XY2ZH8NL)<44v%FAP$~8x6S!aKO^X&tM%iLr57J)J{&4 z;sDfKlXxmf4Vm$1ac8n(8BEM8T2EAJZolIXdM2yu$j;kr#m5vIzCsH5%Jg1dZ%2$OASJ;UN60K~5KqYy>uI_R=H@?(A+Y z2M8R9qrPrx&&-uj2$@ofmE;Q*abgep2+bSxb`UX;DJqX-I|?0L*PlsRHMR^|G8VlO zSXTu7AVW5`dLP zRI?hBsnC*&HJZig05fvI29MdFFsCO)JfOVjK$e^=+)oYjHriU5rX<#EJhD@%`OQ$7 zIdD^z1#1}s`a!-Evkh<(X+jMReAH7l($dWC^=2c*6>Ct7xv*1e!VRpmmpb`hIB(U$ zGY|eO5L21ohdHP$Wx85VnQ>UKsadC5S|4xYsuLTx%o{_^4nA=JriZiTyAeNz3&gQy zLhUHX;I7J_4B)#^y(7=|kN`fxV7poZo$nnsE0_-n?nrE~o}Mtsox)MflJX{ZL^&x2 zT28U86jIizWeq5^!^TTL8~oriK!q#(Bnt1w=stZo1h04nU;~^b1C}AoM+Mwu>5Wv@ zFD@{rKt~VLt138IkZ7006idbs$HY&a3ZSpM`CAS;&sQx8s_N zDFgu)f1DfD!wTsu^0JVD$K4SAFS4JtXwkXzx_NUaH`mAgNgUKeq-GSE`hj+|P z!2#+sfv*tNpuK;)? z@Tq-3ySd<@yUo1%MsW*SJYIujT)?9j>e&_BSvA3jo@{$ubdXCS(H6#Wob&fTIcZ!Z zhtoUXaX);gqd_B|CRZKe^b>i=D)7iFPwTwB!rgrjrpkJd>{3xE;mFIzI!VIk1v#M? z+@G-U0B!FAoAv{m)(1cN0-W}Pn%)5_vk!X6GrXi{cstp>z;*bv)5^Ya+4Vj#nAVNR z=J&5YQp&C!@a~T;Yb{RxV=<05ve(RZx?cx=->30@eSX=t zg*UjpmQtFp>X6T9>}c!9INU1PGL^GD^+a%2uney8dHADEBCl45Db1T)PL?Vcm9?3s z8G8=ZG8MCwcL=;v?#?ahlhPd=lQ(Jk1GbL})wk~mpJ|_^kzm{oF;k*U`q4}v+dHw%i+N@Km!RBT&!U8%pvot8;oT16 z+Gju=_>mPl^9ORYPvFyZ=Z9ThfoPijml>alI>Io2POsMoB@udr0K3loPOy*5 z^SCq0J*>r;3i@m$6NhVUe!69a@~8A!(Lny*?WijF%4&7v$*~pBdhco;`sVP%WxtZ# zGW4=5!^`S$dTkcN zqqxP}dK244&^a{iDJ-8aVpwak$WV=qv$a-ajhDnQi`d5rb+;OM$Cqe}Jhju>W}`Ur zm@uQl%tOw_}tVZsuf>bO>73gM8TjTza5oMUx(%I5~`BwV7qAgvP4gH|22$^wy zRx~~HUwDYHsUe4FSD<5`$IwgI1^B>93cE+Z%L6UdfoMnGn>VE={&~#Zyzz&wJFn=* zl7bfU8cndqsg`z)dU=o4;5J*hb@K!fh_>YoSlejxh)i34-s{RI`*HIV%58 z57|uGGe$D#H?EtFtI}ZgS2&k;lL$iCw@L?xt*?m}+oB@_3_Ib%oF;kp^?+!`S zANu_#3uib@X@fvr2qtxE8z?H@4{NByE7O$4SN{X?ad@~{CEEq1YRkDYyqS^Y?+zh3 zIE1y#pXvqy>WIa(Cu&iw$Mva`RjS?0%gz|bM;+soffNJ)>RtOb;K`J@t&X(T}Z{g zfW>;Y(2oFZ@g;V=@mlXH9Sjx(UVYGK_FPi@6RF+r4)gZGkJ?)E=Wcr|o zG!kNexlTFUmGNl={0V@7ZrUSRW? zA}de4{10EuF1pRyS|(53s08-VH_mb4M|`y!+hLcIRMAFR<5tWgZZ!&bew>=@H405rkG=p*yqJG!IWnYzqv!RS}e znB!*~8Z)3&Mz&PO-uo;-8gnZed~Yq99Q7ksg}Vd&N&{bi`uJiRWaz<5(()Q|^AKW>$^h`XV(or~!q^nn=kS{(+? z%Kp06tCGVF9#02>$%NZ4sU4@*+cK}_lo=-RXiCF7e6N1*Mua97Y)5^&CMS;m!7o0r z*T-!<#bCeqg_%XsT{PD&GH1;LpVDB`ouO<{ZD(``(@@ud-u69OzC48rl|@qL0Ws z8XpY7-xbF^(PL1QV5y7Bn9krdH(P&>TVV&V#Ys)*69kL_%7l59#;HyZ1Zc7^Ifp{ahw`oT@kG+97lli+9uu>!B=uVA zJ0e=*aofJcI2aK`<3XaY!wCz^rFdV4Hlt%Z*A95nviC>^Y( zcKFbUmo=D^ysAS+xh~7S5LYDD9Ng7ITG=Btn^p4kB>z8Uk;Y4b9a!JjsP_BG_@9q( zaaT)|zYpvbg^urmjgT#you1waQ5zac2iV8zLV$$;F%}4v_-TZ{NA$;rlkFW%g#hX= zz5FFEW&UAgMo!Ka?ipXtHa`H4A-8{+uRkk{ch$G&Hj8}Y+!18~AC4@<_BU2rh<;H_ zSN%){)!ix6!5qOXL58e;R*gPO?=>GiIEZ0fsbGqz7OG%hN90^@(5k?^bg=@7X{C_L zm57cS7a!TXDA#68J*>!q4*w{Q7f(N@0e90(6|n-^mRQT}c6PdPPGDig3|spY;rCa9 zEmoyR^EC>!1&obx|F(Xys4 zhTk`W;XfluwW_5uvNQ@WE>MywP$1#;hF3UX;XyZOi%72p0INZY_pizfmepkwGFIjS zsGslhbgHeYn!dlqHMetRB!W?9zvlOACc1^m^zhn4>S%rm^VA?LyU9wU+L239sAy=vGduZKKESAlhWLgbEc} zbFm6-?D8C76=||t44(P9c@lc@R-0*!C3Np>#DcQ2wRl38UUjW)z89M8(r)^{1W;=q;3<)|gGkA%Sg> zx0UMMOsg6n1J7il_63Wb#;z6%btmPwm9GtTx9Re_5o$XDk>6JO-8n5uVBBcsxED5# zuzgNP=P<)V4;4mYBStPuaL1s1mxMbcYH`3LuHL(Q1$6i%WrS zm$0s!cEli=EVcKA$dF}gX?p58A~?7HQTDj%2*Ph>nU9qH)7F42ta~mpN9hsU&AB@G zAg=5E+|a;SqU(#lwBeYWMy(y{%GN*fi-N;o(%cNCLw&AJGWC5)W%3A*AbU_%h?HU7 znJHaoK6q8CjJRAGP1#3N$M%g(4Sky%RWh>-)3>7}*%ill&)`sTZA@l+gz}+gNZlSWF7epQUjxuZ#{1C=vSeb0wqXQ#$6YM_T1@hE+qSP zi7MoHUGF&`E%0F5%$y^s-4BuXu_X@KIGwdQn3FjzN)(if4bxR{NMR$N zO^_K6RevhKguNII)-Z)DfPHFZEI8|wpAnrIF@xS zi%yW}K>?KtR?>>_3MAvM1QvC%2kA>OwgFB=8l$g2h- zccwNkrVXSf$0Vv+Cfbx8$nD|l=ym0muXF2PejH+?ZBWIFJ@-#Ni1nPzlxAijad)Co zr7@(CFHWoH%77{logY6%;;!C>ZInz`Lg>wcnkFpYwIyuNr)rIeBi&STz+OPQrbzE2 zN8(ex#T<1&6NGHXAVG03WDX+{o|p#0(qNhdnPHNs?e@66?;CCm^uRzuL!p5R3e8B1 z>+!xj+?YzyXY2WTJ4!lPfU#xH+Tq0|%}3Y&c%Lcy?#l3fa=E(US7XDsegE?Z9ZH4- zwb+2t6NEw=>`_OF=}|^3qYHkkRs~*?H}PM2V|#11$Tp5aXi4C?mDGb*fy=@H6VI?;Pa|*-8Gjj(K?M zo~gx{lr1^G65dvhz+l7r9wpi-UP1C;lcwD;7$(-(5Z;YQO6r(H6cA^}3UPz=co)X# zud;0E3@d+*BYf4ooM~euOJDgD%#F79-`388nxK|YRBX&B-(J(rx?p?f z7nI)#SZt(6Pfx;NYU<98h!N`4g#~1FVbds2kMLGGDLrDgIDLq&$(p*sUk`CDZ5rxc zB9K{SipgJDBf8qI6~z=S&Ep5xm!Rts0;R79{i(tNEx&Ua#s4rY zelx9&Y)t7b?VKIHZJ7QQ+3@#Y{zr(cPHK|_W<&`6l4OGnM!4=MJcxGy1_dH4fE5WB z5Ki7+!(cFhzv6BjSp5U^Q_~MMzu`@^MlPr zo35bw5&O6KE*|ydR4VPy^7-^%f6Q?VX}a*ro@-*DkZOVz_#nON%6>Q5PQ15-RO^mX zYYHNkKpiva_hD295BS;O7JMRWsk;{|64~fe%$O8svebJZcO}(hE@lQ#FC5QGb|iL$JZWZIC@_a}_?mxOWd_G_I!$N5u` zvc!E@HP%C1`A+I!4UJ(wDH54^J;9tDBgQb!FcM1;WLFI0-8D4{4$?(PA$%K`a89lV z@INm*m=Z)4)%PVg`F4@i`HwEUvBh5ibK`GE2q$|Rr*AgW-&`a9@&50u*uSwR|1ypE z{#xn#kpF6(Qr-BwaYT+1h4M8zprRcSZL*?>C=^NPpoNGGfS`9495KxA)U!np0hp3b2CB`3x5jcB4pKmenc z3h)jP>9lyQ9A)WN2GSu8LQ%*ES}})d1I)B%>@pwPs*F$OrH2|d5iE38m-WxJ=IZ9x ziFxx-%C(!>8rqc`Wdq!g)-mm~O0jL%>Z&iz?r*@v=!!Jggt{%PkHz$uCr{QxH4R`! z#?v!%TUd;x@0ob?*gPytoTTVALe=`;0*uWPo!=oBCp9!DGLRu+2h~86UpGT3o$Kq5 zjTn=du26YX$mZ+gnI9i3?X;b4f+8DC>wx5EBKDL-9VKgR7hI?e#cc2*a?0QSNL}{) zbUmRQlW6L_NZ@y*6*W>dBA+E_ic{Vw-K)Ah+;Yncr&FM=Mtg#Jdg5GJwHFtEb(js} zC#e0@?E@{Gh_&l9&`5)^XCA3=IOpi%RDS&_qN>+nAU5;o=?ToJ+NwI1<|MM&aJ#|8 zZ=E`dk*+~)E*ed*{$P7+1zMY?IFbTOMMoelawA>I5qzP_Su+kaS0$u9lEe%|?dO9! z@h@M#*qc(Q*lKLKj2lnOvV~V+=P*(F9JZTzQsWs8kasTx3_e*eq(YBwiH8d1$(cid z5AQ1#zL3Bh{EcyYVs}6m!GcN1-E}DwI6)}^<#zz0Pt1TPU=V(xHRtM$)^T){$NXCx zZqlU&ad0l(uWWQJ34JVgCG({9#aSX}GZW0lX4BBi`0i%9rG_{r`(wNdeBD*3*-qI!b$KV(q5y&v?LIF3n@Rkwc_A56?LwThve^Zob z@{>}=5QqgLXUFqB2g}q1am|bXAj*@IW{{Da#LMm5wTS(@7^X%WZPezw)>87l#Qc9i zho%2U>HQxtslSRd|Dfvqv+wcm_idM|_FuLapP} zDT)(>wrQ*_W%jh7R${sm`lnFr7-dqD%lerHMD~8e3D@s$BpTLK^1OB)uoc%tg$gHx zRN6zDi(8oH9vCofDgy>7H+iQ~f2WWvX>M8C^<%b}<+}7LHHU@Otxe>ex|Xkc zIAh@6Y2b-c+~-}3o%CZYwtfw(bsp>*&J<>p2a7f#gzgow+$Xy@mC?SqLty?%)Kl7^ibZEq)%0puJK^G8N zxS8>3KXz{<&7*MUx+mX4dDb%0H*o}8(99kxp;4>ry>&{~!64|jh`Hf1`8CqVcmH@L z)%Tug5UQ-T@c0-`L(Hwo1M){=8ic7)PPEU%#B$0FnITBC-WfQ-qh30cg{064zubG? z1a;+RlUJlaT|S+Ijz=0zqgXF>bVd|l=sFdn_ea!Ys;C~^gv$Dl6NlX2STFhsbl&WK zA@}t0dA*{Q&Fj_@V#vlnnp5~JmV?ZA|9TOgtpc9{D>z|~Q8Kn_F`{D{da9Mc!XuL> z;$RkWAPbcoJfc64GO7Jm*GU6|d_#~SAOQYat8rmQq~v`28_0h98(9DEXQzL{%uWC9 z0roFb)Hg)U((YfdHbd%L&d91LU$%*4w(TV>C{lo+RLO~AXvy+Hs5XL9{1md3Xz%Mb zY*VQw$nNY?xcC^RC^!mv*$H=jnD|^=(aV^1CElk=(=YZC(mU_pNe&4&Q{K$*$Osd6snt`noBVGou| zD6^~lggvCv9@5g%z)o~j`E;c*7xgLZDuDR3JG?gZ3-x?-Lo~t*BSjxlY{ZuB857uv znWK`CnaN0%l4LZrMN&?3Ny#W@KO?V}30joKcm&@Z*A`JEOOTg~Re);6Wv$xHEH!!8 zMSC-y>jkAI+(Dw%Ap`wYW&Wsm3#nEmjNz1!t7O0f{*-0S(aAl8$9Ko_qGcU$KINb6 zKSR2;6Hl2}!@QVQ1nj=H5i-48aB*eGi}*PljwAn&Y=+9oONEW4%`KFdGEWh+4d>SA zq0`h(9kIDs*AO_qGHx1|)=NvdhO>`z%=Jo&i?_xJ2+Js~Mu#9neu)<8GMe&$1*%57 z+>%aRkY0`!rm>bqfjMCMvC^rsbA-EUqE=aR4ZE_Q4QCd19UM*1@!vQiL!hJ~_G)I6v02D;XUruO{$BWmiqM}o4Eruuk z=sPsse)fCkAFtF4QOap2wcdPR-=z}e1$eWQ=9@J$zD~!r)KA|t-nUc*7E^s?KoZet z;-T9s^a4X6f%mVnTL0}3dV6}EujS$Pm%GV#@;pTV(8g=V*|)tFXTQy^=9jI>pf-54 zvhIDwh~IP-Q~K@Ly`YGeCQwEj$q=}hh?`N<= zHLuS0cfNuf`LU{m1X?SFw2kA=D9o1UF=_U8e>e8p6e2*cFJ4KWdOWKJ#d9*NmMTF- zN=nr>2Oevfi$HW0AM1 zgCcycMaTT+!W3}qv%I(1nTn^ElhnkI>hdxV?A$^}Y{~7=v`_!5Jxqu_?%U|8UN7kG z{YJ7)59m*aLo}crXXFjbO#uFwtWh6mEX$?<9XqnH4GWvH9NK2Z%Uy-l=m4ab=)QXg z1YEfAh2p8-Y&9^2r(7a(f{rM@{Q{ri2kv=BnHQN=GkNW=VWSsxj$$Y1Ye-uT@ABvd5Xd^w6`1t1Q z7LovED&@^bMZXvKA&Z6KB_yE}1wc&~(M=s&z$2a!Y;Q96Uqs7#=nh~%0Y2rUXSRb< zS3w!F{D>H3U7p?7X0ES%XnnsPPIP~u)G7~ycxm;MzAQHLG?>h}@U|3NOnF=4s5KZ( zp)Px=4?4i>f+JmD$dO6{_DnBslG!<#X_#M<)f}~!@41binxvlcvDX)2yUGSjABpHA zi27u{j-Oe0BI%}xbVTPz9`>q_d2bwQDnoO|ME6@*>wZ#U=RmM?idPPpIJ>Coxe?zd z_7|D!*$jdt3*)SwAg#@;)M&fz?=x?raQTT2&e=hEh^R_8XqOL^rG^rKoMdH2Hn3 zo>OY&;OQn}U3&%Y7NCBMX6-5+G-Xs{I%XJ*ot=AHrPj7SOL+B^dcdWaDEKh8DC<&` z^V{Ysk-d*yJnbthMJI)Q**U77r8K*GtU6=%EU$!hd zX@rO_`d%h+xLRYO+3{ob&0}R7%8#{q;nMtOzByipDnvg~%ri@j5v2iWK9)rOE~3}< zchOrxn7~LvSmnj6qY>%4yFfIy@c6-nE)w@s+~TY?VyKL`>!kcutET_D<(U-L!sL=_ zp^kEK#GBG!xSKcx^hA3SdpWY!U=e`|h1!r22yC57A0bz@-gn=o_Rz%4Y{^o&)_6=# z0^-AFNRBE8ByZ(sE9*_{@{_X0$t&c_mgZS|;bi^UAlSVH<{IP{VFqA;u~bz6KSke9 zK~x8XVk=!dfBr+IYnIUVQHC9%x-v}?!6sMWtLE~=8O(EatXrhZIkSLPE;FOY5$ukW zIfM+DY=M?88j!>;O=H0wty+(YQgKlEKD?6IPduFDsb8t%QdAumE$aQ8`A*)BKVeOA3i|;4gz!#`z#(Z%D!GXITXk}oFUDh~Q_@12zT4n~- zG*bj)|K6m+x)yFGCY6j|pS@b9t6C;th-1t=%Ij|D#6A*wrZCD0H%iIq9#?K-5f2-y zdZzqO)1aZYq5Vh)wivQ2d)&+oDw(jpH9dP1wM>MNhsgQnx82ElHshZsm?);vL*$NZ zJM!z#-gd|8nGaCWM)udWY$xnk!sbzk_QAJ4$&M-4(4(w@ux5{fDXZ5(kUrxN|P!;tyU?u>szNNK-4wEhAi8k+0>HT3!h==={rY2w=7VdP`$=~UWg zzia}ljL4a{evs$I{sbTgpi%H2+*(8*M;eK?D)Ben1$Tq8(FlVaWQGl5J4i)H_y4s! z`VAvzf0(-CW&CshbU^yUvbBg`P$$hlSRP5au{7V3LL*#IHR{5iYNQTfgkm6-5^HR# z_%9mijKwqBDvDseg=X~#bPxd zmn;MkCJw6(?{OAiT--L_5TU&TbCZjb2K8OAOPcN{9Yg6=rKmGJ7$WDt%XM!Oawj@=M$4 zzWDTQ*1SopnN6u(0vg7|;8J;f8hWmGUCUq19*)?foB;M>k1Ms^3EaWuos7UcHg0#uj6Ti-28I{YAFMEV z0&l?RoeA9i*n37(o(+YCew#&d*8?DIm9X!I&Ex?r0lLlPjVL0^9QottU2O+8*YNm7*b*HS3%bsq{WJSPk#eC6dpeODvEsw=X9A+mER(51$&C9pU2JD|vS zypebHv2N)(KnpNcuMWO>vYfY{|9fABI>>V${k;RLhxqYB>_0mF|F!!1H*m~%1NC=) z;op;DmCDUuNzn%d5Vapa^bxga)qn~>lK{mMLR*!{PQ?eo^jny2fH&(~Xu zEFQ?CSw9&Y&xo>!GwWiT;sq)AVw~bqe;p8S0HwUC z7#|wYR0Anfz|uiZ<50uc0$BUU27t_iQ~S;dr)=|7^T8NM2odDYlHL4Y7>v^9&qPg9 zA|}8RoX`t)?ZDxJ(glFsIF$Gx6bHfNA@ybU<}qdm;udAmn(fJ0OI86FZ6Z00#&VHn zS}h9t1CxafE@~w6`r0yqhzy2O>CtiV`qb8e#tOxSXMvtw4CU)WXUZ41>voy2XGjkda78G2y1e32Y^3ecUKUoFQb#!N<^kvlc8m)`Wx7l0j zzcV}(l%~37iucb8&c=lXv$SOsCS?B3Nwu!m z*Io@i&n3J*-3^~xSEA3|Y8hX5dsQ`macgi7tQaSFX2w8(#uYpJzZ@fC++1n)#NBIdAM|v&p$^ zYL#=J(iFvddC9ZXjs^PdSwD#Vj!Slkm*X$(bd5a6$6%d}ulw@|XnXF4@~>=grOM1vzoT zZMO)V&@O8&Ihr4zmlq8ANkTp&)9=DOby!y3pr1S)h_%TOrkI_^P~ zr(Ir`#ZWbS(($|ofMNXusjZaU^f=)LM==^+# z;Jktnaf>ukCHRfSA0P$^w2|`SS{JRA;0RQ@V9W#83caG$;g2t2cDp) z$g?+xm)9Y4>1uaHqOu&9sSjr(Uw%wAt(;EhB7llnvs0Y%^5uxyD=oChL5tL)qSoQ6 z%0*a~7OW_9cNM^#xMz*ntD3G_gDW+np7 zD!SXelU13yWFfW5=7oB6A66&YIp>Xk!T#&c`zzx^;@3ANeRm0+-&558yE{+B*1_1^ z^zV7z<}ZgvM_Pyfc0r7uXlL0~yS4m@liPNzWRRxF_ z%Z7h*((5ndjwWw&UVn&Z7>zd$U^0HlXI+n5SXexjU1!~CUu}1py3SM=?R>o)vHoza zO$rR}j0U{6WUJBVA3^IjKFALSb;F#m*y!f-w?dvUmjsX}YO-O@Xx6j@k4)B4e@kBbZ9U>;)udCc zF5R9=g_wWT!ri|6=z+vRGU8xqGWTRG?eWLQsFN?Rsck%9{^6*;_a4^UKtG4FL_?Kv zjfcNnGD)Eqf?oDQ)c+l8WvMz zWxI;@y}GQDpI`dpii{>t_LvBZckQL-(#j(iLA$)qm+8d;$VSr#h~F64b@-4~Q2C?o zx{`oZ596c-Ni9ifw_RtFR5GYn&0bKjvcnndRhYmMIAS3gQuBP$QT;|W>Z@>|j!k1% zxmH~pG~?H?M?eAQOQx>C2{hM0d+)$kwx1un6szD-z%{orWc$wMoXkWuU%w&;|-fM z{*?ACl$1Kz5?DC2suFS=PD~G34YDbEW>|ZePn&u$UNi|6*Ua)kXodXx@pq<*Z^Xpt|V63K7VZG<|dYd7UBO|XMZ(r{u zc;qJhPu)(=AZbt^RIuL!#2k`|+7R5K{44T2#-7 zkGNm*A4}EehWJ|XY8{w5*|2{k<$V?sciJuF2hN_6Kf%%iNap9VSjnF%Af+OYxkm8|IMJ_unKx z3oRs~^xvWX_$~R-{l6-A{$=O*51Vk>|7M>1PcO%R8ioJ83c6C!ltuh&Uy`ho3_?Mn zYMZNP4jJ*w41^hYF!dK}EU=e`3#i)GHOod-c$n>Qj-f?9aonJ&*t`5N<3KDbaom$W6#(7JBS_5RACl&^bDrh&DgE z;X$Y;*TI)9x_SLg!&oRu#s`iZCh4EelW^&DR0H0B0nyWP|wHl~b>ZD1(FIC)WrOyW?^JC&EtPBm(H;PO581M9&=;xJ2g*QYw z8Qv=CK^AA*SbS|qfw1BI8}IbomzViWlzo$lMlp&_TepY z?USO)q!#u8ug>PCHEv;LG4bxK!{V_qZmO5_RDWf2@%kvD6RRz?Ew<8DJE$E}ZET`KFs>{Q)rr07!pQT`d z-tWHR*?q+7_VK^tV{AOqhEBmnQ8P-}0tEuge#m>qb&HgmF0PQW^mW6R3Q{&9JmDb; zajt`n5fi?i-;SRCdIe@QBDW&uk3D_$Yv)cT0WQ5FN~ZBZ)VWX9kX+_T;3J@d7eZA} zWb27n;C?zggvl?%UTgr&Q?tNy$PeW!57onOlLq44=JT!(mGk3cOT#z?LxCrcb?k-Q zgXmv$A@s+IZTxj#?;%1s{2Q4b1(ZEZj@PYb>|)GvotvRF~(JS7|Bd8fwQk(jUq3 z9t9%>VMo3ttT+Ix02#}{T{ixD&z5stjzx7X z6E{^5VPo+A>gi{cN{17819&GJl>Vi%4?qMb@8um+PNM?{z-pqs@+eD|YDTN}tQCsiA=W(h-i$6u(IgAAN&dN;u0fHDd?OZA+C1_~ zPlD{p94;BW4cB`@3`W1xp@K?$avQ@}(CeQ>V(?q^fss))B_^`YT4@JpZa^FB7a4e9 zJ-C#>KkHg&!`i;W0}E3Z84@{6FkT%riJ#6N%<8L*@JviyiQs|Hqo8i0UI0oGnj3Lb z#m@LOhXo0(Hf!t7dxxY!i8CGSAelj(nb1_?WjlXe__Y{vDEg*4*aqc+V{ghdZ}CUv ziB`MqXy1(@$7tOhSGygClLjb7u{w@m3X6F5#9eHg+NEnu*b(l^6A=dAYfanu5`CoR zz41nyxZRtsvv1LUt#R!3F~xQ0*j_e$rkh3Ke@TInqb+}i4YB0OrGuJ}$U|ya6E1$@ zBeRU9tA#rx(eTI7fKaN&!-z3x*w^wsmBdj;@Wy};~ zCfi3JV@)eo&XW~+oROpccWL)u+efOnboJeDNtDQUr~IF}|NhT|_z!3Q|5MiZ8(GES zUnf!55|JP7uYDs4x3!h^hplB)ywDwzmnFGaErwVVoOPXTMhE>`eGBUE-w-}%yn%Yi zUbjFmd4p>e0(mH2V*}HZ)6=#lz6}k$zTRH|yXZKJ^dXo!n^w8un$XQQD|RKp%6_kL zi_|*o;8ZX$M{!V1Ob2$Sl?(^ae&rdZl}|!?zHmk2rBW;NtLdd2G3T1^S9G|0Mh#<3K53;27b5344@u0m1~h(ksKLsK z67oT#0!|+2{6e{YK${G$>7D0AgXqi<=k_~FExeX)bw;{bcam5p|H`fTH2wKT+i+HP zcrvNlrY(j(qE+opaXfVzOVBdM-iz@yMDaDR&~SzcU3*;JAbOiF+WShN36v;j;$8K2 ziLOXe+X{M9hyCrMQSa*v3jR$UuIZ)N~bMwOExiY_Vqj!cE>0ivp| z`tr^}({N;X3<2!(->m!oYDUCJE4r?}kCyab%kBTHBKiBq`d?QZzmbu#k?`OC{pSVu zk133jw(R0J%6{R>W=$g*83nlKuA##+6;&5$5Kd{(%FFMTr}2QpYH}ZJPfSxMJhJhiPXV&Ryv!BMsN5WjK!skTHp^4+3b( zBdw@vg{HlL1Hj(FIGo%lB!8SBM`h-t7sk!1T)G3iNk;ertf*mS^uj9@iE_gx8t1Ci9iZymuyPc}Jr;?e*1m<_^bvQZ0u`-Km8p=$sp zv(8~^md;G|NtB{Wv%rqKz|2c} z&V5;}MT>9>nc0vmQ^++Tktw9aJonbMy1=6PicGP*g2u+=<=~^~?4yW2KeP(0Cq3d^ zn0k17(HNujWIhF+EpurBtuCA6@GE_e2JpYB* zhop;n!7DQj5xTJLL=T%-=&`Z*?2a~E5k}>w{%#FUMaD9Cd+$UjGm_&!oSP$jijIMz zrR>RFV)E{}*gd@ku6^Qx-#GLzbIavYDU?K`O00IDn}Al*I<^IoNn3tY2_;pDJ;-5t zF}!{ZKVM`aPPvaz(x`WW6*YrKFw5Oj!yHhv$XXuxU>0W&GsRH7*B(h9InnBu8hbr) zDyk)>M3a-{rh(5te_LHH8PlH4lAMM9c{^MCeiR>bNya17+dVX_~$iO1wx#huz zUXFMvKjwFt%SVVVJSP*cB_{yN!A;j*%hL;G4xugnW3Zz;zc_F{^heWF;JiT3s0wUZ zRqhobxOgjZ=4rn$?gJwIl0uHeC4T&-AoWB7lJvDev@L$@rT|^eYEc-sZ9Yp~kX&}4 z9Rd3+`lf((b|g?XnWSphFW^G6#GguA-a8>;+NsM|c=eso9>vXJ^vQ246i^kdf!{?M9LpO zbpGGcz<*V`|07ucr>AR|I=C0o68cw$B8%ARUhc~yE2cV^a>mN##F)|NLNMe|>toSbWv zMhUuPy!R%@Q*YN_&s{fD-M7PrvVdwt)6eQyx16*Zw{HyZ0KSO>Ift7$%;z*>`o3-%5f{N~HgSpY;0sf-{Zb#bH9skyZ`CSODh zH3J#DpXyu)=S>C&?$^?th+G553@=`PtEu8)Njp6c0-2O@&f2&D3z!gea;HPNrU4Xi zV$r#0Y)%MY**8SM`b`T_VYJfCbL zkw?{4SF1TCr8iIIo^Q)&;`+G@Q^?dblRguHBuCBz4>wMnUMDkLgc#Q8YnH5KTd7PG z9hQdsJlPp3Y@yH)j{$E$GlW)+wFXL*)J=d1MV|itLE1lerKOtPB$Jy5CJO7(N}izR zU@5IYdS3NwR0E$fFtrpMx2xMiwquQ&Tfj^vJVV4xn9PXLEZk)fI9{-iY-dm&-ydO0 zjt9?)P!Q3tnBIt69>c>gj&A8KF^OB*kR;d5wJsEF*mbVfE@otXO344T_CT1Cq@)%x z8YG>?Xj*cn37s3hK^R|Yh73YT%MsqC+yhb3Eyb8Lso`utLD5l5yG~B_5Lji^r3B@t z#(?$~e1keS)2Km23X^;vx5yQ44;-6uM;aB8l%Ak6Js4)#Z)60Bir++2W@JE6)7m11 zAtYG@I|>VSBiosUr|e_maR}+K+OlqR#LLmd2VGt)?*^>`c*N8vKW&=uMjHYd=?9}DAW z@QJ}H(d9vInpZ*Z4@aXI81b7Uqie=vxsKV(_T-yOChaipTKN|M2ijC^!u^mP>Kqt6 zDW#e)ygimCL67DX6`@B|?{hAUw*(Dm{L zrwaB{u7B6B8KW13jZG4_D^`s;?Je)$J2MGXd90>pA&`G1k=GW++b1TOmrmPZOj%(a zW_J;4v9#YSSqXBR+j)*ssVN>kN^sDdAG=6)$lMR>iBr$g1}$cgP#SKXiTXJkQkdT7 zN?O5+4Y|%$$2p&hUPpHF74XmId8`XwIYF+@h%&;kD5s zuOYLfV^fQya80C`VkbD!E5A6?OG}~tfE8_LQ=Z%f7e{3rGH++oo}3@Dq8A;}gkQO{ z=@cEo=fbnwL(4*Udelpa#;lD#^__&Ev8#hso>U^i?Ga zi{o*X*Ad1;pX2T0R}dfly!XLj(?7-WYRA~oSa&Ya#(L5c%E3bv6gji4&+aWJePUI? zah>47?Jw#K4`*5*F+T)YCx>bpCd_f&58$_CxS$A;II7*hM$)08ok@*iX%I#;4SxbL zIi{I)qwgn8T4uUnPwUa<8>O#ElBE0ysR`vVQG6nBoMEW+4;9a;?aWF`Bhvg!&KXXk6& zuR^!&!RF8X(g3d4QS^nARy1paB9FRsW)o|q-iQ&TeSKn?79Jh`b3jgSTft|is*(fJ z2X~;cB>74LlqjI|V@h14ef`y8Ch2OyxQc_}W+6KD5Q~c7la)o*p|P_?5f?L9rfSlc zw=gZV zH4N#7Ypr!TQO-D0j>LW0_b)$B(xIaHL)j#N{8*9nA|ncHP=SchM`z#3od{VXb`5vh zYlW_GxW!__w983y( zb>PpKz($Z%VvzoG5tj*FutfvcRhchx z^G(wv5R0-aIt1$C_dh|u)+l`8#j97Mt5ds`qJo_WK*7<{Ru^ zr3OjPLj18s2;`!+-<&M@QNtC}tIqhtK9rSswSTUN#8i(`l)LFi%07cm(56&d_@Dtt z4aSK#pZB@ebbQ9Ja%?!3<#@SW3ENnaQ1sl!X9sGSW_yi%jmQUg4c z=F1st(HzT+khlFYoN{5bGn0-h#mlVH2yeFiDHBi8psWhSZLCB&1rqlP>PX74554G3 zU1y;q>}mQ>3nN_OO(?W%b9DrT1XF@b*@7vc=~E_xY>tKzEEpmPVV#plYVdT;4-*G& z=gg6(n4Oz|QU~jB6E0pa;ar3 zh_)oCtg6n-e~RgFsGnx~?MsVsOMtOeX8orJQpYiUXOCR}6#v2gNbMfGNsME6R;0Gg zeELY;%UF&{lRaqk$@GDhfwTyr_l&TO*2UyIQe2Y_A@ikQ&QEihxF~w$qtKY3%Qgi1 z=t;EajOo>op`00Us??jL(PP3CuM202_h4q(6;PEGa*>EEzY)7{p;XF+`J0vW)EWBJ=4WXU_b0z55IMQ9CrWXBrozKsH(a*D!IL1p+yMi zi`pbb)2>W!_PDr~K~}$r0+!Oc(HN1t109i_ldQZSMOj~eNW8KW^-cUL7F0=cQGiF1 zc{4;_ns4#(sMOb8gxyY)OY(4SIo~&JUaRxxg;x`VrRZ*1Srsmyc2*3U!$i3q@OHXJ z+Q`F&7XW)nc|fKk%|qO87&JL%Kbm{ufNRdNy0 zM)J=jZ-K2MdOH*wd9+)^G+a4#?HC8ISXUY3KjLKE!C_F3^h&FQy>OYLRxj9cIPEwPn>05TLG^rdT*o*&cF^s&+>>yMq zdARvTKZd8!GWV#GY#SuGMFbc>p0)YJ^i<;ZNi%?QQ(R!Y<0J*B%RXb>#GAL`s2*rw zP}a1pnzts~#SO_Mm#$GsDN{*9rZVv7+Yw8ScoZ+16sPnhiZiHJt7vWW=iU&eP@dIR z*pXKEX-fg0y9P#jqr+SK@|#I@uy@U(J#D1K6ii9<(FX^|gIE7H`&p4`UaG@K6rt%V_0hADdi>ai z_rOthUQqT4WQSzXiFackSzZ-5KGZ{?QhG?fDDxlAg+H8tAm^x@yQY51L0*8VHEK~Q zHvH)h*H`cD1y+|-sZXygS;_!M4%m}n@Z6R$+w7I=3F%#}!L!HAu^A~r-}glC=7$5Z zf}3jMSMuvkzy;f4_6W(g%=39WA6U$hJ;UHK_r1Dzir=x?U059eL1 z24^48irNJM^&Eu&MH%vApd8U(-x&r?g`BQZB4AIzUtgLBExo>XR*4DiIv){sb`KOi zz5_i{mJ#Y14k~BwTxZ=2SMZhn=Yx;`-b0~pXyz+gu;Ah251>~(a-46pbuh?)>DY;o zUhCx-Y;c9hkKi}+?n{){OKrzdo4qjnj-U_rt$zGhx}i&$>SUDZs;4UAAL$p_NgpoQ z{BsUy7tMCGI=D`?F(!{0AJKgx9>o@U*?TX<9?ug@yI`(iruG!shLRth^G5RF4OL@W z6=}0-ceqO5kk=rd!PKPq?^>2eO3=03f3&+*%cdCSPn#{;q)S4R z7Vm&Wl7_A%FAG;xa<>V{QN%e>Jn|o47Q_asjuG_f`1CGY(y&!c5>KC)c zdj+@xdyShrN=n`?c0PVze5)%B)#l~`C86o;)JKrDmh7SJ-5*&A`~cjcELy7*`eV7I zum{lQzL6Vbf|C${G5QSFp6-gR{CTGtT$*&&-R36lcn&sX_nVCn{f96!j^A<};2;nW zBS=c5Y|bG&1C3UKOk+3rnk^}0+M&@v%k^x`d(*r$iTkM#uG{eLDb==|gR%P|rLUjD zNsslJdBoIO-71r&tzV<#Y((bLp3O&AYTdD3!f24+UNE(4)PbE&Cm9GIJit6h0u{T4 zV%VBOQ0)$B5boJ_A_o*g{8$5K$T|v%=Y=UVp4Z{KGRc?BRUyeAMoSc>P-bX`r_*<} zSaZem>$vCxD;5@-+FZ5R_6Z1 z$b(7a%m>Gq;o~~7P*H?>GN28)3cS&?Ioe;X_h)WmJDoCQ*rh18R^6%F%yj2%kcKgW zR0NFg$T-$frdRE-yvA86q+k3Nh0%UEr=RK$!NolYDIw8g)F={}6JG<26+Bu?L3M*l zLUjrng{*?fEUZ;lLoLREXSK5IdyIcS&~o9EpQln(0-c_pK%35MF!)3^m;5*y)D)5k z_34ueqQL)+G2khs?Xe3aL)R&U3Xd^hx>!SkK+FV{oSQQHa{T;^9i#(jNh*d1iai*G zSPA0aAf%Pi9uYg)>+S?ETumw0fjl@W`)J;J3)EGYs`Z0{xr<`I`@cae{)!*ZSoy@f z@6A&L^#2P=`oG3O|Hl|o(N@G%M)Q$TQxp3JAqfCf2@4D6YLg?G|Eg8Em}aAE<(ko#iD(O{e&Np-*K!50JJ9wo1D(%#=UXhIr-q} z`TE!={sqnjosZhGF&mJE2i<_b*|!CEtuHg=MR^ShKO_Jbp$1`qeiN3EinfiqNNJ!3 ztq*-+;0D+K6DM3>aVVK>17;uIMae67Uodz%a1VVWh{`loi#aROX06R?d&!-kB7>`p z)NNW~EjwwiJ+A3-)qw`nnE`!7=k{ibu5nVM`Dn}dg<}&f0>eh#aG}|Tqj?0DiyP%= zOgh`~zItq>HDiBnzHjmtCIG=1p>QfldE)ruk5p#Ih6tB5r*=iOd7&%R3WBAt;+;zs z)__749D_h+MM|D(uH6_4wn>l$R5@%qzKe|o12A!P>IfrnH#ya#jjOkUFRO=!*7_uz z*9;s^Nkkxh0hrt`eHjYqO!LTE3F>IQLXqL^b#i0A(jC*?LBh$uv?i|3TdW% zcy^Ns#>o$6LP|lIAyFuA@@r+$iCatR;0kIP3^~`APOI&Uk)eIRk*mSr3!}CR^~_1P ziarW_1Hx9~A}VzPSI~0PJ!kkLjMqE00pmyW7qpzx7o`Ey7p);w45&f$V~fQF76z`8 zoZ4Fm+R6y-a_s$@{>9iI9|;%=tIGQ3tAbhsJo6X~wah|v`T7Wo6j;#eUS)m4(SZB` zA)UdbFX8%?HoE4E6gK5-vvR#~1O4twwe4$@BaZV^C2LM&3USYsjWWzb%v>QXsx!2W z#&n@n6sjvpc2jwpg5KIZq$*HZzzz-d47Axn>vGoFW<*gELnZz-Sx)1`-5I&c4D@JG1iO-kof0z}nkk4*ja*CNc%02p43q}Sw%)VE5%P>}mGpAsir z#Ugt(MgMFoMi+;3@F^^66SmMS1YC2G{A|`z64?oO!2wS#>md42HMCAX8OQ7L^E}I% zf`hyAGntYr)r6Xzu4wcSdy{^I6&A?}5Ek(f*hQxXa*G;y2HT{B?hkR`lgO?7GE2R+e5!!{DI+S=aZLAJE8a0Er76yie zhrm-Hm_^Gj(54ALWgA|MLBXI!%;tH0E!%+73zxZuZ#VS%es_(>oZoT>lXq4?AF02O z0Eaz3@(d);y5Q?_$ZAFy(%O5AooLE*QHX@jJxB?)vri%2j^@)h^b{(0r~$v#lEhOK zD!KFZ5YoF$RHyAHae%izhJbApM7O4&c_^E3iLL?e1z$hIHik9CoE|h6b}>tQyhfNY zy{{b!-;c>;8!{i=Gn;SlE(=8-ZWhp36$*1fX|MS03+ZK5gmMP2EpbVXjbm@h0QZdw zjsINk`Im6>uZu8$2w}hX+nyqZ_CFPF{%cA4uVvOhc2|G-tvUWfrj_>LiL`_~(!;uT zNi=XDe`^9(x(nfM>}SvjOfC)YYJCl_Km2qjMmK-=QmQCtvGQG)u;x)~Evd!6$^L291 z{Nv%SC{zNCAe%3dbpxa^!cHI5)+PJ}--l>_s^oR&gZ z4uqS!5KqdX15tibOAgHmX1Y~wLKhg0<1?-GLtFHOG=+SuYEb`JNaxZY7ng_U+)+t`Tr zsXM86p8;hc-9q{laUsY(tmVRm62SsI^Dq>mgrU}kh%wQ$nl$+I(Kd2}6O-mxdh%-$ z-udH^n9S;tHu26VdYS`i3Y3YlB{7Vurb>bd_DZi60rhjf!K#1~Le}8u78&~q{S;eC z&PCGT=sd+=W_QYxt=BAm47b{6I+Ta*pgYhR$*-0_w5qL(7KcY-Jo{?x zQ}+kxBzl7S;aX7v3`ZLrqx6rki%4Q3^Aon+HdQoJp1iTe{uF*X*D`LZLTcQ%QcaQ} zVsDDO7{RwOw9myJRvC@lPVt2z%1wI4v$}fuy=?!VFy6Y!;}7l^8WcCUVHVhCe1S|NKn(e>R-=XZn(a1vwMA@Y$I~KMmw+|nJ3>|8a4Vt-5{>kUlC~{L_?Y#zhX|I zO~rJifZypC$T+S-fZxd#mysBoex-tDog&zc1x%d&{iDTJb5x+4v%2B=Vm0%r zc2g(Gt*TQ}_=%Qtd#nh{Gob5Ev8|U{W5J^wckumaBFSDe110<=k*A`2{k&)_`&ZwV z;1C2)FURZk71bH+g(U2!_v0595M7^=t{R>V%M4#&Xhjo&B2mOd-x$4{fm?SFc?PIoAjJU0!E{d zg2Q>mvngd6-N}2~vC`Wl6rRU^m+R4TlXTLE3&fmyk4N9ha_j9j^124%l4+YD*|In! zBc_05m_AP@4d$HT?5zB>vta)|-uDZvfftmaTu5>Zrq<2zbUynryXyL4WQ>Wa0qX$# zk@bO>8;}_lTf+{E(a!WvqiIam6JkdlhLbMiY02YG@#D^qDR*hd?N)YM290IMC#Z`M z;~3Cp9stGPl5!1EfHHXCn5TD=PT!K0>BWg@~Aof*_VXe)| zPFmI;2}!INmQtThB!&e;FR~GJ^=9YfFlviIn`MtXu#7Q=;aCYf;rdDx^9u7SB07nP zjv(}JyTrT{bSc56I)LUy(i-B07gD~IVNO}%8s-Tq>xD@uWvC!R?cKQM#=Z*AZV^ra z;_dXzWg&K4A7Y}8^YkcXq``G%VijT=0{8po1lmG{5n~M&1XcL+>xqRk>xDDL;_c+r z^CSt6ZHJvv`k9K`$BvVLl(r)!23EN)Am%#a?j7OxF5f;W8si%x7%R@?55L_xZF6K9 zZFR*cZGH6^x=#n$`oio9Of!w>Wn_k40GqTPA_iO2&^`_mq#^+floS|jn$cNH#>k3> zPFc~7Nryu+(ID9mkRs~HkPSmMqL@O$>@n%@&*t%l$>?ol$Ixogfy@~w%;{M&BB^B} z6|>Mv?1w|BheZ|WyM?Z3<~uXcp5YEA4i|I`Hbo-JS|d@dEWZqf}o;N2JQb4;a$BnfAzjm;x0eU(4cu zpw4|UsfxOY&IfF{c`34**qjem`tPGj>}yCEl3fV>aaII@U6O);vx{9$AxJ`jW^kv6ji$ z@f96nuW)p;YsJjHBakK<_77yc#E`LZiMV#qnYgm~`yJCZ&q-2hc^=M{GkzY-z20JoO(o_U^tv%{}!iIGnHE+r%}>j8R@xjikn3L|R=P zjg^oOoU^{Xt_x1K3Y{To)pRq->0uclTbHu+!;*FgkHMY7hqrdCU;S*5I@Nn63a=_F#}R6L~fOVQd>)%2CO zQHFN?VtR4?c`MLPDWEZJ%$0}h=Am=v&HL?wm-ihw7b0iuR<9>e)yPP%ClaO6VV>mR z$9lsp1xM>Tc>yqJo0FIbDon>6#>tiq)?Ri2*B>;}5#rA4VQ_F;yB-QcSZ)MBhUB|_ zVzBnSwz&(D9L$f->}hSF%*;cg!GL}Q0t6_($t(|{mUCdN?Rpvj(=PZ$;Cju+&}9_Z zXR~AeCQ>14cWMznXy>xx=_jLth4U3dKu`@pk<}VegSpnT6@PhOzKbW&rqpfJy2sjM z)q-|kJQJaJ4KYYd_=z1lB>4f4+%2a3tn?+UGiHp&R1wLLN5*t@%33lub<~$}OWWCs zVX7%CsE~Ici(R4`R641to*ap*a`6Mp96G8}4T~5Y@K;h-dFrjuMND`}%tnie`Ci#t zXG=4f!@yYV)PS?)BGxr{yrdDBpgW==SfGSwYF z2tX#kKAdFoIcFJjL001$IL7dn!ZWNM8cmb53OlZGJYAWEJR*Eex!Q z1lQyuU4U4i*47240z%q@l-v~u@`DJn5$;ig*dAbm-0X9MG_98HQn_Y8Y>$8f3M-U(!=yE47g^Yj$ZK=@pv_4#n!G(UyY&f#EUQStpmnqG4NQ1kd^9O8Tq z53ecbQWE$u@)(bF@%Zp32ri>+j-Fbdu?){qAz%_<)z=v@$!<=GDg;&C*etZ~gCF^z zjr;N$L)0&n2>2&OlA}qkIlv|Jb=EWB5GrmVjILgQ5^5X>VkCsyB5cx_Sw(--1!#SZ zha8!?BBrXmM(G@rr4i|bZ#Uq~#ZbVSmP_@wRl+ki&v|swlJ2s$x}rUyjqPO-zo#>r zY{sX3Nj78aSJWx28SuAti%4M77pLcny3fImC>;B#$KnNbq%{%Tp}16NVnW=(bMRy-LvGFz}TWa1{!I*3y1{ z{`^eM+T`s4oLgE%{{yBX%+li$ExGIaD8bEqfuEgY{CxQ1WXcFYyMpXT{y^YS`(v(q zg)X_TFbwS@duEh9&?m~R6ryFj6u5%N&#~2nITqL0GP=fb4PIF4gfX}Z0b1-5jM%?z zct#UxLNF=gqLfF6Fp%I5m()b%B+YnXS>(&Y^-|VyFlox$>f&}e-M@%fXsr89Fm0Ke z^(gla<(1vyT*`}8(4%|eDD^W6&^D|&8RY`76X&bqbA{k67h#}OFYQc}I>Ivz)tnY| z;#S@DnsN#{Cs&lTB;DoX7-i81_AAuROI@PyLe6PdpQKEiDtd<=ST-t2e1us7_{`gC z9I)05N74OE^D{a9`#DE1rZxB9;s0z!hfi;ip^ePv*cPS!FV@~ENYiau+wLxOmu=g& zZQHhOtIM`++qP}n?6SX_Yp%H$_J1&U#2@iS)ce#~J(XkR7@2oox0>K`a+Q9*pHTZ9 zJYdnVQCNA0fK%d1$M}d%Xq@hvmu^yW4MbZ%2O-PIuR9Pd&^CcaxptEo?cpL^2XZ1# zgZRWf;Ic~{)DVs3RD>42)?rr)yR@p@SOO|E*Ee=?4O;nKOM)S%*ycc{4Nb^ve-t^M^eydy^=!xNEqH```+=l7*WQ00a(!&l^y@%PX z@=-M@SNa1ABS;Q!8*OL)Cf8&^BHA!Z+A>R9W?9b`P3^1w7qrqUk>IOT7;i(qHwmQA z9~H7m2$_~DqTbfOyBgYmGbu&r-h(g^g_#S<#8OmxHWHT$BNa$C`z775rd$Ji0(tu@ zX%smI= z#Nydk+ivgYCoWZOb~v6b;C+6EeSSc97r3zdX|2zM19>6zWHgiWQTm6GUK;fd3&8~K zPcoz#Go(Z4bE8kt7`1Q>2vUW603n^zfUS42Lj;}ap-?Rq&>S{*5{Ey7NbPAwx?rnc zLhpT#eA5Af-q}Io@Dpxvk?4!UZ-(Ix*)DoQb?2_!0d?|_>ziVH^1K0&} z{2?*s@DrG+-<=4UkKaiN%mR&((zQH3D|Rw~HUVGUVSW;&MYNB$Y7!&~Ypt7$#^v>h!!nSGNv6wMemiPo( ziu^dKK0BRbyqa+SKxN~tW2R~!W1$3jT4^-b<+8m|;=Jx?guPIu07sP;vZUH6swpUe z(v)&GVf082aM!-NgpZEtcadw`T+?R4AfniixD)oIig&CbhXdR^k`W2I<|1IDuBrm1 z5+k)ar<9@QaY-?IFQ+xmClR1x)JyoiH>-%CmU3#lRyl>f5@Ugi(G<&=p6dy_O zVD{7yxwRc0sT+RG(mNo}f@VWFAlBrC=CzB{E~N>Bhyqb2Xo@wD<*IrZt`U*s}9NXEm>|u z(>#RE2i<3*Aa+Ex&{;1+niPrqGk7qj10$4BP(c7fK4p3KybCd;cBK64wjBH1}1PvX%VT%)Ajz0df z*^MScFWFM~9+49>in-q!r*g%I?vw|JOtKw-jPvbMfcpo64sqpRcJ4xmxeet&D+SK# zN!-mFbnGXt8M99C#~k5FneHsgVjU;yf*Ufd7N0$yXvFY}-xaPJGHgY2Zv7lOf{fXa zZkAk|bV;sQn{>W!l_9he$8H}LaUNSv1Dpk2Ym8c2ayPq)3QxG3C3Y_P>STnV0P=Kd zxYeOlgtYKVQQrC7NCsM#$_la4!%FYhw+h2QK2(=LT(GB(T|SKl4(LsZHk)vb%3K*; z-C0gHW1szWmj|ESuz2kcVoW)_%vTqoFsXk%$cFydroMcYL{)62JyY2;Mw7Nv63V*7kdt= z-rz1sDm+@ENKol5`N}9Cb1zdKugpzUfCF)L|N4p6T^ht4q$r4niYT7z{wP(bHi$NGkL>Z)5B0vp6=dObD8j7kk~m|~{C6Am zu=PVKj=I`J+m3y}ufQ~J{DSuIEDLrK^xsI{R>Hy9S4D{eS3iS^AE|PSV$UQ$8cQ+A zC>?{u!k|6MQcJrn5taeje6dSk9;*IJgumFQCI$Z`Q~>)*tV(}BsVeFI6Mz2aY~Npx ze@1*NWsohF@M1sea09ulK|zG6VUu}vf3RdFju-)~y<7?=4o=IQ`1EdXA$@s;{c^f+ z(qR#E7Suwrk3`0a-%hVqSf#1#Z0<(srM-&Kbz%qYTtXlNA(P`bYv8~F2L3L}Eg-GM zfvbj93BY&vT#!pvK4Kca-t$A@1xQV!C26CJ+C^?tc3~-4W!ZfyZLGKBTw=m&qt+x= z4V%}js@ozgK@L8_qDK{-NAIYJ?ln+SMLPLCXe*YT-?#(%Q~(X4fmgkQ*Fbu|J_U*H zm;rNMC(anTR4INfTHWDvUK9DNYT1X_K@n<&dH&QGf=v8jZe6&26v92|3l3_NV=dw9 zraZ_|^+TPEbU^-LCb*aMOXp?49YsS4rIBOf^-H~(Gm;sFn?6+ggWL;Nob&^@Hl)HK zbiHR#dEXmnj$b$4$kC@Teime1wEgnqznDxdfpX$wUtu`<6^4J0NcN8c#$R#w&!gR6 zkN!TH5R)>k zB5KDn-g8T?&{mWU*JkS)`|cfIng%H^Q7SL;;|r=s3qtd5HAJU=w`cAd%2sR0?zhUq zz3esEnXXVFS&9#c5z;|)8nO?ex-kU|Fq02pURt2C6J-c6pO@9^K-&-YD3y}J{~@t!yoXqMiG$jULyEz<YkV{t((a zudFc^uz>}%Lk-_X(}Msvo+R`;YliLD2q=6;n&83D6*D@^7C^df#_Z1kL9$8OnfXKm z3JkL3vyDS;IXE5T&_0uZ$Hy5hD-A*hTeplx{Sc>=a3j2A;TN}(!!gq|LhK5Yv4a3 zf5~KozB?@Q)aX&DwvI$8I&biZeLJk(`& zh|&T~@(@6`89%0T9yxotPj0?FEiprXyTdsdqH=hZ3G)YodN#d;;t`C(rp{ybQMOTm zsv-k<-Qmx|em_>U5m<$IvPGyOWjPcEZ0%s7IuiNjkMdh@ISk(Jy_F%93`N&ur$s}J zx!E$mLYF^zWVn2qI)s9sqOeFlRri4Ixtu5#RT6nlO>RFNb&N@lZx5BfZCnz6#4-m| zK0ma}PAm$*-n6!~alf_w zq}DhBgI`BzS(e<`Uc6|+rC8q`cQImBqst-GcvRN;RIXt$vj@Tw&+1Nq3SP8G?m*sC zosDkTlFNw^|Ajztvpktfm`g!WC%0lZ616w&`X-s&PBDh7#ZEfOXa4N7cVt>!(+f;W z4w3#zc<#BJDiCtyHS@DM7ZCZ`uyR-QTy`dO0|I}|`JGIUr2waLmthk}foyWSJXAKE z7Nate2Jwida$7R+l5#68w23BXyFFC2UDA`xeo4Y=!X(dWvDzr|2$G)kRYCRnY4vx* zZhk0fd)~HRs533^&%#7&kEiRrHgfx0Xlu{b`s@2yX`i z{0ohij;A?iaPiv#?amDO9@-qd?-@BaS;a;0$iJ-Qz1h@V*Jv7wDQnlI-~)-w#)m1s zmx^S*Ft(OJEzA{)R-O!_z2KFBmA2Izxt!JIsEks4d9Wj{xt34P-RiT3 z6%IWh21Gl86M8F2KqrW0(<$YLzKIK}raaGlp7^zf!3?_aCC~IUsK$qe~?5eWgR6?nA+-lnDr`~(gXuu*YY%SJ^gTouS! zk%@PTa+&k-18P$kaK{wlk_2a2wI6=gl4e*c>3F==-exstwe_vY6)KmXs{g#LMY z{GWtv?P#ZO_%EzjfxNmjnk>u*6a__+B0}-wW(BZ?X2UYNOW$&Tz&wMws6>_$%Piv< zl`7KgM-i8T#C*N!p1rri9P3zPkN8Wkm7S6CVVZR(DodA__bVt))IAA7F)f9j=wNdA z0gBMI1jaLpp;G@1ho7wOEx;?DUwkz+z6kiM*r0hJk7=52heiW>scu86rSL&Rq1r)^ zSwvHK>j4^M<*6k9#c^Z~cCtpr6L#u`Q>n+5eH?OdVeJ@>^-AIxcgr24`U*wY)*=cM z7sNQ`<*`v(6N*^M`L@MuqUIh%NUiQo)5YL-=Leub26sy*Xw-U%XOXMp(h_w?MSIM? zQsi1dW~s!BQmYTiXGubFYnzz1#ppvSw8WiC+VG8RV`B9jv&TGM_YkvuKIb(kT3~uS z*b@6Dyulj)b_AAsOm3Oca|kYp;yHYMzcv*{&w{I$04wziA=_>t^Letx+btA5?Y$*l z@Z17F^J3NQPL5z9iy;1O>@8ypR)# zMr-i4pTg~@vnb^6+`EY-O=`c=J`9soOQaezQgu%b2jMnWU|U~i2lJ-^q9vc1D9?xE zRRC~%gTY30k_oQ9tKRgt>J))!;5;R81d>9N+S&F>>kkec!CvRqc+0X&*^hDHxTC2Sy59H5`1Np?EUKZ3?OKL@#ec;z5sE4oK^DdKei|4O6T<6BSvxR|VAtu;l zb|q`Y;}1qqg4%*2w_oqzebSNZMzW(ER8rjxiNk3nUW4&_g;^adk@IJEIVJaOV1b%K zn7cXhpM_0@n;%BAVHL*IZi>i2LYEazZe{Q`F%}G=Oy2##rw_I2&$X4G;gcmSmL$QY zER;q|NVmhCoOrmWi0%eP;55HAdk9D|I_3t*~QvOrHkW9 zgW)?)^4u^bKmSApf>&5cNzSCII6dD*V@a~UP;RQ}1nt|QHX#b0mss%Ors=(3X@IH9 z*ZSN@wm^y@nollBsiW65RD;Y66NLC}XeI`Ik1>HoLz%C3+H4gN4;5i_Vy4oSujbaj zP1~Sa*5VYOL(&Z7vtv+MOp72O+Qa22WT5;*_Q#b&EOcKbB3zLHsNun2^(S{IpSwSt zZ;s0}URa*lyl7`HFC1^fF3~;plj-Q5N(EVF8sECN=rmj>4CX4()~Uf%wG=bN1cpfR z@0I!}>m#Zt`!Ybp%G_cdcH^Ts;imc&lq!8a(cMHWC6gT!SZYdaQ`hd)cW+3!V`q32 zSrI-wal1;vl$6%$jYb4m??^ynk&DByZW}ydKROz<6EOC2EZNpqc4L3Fc>P^4Q_%60d*hTQN( zX)~qQcq}N&l3s9+BJMb^i@tyZ^XSt+kwv|Y*UxN>(4atk(GrIOAY6JPY>J3j>-A+9Ss3QfKh?FgMwQ-9WEKU7(eV;YM7rIqA5%gXl5^+rp!+ zX%|RPv$o}bw=3{Q7T1uL;?Z&KNpT57_uZt&L!)YMi=%4qn4@lOgKZGi#_I%*7OZ0i zhxv>|Y1~;GY787G!gFfsqQ0{XE;VHCC{TG5&`5BkrWejOo;T|(*Te!w0ZG7CAQko$9dO{!dTOW<;)ZSqctGo>kTwyuLGEuIf^Xn88k#w~pgk`A- zk?6MD3l<_IVw2g<<@assUOaLi--)namxwtyIzKpt-#1`h5Hzs(^)IY&@uez{9jHAnIF-WCD8>q%nl*P05Q@?=TuSv)kq!3WQ*|U|IPSMaGS@eI%ORz=i}~z_L&arB#Rbu2 zZ=B)&BnR3nNXukDu82?*svxcgaq?$#T^614pj8P$a~pjCI`_+3T{Xo2ZZ_sx<0Ibu z`b&s&{t|S4f%$1Y%trIq5T~~Gp_b1P85x=tF1HMEr^r0D&D0t^vJ8u~kriw^81S8k zU$2EA=*}k3Ff-`*0)pL7-eTD9ht(Vmo%SUkq3@Q^2qUS=Kt%mb^=>-%OJNo!!~i+Xh0y6;P%AOf@NDU!^t{VPXP4G}c4*VF4q zM1E~TZ!N4=ue?|=6I?1G?2 zMx(5`I+m2$kJv;~vN-NEZS?m!P|I6=MyReGb`nh0{?*P_brO83O`@hLPx!OWA>NNe zd+ol%z$Hbf95?S`{!n6j@(Vjx)$R9fb!A+{Z z&O6vHxWL7^wyoZuBGOnP3z#G3(nW9~Xnh88-gfCiA#0asL(`)1Y;^IiBlWbArO&b^ z&v#6A2S_T^X&?JPFTI`JmyZiyn4kGC%+LQHdG~+pF8&%D`8Q*vKl5%wqNV&--W~cx z2Ef$?^$Vu-6U#~UX;tiB4a{ZW69lXe@XNj!H*)q}n6NT(o@zmh%nN6*M)4lO@~#fnq)d-(gM8Su2L5a z;*fGkqbfeMu&DsiQVn&ot<}idJagdIgcb=yt+PAIb%U}baW9EH(+tf}k@-=v@2&!n zxLT~RG=Wl)dp;dd-Z`V&-m*$B&8)9E|8QMy#4*#vx6x67$$nu%a&;Um93#0W)Noa3 zgYE>Xfc|-DRXSA-ltNu|Zq$HH287`qG6KI}z?Y;xdw1sP$msRg={ylb1B^?eeKhBz zY-p0Vg=~Rt~3o;=wtj$~nP71Vh$%J1&?AB3(qCdAq7y~8TVXG1yI*Ie# zk#Xs!l;-k6H$_c0HSD^$vq+S-TNd&JkQ19zxoztZVc#&OT4Rkwk6&IOVC3u7Mkc`( z<5KlQloTb!oOS)p+FH00soK^?vG?GhiX`j0IRx`zmodGn4SA+jr3y!jn~~hsj&RX7 zoDgEU9$us|Sf;)jFP3@ya*^tb!YwqZJYu;%e^1j>q+C005MsE#AC~b@tzZw4KVo&k zwz~!S^3Dmkl~c<~UwwC(loF5c1@tWs^GZJM^*7Js>m32Y`yhKTRD&%$gvf~z$(z?Q zX(G8ZW9f+f%rs$uq|>r(p__)1pDW{7?{o>|zTNyImHnNLApq03z*fV(W8?bcWYN22 zC0%9Am?g8u36b$z1lHpF>?+vu5x+vbS_upTM~^@6`FTpH!IJYo1%+X&RoZ;?`feNXu;_j5wpD%v85We!HQYiV`3>qFc$HvqZoLW z2&E_JQzdLNwzRnvvkfF2pZi5doTWHAFU*kfZSe?do={nZ=QQ)+&sJ-&f_e}< z5V02?O4qIyi^&M*wxLU{>aEgWq0`9k-`-^k>eA{@Q7Pi}jja!jK5o}^ua2s&xW8=! zTP$WnL>cD*NvFH2{W4Zu#+eptK%pJmD&>lTPQVC0ZkE=mp*O%6(kH@qGi!*RF^BjV zG34vKf`qOK;5mqh?!AO3X>4i(65BiW5El8M5_i+^*6T=S7euUW9;>(cAW*3_?uBt# z09EAs#b8=UdR4@*54d_HBrqEqAfE^}s-J0Ndg4nv+J`mf%U5jFZwb}8u$dXy^+0=T zr>P6%#2qcCYV<2sgom@o2X*XT5N-|^d@3R~{#`Pc_}F`z>|oVPsNr|;04kO))l$3Z zY}wPWZbI;yJ8B|bIkQ^J7e%sCGWR78Srd?g>OdLV%rDak%-c^ zkl`1uCc1#ulBiX3-?7iPw~XGje(a*vI>1MinfgHJ1YRDZWO@wWwVyKScC zfmg;=euD(lwi_su4@I_JpsfukGt@y%P}=SRGTiFZd!D=`M5t6X<7&P10-8d&t5!LsMX7~INLHXFTS&3Q>B$|48wDOjD>aCH(&gBhsr;2h7E7q*HK?#2i7$1-&8^co1o%@^*0#egSH6^mnIEgxSP*y6DKbw%Bc&fboqN+cpYp!{J z+^?yBYr5e8MFhqaEH_b^uP)UG)2^$_*Od$kv|g^8%yeg?L}$C)`;N`AUy$C-(AIU} za|M^It3Fdr3bU2?(@PnwT;a5$(6nu%af|lAYpr|?&|cf=BJgZQ(p1fIEk4phY>6J* zVeRpFBW|q|-`UG-%#X)n!d8tNjKE^4Of^zEI#*(?aKUQLDvz8-)zuVJt?+6k@_G8S zbGd%ifm*cyBJs%i*bgI|HNRJ7!07`M z&Z}RN4MR}waivCp)_%di>dFl4IXZq;NF9^N4oCA5hdL6Mhi{W^DQUZ+S8h>2NorO# zzDa3rHmTl>^Nd4I8gIjW22-H91W@|+!mvV8?9}+Wdf?E|PHO;W?NU)oLyYT9@<6#l zu6dN0>HL(2oWBkSv_eT18tjIk11NbE%%NJyNEG)d{7A{(wlKdcD0lCFmhw(o!Yo^( z6z~+?6fSU2DL&b5lz_0OAvTJxlp=keSQ< zOT{#j5O8?1dH{GaxqR}%r+c8giH2+HqR<&qRAUg4twpS@%;0$@3P;Lj2Qyx|9{wqM z(Zz;|??(KIB)m&f<$Phz>;t04SwHTKOgwaj*2}QNm)rwV+wiis*t1uGg6EM#@ z`yvz1Hk{?+b3lwY$1#!Sh(?N|a!$$@1^UE;4;w8B<~J*52}Wj@*A2qRTW{6$6iuzo z4}5RG8RM!c-8tTMLO;!XKI%9FWj{N5UfDVtK+xw4B0{BJi>Bal<0p>zZi2CWy=U$0 z&o}G`anE!8FPyqU8@!el)V;W@=dHpPs2nVs(W{IcFDVaz_O?~<@8s&|mggU*R&Elq zQnX&-Av#G)3p&iGuNjS_utcS8r?5n2LoiiS?rU?-;pYS~7&+&hrDIQY)!Og><+nEK zoHnfal_;vdDxQDOD*UfR@vp(WuXX?b#l-zHc~rWKdFy0N(&k`y*TXfV$rl z#-hMMz;@^~Q(vep)vp<~J+(2+B)eSye98;2qZGqKq1H0moa|)2WvaWvuCo4S1LRJ% zEJMxz9gWZ=Q76fV&;wvCkKJj?WY~abNDUMf1D+%kgw!F5CuboOruwyJ3UpqG?{}Fh z!@+5)B)?UE%}_6>d~f=Zp!!y5eD}d{7(SUn>NvuI7ayk=zh`DBj~T4(C>*crFg_Jy zEk{D$EyKx>EW()Yb`JMjX&y20wp(!ES;Yg{m{h7Zv)WkGA><`XCTSFOKuz=KSaM~I zQZ|q|qD{8Q_Ad4o&-UGwRT!1=oC5jbiFJpk&sd#pN;B&ol%vQPbTeb=}9^V>iA(Ekgz z{qOque?g8lzaYm5oN-Yb1Xh;iiu&)R7iMteRH1lsq#|=-CbL}m0y)xg8>V!&bns5h z2`_+e7OaP*K_vLlVbvg1do6 ziBodvyqiV@vgFJSm>3)|LhX?2$!Kg_HgoaUQ31KfH9V~3?!nLq#h+AGEF?Se{%OT* z#W|DJ@gBRRm9LwXClYVGqn(I>L=HCOD~*9*fR*GRM(voszoEcqPX!+tyx>N!P{*#(^gu~}eIA#$ig z6E4YP#@hJr(A<6*9#kE|hnl~QxN(x!-2K<3z$pEmQR_j~NIk@}kZVMc$)muON``(H z?_yz1rw?$zs*}E>jUv!9Oy>8w8R>t&FwLI$l6;4;2-`y)ky6e5Z{YSH$B3L16%yvJ zV0`}S=d%30W5l2IT7C;%d;5PKJ`3bEt>I*0IFqV?HJ;7PYZOc=Ni5Wr(mIpTAoWs{ zqaS<=Mfc_mTeg{Ad6x$Qn7w0(lp;btzIn&nUiu;U{*=@Omk$7(&JX+y+7R$f4U*F=JkIM%QkFR#}l2xr7bn zFmrMiczlYvlfpT~Y?*W0Spp9B9`h0U`ereYe2?mf9~htudjQ%5%wOp`vSqumDIzalxm<5Gk^uCkRPoS6C*TW*?ROlE>@WwJ6hlvyT*QO*2 zZVS91Zj0eIy>FDCfI#FqSjMJ27oV5-D?s4^pEAf#rre7W8*QOBjM5z5@vtAN^`==Zo2CYFoNr$mkVi+CwUKPckjc#$NROcv-7U$!=G$#NvrOH?%sym zRh}w7Nsjy0^^c`Y$n~z0X97|`UKw`@-D&HUr8EnAhY+{u^Jjx1TvlM_f+QR9{ZOj3?j!D3YF4a zSI3u(e3`%@TS_&MVj|;Tt2N&ODIRo#;7p^-8k~9E#h2rnQ0*e1-S5}5S`t&o9A7Tn zvet2|m$Wh-tmdo49X})k=gB7w0~wxRazP7bqKQt)CSE@N_(O3gaaAi@fkzJx?NoI| z!f=~F#&z&?3)u8>99G4^$^1it9c!uMLWzC=H*5&=5Apk|kkF#o3@(DVqvwX080BTx zd#!N!7U84T05NXN1T3&)Ts6tL^S#rGBNO-KEO*L~m0n$D6WbGrF}1b!jkw^Xia2Asr1b&-dgQD}Q!RNn0)!WW-p6 zD|(L~)GR2hxaE>gAyuC+aF1Pn1eZL4^?;<#snyQWwj`mJ@;FqPDLWO^Dg_wBue4Kw z#6w!zgyd)~K;6}WRccQJ`IGyXTd5c#*mS3iMKcMV^~sKAO9H{(Se&kolcc{C3u>6E zE}{WIN#q+%$Yg{HV9pK-?<|hfHK-Qf!iUT%*)e(q^Z-BxD_NZ5BUC}T@3APaBg5C5 zD(59PG^XllxAk4flo%|R(d)=KS3;`|O&E?|2rQ>HsK7nL;5TcYT92+9M;_oCf}c>a z?MXeMnh+Kx5cXMNCpF3FSO%giXtCEgUzEa-Q3|ZDEv^+~39%IZoWbEQeXQLklhZAI zsZgP#Jzf={$vR&>!C;r4abbYxv|=@4W8&|m>fpGpqg8b5dB((ToLntoCz6>3P|D^M zoujNXqVtXBV`qr5b0yFwWzxb*jZ7iBUc-`{=Dd9Wq?<$7R736?`D#c+dnB&LL9F&X ztfYt~OeM>6Hi`_k#81zSI+Bq(!k`%!NLu5>PpXu}-KcDnjLD{gvZNbatS2f(i3V0U zr0zOoK&bOu$s}PqkM<#oc2u%#x|jqrs!qSj8_2P}2XJ@4@i<@B6qzTAEwc}#Q8!2w zwV1oF7(Qr?d)DBd&x0dLH<(z(;jqXVs57dc?T2&IrejEzPQbkSHInm^=^rirz@knk zscrgEn(bz1O;Sm!kRBA;qplbTEzn}Rgmb9&4DxP!oe8DKI-qu<# zO+T6C$EsY(bjhU&oBpU5tIjAdtHH3Yyj2prM2r08?vH`^wqGh;!MBBXW158l1rzbX z7~4XF268CdP=oQjg73isz-7is(-Is}bwpA-T0Nzz7d#TIrAnU&ToV(BO}KMhYX=(* zI=AiwM!U?2-OcNRsVpnLYe9K6!3lJPxT5lb!^)ASaj{hV$MI=Z60C<(PoeP|@Y=no z@^o|-qqeNN!=mz1BOQh7MHBC<9N81>^{z4|egnV}&d_VY2k>l<2FRISmkrV!?mPI# zR2(-0OPSd2_bEfD;j_+$?aJ`&q*n?o*t3V4V$HTcL^tDu4mJuoa;ct+E%Zm34(i*7 z;)mkbOzGg@!e4-J7uy<1Exh zCYk{~i4eV{UL5~@$y4oN#13KQuL|#f(h(ExS>`y5x@}$^2i($Wg1Qj5*UvC~E}xc` zwv&Bc-#*_Wa1@90UKn{o{+B!f9nX^&8u*XyXzSgGUBwwgWZc-Gp>wSv39 zUmn}XYjrbX^`_(gK7TRkz_bmF7H_wAAPa*sqCk)eGGO83Kgm?I2V(!+yesj|e-6$m zmpC$yW(P`7>_-+NuCJ)9I~cQBno-D6ew>^zT@0uoyyhO2cH=nT^X?M0q3MggKt|;- z;~tk9eg#1Bk@?ihhvLc*GdsVKVruDK|D)@DoTfVIgspY&c}F(j^b6{D2Hl$%JX!9E z0)>GN5HhC=7S9i@vt=8S#LR#U^vYB;h*yaQeINFd7yhx(bgJXs9FU%@BR=}dRh_&MEFRcQTh>$U(0qWsMRp3=v2g1A;zu8z=IX?QCf4IzSA%z zN?}o5+8V5ue!s+{Jq4jS=Mwy&=Df)C5!-OmdlW;3-_ru~Bo;G^jUe*oz=Zcw=UfrS z*Jt^fhF28Mirg73Ar9%n0cK1K`bvu1GBV($RP&iS;hLJU*!*9=8y$NQ-)TfTF*;lM ziw6asJZK80Gq8YjEl5oq*(JSoHg#GjUt_b=?<%T7buK;|Mx7s7>XAk^kPx%Hszp;5=q>V~}D7R4~0awyydk^;br%2c^H z@@&r9v%mSaxfAONT=4c2!<^%1)b+5pB%r&YA4NN-+UgHYEzm=Nt11aabO@0O2UqhxWn z-MH{KM-yIVrCq6VB0O^%o(;v4AEnIL_SZO@qD-(KSiNl)fkPOA7n^-9%)eX%JgGSx znI{-o_GHtY<`a}sNc%ZgU6M)YDfUM`$$?d_42y8=pS zDR%msBD$x2DJpS&&4G<=HIbIOe9+a#9NK%XZjvH)FOFoC{oY$221m@T$MsC*k(e9Y z-Z$-wm4}netW#ii1C`vx{I_gC7})}ZsJxn5e3YpVYc_xYEsJ^Ck#YgWr$sT^WTGbe zO~DuS$(eqy1mZa9v(KCo33WL5TcLUXOu6hwema17v9M^0U6mJjH~yD-SF7 zo!aSeNjF*CmUqF<%w_<;Vc3)&=gfCt=JJ7t(-i#Ra-q&eH2lG3u-*3~li`~F2N%H3 zE#8vkvy2|M_XA$VMaJDk_te1>;_D%mC*Z*kt{1kAVu7m)jVmujJt-3mvzfLhfS@f{@++w`Mqz4s$+UL22Ixcjn%E|3d0^K*ium- zGbD}IZ5vcB!?xt3-AN08;UN5Q#T>%9qV=@I<^buJc_3R!o}orF0XrkRy^*>ESkscF zGV}D4?4%I6rZVxW*{e>hevBY*IPCI{#G1DpibJ3YH(?*6WDVK3avmKw&Mk<;PfS!+ znm@1U1W}@tqS^2~syfgXSshx3y{?UFM|W91SVOEqw+5D76gCX!57DlYxM`>Fdq77I z`S0JrxN=BfMMV#pvTf+cAK9Mkc4O%Tll=h4EV)&~!Y(o-BwI{u^-h1_*xMROCm)tT z6pPgT3A|b|n9b2vyKL$FQoBqa*zr~`txpp6UZJIS^{p;+Ywg-F-fpso0_p<0XZ@{v zhr(*Bs$}wNVmFfF5`$N=EXV9MLU#QMQry>9+c#=fKTB`n8HMtN zq3>jm0%MA1oofU!>o66z(hceTZV=_dbG^}+b<6X~&|^i)euU$PsK+mnkd3)`CA~+6 zf`r()Z>|QW7i@*Ivh6xQt%>J`l~D^rS3O)d1%iBO0k!F`?@P4+w~7fOkW=I^w4b?* z%`jl{U}#UTEGr@1J0pjCW(PZwbqr~z%aaXgkGZ1uGdf3vYF4ju%%^XKWlAY%#0S!m+tts-GgL*>pP%5IRbX++MK7kj4ad#l_79?QyrxD$+9oaZ_10XOg0Xf*S)N= z6x|&O-n2Om zLG}M~N&Z*$@ShH8e<=?{|0*l~r#)JQ{Ds+nR1PZ|R~HD#p#H2J^3j;aP~HoBOF9*e z%uiS)Zz%i*;PSWLwnh{Xc=^T^?_#_F1Oz*8cr?lR#bo1LZ~33np&xj0f^6>qovZi{ zt=bxkZbSXbWtAG+gq#C6YQp{3kWor6L9B5YIyPSvl3HKkHexWMkG*q21-KLbOC;eo38&*=U;> zUPo=GCxLyH4o7H842xZER9@}WQ|=EEMSh7gPi!Q#Qr~Cb+ftB>DeVW@=H_}S7y7eQ z+fEFo0wOPAD%gznK+a<_OdF`s3A>Qwa&3il)Nn5=(LprUM>hDU8Ld&yqjHpjd}_f; zA?_%^a+QG;h1$sF%z|bi1wzwHzA>w9v_VL*hvsiW2*wTv8-EE$o3a{_DGXdX9rR^O zS5PjwAGi(}z#@5fV(A-UOCnGFx(b zbX%QGYY>k!AJ0rBZ;~uG(%pr}9_v=X!tkz2mM|^PmI!^(9v%Ex3eu7*%~GYGH5Hsi z+9^SZa86vi;qJfs5kc0ypEqB@7yi|g_14umq~%i zVsB~8XK;U+QhtXc)d?>~3LPqo!b=mu^761vjHf4UUKLr?aN1*KbyPZh%G8m3e`4 zj@C%5-+RAL1>}dJRH#E%Z}zoV3v}&+c&fO|85# za@uw9>6qBrl*(3U6fRRhAWezbl)&n!(kE}A4_v4b?b0UIby^Yl^Ni_<7h)$bCMxYb z?>QETT51Tta9BwCrWUz-Udjc4=&sHCx`V<#V_aw~yL(_pp5wZix@6Ehft4f5meg_n zgcTC?$LWq-m4{YKG-KDnW&_Y>10_o7W&^?vy9(sBVnu-pU|i$S`%lLjJ(54XStAqF zY4Ai9dZ*D2G{KwVB~Y>66rlo>yd$~ir9a%cU1y}drlq}_vlcee<*68%yJnu3o-b(? zu+a4%QF=dP#_OnNYiI`2XSWxV%E28GR+25G=L?4=R#OXwm5PLi)Gj;{?Lrv121Bq3 z@6ZTiecH0RAG#R0bk03LlDKj;wA{mfi+wKxBF8_5El0Y>{Ix_YD&6SEWMm>oo;*Og zj;qBN$5e^5*2Nokj8dULP}+G-<9jL1H#r0zB$|$+H7J@pSC2N}dSbrN`Cl@XScOiD zj<1#O{FQRV|BvBl^M!XZv~zH!7PNA- z>#HsYssvz_ttC;y1B>H}H?uaFS%|)f{d*PUNztYh2#(ta`&Y7KxZ*EsUYZfJ!!)s*JkLR0q#aAg0DU))T{sRX$MxWrlaJ%I6i32C zoz09;R#FXO=;RemjG1++I2M$)P2dbe=1V5Z_~g>Zf~5>3l&0q7hzS%cSI`mTWzj0N@y<<5=*;^;f@(morMv(-W2ksSgSp0jd-}= z_UGWMTjRF+J3X84r3uFXr^XKPNhejn8BUeC1!i_1_x8nA2Cv7S{Lk-Iyb+bO43CE76BbQ?}udJHZg6p)i&#<4XN|@Rm&z7A@&DhU@mmt}1!(D*s8otZdzEg@h}c z6%WmctkrCAXtQ%YE$h?DG-UL!(Q1G0RYA}8HSJA)1_m8(zx42x$Zloy|Ja@zQN%mo zcR_BR@|$lN3)lFUI!SUzW##5`h6<$#-uV=NmgB@yCxgRh?#VM2y>|1LNGq6n&-2CcJ^wJR#QcbTRL`_d@ii6#$A2#I8%JG-LnOiJ;&uWL+5aM zH2qXbAG)sgGi=2T?u>(HLwLAST$^s2yh-Gg?7wuQ#V`J}(cG1pspSHdy*bWuo21l_ z2-UN7dUSn#&UH;o45##7a>;+Xp`W>gj%z{^#ews$E8*hwsuo6pi8*kvd*3 zfa`K%bd7Q8opDa8!&zoc=`|Zq?JCPxjoe=y%^mdHE@5YM^d8rj~brbwCz`Dc+t^qn^c6KKJ$-7e_@;Za>dBk81LqIPE_Aaq zvCr5YtI>Q>V$k|>)wiiVhw=-~&{r7zjJGsX-})@b%%w)h-T&dBP|+N{d9$XRII4GT zSixOYkK5}pC)cX0aSX+8e{9H#wQFe;u%&S?Vcf3Y|8opCb~@C zr+(L8nN|Muc$a|TG2GRxi#uLrBw5(*d8PE-RE72T&4J~|3_f`E2^>p0F6tN+S!Hy$ zXirwL&ibBr4~rl4tdPkqiFB69TPCWL8UJdgg`&qvwF5Px74&!AKJQy`F5rFEs>;jD zdKyFqOgj^ztfuUK9rR0OtHqI-rsvvj(p%JUAM4Aj;pRIc-76K>nqLyDug9FW;^et$ z?Me%LmN);9)sb?}-Sb}RQwz(v710G3oP5{@88lX1JS%11i<^HwVXk=5ZCR-nUfD`| z&RJ$h=wB#FZrB+yz@ArfQ?h@z*eki>yemzgIKnT>M6eHK&r(ym^SSP&;C&0%AED`% zE7okM&${H3HC@5ZZ2KB{CbqPkfn&`c4Ru^qoE0@12lPZ1UhtNP6T0)|jrW%AeXUNv zOSTzY+G@60`OPc;#hERxqmBr(+5uf4rA+1iF1Bk zb_sLfh2cHf7A+MK)r%-Fnk{r6lIdQ z?iZN5<4A{1cwooDpsLtIT!~!C`69AHJ{#{P9J>ET!B=#a4ZTHQUx~uhWw+;w_b2^i zdRNh>lWUvwI5+7aUmzxTmc^s#@?4THWZXv zTKk(mWiO5nCE(EnVq~IxPAMU0&@!six(fJ4)oWqd4bctQ`GTJRhlVdZ@d%@24rCT2qP8V8Iu!r-5oYjYeLVhyF=ClYMAGiY5k|JSzZaUs12c^3|xtk`W3(z~B2KBV_3Q+j{P6Mo*L z#cPE{cbadDulzLQ(T}u4UxH`a^|s_k%II+0^*cxuXSQm~=(kAR>U5R)8KkjIO!V`{ zTOEse^j(AWOKdm~sAqZ!*d5*65jR_aH71$G6)=BcSJe=!Xe?=&5 z*~2q+L7DP(PUkj6@y75fBweTX6HE6MkPR_z{I>FRc0s|76CG8o@$w8O`WAQX(5R40 zQmeb$vTIJm;=Oy@wB_?t@}xBqyWQS6ZhUzq=Czg-FYj6%l`S!4Qhw!^q${WXG;Lb0 zckOk!>~#9YUmob-BK_{o$$uMG$dsVKwzq1}yR!<)IjxuJ!fA4192)z1o%E_~g8eFL8bBJsPSEDUqDh=!5M{w2vNFi0w_zP_9s_b!0tv;Cso} z4NJdO4-0*$^R{YXoN+O@T+Xqz`hobhKf;%e)93LVc$C_*q5Id9Z|q0by6rml&ck}c z<=}GGv(jx_9j4c1nx_WeS`wCS_TtR0yPN%__7Zdt}>ovT;Y-T%dv&#Q(0iJx0iTy*|}GNa`OYDAI^r9rR zhZm%`|H!LkDYM+z@GP~#c|g|I%0$|E!=*}I>r-zF*dGjvJXgdG?s)Z!Ztc^$*zHGo zA4*@B&dOYBUd&+LQU9#bAbq&9lFe@CyN~GxyhWj(-Zk!%KeBM`K)j;9)SUqC`?Z1B z-v|7hzBc*Njsq(_QmZSc*Z0l+X%Dx-;~;(ls`{$iBD)q`gJTmjIM&-0F!oz|?69I2#F*>Z@0D&wF;qmNDrGZkQ+moXXa) z0^iNmXBh)yPQ1|0v6D5@dV4ZKr>M+Poawju{0BR^Hx9o&A93s_?#0_>Z%@@UuzjKz z=H0fWec`vuf?@IkPPvYD>X*WWS$H?S?+~o^G2YeqvVbFR-c7anYp>Hi%isOBK|3vg zcW+g3lUV7ulDpi4M=V(H_f?qn&leAlzPi{w*w=jDs%L?UA97EyKdkX?bZI)ld zE{$rwExt;)Ddrt{?n%NmVNCkJrz%zMGpgkm=ZchX;f-8u_>n*ITuA%}mkY10`MDle zMa}8lV?8A4d|X5J;_0~lb-2>tAvufR8ot}s**>_q#5i7PAUb$h^x&T)<2^X>yS`Or z%)S===?kYEGJ5geRF@%Vu0XlYH3yCc*QpnG`Bqr5#TGu+;W+Misq>myYuk~6I_Jv{ zOUgc83ef54w_X*@SCJYQm}{lhp=>Q<{c`AIdFqSY^s@Ymr#q%D)7QLy`Ot0gHI)Hj ziPrI6y4zQr*gp6wYOQzZuFPTHn+|n}s&S0TzihIbJ2Ed0FD_HG`04y?;mY3)f9~zR z^LA+c{nPJ0uRI|cFuw+Fi#KSii`Z(xsHt^C{QEAGdWm{J4n7}krS;!6)IWRc-j4pN ztbTKAqNj+>rOp6;ZHt6r?K<3=>-ICazi>F7Fz7j|_mIA{HnhpOO-cB0Fz>7M!nZs( zR=rxD8<5*vHs3z)<*eM*=0+S#`|X!-SMHw(k?Xv2-uCp3 z^YU_*i_b@Qg>aiTm>jrWC}g-YMpSI+=K!f@qr$4-DV2fqrrp-K(xz-~tEAZOxXRV% zq>j|Ro_q0Ijl!>=X6|0UY~jjp7v|2qz?o$!(@-mLJ6FYBGwEflb6xa&*nnXK31e_K$W>0fXqD zdqq6A*C%`*4&7_^y6(+dA9=PGmM8kMgT9AkyTpU~E`?s%!8?nMZzg@2IB&K43U`aU zM%^>^ZQS)a!1wCwKY|qvDh!w01)P1JmU~GI#GlMOerl8L+K4C~my2Ic%S-XSmzbt= zTr_*xvQK-(WW($w{8U@!MNRcJzO`C+Uw8cNY^Us>+f?U^yL{9Y^L12oZWHd6wVdCp zcYB_o#?GUhvfQnVbD#1Dl}6@fvU%r)oOO*MJ4 z>$vO!3EM@2v7c7Pm|2|vctCXBF=P5`yj`#C7v^#9-Wv0p30-8JS6|Z00{y@g=m(l& zDy{KJ74f1Aii@g7?n}d8S2g;!G`Rf&+Wo&Hmt-B<%gijvA>D8My`_-LcI($uH#nZm zPGn~fZv1qj?P-xhp2^vt@IoX#g+62u+~sEU@`Fb;nw@G=Du%B6arIEpu`Q@DQwPvT}YNq)TtV!E!LTXN<8GlsVJaKg+H z;)NfV->Ql!cu>S*myj**_f6sYlZC^@yH?<)x;R-yh00`odB)%x?i}D{>(MW9vbLP@ zTTbnjrsvzUSeMnz+-rMZ-lqSDrV>x$a>pq*mG(VUS;en!@$H^$bzhLyw|UP39n`)n z_r5Rjd9z5PNh>L|G;8_Z48FNtA-7FA286?Z-Fd=p$z5g4{IvZDr}(xr3EM87O*Co# z^`%Rhf5m6s1&UV=?MaN)w456>>}9cez>w|FXAkxjN0XL*m|4E8zu{ALYUSnp(m?iA zKaVnNtzi**#TuvnNxM4Yi-QM!U%~wN49NC;ikm~ zR}2@2X?#*FmGtHHlK0*nt!Q%Tv1_o#;cK1_v5%yZZy!$hB)??NwLAAhY<}!%nijn< zo2xNZ*4f2=Z_Tj5)10geiS&z~JhEFpZ9zd&HA_?JYK`8xx(V;o$;O9_2rJ7k zKQ#voFPH`ENu#mJJmE6jk&^ywahZy{4^gWfkRklVjo8bzh8h zn$9sQO86wH4qXzmi?y<@*Ye%P&EJy16x7n4(;`?^Thd$7TeYzC%3_H)zaj_c?=8&* zMa@O&+YH41{Hj?PMqeVjWvk(yRK_#C=JQJ%MLvjlCRhsR>bEUF5UAyTaEswfK91$f zUPct~6ta9aiu2%jE%qy%dEuqrIlD7E8Vj7u-OL#GexK_1LZRW@6FHt!UaPVg7=;hq zk7|6kFK=1i?mShw%l#$&9x~T#I%@OVwkf}8)wgt$ht^7=Q#Q1hlV|1 z%=xU`V!r=`l?*Fe(sS>E;!>}d{v{6?4o1(*x-YRJ>pr_w=h7)jN*fYZ=(kNf;L0v9 zqMsPV=p1lVIG6PWx0JFvpXre0zU`YYT{*LxL6ookR8`BzKNqKagmD-g82TB+zo&Po z`4VgU$H;AsmOTwY{AT;Yc;cCvmc^MXD!Q3vdVjjWz-H0;&}(+uL+h;RmRrkJqdpwC z=@O;G)AjbinuN}-^)({jolfVLC!C1>I<5Ua|EbXVF40?DE?n>TDyit&q4kS>_=HNz z?o(Rl1ml0i-`$wjm8+=C)L|HZ_lu#99QOrRJ&8ZeYTJuM?kD)%ma*(&aNM2Pg8QnU z5O}M9dgQD**UFWmW&MmIAH7`sXx$m+2CjA`83yfW0a1x^hLu`Y(^kgIax(7PbSOex zs2nG;Uy#XY{lUdtc}wZuF-VkOnQnYIqEMWPd%lXN!v+t!a$V!uX476Bj3|_1GEzS% z9dm0H-MhqjBEk_(NfCuYOpo>p=*6^7UAIJ6<*LwrVTNF{S&1Afp)oTUcNH?`=&rk# z&TvpBL%^bUdX#{C{JOa+#Sf0=oR}`RAY4jEMPvQJoU;PDz6a;bdAA^Dcwnsx*N*9l zo6@0+(Yy8OpNP7U_kra-_j7lYTMT?~mx&N>YgUdNe3v4AF`|D}dC8#Ru7%$3H48n$ zqLwS~h5LuYrYb%N(>*%GQ^<`wsv}_Dw(r56o6mkO`_6m1rY_{8nu@aEnZ%H$5<4YH z$=%P&|FqvB#~Wk{JX(#pb2h{qVYpsS57S~tx?ax9VJptjpRn8!x3|@{;2hmZcY>N# zdM!}r`V*U1y{KESC;x!j)UQ({M5-ON7ltR+s~%@s5@)T&vqd*NcD2t9o6lAQw=*O1RgF~ydto57b&=;pPztl6%P};2frYcna%a0v3uk3z*|HMRB zws~vk-7V8Jy-m-&_u+8lnHO`T6(?I@d%B!<^cp})|9gSSS~_rBD|hXGG+^q(u6 z8Q3aW6Rc4oJ>SOV-q)&I3q(&?wcTEqKb3y_Z3|y)3E$2xthGSxQrO89o|c`wF`6pk4;nJ9 zr8|ZWiMBQVc*)FtYpbndfb!lQl5$GU2hDu+%Yq9Z*9s4?Hu^I^%(S?Xb}!`;u48X7 z--5;0_g%JIoj+Lmu%r7(K;iCwN!j0A! zhW6Wk5BnezX(`Op@lNG~{l!Zm$sQT2ZI`b;Qq9+>$G!A|>C~P3wi$i8sd*xC8rA675f5up6UmxoVzV7+MifNs-uj|#ek*~1C#UJ0efvOQpm~~0ZnT%>FevT#zINcU@BU)Z)w9=fZ15L(WNXE(Ajfn6QNR_m)IGfl zkIXN|v~nlj4x_7axYKn0H}jIP4VP!f3h!RF2j0T`e)*wipHFStq`BhtZN_JBPHGp% zKHzEitU6apI#E>LPJOeCtpBO0%}*_6JUZHIG*v@()t-+1UxI^^0#44|5g=U6r12ne zclZA3r^J|E)Yf@FJpW2_$yZfjy+c|&3b{&ptouY`h4|y>e&w&fTm6zZXj;TGK})(h z>}-Z~ecZ1y%f)|fs5`a)qx}WJily?VYB8+-T>S8a+67b>Q@iCo(K7lM6VrVO?ATgF6y6aJg-l#LY#~J{n;>zdx?#-JQ|UahHlu< zSc@_AP`#3vkmwlO=+eX4ySKMf8hnoAy6bzoTJpR=f~Yol0!Mn zQK$FqT(?&8c6aK$8Aex^4pygZuRiV<`1-Y-?G#=I&D~Kkky6ju_X}~Bh43z5U0HT` z>V3|c_YZ62iDmZ`H?n^_CCpX5Rl4zAeScbUrFvtlbX}`Q>!a-Vx+dQD6GE4^_odUT zN4`98EyK>iuz&l^$StLwNuF01N&7rgJa#XOX(Cov#}(g?FBbo{@8>-~RbR6x+heW%i(at$@iltv$*vr(-1vuWTi5Z+ zUx&Db?wX35h@ZEwyHuC0wc<>^VG#Xd@tXb0s<*@hB7&`!Mfqz9X?Gs#vX_N-ARU=u z!^7eebvMN-XqT_zoc*ySPdTqD3ChgnPt-N#Q;6aiIDf5Xw%97;@;zpbdj+fo4OHGf znxX_oN#`wE^xZg1BZGRQiG7b4nGKyenB`v+?5J3qn>5&?TUJy z8HExQP|vHv^t`cm>Wx+!CBixs0zVY;6H`1E!O_dp-`C6C7jA7p@q^?{Bmnq9gY*j` zpU{7R=3wvV>WISJOo54b(#QwFZ24!H!1Fd31VCX^@{8n%Wb6$Py8o|qNBAY&i8xxZ zl+eggd@}USe+CVAF%sStLz8ngB0Aou7eO@nznsIZRJ8cjK>_ajH-H%Aj5e>&{|0v) zA)8Z#2ego_;kw!XDP$*#SV;+}jS_O2taE;@e*QR5 z$6!aKT|pB<5(S|Lx#z^fBhFim_CZS0(TULENj;Z5e@qKO8AW-=Um_6RFi%rPD^W-) zkW6Ej5t$eKE($G%R-s^y{v{0IJO(Ww2^3HtHlVR#mr~_uF|B~=0)v=F9t-~vb>{*t z>g7??$4>@^tPENJ$mMw>AAJ7#cK`&t@C{p5p7HE35Eb8Igu|FIa zf>wk>2Za8=g%}ffD3d~T zK+u_uMOI@TN@7k^ZztM7_v_3i1 zgO5+{!6Ru7ig3#3qr*$j5FU(lu;BI>;3UvR~t zd#IFOf~0lSmmZM6MA@CE{35IcqrTXK{-UEjx-(DtWf;>R^<^FoJZ}i8__jWL**9Qp zOPv9pBZ#QZE3sKZ+Q7o_|HmsD2C;x=cuI?y(di zi`jyJ?^znKAL9x837RMhUkPHOkleB{w|7?`xkVMupc48xV?hxe8Qwmfybb`%pz*4Y z0^K8w1(ZrNhsgSRe|0cme-&RBzp>Z|!~Urc80*147@;$=9)-Ph5f*IXVgfhA61X+M zPsEUK`KC02BRWqFZi9$Jpr>wzLUfXx3?eyQCU$33oSbk@_?J7X2N5cxu}mWZSAA={ zUJ44&86tFan@}VqKn63hQxKUZlYq}hY2J=Yos#69^3ExsdhRi*SA<5%-%tWq^t(C- zMweFbbkXg*t@q>uqkCJflryE4>o!X#b^Fxnar`&)akZ00l|!UF_= z%s&u68R0YGSIk7L$2r>vxch_81>ne6#8QHpvPw&LgXtB3>8TKr;O~rZPxuu(STK~Y zu8zo&VG|tOCP9210wo;(BApydfIAQTq5V2vZ4z)~D^tTaz($6tCs3}2&AqBCfISsh zH9)Z%s{U8lBNzBPVFGu%k&y2J{&ioRj?NMVo&rG?vz*C{lZ);V^B$pshLT$Q&Z?*)YcW z;olTVgF^&a?s~KY8yHs&aEL|@wZ@E0Xf}Y`;)4beS`X*zg7c;3wg_@`_Et9|knQv_ zrv1$ZGxA6i2!M&0Z~)WM*A?F}(?=Ra)Z^CB`JOsaz5d(60R?2b|CWmM+R-wQ*Q*s5_>o8_fg|Ves@uj+E^H7!QBQ8yScg-#JeX zm`3^cQrkqok6_hw{xJ?dhB)ZYy4e>o& z?+mLu0CfQPLx=Vs?vsNfwE>Zs16eAvqD=rUviW$=1^|}=a6=TYVqSj<4z@bp^&6vC zRD|`TyB2+30Y)1D;TC+I^vMWs_5MrrkxnAz?H>?{NR`5PF;J*L;ioX9E!hzF(O#77 zhlLnCGBK3|&qb5~QD`(Yb@yfQf4is|nvS+oBd_KliXkIhC>S#^p-D3)VoVHw?ctP@ z$UNNwPy~554{>78sBvp~LKzOh9spqG&JpI9J#Z*J}0UJG7nH7i^ z9dbEh##HDK^+y-kj$;dBZ}=BM9`2)2HbOhFP{S@8v18;9I#75(kfP`VU_&8zl`GC~ zG#FyOy!PKcEI?{^A-=-`P5NYn^BlyYI4s5Zs2Hs6kMp2zLFo|H&G0lP+DKUw@tBQ2a;?|6 zEfoYaa9GUjIT-i>z|=-zcAuRjCPYZ&A~AevIT0*Z%F`9QfmH+WEAoH<;#cAqvA_~n z0|Zdp(+L+uJ?TI=?8{zll?cYz2VAP5IAqMi1T|8<6ZHs-56;8E9qzxPR?Q;8Yx?2* zBMJcK4{NU#3UD}k5`ffmN2F&#QPhpM>{>t9exV6#f+P&6pqn>mbN`ACV(*413Q`6{ zD^4LQSgFJ0F8~IXHJgrZ4N4-;#gm|f;zBCw5nH2k-Nr?*Y*YZ2AquOl6blwbkxAs0 zSb0rQXol3AR4{_xbD&GO0foM;3KKf96D31RIZ0ARl1}Poj#%BJ#7keBLB`La8IE2u z+iU+4nR>=YOW6n^Pv!kMlfbn-!L`xN9OYM72tj3g6e^zxTcV8lQ5|3}18j6OTh)vO zo3t}WiZ2149wQa$=#z?+>s>|3hQhrNV%~t)qZ3@e)=9yVw|EVRTX(1nNR9|{)c3d@*`5ROCvEtG^skM_UJGQ(w{$0k_J;2K7KZ5f-IP8>-kR1B#X|b!9GI>E~Dg3>tzm zl~D|Gz?nLzXDN@=IgwAqA=}AB21h5sW04SJUY-`+q6CX{iW=oYEh#)1ByxU8Y)s?p z4ZJ!@Im1YEdMqJ`cqL5V&GG?u`}pYS)}dH#UV({_k>~;(qkU&A8h(LbYhTh1OBDmd z$ldrvz>M%r)k&a{xh8J}pmtm)NYKunOZ%w{de#F&UQeU}{>})Wp^k+N)GX|%j{NxL zKze9<0vn`+Y9MOZP9c3V!f$9{MkF&kvg?7~f|!8kEBX%E{=hE_43wZ#Vnw~bpa8fY zS?I9sy}WjFep&)+oiD6)S|sifiF2D{K}Y3-fQ^)V6ZhV}5o1B=dR>-qpTK64fr8H!!WO_K&59Ze>NE@Jc_tOeVi4I?aQJ%>49h9-?KjyN^( zSK8=EI62O8TJJbW9GP2DMKNCFj0K&X`x24eU7hgjA@zV_9wc0joY$=cj#W^2w_UN| zk#c-A z2pYK8<9`6V+B>-8#w{+8R$1twd9#_ok`rM%bqh+sYTj6Yu@o1MghRxm@-6rgIaloE zOI__xwhHYY0v%XFVu0S+s15l4RFM)vLRLh|P^lARpQicv1Q5dn(G@Ks_2BZ2Y|2oLK5$W zGN+u~|AeY>i$oCCc!VLIJ-yRReg`P=8z^xbim~?%|HDa zg1}PnNA#*v9EF8OVtPtWpU5*{q-2r0jk9_Vy)%UsL(+d#o!>s`?J)uL{27h;a5=f*J93QpDsu5u-*yhC3 z0h-R7#4B6H+v##}a|?EB9*X=3LNYJ4n|SrN^ure?_In6FFwLT#CYWh z!Jm*71N1~)8D*vGS3ql+4$3cz@rdrnlg8E_RSRJOuL}_4>jiMgBq#!!c+LL;$4i?g z-|OQRGTVU>Hoy{zmig{l%+TZ$i@>-xoVp}1txi12NL}W}^UU1MLEkcCQgr<%lfWh( zXCzK9W7wTQV!(w}dRYP>@Rh*58p{3HUtmHf?M@JZNk%@FT?BA*oLg@!06m94>rjA6 zFDD6z#26ZAh%-6Fami)@3KOuXibC7@YI10Vj=}_ZauVGJUjPT$>PD}O(G8Qs10O}+ zw+07P#|V~SSL3C_JnPb@%YZs{A*{n9Li%Kc_c#764FpJ}7V;Y}db-uib9KV{*d#`2 zN(Wv~4wn!%@qUYk9BWF5ay@OnUe^IZi-Y$Vkk~|0fcnnK0gl>P^GEj7sJzXHa-Zd< zb*EMvxU4I*%4|^J2cR^A0&;@xpexC7NZ`~r*Jzj7h#c;P2+csYvS)+v(Q;`2hJ_SV zJB2XLMwk$o82oYVfchfHSIS||NE;=G^}~|}C-#vhh7B|8S)@Fhj?QE;CC_y*)jP5H zQ9MJkgs@HMwNDJ*=izaECkXo*Y>J=-9wLAle7qsDiSqse;hk%cy#FM)H+s+&Cy50- z06EzSf?n@G{tOvnRW0wu_lkg3eFpE+L@72CUUoRKgh|a5Vxcj*uQ6T>VPLz>_!AgQ zf>s&YnwCLG!vacZsi@&QIK);Jt?d(pS7W7HUdR=G+j;5e+)=z9g|Ur^VX^cz2(>XW znvbg7X;q>-Z@yL20u4Ne-UhmG7hU`RDWj~9iHRyQnM8}KB;KT7wqP4qq4sn}$?J>i z|E7volLJ3VM13{Ttm80P3;El8IIZf7qUo9XKcop&wv&26&`+S{w@Bi{5gY2}4e}a> zX2&WNeHj}t(MR5*Q?>WQZGa1i#tH%fVySJrdKHwj3c%2g>tQ@ep!NP9>e$ZVyR+E7vrvk*<6(1@|sU|JULg+Xm zAW^{qY=49}u^Gj-hZ80`Mp_|b$smRU5+$RT#_>YG4(5*%U@A5`q&bQ zlCh?b*9gOc&&Xh3C`baG`u4hF!5*)6HuQxtiJ!={!R0p?{4x~hZ9B2xUtBXD1Ck>d@!t^@4iD z&g16TdKZ@KG+-Q!tbY+RGUYxoq%9L8i@Qnm6$A2lKt{*S;OxIfhWwP4tdUKxPcj>> z+yFnZXAd5M z+-W6y0y$HQT#A5(ym@PKkm^A=M<`Z3U63@y#NXaOV4Op(r@Ys(zXmREf<)J$xa=yz z0!gY=A$B3#{&0{i(973p9JIslcdg$7sdYVcAJ7bn-o=JSwL~4+ETQfsc8eI=5GRR; z(g9rr_CCY{If?RgR9QOFksdvr*qZmidFxLDnHUmLK)JgGTHX2OKSx? z+jl{*z%;PHZ78}1>;E@h#^#S&q4FR!w&;N zn^6RH!hroh5EqFcd|3^rV5)r{QS za16q}28zJF?=cZbZZ)V8`e^R7T4)F+kDuL_b`VMec-?9g=7KIPn8a)eReMu+a1M*i zUtGXmAvh3v<=*shGEjup2GIt=i$|u6s8zNIi{YPh<<9_%tq}dyP%Jimo(wLr${_UE zsW%u9z@R}+0pujU7sylv1=!L*89;P02+P}8xgv0TkAJU0c%iEg6@|CkIOxu76y(xKZY)WJI$h3#R3f=&RGi5`AP|Mhp^gdIDX z(L~VLszW5+X4u=X2NWy>kpz8CdnVmf3~`OUQRLY=LhPh~fH}im`|r z3qGFjF(s8h%`^Ro3Zl)vTHgWOt6_53SkuohtP089|zP=tLj`zM5(TN zWL{BZB4|<*)-Ckz5I^`Z22GO7u`!uEt+EWUBF+bE`s2WZuQF2}wc@qGf=zT>iiDn2 zD^cf|Meyo%q*g~}ShY|}nC&nbR1Gg*99(z=6$=3R!9bj=r$6;_3E}n0%|)8Bfch1p z75W?qi}Peq$tepVDI}Z(Mwb<&v~a8l5Mo{z+`9*pNOW(2Aao$P1)*(Xr4t2DCT60| z;qlTYsf5&xEf7&PzzonCoT~fZQ9{U7N5U#vDkJ$SHBt~y&=R{`)B~jGA&~=R7sov@ zkwUpsjX$z5(mK^9?k7^$$M)S>X~>Qha$p=Sg>P_40S0|gLX!&yV%#KAFo9{veV?ko z8N$<{#grrO8UBAo3ehsg5JEe{L(DWJ#!{jQ%=E>WR?#lFjAvr8;AEWMGCR4)75oF!9$Bk0-Dm;_f;g4YwkV zbt{2}iZLtim2>}>hKcy^-6TB730AHF7H5dkd&fmA*kf|%Q6s7or_r*l&(|CQ&R;{M zRYRe>XJbPrq|ro?o8T|i9e?r7TzHXw2*ex@v%n50KqpAYCN^{0=_=~hInq`Jtr5lI zl23!rAl^TPc#o#1DgXb|LrMaP@n^zx{=}}~5@Z!_0h*wiCVeu(Ws9)TLyQ236(FrX zcj}!uWR<=Cv!yp4U;-ffQXv5$bMfwXCIbb@=14CS$!^Ejd_~}~avR_*2h0s!v02@p z3>-PrLHDId%PRGSJ-zXl8#T9{;Veor& zr!}t(6D=c2hMK#*pC5JoBI}rN;-`66A%FNJM)?+ibrq990iQ&@5)k^HYWV*I(>MW+ z{sF$Y@f!nq`)`}f0!9%J+lVqT+^b2DKvp>+g&?{UN$2C|lZYhtdENWd2ku#>7#U%rL1Ni`--ZRV0aH>byR5KVuaMz&HR#_g;U)g-3q{tPfKp+pykV92Uo` zaT>7wp^ims`s-UP_^2$3;tILZo=u(mExcQ6KSDHJ2-l^c#XhYQGy2#RYGUB?>PvcA zz{FC(#LzdzZ0y4fOkBdLCQ6VP8hN#bcLufgawY2H4%>2j6^hISfSbaGt%;CL;^`Sm>K#yHj-D$z)b+(}Q2OG#4G%)&@gQ%p@v*DKI1Fzy^WP)tsU&pt?uF2T@jHa58bV8ZLDpLjII8u@$W}T@#l>VZLO?~4V}zwZT<=8_exOy6&xEU2U{x# zXDj1B0Al#hfb8@g9F70k_P_NVAJDCh9Zdglrqlgp@c+&bzh8@g-Ms%m`*Q=Z{x5X=w}JoOXViZg z)Yib_BRc-Ur26an{T=Ebga4m%&tLcYzk&X_MS1?y!T&?!e>3dw=K#^4W1G{n{ZXp< z3n}YYgkM$p1Hb%L92OBus$Sd|Gr)LrQ=_S{XaMUC#oêzPz9RS=|E4jt(sy*MRMAvL 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 z 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 literal 0 HcmV?d00001 diff --git a/web-designschema/libs/com.inspur.edp.formserver.viewmodel.jar b/web-designschema/libs/com.inspur.edp.formserver.viewmodel.jar new file mode 100644 index 0000000000000000000000000000000000000000..61fa3cf83c620e209320ef5f5d5cd84e9f764161 GIT binary patch literal 284199 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 z zJrk1^k2*^^%eSPuKbKg#LY%YuwJzjMrfI1q8g%(Mw^biEP%AA?pV?&3-NnAu*Y_ur z+W#^xdkXVfMbtrRVpmIRp>Vj^=TQ zqCU&*W#LjcHZXgIh8f4d6$MKHpKJALIA>2TSFzV<9iug+(K!!~MB+yA(K2%jARA(j z)}&BN+sf{xO-81}R|8wx+x)zlc{Pc}-?X<5BuOO(y|S~{PFmVh;&GykNvPPAsyh~> zrv?fjVd+gl6t_i5VjzR@ChWNQ!DH^J{~hPM z^6p-`5$K~hC>j+IgT}K@-BZ2%k0>kS0zvkiWK*YrC)4*h&F4cFxKb*o5}BQghKq+J zO(I4jRZUr(CC$qR;3$||je#A$6Hc+EI81RmKKUft<)u(4=#K=X5yX*L7jt32Gdk$} zVK`nGUkq<35gT?ehmc6h_lTJ@|7R%ceI+{jUDM5eH}IDI=7O84LshT%$TCiM*a_YY zQoj%67jcQ-uJ7&SxqXbjKvq~i{AHE-r_}x7PGzc4(UGG?e0BbIJY8W%Ago{VGT?SB z$UBiO%U@XUthFtunRC*o^s0tXzG6};mKA%6DMJS1Dv4CNVInhyqz<^A2O88p{wST} z8MJw-yDHfG`;q~4@+};~G3tcP6}-;hDp4$^JhYR;s){c}7MUI^*+S0;ET7CQpEAC) zM_N(b-!CA;>J7Sp8J(XE{Ivi0S?b3w@(N>iVvH>oM>v{~KUh_E)DUiKBb+2VjG-SG zU_-FW1@VFl=th^%)!(ZKt;9GBhEX6FqX61UF{>ccy|fyG1Fentnr#ljZ#9CmisPS5 z7mzH5bxNp?(%YVR&f<;s{Dl0nF)L6#jsGqGx=vDP1@1&pU8p4l7sg9swiZrM=-N&F zHx9}L9HSfBXClcYlgQ)cRG@+p7l5U1!=uvSQBf8v^H)M#jNW{AU zE-=Z6v&47u_d$m65F0POp?|fs^!SA$O-EV%FEqb2Hb0MxF;RhA~pk?k@ zPL#*R>T&xy$QF|dQIy+#9ZTeBtdW94gkh=&fNW~PK5ia5#uw$(P4QM`c~TR~*$B7~ zZQq|%y#3)&Hq~ws$RQ?1%SHq1S-m#z0|MLjFzYUE z`KH&n4)JKEN|+}TS=bpDk=(u=yd?D1IvjGelIi1V_zspAQQyS%&14UAXp6$itExYnZ0Z=yUWAQ!mbPhkE5yc<~WTdT+@Q~CE>j4Gq^ z9vWZT9zs{(0vIm&o_-HI!8Jj&Q!?zXC9+?n^H?}MyK>|-<1Nl+^TEaJd-kouegina zx6O^wWH!vVMIJB+x!Bu+Wf`ycNhGgO3%tBOQ31EV*9<+WgC56SmO2L}?2}j$5I#}t zyMM>^4(Iibj(iTO_(;R{k%QP6Mj@jhN+KlGm3crKJVAAGQz8J`Vj~ZbbexPW>m5_A*a zLx19CD(R+W+0MUpku|}#bM&M$?RH%HrsoHxPgbpLKmr@Krw?2imo$qh06zx4K8xE& zfL$#J787;}h2UI36=lnS2UAEEg$DAG1}`3-uLeCrQbf{;EI^ZB&`EuaWXO)uXV^&y zEGsg)S&68dXrE!Q7nWgz?kHU-)`VlrWPPzXnKfU-N!udkq+uey6mr^Bkj|vD)e{cfOb z1N5!glNB)o7GCbU@@&?H^3uYK%e5w%sx2A!fhw5#f@mS097rPF1!MJFVNf-O}CfbJ7~wfUVa3(iL?rc6-~|7mk708?qB7l$LEcW z`cJ3_m6~t|FEK6`B zmJ&xy3VWM(rLR^dnyUa+^1J5G0fsXYRyC%D!ZG`^_~|okd{~a0ewZY~{CT6@QRwjiEvx$V4B}O6%Qd4R*WX z*&c#xjo7)tz1sD84~OeyzZNDL^A4Ia54?HXRvx@IfFeospaRhvtE9g&#A;6bg(IvJ z4B|&bY4FqMcC9}0H#KH*s+yYGXD~{@>NiPcCW!D!J0gU54~jYqr*BlYlNk%fThW;g38vPmsDgQS^ zpntha|IwbB7z{waR=djdyTA|6b6z502}olDA#V$@k_1Lg;GVAn-x!$M zD2$Bp%i(~!HrY;-OJE%ChU-Rl27n0#z9ioXyx#icu^wmWUQ-j&?+uKa69zaf> zNxyJI;07tQ&2<{Nh1ZHOh71x^t6JX&BrbgtTQS`M>wvb^mMOUnh)-YbYJB%9jyq5O z_HB+-&XMe{{mQZAnadgVP_FUd>?M1EnFJps*f`?H>?=Gu9ik<95=+v4!i(EO90q(Zb9T{|d1@vHH8c`RrZF$mm9HUgoJCSPjbtI2(m>ZTlg|5~4% z$ibUVmG7IRBQdT;hnkE;dBkjT1O4)NdM%ai?#x|VM!LL2)t4@9`#E93zYxg$U#G*3syj)$2)rHv$cMC)eoi?D$GEP(0b+PSXvoEw&Y42$4KS*f1f5kPvS3OYTTb z^;E%UaDiudWd+)E2iMKnSF^7e;g^vm#(Q%Ftd3__!p~E=0LwGj8d&*)ESc2r%^GaQ zq@+&d2dhWwO%iE$cq_F*-1jTXcSm6=(CpM~SCnykuxgO?H{kz7VuWAO@$;7$XXtD5 z@SoZe{DU(63yG>We?suD)9f$(+~2|YzuJi^B^kS~!&)C%)-_^l3r$|kaWw)haoQho ztpSwyMT)}BD3U0!JRDdp4)zzLnMHwogBWq}f@OUEc){p)@Ll-dm5Y8|bk_ZxT5x~= z7+FyQh@JhhOUXKZqd=ADHq|GCw}R8UcTf_$0i9jzMrbxhe!M`>kSKrV%-NEUE;~SE zL{?r4WiSwoOoqgSOnEpajfwL}0pHQv0FBp~4H>d&5Ssr$te`lt1}oG(cfsUN!#PsB zo~(H>MFwO5_sp+g++~GW{kka`>Ib6c$&}Mcz=A>A1f86dz9D=e*`jwXmqMZ?N)hit z2V9<{J?7TWi+&GMYG{*9o+#;q9l16N?PLAYinL36_HDcj7`zT=7x#+Ex;;tU!3X;? zeVZHOQZhfp#wr?SwwF~X788jE3rWGKpkY|J2MZ}$sgQ^XC5207ZpS194kIvTxxX1% zPAQ&IdB*qxZaAs`=B#JMWc3AY`iMl#uk&y}u(Azl(~=pkEP74n5pDT)u^f5GjK)7l!7u-oM?sEK?rbjAO>!l!DZXyWYRX!{T2<-a5C&$73q zs^x~Hg8W;SHk%&DS~_1{7``*Ev9ZuUud#7C#nLK~AF*)PCR-ZT@nZQ7@tkObY?YDB!r0bZ}%2D+VXvs|8+j~cyPfYvBGm#khC7&RAS z`{3Xw7Vo$|mXuOw=>tztChEyE@di;qJjQgRJA_0JQYdL#dJW^dx)=oSeq)J&`Vct~ z&=Q-O7*pVc7eO6-mTR`;-r0!Da>WgsvOH2O*vmszZz)a}j8$qkHl;Z?S8{pHI`5Un zuG%G7=_TuQw~t;JmD*}Rr!Cbd?Yq-7tNiP9UnvmA`tZsQ6qF{Q8rtk;P5B~QsS)42 zK#FezkV#R>TU``D6!uhl?DD`CLpd#Mn2gG%*+qm>JbUDW`u7^*0eW{1{vC`_%C&ol z>J~mT?lgSz$BYi&zdw}b6fP&lTd(Rac&CVG9d%xdSQ2HN@%{cLw^dmN26)unvAoiJ zkHYTP+YcVa{4}Mrdqxl`%7bAaB36l@fowu`#p#KhOEx(`# zYF;mU6(d<^suyN(_!G0*0@Ua!$Tr3YPO?IZqZWO-S6p&>TOX*U*EQjo!hO5IPRBkgZbIrTjzZZR3`e3LJ7>o?RpMh zm9Mc_NU!hUrAw~FKGZe@dxnb3zm&m~jX)Ltk!incG zy}E06__fcOQ((&)etseC7n{0NkkbCz@TJ#1|gVgFZJ&jY$e1id>AOGbfAVNfB% zy&{+pL*nJ`QQDXbJ$HsDd!Kp&Lkh!*upInRqZq}jMAX8ViJ)7yJPl$sqlpTEap}Ha zm<1()ok- z)`3d+oP5psHXy#lfd63?`A06rKMAkOS4zcS3h!){4b=@%hQi-?q+)*t)d^iidtRjsr?k1~W`FM-TuD>SL zH={HnRpFR2IDTIEOy@Ao<9)tAGx^^?iwf~oM;eF@!N4@MmJ9TWQ95F3I!Hm|S&bT1 z!`!RG4-|wXJ`;z?9T;mNZnp%l;Gj%k#z58$y^&UnMfRI~-#Ra=R6%Nh#*0JGT7> z8&0M`mHiHzWC6yq^c>Qq3-rQR1b#$pRd636)JP)`Xi6bysc}kHh1zZdW3`o?RTKm= zPN}`-h#LJ#Bc_s4T}7dP0c;Elr72q#IQ1#HkzjDS5e^n5H4e%uC${uSt3QL}K>#co z1rFTa=?#da9??Wog#`*nI*>9&c+n|YqG)~V5-T(i7Xrt`KFL7)S#kx6ZK5Q|6=+dH zjEpq=R$7dh`;P;NZqwFhzUxU`lCw)0%t+ow=-eMVUa|_d^90V!)(8=&dcS-cj3eLZ z&pA-$0Nx0PeksX(egP$C)NZgV#HxMC`Qb852{AHcWC+4d0xmN~D9cy%0n35%u#bL; z`1kJspH8qKN{Ne|Vq~5xu4U3Dg|l6(%`jxBtahN{t7~nben*-@esw0V2Xd@!L_hT- z*8n-3#+?Viru5&FvOSHM)f1P511I_2EC!zlQIh*hH40cbGI0%&@3;Ny-$vq*SX9(L zYP+|UX;+BZvhw{T_y&=HkW!3X|MQ^DH;eF>#wfSAu*z&fJ^G7j9q zgbZ$44sr55$UnF=3ufk7gb^iS=1NZ_J|Ri??ywr;F*S1_EAOJXQNn#8D+Z(Y!5y6O z17siO^sN22LFb4xydc_QFRlqmUP9@kn5T#s6)k*%kSH1b;%QU302iTNc}f8kDtpg)aiA^2Jxk&)9O;CX=11ge=ErA>5x?*=LxyL+3H zA%U1R=7B#zRPM}9JatR-4kRZGpAHqqYK)op_M}rV4Yl=cgxJEsCSw#xtq!$Y$c8-~ z+;~g4au@#re;aI*JRM4DaXJ`}H>)coRwyde!93s0(jFELzgN@dpNxWiEJXU8u`&T4ST4ygJ=E-!7=Mp z=4cA-0_BnNOWveqiN=L16GMcm<$zJFsEXD*HpE4{{d(Gy9THea2yHxaN zUktPe769On$e{m=TpRnZ+#Gis>nT+Qxea=FU$K2YW1qFeY}8qOa^TBv%*5#8wc#ye z4z%SOhGNY^7(Ko*2aOiu?W*F99*)yHYdbz}yj<*lV@%f=MTUX7(WLI&cm7HUOkdLg zUtaBk#5s@Fo|YaoWJT_8OF0g^XV%P1?d-okvbcdpitwEw)khb5I=XISZ(21+3FY*V zGYiccFmiA-H~ZYVZ}IG^ucM7*;SVH{WDOd7ezN4=a;vz$YRVVT41C(2!w~2yYh%R^ z8Qk+ho^J&Pitlo2U*N!(YY3KgM+}fl_>SbMkF!h=+-ND$gephW)00vqBLuP@gnYN0?kh+zky1p_NXKN+DoJTG(vb`rb5DG4N8FV3fjE`&)S(E`>tiew zz2u2|YvV)VHn5V!wMsq#9}=RXV@)3F)~n?=fFL=cWo=zoq>5k?s0A(H zyYLAfNd>ZmdT9PYVVXH218xnwS3m)2SH4s?huWhXSHGy}Vpvy3_te78wNuF#;nXZEutWoBxC?blP8#Q#dQCEj98IA7e6JKOvRm;;)0?@e1qD?&v?ut zvsCp?I?`vWCym=V0b^#dd;VrI?|aT<5FG_DobJ$P^V09Sna{v-&ANm^F5LpiU}PIH z1yR2|X%1nY4s4WaXsga1k-b~7dJK53jBFG#^+srvJ}@(TzC14f=4AZ`l_|3{HhTGD z&PiW%#`HgILcY#Z{zy*#{|a(a{PI6@bTY91YX$iyz5Z(|uXy=Kpc7AGtSx4XYN3o) z&s+X7|0Zd4s{#VCCiq~W>b@RX$AYV|8|#H_0iFJ5GUacCGbZprVfZtkXY7)FsW7*B zWXJ-1LLjFro~LalC$p3yD^u}Ifh2?C45dNH>S0Co}_N76PY^`d6QmpKMP> zZr>mSwwe1~&-E~UPouhHwMu0%p&n(&kYt-S<+`g?l{uG++pXt>i%o~2A?!W0QV$Z7 zgTjc}TP9uiW%s#V&)UYzjgMJFPuG&)i)C8Fljr&Ql@?N}^Ko>Kx%3KD%W*SY_51UV zUa>CT-BXy_Re)oLX624an)w|1FhAS7O-5L-lFnfse;3MZ0@X9ITSA`@yU4=*( zUC1DY1M*0~XO$ZromWx%cMEA0^>N&dFYs}Hf$u*ZApW1h_myg7Ve0XBs8uOWd<_u4 zpeB|Ln%W%Foa81IfJlM9{{4GsoIC)9B4$8Dzo((xIKG$lnyf#ZKMs}p9Zd2naDeja zJx=jE$bL+sWV|}T>SWtb?HwkjocoWJ)EWTFR_#IN6qqdPU1bD}EZW_u;RcYb1^4aV zhyaz4C})fx%TBzz%_B=OUD?8lmz$<(7QmFUt&*IZ=TIS8NUfO2PY@+n;v|V3&}+Y_ za1^mDoSI3J&7VH1!*Xt_$r@dD?P~^z%3stcNoI^EZ_18Kj&`U;?f1oCb?i=o0^fpNPXy1e+`pWFEC#&{7Vy9IzsFz8tCN z-((XJ+dYiGzAD(<7ocSSyGkbUPe%3SHvV-r`xW5+uQA}C6{|SDPqv>QKIHRTk$(ht z5Ls(0njC*CGXra%x!{2hjZuT~2FZqv4;vh>Kb%Qcf1i1$L)zpam-lDx%}h#a5^EBN!stq$VYgw)@N+-yx`q@u3AU;Ldq2$rIndb1IlNY#S*{*j}|IBXr46;g`Q3uI}qJ2fvi7_KPWa^3-gMzmeZ7 zJN3AcauA$tt6#1<;&}*mDGvfhSqqEpvihhs-eeqA=ZVeQbw;$RTohPw-A>7x3=+kI zV&k`<0Ejgd?6A*lQD!9+tK$?$t5YnY-+t_F*|4##($~D{VllSjt<^4r!S0!jzA$GL z`cn&w>}s|g-N|w4Hp^T`zo2y%d33e*RsRUl*|pgFnk4HnBf#AhkVob0va*u{9~XAk`ee@CG-SwGarU{0jc*P|;5C zi&K}NnX~(s+UdjOz0h=~@8XFor!Rc@GXK>9F-rj-lr+nES8;E)-_FH-XaG`qiE~E< zB5MJ@ui8pPDOaz)(#Z=#HcXQBkbXe&zD4YM9w{UA1d-On1-|2(!!Dks$OM$kgMm)T%J~+ZAj7y<7G6oDKYfP zGq?m#SoLz}Wb|&;cn6y`z|shg5OfH6Kt~vW?y<|6+B=4MN9?OAS2KzsY#dS+XT%rC zBOIL~IW0zw?xO1By`6p1!F|dL?r1~A3{(gdN?%TC2Fa>mvdO1&Gs^B2!AiSdZyFR$ z7l3x|oLZlH*p0+KJBQ8ilO(}>2l)uWeWygQ#WV5f@1N*D`a>5?(Yu+iNALc1&msK( z>(L7uIQ^AmRjjNdhouJ3gLds1tq~X$jwFtS4LOL;rj_sjBm|+4?+_%RsU$^wHek4u z0P|Sgp{re7qmsN6*TUOG$KCjqbt4%)Un=>*^zp5#V){q)d0KP@X#$Izsq58bdb-oc z+YTQeh&@a(`Mx__;L|I@Fn1(%BnV8T0_Tod9rBP1bwhK%VX{cf5N4zcDi*@#tbHQT zJtpt0z0|JrTKN)=*7|n)rN;Jvw}`&`eZU%XbcMw=hR96QMHfgwgUgC#M$RP8$QSe5 zV6;-y|M5Yx(@J1->N)}*)&aODGSS>g5+H9`LY#M)1*wCz-e}$CBEOM*)!e3)ti3{! zxs-6KY2A_?;kIK5PHl%MKTwbL3uq-Sx&5~MU>S4XMsmem^X?w==m)0hS_Ae5dD^e` zABU8`PJH*X|Z$;zS1nL5W z3OVLh5u?$(RTbUZjMaTz^;IocSCl@@*hw6bSLZON0aF!muDhKTxd;$|IEhB%@isk<=o zoUIK7M?|E}$xlZ0rABNXHw|tHc;^|WG~-1enE;udB!i8q_Q=NGHC-)j>*FODQyY}j z)Q^fyORHt)MGZe44#p2pE8vf*NpIbFcVV`m_&pgV+r<5h z9A>HE1@V*uf8)KSq5PH@%xlQ)MzRp^7G36k3Fku>{{)Z6z48j2ee%6IC;k#I2Fb$@ zfY498%SRDOlH8?cE8YMx zm89xoON22@9LuiOx$&v-=?=cs8Gd=t?@(xs(oxPMEwoWgLaP(2L5XN*$I5YoFfoL? zObnvdUPuJjWb$^=UbY(&+kL9dyG*HOeYXs+?-Re34{pqXB`mFCIvL1;CNQhtL39R| z`0C^kRydtU7s}j64+iRP=-9iE_H`q67JJX<2`Daq$f zVBKd_#YR(_WAGJDS%o*IWXlj=cE)GpDAx{e&>K#lNG%%BD2ZmX=MpuUahsSTiY||% z+(Gz|rn1`{Go|F@uH1)v2=Qg+2RjQ&t%an^NXI#dqkG|KQqO8cn%%V8qTQ`Q(CFlC z5iPCKFqE)J>D?)s#@S->u!S~i$CN7D|E$oqmn*?;FO?0lDaJQ(G*z8hxAo3=aB9xU z=Ez`k^4w;1mJ+DMIta8WLIPv9ieW9&%Vjogz$8$#P&lM73rr zpIXRqOn6uBtDlN;5J<$2Hj&GO40$(`JuO9IY8N4Hj-Nx)oEEv(fx}k+x+iF=Ig>kEvd~VPoIXE~q`3{hZWMCKF#zc=FER`-c=^Lt zYP?aXq(-lcvtE}F1Yo7e{m}4(H&(^W&jrQuB@4TTQnd1hfWV3z z4&$Cdw0#lDwdPKp$}Koe#ng7@47N6bC1B%_`0NhWNTpV@&B{+?N5id3)H}PBz{08= zto4!7iQast;!Um+<*=iRt+y$$e!>fgX-$X$Ij>FKs;BUFS3E1P-;a@#s8GtYoHk8H~h`!0C1J zZU#^e-8stAJMva@A!p$p^6c2X$9Cn2C;GMz^FR&mrIYNZ;s;FkcY@|mZONH%0jh|a zMA?jBZ^@pCIAqKFmrYtwW$3+Wa$SX6N?j!fre-Si=baj%AplSnYawlsT<8x*>D{yl zU|R(TD%Y}Aip~vtF1@{oEY(}z3q^y#O1s_6Wc>>8inKcAD1GJ#yK;7a1r#t7^brD- zr~M!WZ>^yud&o332W$xxs5CYB+zj?ck6eeoCa0a_y19U=mPhpuM+zVRqrwFtPZ3cMF&}ukSDdHl7E=i`Z6@ib^kAt&Cz_CO+x+)#Jf31!}}bW~Pi>O!sT)Zk~>&EXbWR8asV> ziEA1Sl)BYm<^#vEsC0~`Hy46drbHcs6l!m0R! z*tTpgtX!yH2*?4^*qVY5I{*scKYQo*1PX`(0V=--IxU@^x&}DZ$B*;mi`xJS*hGRZ z+J-Yma{=A{2EHK!5Eq9xx)s0=dms+~$B#UV7L%bY$VN?SoB*{N&7jS^wF0piZUoJrwliDf~*DSr6ZFEXeB zHwLk09DzUp%)0+%TqqKLK@B}b-M~gNmH(683 zL~17x%?g@S9YF}+5@Ss&nZU1j!OC)YC8O3V0_tpsqYx+>i0O9wi zH$(joUVrD=57Bpi-Gb=}DuDPEAqc8Fk-gQ!m3Xszh8fdNIf{ZKL`xwk9|t!S-4m*U zWZ`qF{+Oo^Y#WguTI5@Eq`I8)!Z_841F`NOc6TW65Si~c>=#YN@BtsOAra4Scj0+KC1=Kyamg6~%4ohkROrxxlxS>uUqdvQl&`BUHa zqX9WuRr}CmhEv0{_{X4}pv`vSyV#?!LyW~VOQ%b8!KRmvVo!Ba_jIb}A;WR>^OdcK z+#$__bO`a_*jTMFGY7@Bg4i95wGJh1sgOcpP6(@mE@izfn(u-x>M%$RK{B5;+Y41A zNuD6yKArURz`M`j+UMNo-_%@xv=A>K>zn0YQykT=<@kS^81~m#(Dln3=O3!@|Cw|C zH?7TIvO>j)FaHT-9$C_KQki@i0_Mg}RPk>rw;{Ipl4#;v%y7WYkFxZA=D4FwiN94R zN)*vPzBGjnJQ#|&0{H#Z)jrpoPBF1QbhMwpfog-72&t8!)Ca||a;>Qu4zb476cP!v zHtf-VZ0(9OPBtgean-FPzREvnS0rf(=(WbojvrdgMaU|T&f5F}ilyS?j$}y{Gka&B z)g}KWZ^^5CS1Oi8i}oQ7^7~Uz?t21PQj<(GU7`A0jJ;9YfIQ}?xt#f)%XcwOr>5xT za&*WmNWWe47s*^0~SA*~XC^b?XG%_k}y?=3fR*cSqG`WZda(U`#O!+}8O^b&cQV>7c zK8(k6SjRn3Mkdi|_yh14lJbM@Lq)(JQNAVo4PKFM;p!OIN)euvw%J5ZYQ7&Koh&K2 z1Mfz6nQ-H3h;6||p96n0-TFf^A)@40@$GBh=k|3i@SmD){hyJcYG+~mzoSD*$8Lch znTParWIZam4h9sNl~;*40}UQAiaM?T7?W-pf(+QSK^sthQFJV&?F$F55u7eA1%&CzL|v{%n=Ds&Vm4aQ87is;&#ktKkZ750 z)9@fIn?J#*HO7oRp2jJT6uq)-gCoVUwJ;5o-Y-1}PNhC_k|=SBooAQNMU39_Wo?b6cU-noQa1d(J!mWIm3Y8N;U1spDw@s7uzh_(nqFI@z;?QFLu#p} zTGg&veuvEH0C7rt>pi5u^L>HB!->!jhfQ^?hh42ZXKZWo=4RS7f`eMFN zNA!g{zW;6pqAK$zm-(`1bg_2+Ym}_~XIfzi8fx>9<5NhPdR=2M${bh_B6xf$YBWiw zTq*)uOGoBqv+nQk9{)iyX=Eh4sP5OoMZ0F0)czpz`Y$iWwd<^xX|{&9`;`?tfUARm z@Nbi_z5EJZBtRxe6q6WfZ2IX@J1n*OyEy?O0ow4KHW=koEdlFsFeLPfYsoeiZSxy- zmI^2CTvC8OvDh==DIf{KYcv6i89g%Q)%)(2g-d0X_DaiJ>}xH>9V9|xH64A*5Azm~ z)GF3J1{}If=D{iJus_gzSIsMGs{|`A%T{2PooOt@Vy-o`mX=mMsxxTV2!keLB4Wg2 zP)uhE(k*boqS0iHnBSbW+G)DwHma}Zcung*^GVf>j#pK!+Al)zmNW%+L*v(d?}k+a zWC>Qol!@~A$%1_~cT}3IlON7I0E3#u*J~;m!%z?mgNChv0( zCW}xxH$H>x6J-O3a6Aq52}IdXy8@sOp>~;1g=xA(mDsSNnoX;ydct86Y^{F_IEx7d)*!&za${( z9@tf)xgOC(pY4e??mR$N;}4(X_`uuC^q@3VCd&uA8Cv-oLST z(k{Z4<*(1~G9&OOca*Tc1g*4d#tX(4 z0jM-pjm;4-5~t0NY!(RMGMItI+Po)uN9;>jg!iFw8XhJxK3l^(V!_=`k2_xO}me6TYRG#as%v` zm+i~Z9-mn&K3~?3Nr`F9taDsY9g9D&P`F3Us_!ixR&Lo+?6yu#xlCxgSj~NYVYHgh-bnUy}0nc(jh6H}_*uZ+a=)fr^pXHxY^IxhY~5i3pqAc1y^*W{=z2$2#oc`+$SNt}&S;O(9>N`mDT+)t!Ra=o zF0v$#F(>h4vsCJt;<9y2ED;^9rWQJDXU7RzkDIa&i8m!V2|raz37WvWs90voJXg>S zOdIK8oboJ{V}#8vlSD?z=#*@(yY<4IB^tNcG1Fk%160ngseuLe1>hgnk1y3%8rb`0 zc}T{Ixta92i)ZD0?JVD8D`~Cmn?45!%3EFkhY1_7KYudJL z+qP}nwryh?U)#1h?e01KpS4b$9V_<5jvbj-85LD^QI+}TlMgBk#-W1(TSd0=Ev;#Z zhD48eEaNEf3AF+n)j)iIagX~c`38!>7X&-JAdU&fB-G4v3mvj0IFf3lAuvY>n1m04 z#ap4pO_nFrAG`p%)U1^yu<9!#!fq8}D<+5awm;QdnT$tzlGoh*svTC{&)3Y-k^Qo% z*T{IDvR$q(7c|~EoVvQc%iA<9bN&KxP}OT&9D^-@;7~Z=m^TDCYm6W|eZDE})u$QN z>QYRMJ1*DZGq=vyHDaR}Kb_SvH)0H~hyzsmy*~YTMMR#fbazzze2J$aoBA>dka7(* zZC?O+J4!nSxsa(RPkpkJs(|@=vOLl;Xt&)TbcAZYVth{G`BY^YLqdsi^&X8MS$`E; z26@SlUAcJN@w?{{CZ`hJ!T`A38cdGx3GK;<>`%GT8NV}IM=Yxw}0`2@AeVD z@9wc5p%3B?m=C59oI)6~s2}x*V+sqxtOrFDz(OR#NNFr#laESc9_m8>KU9 z7`8fcBY~!>hXlO~d0>S`$^>;Fisl$#`VYaRIqOFY6cKcnr$6&G=#4O8ufvF~hhjrx`+P9??4(ci74vx!9zprC#B9%R_qAV>_F&t-0O3t0NVk-Rj zU=gYrc5EViXjKwnv%*$D`%qr6AokJ+ap*u+)M~dTw&~-oT$q;FVzV z3vyUWigG4jo{1!b2)4|Rw>C3oBCQlQ4=?+mGpI5#i5mqJQfPnc*JE@ z8fzNx)v}V;hy>Iv`{NC@oO-sF4{aISQ6ejDih~~-?OYP)P<#}yG@R{`Wkv%Vg>7(W+{lzpXX-#O&J58bP7$BFC63OT(VB<37L{RllIzkrBUMM;;a? zU3=9)}8 z4>k{Y7ez_oYu~?*I&tJFnl@(Fy{03q;ws_|+L|E7$d)+x-WnLOM|hZbRPXTllpJuk zp}PQdhVnZNi5ZP$u51U-aApPUas;&AX|?=$`IE09x@<<8i_XCJb&h3%4sB9)|3d_BJfm50mcMYB$f8Wn9y=HwpKZA-52-=)!-7shxgNu`R19I0!Z^`Fb zd;a7rd~gDL!~@x~ldb)^S{I6K1zM`L zu_nF!QPG~56*{{8TREEfYF{o9aJ!DK1R^iBc6&hW6%r70>i#8+n=K;z;P5rs3E26I z7ld(JOsW)6U-?VFVtZHT^dC?l59G?*X=k$F`Pt{t?Tly5=0tb_bp*Q+kHlrT18Vqu zBnkZvqvl$?mEVifhOAdM?~yM41EHP>OeyUH-z!0}j2O)zg9F)Klo9#iuYZJ&ZG;l~ zef!Sl5Z_K9BNRi<9#QZgpt&>rL<%nHDKsvcZ(1@#GYCl21y?uB7x5@o2!C^kUCW`q zV=kp+)#T&uu3cUdAT|;78;25a!_8mR>9$<)O89qw$ z@h~;Icsl)kZr*?nq7W^xPVzc=X?!)K^uZxS97}qkZ}Qi8HZ;yFUiDo70$h7bv*Q>j za@bcTmL8}Ng?U^uh*9F2b;=M~4L93xz9aXK9rX-Q^|&Fl%1)Q@lb|Rqp|^qMrcCpM90iW6xmR9TBjTjEVNu2q*En8q8zn%BJw+rOqO8 zlZNA+Meh*rw>2?_@R7qkUA_}fZDcz)W%0glnZa7Jo0JZ@fmD%KvMTOAKh;TKRk+Zq zEiI%|Z_S0|_rhvJ><)yXf>lS@j0l0fO_1^d7D;W5=dY*vv7b<5tUyou~;#m4#ulg0rTm3!|lLQo$xEa0ceYLH9 ze_HP6=bStLFU)~h!VL%N2(6sDamF2$VJtjz*BDTyC?>qqrTq?U@{9fPlBBYwbx*S1 zQj)S04@4jt8cQ)a440nT!y1l?k5FXS#6o8l~Apo9Pfbmi*Qrppb5~eIp^F-dS#ikT<{`3!#P1$Kxz+9&OR#jbue^FP; zZ4#Ji$*iOO)Rh?RSDs9il1xbsY%(8y6@5nciT53rQ_*5KS(9Qxp9#hIyCD@7Mzw*! z!qmKYYBij2=~n8rj7o6@H9oAGm~FVbDHBek6SLWA3WlvuxA0hS^Q;p)(YUQ@6dun= zhdM7aAWj;5XAqalY>#<|%>gVJ_)8v6cy9!srR=aO@a3*=V4_)he85ly&L_YcoNvSx z1j0e#IuuqTqaL))`$K`rYcL=(B#^Wu=^Zr8ok%7#eMxPf{PBcr#%)@2vMsYo9lCaD zQ_s!TX*N~!kE_ICVAR8xyREZPse7PRrx6<8k^;af#*jw0m^fO)62_ ztHNR`nsNB0u2AQlGOJK7Z&5F=vNc4NalB2rIU|4TqkAx#KN&Vv{92kI-9f0BRZY8B zTa-R(%$`PS&{+fApNqWw#106pyqAzQ zwR~^FHTO+(EUR+D0u0L;Dr@2D_uMr573S}Rw=M&O5$RNlzVnfcdi%10!YOdC_=EL_ ztvCJWRSK>u4%Uso8fo59KKnlAf4gv3_!pxmp8X^;Rdn~yBs+sL3nn-M=Lpi!r-2n# zTl7cci$FiKErG(u)tm=y?|NvTXO*-P)`Isx)25A=wWDTR%n2{S92w>;akI@W=E>2; zht;QaydSC89vO$61JxDcug(W}ZparAAdfc&a2OoY+TE9{VIMmD?k9PwCZOXSg0$+{ z){QwfLHa}LMQLkr9?-v!#0vh%1b=>Z{7)aUs)M~cO=;kThYgf-yifcZZOF?GFBSoS zx*60^Px~R`jXwju1CGGms+yPkB+m2Y*`lN8`ykyi5@C0Ss}6{e$6S=R{L7Lvcsf0W z!5QC;Uk5bS9t&SVkVb8jhLQ8nPh4?My|;_=;3NuUf5n(U)V24Sc3$baHFGKqbw7KQ3vig7R(b1 zZZW+u%cNeUuzAk0J8bc0rUxgP{IZM#mDdsj``bLG6-lu~{YU*EB$<~a2f_EXNhY96ynlg{*~LMN)*SQ)*v zP{K>q&!Fj<)DnSB5h=n|;Bz2t?giaK-mb2zlAHyKT5A;pFy}7yq&_SSQb|j)xzaxi zwVYn{uC_~0vf|(i@{0^GIrf1j`R1D~(5TwT{-9qgq{Wj#ww-DYN`y=6sThzis<*~p z4aZY5qnRZl&I@HUIAOg(mZ!42Mtc1n^f(!zG)wZSi#gCE)-=B@9D91_oGq<`?gyIw ze9&jJkV_(TfNjz&j+K})UZbh%s2EyhhzJhrxmZyOS!E271={Kut(AFCPI#xUa;);x}p#`p9{lIxt@_u*nFn%piaQz7QAp;ZJ8{zV@_PKr57!i z$`&>HSl|7C=#IM-FU6o zR%kBM!Dd_3Jg2pl;*PVwD_g%OdT-yJhHJ*QotB(h)YzVy%>7T_{m3vPvF{5X)wjV{N4UU^@A;z;@F5sjZ=Yy?+nJx57X?e->!LqgX1* zff&0~&8}9>PIq@dLd?!l6=C;tk8`!6*eZ%@)lKwQ4=bci995Bg@}E%_5ggSywQ4uo zyZbF-H}0tuiDQ`b3(bDby5i6nc`@-HVt7rxvVX<%PxwOd-?wl27uBFp7*VlC z$)3DT>=p&z6vjy|m%vM0%<-h}$f5`&?uvb2}8jD%Zft zg*eL*I@LsjNbEx}Q4{hreF~&>b*Xr-4!4XAV2nfTlQho(ZwsbHp8sF#$p1`%2iu$0 zQ!KxJA!q)d3zq*kQ{aCA!ppu;2B@P84zBX@++C`{K``?AKpp=H~Jeu7{p} z__6V_@$xRK{-sMQs-JT{d}asXpTK{#=l9LHZy|fM$@UG&yOS7_f$us{`pM+g z#FEG_$0iSG)>U~VMUz*&XI8lUleF`$yI_#i!$aqJ2{f z`p>^wkG!U;^vI3ksPstA?JT@*jwBp?<5B5uX_cJ#)V5`SEW{ouS0~Uj&4HvUI)WRP_U1)8RQY^(Bq} zq6ubKc;rTLKo0AI_DYVfE`8$^J?u)_Q2bj76n@5A=9Rtfqd0@0{uUmMSNRkfom2S~ z8vS{G*}X66^)AYr-%vo1^#R0PBrtp^)o(ZfNg1^y)No-*HJ2c63#oAv4e7azq%?3H z$zpR|)>0a!Vwd6~9yBbKr-B1YYA<5lsd@Mg{c}-Kd)ag0ucy+Yd=NXOcVoeYPRYrV zGL>-xK#DPLgCLf`s6cp9sfkfw7WgS;FLJ72q!jzMe;pOq(x;SATC}a@0KMwNS?!?8 z5y}Qph+Bm)RvB!$8!~rV6p~8JQi`GkrWHy}sh_y@6edIqB^Z2K2`c%p8uItol!g#9 zJyxFj7)lZpq-3-LIXQK*1tGxzk!n=L;iL*G&mNdng925dQIv3Im5j8C6iVtjq>?xb zYbmW_rX=T>qN3a=Z8)O9 zh=N>^8ig@UBgz$CAgj_NIC}Z>IT^dt_j=+Bo+|$Y74-+`^(Wx# zh_quALs6x3rW{U&Xr)L;rj}Q}24(4pxu&DIfC;KAIihVRg{#()pJ7*R3M_o&+0~bB z#)j*-YiBSd$se zRoN09-B#HW9_>}x5+D5%0kx8X>gQKnFQU?hN^xmN43TP&wQCTqd>~x*kz@ER;_4TK zPad%(v@QoA0lju;kP>>SDElo|Akv;pDDuLY=!Fq^2nC^CkpPXw;3L;AuXK-!4WY## zB+rv#J`tBs#Is{n0ccj?*e(1mzLw|yQx(8SPDM}I$$CaM^u^R^d5#wLNR@qKKxj*P z^(M7*Yv5VY3-Lg0hys$AzS%-hRRXz>;evKZ!91h0wnSxjipcF37u}Om-BbImrgm|! zXj^=G-gtOFAbOwlnjYkf`sLoz%X;dm2sqckKBZ*e0E6^HH>vRehm`nKUPvl$sP~Wp zdA4H~h;F5~9J@Zk-uI+D-(!WolU*{ZUCMuD5WC2v_WkAL{0hncI8z8JC*`N+mX0uj z{7Mfvyt?8q{3tB=1tAcT&x-kxVUZx^+M|RaMF>?A1rS(+kSisMh6F{K(YVp@D$Xh* zQ$!Lk4E+28es8@*7AY4=NTZ%-oz+Cr!#*v%d#N8DX_c>DJ}^sUv)bR(h$>4@VW`gP zuzJf)rYsybHraGGuV?CC*63&H?_0a9GSIV3EeSu6Fw# zVo_=aQ)5L;=3!$5r!c$sR`*oaO)Yb-YN}omKjm4O+m<%Z%f6VE-qAUe@ET85@w&d< zc-adp8~0V05&1`!H_l#K*|@QtaCGaIFA>dd_}D0)R?g*LRgQb@{?6}Skw#U+d2!}V zU2`IDHF5A$;~b-2P5PvM!B+2`yVlO-U*1$$Iub?h-9gq=#+>vqnJI8fjO?J3O5oEA z^?{E}#RbVD4+saz^q4tyb1si76q#E1Ny%BYM z$C4Flm9w|(0ZSz904DjkSMZd8(ojzqLo|DXI6*LM^*Fm{T34H;+KNl6U_$k>Qs0VM z2L)t!>@u_wSs;(7lY5OnxRB{3as#kuGg1g&aHg>DtX7|KZj&%8f})F6l4Y!Q^wd=? zeVOiose|$1F!r0?k@^?3=ws&vHh_v56C)a-rAzDv2Ub4!>=6{SnIjG;Hab{CqK<_! zHHd|(_KuZJt^1_T&SBIHHcg0BZ57Pp#^zki(owRu8s5+;9lm~99Q6f>zjw{OdHLn8 zBjVQTqRKK+FxL0-?z#~V^mFhqx@&gpRej3f!mtSL!soUCGT3*~#JK4S2P<7|!^%hxapU34 zIy@8}snc$WzsCNS2s93XWu}D-2Fmd|I#&QyKe8pE-m#aknSmEfL9&{Ai zTw(`dZ)|%6RYuR9k1@9FTw03+;Me}sm*kzcFo{^vF<*q3VI_7Ep20846janM0S9(m zr%Gh3-|20dL^J7NWSwgvAAUL!5J9n_8UB~BX(o?I5WLV<(P#>!DA7m;l9g0UHE!{V zBzsY zsc^z71Xq&86)VwI6kB}?4)IS~y{vTmBMN>5rs<+VkAih+g!3dB8#}vf)jopi662E9 zJ-@EeYtx#j(evR?NZnX`t1U1L5!1`=sJccwfXCV0T>4&Q|t#SX4V{jtz_!E*w zpes{mb47TbOaIm1Y+01r(skS9!^zU1ablVt~803(OguD6jB@A-xd-IRW zb!#eV{&kwMYF z<%#+jIUCkt+3b+}+Tk7|jp8^l!F5n{3b7ehvt;W#JnD5KYA%NC=x~qQG_kuajXh{y zm(G#F)WI(ESmz%aqa`;A4*Hff<9cCPi* z;j5i03OIVI>q^~wtt~E9gsJvdf3rI^Mntx36qX2SprW@Uc8HecRf)h!jrzKUIb%`p z7D=3DAWjo({`df%04kOR9&obg08)$*{FEatEjW~ML1tIXJrLeQ=CzH>N~cfV*j@n3 zT`NP+Z%A85B=YiWaN@AR8V#@dV&()*@vKY&7$Bl)z>Yx@O#xNqu&lZbZHCdVT>U|h7hREjffK6fYB(F9FsUR2LTxviZ0J=A7ZC0 z4F>#;`L2Ai=@&+c8Z|KG6$_$lj*7x~9gtc=0HvTbq@yxNZMh^(A}h9eT@2SEzNAKt zG!@r5G*7D@DyV}ZmHCMDXyv!kt_~5M zs>nYsj-4GsDC!pn)Q+w6bx1f4esJ67(rBw?q=UkhM#c2(k(Y>re=9$YbhilYMsf&E zij_}&J@j)=?{snz_Jv({va7k}Pr7EogbwCNqp~eHFGgC4PE06!=_|HOxyX>XLe*whTns1H9E!+)@b*eFc#iu6ncP=RWND#nIbKW@O?Z(|}Rw z9uW)%<$Gub!vvuiJ>Tyg91h>DF6X%o@yYvssaw4A$4(!7uBCp912)|r`W?UFtrjw;;e9lxvjV^_~H{>t#~ZSAhOPxa%uo=PTpl zSz%i*h>z$@If#$s%sHr!@Ju?WkNC{`K9>HQu5WqNUFC&$`AgvSJNWfgDb9-Hc%o+O z{6PGnn;$8cKblteQ%E8CHFfLGo|``~zarZAz+LwW1HuIjKvWGosmPU7OueRo23iS9 zR*^L;e-iD&rYO6h8lF{C9E@FE{Zrpdh(h;fODRwUEkH_9R5Wjhs&`jyyR>#^6;|^u z6*HPNd!L&XZIyTtVvPvMURPF&qlD>&6mrbZho7BEi}JVj*O^tl8U%1Fs5dVOc4gI` zB!t!ON=D4>8l8g#Pd3^aYF&!4i`c*1<6uWsVNV?RUISKoVITX*V0(=*23Fv0~yl!~mXj^^40)RzQv_71hR~wRLgI z7ZOtisCDGrhyP6IVZW z{qpL?WvnhOu|t;Rv2xtl$o$zkz_R9rjV!O6`Y9yp$uvn;`=wPVxBBVn{iCaEo>pb$ zV+u&i!HHATW1)qt8j z@tH~1I>jgrcyQZtF5k1d2W8$ z8HzhT>akKoeiTeaM`Bd;Vjb2C!njX~^{{kS>#)O`@JuwHqkgBg3J7jXbx}M|jOJ`u zAon5(qP`Ux7u=mKPH{W|u~wcZIQwG4ei<_+@=;a`O#&v&tdtL%PM#$AiITzuQ-%jN zAH(S>MDQF*`^9We;{tlR0hZikv?Uey*gO4>>R6#Z+aAk>bUu;1@e03vQ##?`pJteqQkkEWdiT^ z{REr%bo9@!Q@VYfdFK+jf~&0RwjkFiE)L#*vaPJm+0vHS62_yd%s55FiLfF{caEc< z_Z@&mz5h}^_E^-5t7KkgP-YkRgbU%|AB0^Nb^cP)SH6Vq5fLiw%n)?HY&JabYHRii zb*}uA@D|{vD4CD%U5v7VcX`TgS?qX()oeZwz-(j^7bu3*nrGQ`8aJGxp)N;_pPUaI*ZSo zt*A`Jut8b>kbMj8hXBM5w<+hiIwd=2P|6`i7Fo5#Gk#o?sVX15K8WKbuV$6wAJ42v zFe~W*hLjwdD(32J#rE#4z7#<-W;`6#Tt+^f1o9o}<|E^l4rtLb%2&H)xtS*M#6*Jd zdEY;1rtuav8>O<-XRGx#JHW{VUy&Kf!Wzl4G@M~=Fw4?lK|nUSLveUt_#Ml3OH$_+?zi5%hqL4{aS&T7OUm7m0z zxl*Vl=1L7x#1&`(S3cIBiDx>iGCwte>LpGPNJXw7ap;Q0o?h;ZiA$imq;@IHXCoYx zt1u(nS4dYz(8>6;Lo?Hq%+Vx@p>1IM58g#=lf}Bb-#kTcSG1oRY0d}lIC~~;F#a3% zFE+|0s@e~bFkN3LHuAR!iA^+FM>Bg+xEqXOF04zf$Xu)k>nJNct}g$O8Qy)N5VB>S z>_&C$wi5SB6L(N1WWrJ`Rnzb6CB1@Q)KS#Hjg}Mi5CI{WDSAC6D+y-Pc1nq+kBwpw z)!t*~X-zEv-gRLEFqgooVQC>0i-k8T+q&pDY03QxWaizpLrD-lpQWDJJSEY(7|cwg zWxKRcrn*!@6xTO_CtFnu$Fz8(33Dws{VhujhEKFxixnuILM_~&mU{A>C5Z=jag~sN zl!-k~YEKs&!r5>)Q|X9!X344X@oEjAkx(CSdBmenT;bF@1Vfv6AfyEj;&c`W@*~W9L*ra@s*27 ze*6_CG~B(;C>M4A>d7hO$(@fITLq`PcakD7P`*O`l}Kc|><)Sx=R zni)DhA~UEPcCi?89+b#0qEd#5)po7DifS(sJ7PwwkUoX*pxm?1)|E+DZ{xIB?|rtD zu!;I;d57p7#nD5qsdP|tKLJa%Zr#t)R7Dkw|3)_0gRM_k4PBdLZSWK-7Hh3)K*W!3 z3+1`4qYo#{$(}|8GfE-fD=kLaDi%aHNIymh+6HE_MC+eDh|{YFgHHzaavFFK?JAgi zbt$DGTsw6r-&*X?&3f2?w2|zdBzb?~WuDuem9zw%{?;qSv&tJ2K!F_Csf7XOeDt6t z6A^jVDQ+-IG^M7^@u6jJde@!=Tg+s{m09a??M^i)3hM07J&L0zEGYImuB%A?#o1pZ zg-}e`z=@eGo3+CpP*%x)*J;_sf&EOygmosE03oYNAKft$)=Y0JlGruexIm1 zfPsw~auDs}d@Uy4RQ#G-Rnt37X}t5yEuSJQqeX}yh|9I*xJQ;W46@{*vSZ-W)XZm~ z1U^WFhG&B=t|nz{-7nv`4Uyh{PS3ha9lI`NdAKfOBW|jtWP*@r-RS5>=r2tZ6REkp zEH_MOh7TnMd^YWSbH*z=>k&SW#I(HL#)!>%coKUdaL8pX&fjquyD`|Z<{w9j?PpX- zc;c|}%tX~G@t)AK7GWj>FkH&wce`rcc45rZ$Tq<1DST1NYvHl|L(`+E%G>Ac4-_fp zhE#d!_)G}mL<0t!hZbkO-I9cRZ|G}~Wo4tZjLwr=?I!IiSvK3}$-YWXDpFiW`=SM1i zD)?POKEus#T%F^4XM$Ea+fwmgoxD8BvfRDQ)oC)IXnNf?YUobIPy&Vo;cGm+B3FFB zHii7kR8MPXN1r+(Zs_-csX;cPu^(ELBt9H1T|QfU-&M--5D8+9rE5L-)jlwW)V&5Al zxQw$m_P$B&=zggy=la_*<;-K6?22*A@dIBv9XTe|A671EW_MgHDq45>hMOBWRpH7q ziNC8ZZRH~jVK{1l*(InkwzM++@&fH*nY%wkzv?mibrkj;?4@h#?@S(A-6!*#Hn*IsU!oj`~w{#;ZUI5@-l%bX187{v5gr@VdH`~#qW7Wtv*h`lacEIr)M zUEyePa&}__x_wTyqH>j)vrPAs@yzwijWLB6Jo8sUK(L?6FCvJqn}8lZvU<&dGY*^v zAN1RY!2SMTR?ou&ZNvlX&Kl$sQ%qN$w64WK-hsUltE4|*h)LgXG*Gt?*LAK=%O128 zIzvcu2~gh{u`APO=ztJCQK^iO?;yl<34NACy?6p6gAe@11WsjyKOs>cm)478 z^D_50^-u1RY4^yqyJy}$Fio0_4)#MEKH9UiA-Ut`|Ij=OM0Gd5qjg~pxCZ17k|Sz^ zv}3`Vo!Eur!?FvZ1B)|x0DGmK9@~T$a{)>**e+!motobUv`gfpOv(vJjWprJ1>v4T z$P^%@3n9}4xoE{t)Ci4R)2dL7#%~+_rAjmBzC#fuBGyc=d^rNV~+xZVR3t zN0x)YKj`&}N8hkM=O=yoEM04a?6thq`K9!M3YGW_HNqL-JN;aM;;H`*{*9x<4_oWU z@G-J9lC78y^$5UYgu_=7of|dxc-m_Q> zptTPgbm)zJD!fuwE)LT=VP0ZRFT7$&{uyw72208V)x45^PG$Y7U*{;x+77XW+~i5i zk|iU{6f;(k0=NX3A*zT0WP+xkvP1zkL2)D&@PcTdGh`O{z^Nu7D6j(vKjP~BpUNlN zN_8uU`a1kD_Jf{t3nnih)Q@uzfnrv_ylDnvhrE>65+WxiNXNut+K8X?M^q*mTbYKf zEPSSOB=glELOr{1g^PUKRPaq3Qm3&K^zKaazPJfs*p6eFz+;5H32Ah|kO}lQVBdnF z??7O?@I(FQ>%e9s+StB_vw3$O?D2y5J4Tl`@)!mX#oY$76DEFKAS2A*4*Rgyzuvx( z-D?at$D?#5BLp<#HNH^eKE2^cjV*@;Ah&+G)5~m)9piU^UgxqNI8i zp>HOk9V81q1APm4#$>46AP}!^C|WW2`IE86?>FVHA!je}?>Oh@WKMD3&=7tQl6@|h zpt)g_loePHB)lU#P9QxYZC|k3dj=)D^$7){S^0m0SV(V|>+xkhEsG>lVYNrbXj&!z6%8*nwoOyunlMo%ohxBPyB#G&@)4?L5K=r0^)pc z1%&4VlRL0kCw-#)-6B3;`*R2-3(HaD=x(wFmCg`9K|Zt*j@Yj$KjFGDA@XJZZnm=GtAph+3{RT(oU(nKBPN(ie2LgPDBgY_J8 zh1ui;p>WZC$Fhf}0teH*(XP#RV>SQji+Ite@tAL$ZBpm$v#|c)At5%?XhlW(mti!p zpaAnke^3A8*geLAY6V>N&PGVx9gI&m^!Vz#_P*|MBy4nS%7TpHJ zViMB;_F~j~C|;RqiKk&Pew!jOkKQ^$Dw0W9VKu~`*V5XXm~q&vun7v8f#6GEjFl90 z5^Kt7YIJkg6MJy$$SZc9YFW41fV0TJnl!2B0GCyHmTL9S>wg9O3-+-b9Nz2|h@f7Cfj=Piy1}7y%!)q$RL35Z;4lN4+r`-WPPE zEg0`!V7-p0okJ7!zR+k~Jc$iI_1OwSmtbk~2|WCuWzm zk_90xUZg+31N0>AgKG@%5FZKD@OnVYk5(EWea`ZohJ_~ZIo&JOV{B==Zb&rqDFLlVv=Eq7bJj$NZ zi$U#e|EJ83vDS}u{W-U!&0W&?Hc;5Ly?2)J&AWnI!MmQ|1_qw^P2IqmFjaLxfE@v% ze!(oQn64SuHuLxlvKbfe0vvqfsu|(dI$`?#fW#@e4$pzV>J-FOVh&xqMGrq>r9JJG z7l`g?AwM*+q-8TNbkMWAz?8(oGi;`H&tKy<90F#k=lTvYIOr!rdE)ic0t(^Crtvk| zFNZEnOYM#ghWp;HLW&yR0{J#x0eB3#*pr+e zoNO6k>=DSPASG7%-BF;GTT&_nOf@9W5#1xKiAgC)uizV=inXl-Pnb2Y^j@$6PqSa3 zUZ1W#4G#W&or&e-DRW((0CjaZrK_cA+R34BM^7#|YKvbe*h`*~j$Nz;%4H=6Yo7{` zUE5@4JYqbfdR`UFmZGHl)6EG~6Qd_EHEZ&Kq$@UFYDJvA5f_h64r-ApOkY*iQ8E7V%f)A z*r{8Ef_o-xhBb&t=1ZE9MA{=`+3c?!*gG}TkNxvl!0ydZy@a)%mf%CZ8oaPD> zp#k2Uae}#J|I>1$$G@SppOwlIrjU$3v%UF`ps{+vj6N93+A`*~KFH%*>lrbJ)-yj) zS5e!kw5>kb@h@a-ajM9fZ*@s70m5s%4g}DLd^DBwd&&qXpQ6fz7h)mgkt3T*4!n|` z9*d^WjM0aApfrrB4!3d>wHaZ#U4%ZvP*iYv4nlbjAqp8^@WyPWi#{-ll1&5H?(G9h zL>Ga)FzGz$pM)-<66&ShF_Pc+(3MX6Gm{GPID_ z!V{35QJ#^$Mo=LfVl;eUsLDRdiav`Tl~jG{jTlZPrfqBpB)`&(a6}UtuLPgdvcs(! zw7sB=6T^YAYP_KS>5(^kgW;X92>O`>MLo*+=Lzr;eCZO)2&?l2^UxA-VJp449MJ;3 z4>LJog}l-?|5tA+VkV(ULY6Cotq5jKbe!0Lr7@OG>!j_HH@Q}Yo?n19;2}pPv>T+1 zC4O6lUK03wdGyADEVB}hXfjQNT3)DmbfW0;4}8>o;x;=)Sb^{n{ozwdqh^jrzL-R(A=TmGH83)t(!ZqUtuK|c)~!7Wf`4~2^ckeZ5nz=SnRBS1F{e?PBX&fzs&{RJqfJi4?BylbE8W5et z7k|)Y+U@-G;~e_yDqaD^#SX_MUk6B1lcYEw>k5@^Um$|mr!Wzm?LP}YT3CTU1W|g{ zs0@~$YwS^iXrJ#c-hIWBfnShR|_SHc#m=^U5oCmJ0EGPH6e?=J!|*NDRT& zuQDBx>BHL=@(2&>4JfTwSb9JV4^ke%bK(7uhx;IXzZOG6@9^NaZa+m`|soAsCAu!I?F!g@2Y=j;aQ7AnzQ5sxBWVFR2Sj7f#GXD9;^kTO0A*Jl@je;;j zA+z@VVuNr7dfSzOqcYII9RMZYV2K0UDI}HKqtL3JjCA7u>I`)q51fE}4I3Zw0r`TP zRs5`hKoeJ-cV_u53(TJdx)WWn1NwJR@HU#`3$x11ziPJR!Wa@;0H6p8M_OUd4*tWe zY^D{8Srzn4lT{x{lve+=XViWCvVqhMe_vpTPf#PoB#vHjcWPBNL*!e}`Ng{Kkmoe*mHkS>^&j+S?rM5WmAHuv* zSxR2q1NP(A8Jr7{^`YAuniJ9Gg3)?izk}3=kbiJi(4P&?fAykC(hFuekmP(I-OdNu z2uP@eyKBbvB%v6(pS*g)(P2g%zc%TccygdoRG+AZof1=wy>ABYLVsV^c;t?&JN&W% z)}?q~FENO)ms!9NChi9(dLj5T_t$7c%-azc6aoWCjDRz!@WsQnGU+ z$*Gmdlxj1sfV+$HSkd={X!C}tuU>vIK8Pb zjZg&i8&tZ3!0K%nFs*IKwrfWwA+31wER>PE| zJJH~hILr)PSs_}?N-7Fe1G0HF``kP_azo#ifWD-Xxz!v>-tBkt)LdoLWpEJzo2@iS zJ|Tm5+_eeSQW1(Zr2LQ@L%LzS=CkM8RsGzYW#j3%&N$u3XhSCfJAxsJ6`7%HN{ZFZ zd232)XD&@?HkMEn{1!13MJm*-axj*+#(Z^t6BA-kL-f-0TAVOI5S;hv_#`TCK-&r9 zJNKV04j9E<`M$~b|3lh423Ojy+rsIjW80mMZQHhO+qR94ZFkhMZQHi34!_y!U2Cs* z?^9pZ+UHcwO3iwn{JY1z?r~`h7`PrsJ2>BOG&{824{yTFkyjzsZ^rkm)w$K~sM$x= zn$X&FdC1j6&BTy<6PN3Oas*ldKO{lmM36EAJFSTaa|^xN4svIB+bW-pn^3#XlgErB zg0K$S6M?3N0Yjpuq2T+|q{BO7V9|?3z?P~T%$G?Z>_&KnqXUs6gS!J$sZSiopQ(Bp z>z0QEQ;FwCVxRBhfPKaga0cYYOp%Q#mHL`h&hLbR-T?~-2aUBaz)-AQMC)LQXVChZ zb#K+F)bFrLAK&f|KKtn&bW`)%;f3D>qY8OzjY;7)qrUNc>EPGxjHpijv4PUU3Wo%B z4kq&}(Jg|Sv*%5A1Dv9keRlYBahplMrb(9u5{PQ6MR*AE@J;tDQeAMMrCSIxG0>9&XE+qI)-w^L3 zJFdd-&FJ1Aq!|4^P~6X^)3LsAD{s&+L7hPYAE*?oOLC)K{_1aAc3hums27}>=bfQN zZ{TZ}yACL$WeO-`#A{LlA!JB-P^h~oEqz&2vWA{=;+bS1NMst+@55E(k=loE@*#qa zXx=#5jdhF@T+*0JbLGvTwXQXFayq6d3E-M*j+~l9^tEi@X*{g9oSdFb;!5vwg5jK21{Q6D_HoaF3*URGIhTdqI+~>#`A!`J zL}(ewg!xE?gJFaNJ0%EU6ymKMMPmxT?0>*QT+&0kI``-5~;BlJSguUch%~z1^XC7|ki{+a(+EsoL}OgTdS{-;FGnP0t{0;7phxmIE?p-@gjcpPAwvz2ZyH-woyqP?wTGSho=)Z(_9?g zT8Qx%16rX9L;jxJ6o~eK83z%p+L{ErLXvXT@}*MMJbDGsD54oQRAFT#6lno+iSpTz zpxLC!&%Y^1VF8we%;I&l!~o)rbpXM%|5Uuu(ALJu!Pd&b*~*yqAAjuh9UP4vXjN=Q z%#E##6adcw#vFhr{}OMMl-8n402slEc@Say*g2nj5XjDN_0Ys9b^qEI=3 z6l__zWK`n96$@#|jyNzzgDq@94vdR4k$ojNhc2+v@=LnsCx%hw))mzn7$IZS0wd&^ zCy^+`lpy7;$7o3W;~qbxnc^#15!(+z-=VVpS-djqJ>s+@EGC zcN(`_wV0v=Bf$43o4v_b>)DmYmlT1ztelLZZ5y5ZRX5$&Q-Bc(W?_dh`N@PUFYzFl zw6m-G)W7|101Y}eE>S|YEEvoa!c9!aNx#A&oXJI~yOHD9u|FkgWXXQqO}v&$qL*g# zJsq_IZ6K5#Q_ffL#3$hPPOF1cQJ41gWbHux>~9OMe^fUOx$Ucu0S8wLSaQ|*k5vNx z`@tC*o0!`e)Be}-0XAR%9PFP16f!pX`x!PUPS^m9l)sU#5p5KsNRaV@7H%rQsR^tj zJ=A`I41*$2{)!Wqxgma9(@0p2Om@}d*qwwfBB= zcjgK(C~y@l?VI3OhsxW1w}J3~YC5wE<*%e{Z~})Zzj((F{LTQ$uzV^R9qPy|;7KGx zF5LJ^f_5UOcJgFQXE(%PcwLN#Jy0}h;y6a1cJu2OghSq%nJB@A!yd7ug~`>tdwm}ZJfeut)C2W2jWg} zrGs{Qhb)6bv$5V!yZReXu9gBIi69#1&UcA)1!CDj`i*AQa}fXLH_d*Dt)!D9 z@NkFZy9d)He+$wKyhhw5c`VTbAJ)}4ZhP>S1*~}ceoB!=7ojtD!)eF;#Om`ulqh7p ze=}ME0>cSFN%8+SIQ$c1Dz^U}Tttk21&0PDU0Gy)gil;0i806q)VI(Gg$5L3L^(Vr zlH#Nw2(kYAm5YtWik3EOmn%9i;DRY0OkTeme<5W0)Y2;-I65DwJ*%BBI}hUrCZL0#|(iA*fWQMxvXg)4acies9G}n*hZ7v;s+L}s@RVsmkP;c zIn^}om4=OsIKoYOuWFKK^AJ6>%^GP2BISM)=w(M3R03yx4N%{WOpf|$S-P6N3psL{ z@0{XyH6k|ngj=DcAe?Q+HatH(&@)Y-PDQG(cwEws8CTd`%Jq$@IoYL)c6^zT!wx-P z>{z2a8nNCx(?sP!ox|QonRpfXZWaue$BN-0v)Xa=xBfop=x}KV(Ju3Wsk}YCe>pVz zkTy(y`aogiS@VtoRFt2KkJX1q-TUi7=*C17=UTOkZr9fD$H@Vv)W{4y_3`G^fy_wF zW@%%o2PL@l&}*(4gHF0y+yMrZC|9DpMYnl0aC-RbuM_F(VzH37VXVtt_-F=*9BzpQ zfZ>-lH#iThTVud%)U;IiL`B$(XdI>ZxYqS)IEHsrLdyL}1ln076jX18C2 zvc)A9FH{s9mWBhTlCkvf_>_s-_|{f8BW=>Y_=*YSmw;R4`?wu-diUoU20@D-kM#R0 zBi5BW%0@Nh6zNRAmG_{u(fn)A42?%g#_r4%n$VCNvTS}LgS zwt3%4bRuy1XLujAtpyHjxqr+wmKDo8(1qB8n@;b254~Zs;YRXNl{_>%XNQUaFiIc z)xTVH^cjZs!%#TJ@z|}fVWns{r=2a_ac1Ry0CG@t87YA4A)9E5TVs%pI|+`vx}s@m zQmRw3DH;}@w9$bZK; z^UW))KLFz(0F0~uzheAfN}+$}2>%Y_6AFJo4q!<7!5CkC`Gmu<0vI4l!KrD#l$S!O zMI4@=Uk1T6v?Zi(=-DS0kivKR!RIEcga?DSyyArM1RKlxQGAWfQ#d&}x%}OkeR28w z<_I8&!PuO`k0z*oug4ZB*_>H)kz^CK{7{a%#DF2(W3e>X{9{l$q^huLx0k5TVPFnl zRes$Ji{>4y+8lXswnDsbDbWklLKkd(PTs&tFWrA%<+-+)VC3h^uQrN~!uBH{iEMRs zPrhq-<-&MTn1x-)?O0_@1!IokY1O=DfIzdvomBG|^;^`7@LYwS8M%US08NdOa-&6t@F+?Vd|@po_)?ceRfl z^#o=$vWw02s2%ji{Fy{1pSPc%*Q|;@6TubbB}NK-8KLH`H5+b}^(px)Za8j7d`+>0 zr^b3@TD_i{$v3DQoqi`cFD6EREeKu#_DCaQKnp4FqToaL;^(SIOBHa}fzo1n^)k|( zUnhvJ3`|n0MgeK^NRK#$$&Fjo1XULv^Uqz8?~6|Xo+E6OhEt^?`A+@UyI+6Gq4FoN zG2X24Qz zgM0ZBJo}7ZGpp*9$W!2mT&D0bPtvNvAYFVZZNww51wI+q9!3+7gNZeTQ%one$1XMX zNG5HT%@ydGdOQR)Jxj&POzuuK$evlk91I=glw42syS7s74fNl*|3i*xM#^B%0pvIr zK#nc`L);rV0rDD0b4Mp*8$)+PGh;(b+P}2O0lug7nh?}+~gQ63svnJ9)`BY79g<@?zi%%t=T#41-*8lb2IC;X#%$7(%V z-%zzNq1;xOn1TrIA3WJJ1tmThS%A`gu#WNb_r&m4r|)klpeem-IOS#aV1&!oJssG~ zCB2mH^nLV>ekkJDg)rph^Da|H5k?Y44~vGl6Gs>dY6X1tM@y4?0Wtkph_6|JU;OD} zSzZKg6HbhVAFx@*+w&#VSoAcSJrQ9p)G&Ze--V=0;|{&b$?>x07>h_l&M=ppNS+72 zGBa}2hR2Iwj2SzmMY-SlGr;$nYH1WJ3dRmWMAd*e2R_ffU+m~+Zp)jxR~>|96r?$L z-oDB-a)KLcnx_|ytB7Nht_sX75p!Cl-MYOiNjvxILN@&j^~Jpmx5Vh9m^Tc|MeBo_ zhlu(Z(t&J$6}9#dG-L+zZA@$O1AkWg`5ZuLX3upmz>2>L5te~9rRnAwk(^uU!VA)J z3re5uT<-^pUtE=kek5K42U{|2HO)oPZ9xC9D?Ba%lR#H z-$zG9jAP0k>56?8>IGXZt0~WMQdaIa8+xplT|uHfbYtW$;ke74P`0i8DB5CuhXChP zI-xKq5>K;2oF1Z42}+?h91>N)xxvIH9>6X&Zmsih@^6{+AGwV$CZWLB0L-NUFlY3C zk2#Y+DfGV~$8X^10MItahcIM{%xbQMESS;Arzw#aS}%6~#U@t* zRn8w}TP~5Xyl%63?S*i47Z zQ^9Cfu6mFz!|V8UYawmc%Z4=!ino1dREak~<9bfF2~t71;AX>eG%9D0Awgm#He+ZC zYm^dPGs!SRoh-PO%W6eo(%%E|L5?sb=&!*kl5C4d#7+WrR>JXh6_v@S%BbT`fxF* zfcL`Hz3qZ(Okzrlxh2clkcnf29z<1)}tF}i*F>c;epjRN5haV3ffmnnzu_XsVFOg&_; zDU7c4*)H|MuY48J)ay6s+<6#78On(lEiTMw=d6lMdDZhvyY6;{1m7c<&G#{j*%apI|i_ z%yvG2>F4*1hVK~<-zO-B(H^a6flg4qvs&_JQViQr4_A61lt4M)c|M~1HG>Xcw40u> z{yWP3sofO)qQu4rpzRgl@TvJ9BF@+i5Z{co$rbq(f`P&RU<1OcPPfb@xS7sP^Zbm$)vv&CK2pFr-%+4Q- zTr%wk`F(Mbu1e+(Ty^?ZSgqDmo3L`Tu zf0?w;y`+twy34Ym!!GUJt&z}Rt2t__dm6L#(=sZs{31WhcjQMEn-S_4-LI!$(mUs{B4E6xhchiC28n^bnWynE| zlwQb0s!eBirb5{crt3WZh*i@aWVBIdx60HVMI_-YI+H2Fp}5Z6EP9Y?rNTsbh52^? zafa17q_u;BfEinqDJqp^vtK0EX5T9eZi5oPN*|O8=H$nc!?Ybl;QZP|)l?ESCoOGx z;KG@%s%y1s*IU)gLem1Ri|^~<;MJ3jg<2mmEZ%l)03{YrzbK6N1O}D}eX%}-D5_V* z4zky1%}dw1Oe}e|GQz>BxkT9M22yL2@h~M@m^uQrMST32_vdOtWZMi|#K8o*q(V^D z6(vl%K6lL7iKy+zH!(CfYs-c*}|JISobefOhqexr#z%8Lx# zJKXifaD_MQt0zp1>20JofgAb4=-Jhb{@*SLnJk#W+WpYYO==C!dP~eN<4wakk5|o+ zHt`_v%IW8W4=gYU{bkBOIL50XX7IkoNxZ=@%kv+D8Mq>LdSP#HT9MD-bp~dGL(qE1 z7L4(JcR-itPNdc)>%FWjtV44l=$K})TV{>OaXwnGb)mLa= zC9YQ#h@!=l0w}B3vgeIM2kLmf_FmEzXQu0K794->!Z<6<8*M<|p#rcWmHZDQlQ}(` z4Xw4YgXy12@?XXT02>ZlX9q)L>3=-^i(m~XYg_)qi{7e^nT18glG&%or%~FzOa+CY zvtLa>5jDv#He-TFX5=ztMfyDQdH-{!Bp@K{c|R8E>b#0xciILbwfnro)nqc$)8ulz zdP}$S%d!Z5w0p&AbMc-B7UcT0z2Zc7Ms0XZtqoL2~qbtlX>R3*Ea0yy*`|>PR z{`)eyq_hk*eb>i{>=r*{HB&NK#X4k}xGHLXwQ;F6*f#ARZ7YFo=eOYd)se>ORs}-mWxobw? zKaVd-9`_R7oj7zQf)1VLiS9lCYc_tdOY=j7uE3!ITc_E%WxLJzt?rvTkDZ&P(L^7sN|0tA@(uDIRY}If1A&ubBLb;JhG!Hy_a6HoIS4b8#Rwb zCE0VhZ!|iIABz}Vs+!0LpzEx$F#NK60{n%kFvSS_?A|`nyX}@^&EPvGc(-r_DKz5s zf5x5-L2>7zbWnr@)kZT!J2)g5BvZ(c7BDtE0=Wo^0|%na$uq(R=Ffc5gXsG)4dFoF zf|1amNmSL=JV;vgIEgF#v9`@g)Hc$R9XLeyEkQC!hU|Xzg*zV4(zM``&7OoHcm$3@ zMK0}@4>miDEus3qv#(!Z$q-|J7#9qPasMg%`Wrgj{z2>inPSrZl~4W`E`QAugWkXmW`e5D^5)0a5v6` zB~O3QU;5UR!(6ezE*&N-R?c(Lj6>13W^1Ev##}$g5W86SQYCC%2T|kXL{4>dvr?OyOlIATvB$NF#Ba>z|oMQY;q7|Tx)0f2RWs)>)S)BiwDb;uuGzPPD!`*bg zFd9(3Vwv}tUY}6GB>Y1$C%Nm1b+DC;Mmi_)1fgUmW=(*ZKGOz_vHb!fE37uc)7r7w zn6aLL%C(o5pWUG83u=lL{k}{WrPFD+b%?2HJvR)uyDlq_^-0ok2uxB?mqj|kX_tFr z`1yD^Yu&+Wy?+tZe7oiy%*}lK${ToLX~1cJ|;KOg8|)Jb&!jG9EC zl|t^Go&2U;_MLc=+N=7qm=h?Cf4t-qzSNIPjXsLVwW z5wV!RNM&rjXf9d2;??uAXj{*AOm#4J^Jx(lS)wj-ADw$oZ639~dU@tBUU@$cQUjgc zbb?bukVANG^Mz$Vu*%yQK*hM_s+~3m1c84GTBmD~t##1qk%y0{#2n&ci$S*Wig``2 z;W`{V+HhNsRd(RJmF{N ztR8Ga;o9S;hHh|E>1lGm!~`|vRvQ~_c!q0xuL7Ui`3(#pr7HvMi&;m9#H^h|?@y@h z72Dvzzcr)6^cx}f7v|xh*wza8wQ~VWw8!2f*KyzQrb7e@$xoue>ZfzjSk)SnWE|(k zAnxzM^7V5N#rxy!bG}9W4k@^?6NrsHv)^jY!-GwjinFCcjDEh4`?g3}Y#TR^yXcl7 zqX<)%(CV!C;2Rf8Y4nA#WV%@8>c`%kbB#Nyb^zfnoO4r8;3I6Ua(-NL@K-6Qyi z$C1027P^6R#-w==nYC@8#tz;$yK8l8*#&tF)!R>?&k_)J`Y_rEiD(p+=u_*T-WclV z2cof!M?p+~JbRecOGYB^F0Oh5Ut-`N&-KQ;I^saO4Kmz;F76+vHh)_}9zn2|n8p%* zCy~Clq#rR(gR3TUQ|9Rp46#+s&VVTUIC>L^RS$r%0X z1*{M4_|c54a7E2AW+5Wdh?Ot~+~OKa?69Gp-aDa!nS^ zf;iJ<%bC=vYXW$`-YWf_1=jquye)4IIZOOaq0=W@M&m^KZ5|}lT+&rUU`Y85hBeFs(*%98 z9I|L*r{){ear>z(TyV6IfQgd2tHE?whByap2_bb&J7I6ppe*t5agj&zyvY5f7?pVS z{Kw4k%q7G{?1=i+ul^6S%uV;BTE#3(1W;rO8v})bg5_!hJl1N*x2Y)NA-{C> zp7K+WQEhjr{k0>ruFs#6`HpstS|f7yto>tzM=U}fVz#DTH+oE?veT7Oj*>!d zWvA>rCQz=6wNzs7N~6u9C>-&^RF<$kG!b=|zRJue{Hgavy6I6+PkmxN5_F2Zn7wXn zBAMMamy@DH@?4maxqwmCw~5nkrOq?4bE36+?w})MxEL=Fg1DB)=4cuNbHr2mF$DZx zA8&&-3UT$g=5o#;WFX@MM*L9$2Kf<}-kTa{UO@bPT8;^8mU%V1RZEsmq$a@i+;HqW zxUUN_)u>s8fg0PM2hsH?E^fAC2`IB7HUk0wmXnT|N-klsPn1C;nQFn^Cn*`VPci)Y z31wWUK_>f_%R1tkt!tA(1j)xy4iD?xMH{E~)n4(yJLe8riXY;JmF(c&JvE3tg(5KX zqwVzC@>p8^DuWPLh0m!`;Ybtg^haNF-}J6$}P!CcHa{(-iqX@ z3CA;B6$3_%ZeLIYFVVtBpLnnNxg?mX)(nIt^KCxthTjVAtUMr{RU?pYK$>N)yZrTQ zgJ)(eU5>InH^b8V+GDl4?0uVAzqUf));^GK#lTiiw?g{1;#j|sveMYxVi)JeDL#FL zD&EeM*Vi=+=kU)D8HA+DYZ@rLlhHe2I^}RHtt6?iG*b#Rn9q-@f6C2ff;B7rbXJqJ zd?l*ouyn@8jOF;1RntPIrhQCOZ7Jvf?L3anbEnCU(`(Fctq78*?1B%8m0(^p`Ol-kvPO{koQiQ;@+`iUJ2(7lb@3gTk+H(J`h){gF`ATH zNc1t15mbe5W2Wq4w*WzPMYV6=TNFmQZIYXQXb~TvRWq3p3;-ruA0#4`3!5b=l0Az? z6coG!C{S$q>uRN1gxF}+@V}RT!9LzOzRWeH<;LRH_lTLhBjTQ#zB4HLX^-SO_gF%w zvZQv>8t$p!HjlND(X02;K^dHV&&C_vc<*KmbvC=FOs-Tilp~cldRxl@TFu-_8~oO8 za>Q_is=+RMYl4w9&+?-_o6Z(Ndzs9|Fad)vayeGT9^nZZ*V+IDK8$dgLaIJ;s75+d zpu`PoZNS_qvhEmhDo?c?rppbLbHMl7%A zO#<6cf%dYr+3m0e{7bke=zb{XNv~g&`G9CxPo-XU06!=^xtki9Tad_psoIBo$7cRv zZ$N;+2PN6F9}eg9P;i!qxWiR`rvcPLqNwEy*4e;U3yn)r38 z_F_Im9%EbyoTx~3afFnv>xsVL!xXXSD79Qd**I^6Lm_tKA#%*Y8Ub>q{JCBhHS$a* z1sDW5UlM1p@+6KK<&=#7`AI~8ie983MiDfcA`8Gop{l!@C9fbx>Ffl9+*4F?DNfN9 zIP4~4XB^&Gj@p$^S8rvib22wM5zx>e)dc_as6%fzL+>bdQvR9KUvfrTbIHu4E#z)e zxVXT&+5a*x>RSSdZ8X!Ct$$8Y#hWNSs0j&riir zScM%3gCXvxKuf?3Qus;@y==TteQ-`L(-U(e8}0nRGZLjWdUT5bRUY1M zJYt#I#E|@1K)Z0ooAGL5k}gNr77s{+twyfj2Gbe3W%(-U7p+{YTxSFg=xwx#Zmu4< zAX2GwqU=Wax40H(uy2G9GTR(FTl5q@C3^TCN_l+Mdte$Ayg0H^g*$4S;3A<$#YX!| zGYKZrvN65gM?_0;B)sw7a9Zvo?;c+s!w$F~qz<*Vul)%$OUTE<{5H(0&~P~NjKsiw ziqR&@Zov_gn>>2@o99*R35R??51safTSHFr{sXqVAtO%STZ-2$!2zgX5Rs~kZt?_;Z(K(CSira}avxEkJ= zi1St7Sz>&X7(Ggos&(o7+f3J=rh&rr(!)An96$sO2uSIFL%IKUZvSk5{{J4@fSNg= zTY%wXgH9q{Vy%IODjxwOx0)D61!a69(6dOxCxL30K{CfcoF+~>m%IxWRvQUj8=ec% zyMu$umfffj`?9jN%^H48`sqLPG%3Y64b&*zlbO&mw*J~a)wcfBIa2+({tVe|;B_I) z-stuVmDY1-h_d~u+;54?Z6i`)Sf?JppR|u%4Ja6X4bqc}( zwo6VNhZOKO(DNP6P1G9IZcpG%Q-m`nX?hC+2d=7qOp;1D<^`>RICX}uB>bNu@RTs1 zu;s-}&Z2851;RFw(^B$*-{J`?Yx8b@F{T;YC_)-~3yQ^pDN%nrV*!?6Lo-{7Hq)Z_ zKp~tipy-hAjrz*5*D4Yz5Q3!4#5i598Z4!}bQ)qB0HrTFpA{kB6NilVjowR@fx-(t zy|a7;J&yWKi60eBs||-0)lf7sYy>dHr76am$jAM#NN$9`G9T?(2{Tr_UTm@BH|E}v z_f)FCJ6V~!K`7c9?tb?bnUvO<3`_9jnECtEfT9=!6;`MT%;qXCKJg&?0O+~l@ENm` zVp;N@MAl*zWBcz<_lOK`TC>>z5%$BNBcn(iWwwf-ggBVCIYRTEqA?~>=il{Q5F9Xy zR0r4(HLIJh830+Qxy?aI)pu$5puUb{geGyJZ z3VuOO(aA_ueXTPks@#JuYH{+|XE7BT^LeR{PSMc5-*NBi?*|eiej|&}jS+E$j5=Y` zV-Uk;ImF_G4Qq(zwp1!YatF2NAS-b)t(>!ng=&8W_Yk+T6-1`Ym`*BlX@fu55EfP_ zyE9OAP6fC5Wk~eTsgdb*g@Le<*jqZ^sZZXFD}a);?2zuiumx(Nb;j_t*Uy#5tI0-0^1r&02d2>G0vef#Yj;UO*=ao(lcgvyApxo4?|Xc=AS_VN3jK9#w7Zlz$aenvT;N%kd#OlODy}hHS0~*IL55{^ zo4k`+;$EIFhw$Ks_G{WksoYa6MIDceCmjzxha^jHB{ZL%mhggmLEpG-YL76|Ng7Ft zw=orY^2)soAjP0hd>RNe7eJgRng(8H~Oi5LDzoEO8&lOI$W^$oBI zQkITUOXw6A@fbT1xFU8Od zZ}fU=8}aM!Z!~q*;L1d(%!&h!+8Gz5NE%YtUD)6Z(#}?hFEP4Hyfk3E_4N?JLp+rU zcE6GvqI#Bx`?&GDQHac*nkM6;E?{YM0y@WXW~d3vPN*13QjUwA4MT9m(f;_|wFebCb-1_pz|wTODd;mv zMdJ}#$RNWNGSZDV=LIx{?h2_8|Ct3o&+ZN=0zg^~BLby6e57!@>vO8r^|V@AhVzcR z_J43hjL~RGN`I7zp`MYFQ;nQ>-T`HIK6ar ztd6q2z6r;|?fz0QV9I*txzu3a^3dg%(bQL;Ks}a(y4R;(R0sBs>4wpfEFMkW8Ft&X zVW1EfK^-aWEQxwSWGEeUG#cKgzkCpg`Pc_CVM$8)tHEjQ&PqBnKY?;GHFR9+7F~g z5rfuGU~2K2|1K^8IZ_-H5?6x{QMo&DDecgA*|FBP8%JnhZano`0F8hh=3h?FWVx-9j zc>9aiji7K>khYK8^pz+Eh|l?;9^~V;A=TxBA>Oy78;m8qlp9FQS7R@Q5E8>MR01x> z(csAex~FJ6OQnFGUJPjPWeX_*tpM`A_&7b!*w zkX5-Tk5SKxFf{CWtH1-Tk|j*$cwlaBM1V7`3B!+CW$tvjP-@QX`HR5T%5O~fq`O9p z#WBRxiW4m04Qdiw#Y0HA$?R59PN#)dI5C)^&TYzi{PRi7$)Ge}wa@xAW@j#L*j8o; zz?YT!Yn`1r8(x?)?lo<5(H3y5hv^C|j_Q>s=&2HtUGD8m8fmLnnunG6z}u=udhN?^5hMc`b~ zhwcg@ZQ@*dSz-mTV{E&x-LZZ{+- zseQz5{x(xK>EjK|#^t5bwXm0XZXynml)xUOrYs30XD>C%++OR6lPi=`kQAJ?D8-4I zefDa$g9zwoEpAJxQ$`<}b!w>KUW|%G!)78Jt^!XR%fyM;3l@FVEE`3-Q z%7?!oBscFZa*3==yR*mcawIaT&U0Uy<5kDwYL2gy&qJ$nqL!p-olMWt4Q$MY`s$}j zR_}p`Q0}MT6b+P44=buwe-lxA`S)mBXr(C`T7Z&2)#%9nhbygCdb7iaD=!yMB#AVm ze7f6vk!x%*X*O@!HfM9;HbdvnZBI85y^&~>yB9pv<&T{Wdf-#)?D3~y{5EU<2Ubbe zMpS*D48q@B&Frun(m^Fln->`LyFCP&OZkbfR-}?3{x82txH^|rrzDe-F=w)360PUd zF>2tB_wDJ_Tw!PfaP9!yK0}cBa*q1$5@Qa zoIk;Nzd6mJ7V&1!Vw{a`uWRWx#j>Se1xVJsD;lZA&1Y$)M@}-tX~q@Qq}Csj@CJL7 z+~P^YjcXeZ*BZ2%Y)XueY*;jE(xrF=zAk40zorqW%6`Cc7-%rK7kJ(U)?{~*QpQXD zWdHq|w|!1|g*ICoX%;T->KLQSGYN^s-c<(l7K;X9j;}(6GXlntQN28%`67^+mM&dk zbd&U%K)YN9Qw?{Snsq-iw#d0mlqYgC(G}Tx`1O$`bNBhBUZ^)(&@hjXxrEXc^X9~* zqO49GkqXD$#CJH#WQFfDEB%-jmsc3!&0OffBVMT-bYb8@6^^AK`hl@K^hg9HD|%gf@_ulY)|sI@@rY}SLsGv3`ADSJ3MuO=g?EY> zo~!XjK?m^96KzRb$`0-O$2rf!AB{@s{OVYrBg|uS&yrOwY|&eebp(NG`E zQ*uc?NWjE3q|rG|VoNnnw!ay!V(q6k^Zi)gNRo92B61EvLJ4W?6!(m*+^Vk1FX^eSotdK3l6tBYGCD= zJ&=N`WD%-e^u8^|^G3Czw+muLyaJKut1#rLFea7|DAoWHQ}}_>l3r!$0Em%umRYyQ zOaN>?F1BzOPlAgQzbmfV;xgmKHSrz1{^~Wllm6-AgxIPdq9*HF0cJuz47p*QyWD%@#U!QA=i9(g9 zUSLHS4LXjV%1OLCM|7PROns6AYzEInX4z~!{cYp!PsQUK+9A+omRW@Xy#1JQ2m+zcJS);uamv>SZtV%QrG;!n;ODevPSblscdO2q68`rL+x}))+CyA3itR`q0?T{ z1`-M3WO7Fw?y5tSsfdFO=a0jdiOp<9~(c@Od%t@x7yLzL9_0Vt@aDX9+-v> zcf&mj2QPG%CxJBc0_A+y`HY$^*`@ULKf?9$d%7jWU9!VGV-u~S+}B70J>La>mlXOb z#3NDd9rQgVlJO3U2Jwjup;<<$Bp1p)XyI=#`a>CI6JA*Y0Wd-VOqD47uV7?n?4a*t z4(NVL>)Y8G8wncO0ai5i|IfZ>rQ(PL2tR^%7WbanE>ctAHnoQxUpsjKky~7U@UY*| zWZ?o_T5z`b*Utgp>BxWpylv6&1?#wNV2Tq#<)vF4XJyx}b{-y(<=)z0914KTqgb8+ zeq=Bg+MSxg@Wn76NgK?`Y5G`PSuk#ooW(F7&f|NdTuJ)|;gl5Nz1!4*goWqvI8h3N z37eH$-qrB;n3qw+tYLQeBs^$lgi%Z}`vYWCfG>~!cF+$wt{?T5w`53J8l)VD5lf&& zlA8%j0@jSn*+^W7Rn>+tqzetY%G=rckFa&3>UhkLQbKjV3FwJqJ_dj9nBA$d(WpyX zM>C*l-V$t!>(1!ed@%laa)I4A=5iTaf2GMr?#rn@#TN?u=a{tc*pHOpmN?btw>=+sMN*DnT()&&&!VjDP z8X`SSL`5G7Ys8NffI;=naEAzHvX_xoQ>sKwGe2vvkUTJ3opSkF}I(M=8G+`u*`#pPZ#C@z|%iGoasq@L%u<11j6(0gi!Ta@dxf zt#G@>uVWqkUKkzHs2NK0Yef=%H4R<)B>FtIfj`TJ+2ZP3&`24yJCkpu$uouwLFLRt zXBeM$7AcC|Yrqe?al5n48c*$E2qC8eLDqF#9&blKx0elUg1lT#ltozT(*ku#y%rO* zFWlwW${dKVOkK7aHi?i?7nBy3Y{Zwz`iY90>spOrLB{T$alk`b3jG|^0{fc4{Ze;U zMn2hbd2K1PQK^XDD+oq9)a4Do19V(t$;yO{$uJh0gvOxeYWeQOCfX3KHH2K75R|6m zn%E0F90i*sfam7sv$)Q2mAL&uQ_NHNOcJWOON9-=+-L5@J%1R8de*D%FOve}o{ZvN z(y{f5kgfB5KNBqh1g$Y$?i%xV+`i!O?XP}H&&)b>uGK+ z(9DgVa56TMYd&|!lbY408}JYpoU_GIHm2})G`1gNlPN_lzG zK#9r}ozZ&~**jGUZOCj@+nf~H1CCHg6f*geJ$Dp3-H{Z4tbxL2zyh`U`lx_HW``-s zf0Y8&^jf<-S)tv1G2OAwBkEWsGM1Zy3iU_WH?zArlF5pD%O7I#R^%ru(2a|dGAj z!mh4+cBjn%vYD1%9W)u%@Yk_nm3kTIp_i6ClfXA_B>Yt!eoW+<0uV>aCFX0QZ4gOm z`HbHiu<0$Mde!q;TT^Sb9g?-k^HC^UBh+^5nr6uS#^>9Pn)=hXrH^A zgF!y~K2*(f+L+nZKrM9$W1zrTOMN1* zE}~X9O=||&d+Kupj3;pgUS-b(XE8dt>wWeR)2`{p2+LWlOc4cDO6-f|Ky^gO8V;ZC zTHCgFLQ+r4qD;>y{g(M86dYaeadbFG);qXPB2?01tFY)DP5xbR)i2!gbfyGnnQq{_jaFZqgq%JJYbm4`XK~9M-YEnv+RDYv}pwzCS z`O32S!QmKnF}O%YNWR*lC94d39C`9MZeb=&ktR(ZE4+&)7W1w^G3=e*m+c1sxwf10UH)?)Sy;ap z!82wu!`>GQM$P;OtLt7^a@(y6MF<#r*02!H*5=KIBiy51J$Pd%hO;QoaU^051~__z zZJW?$s8T(S={^!I>RY`8ZXdEEBHBJ8b-9L0q`4xAUMa_f=2Dci2KBaZ&dayQePZlk z{d%2uI2w!6+NM0_zRh7^eI)S+WxmDp$&)-l9{i*O`W!F0##Xr zmTd|Boj!2k^RdDGLlt~UpUkq2{)`TF$#p5qXuV!9uICH*U-jExC3~{d?r<^SywsWR z+c)8Vvt)O5v9w`Obuck>F;%nwTcW56`0ej025u-1mG29xIYjo%o=}poA&R2?0bG&U zNuY-kg1|(CfrM$?<6Wc(#}W7BI={UN&iA`JIt5(jd8dS1}*0x#9vR$ zI3Jm;!--Yu@Vy~>Vpq6C(ryv6(xfV?-fEO5iG^bfl~;d#!PuV1Fom`ou!9A)j$HCM#vzD%h{K5Slbb zjfn$v#^v!TmDezo54dgAlDtGM{-v zIL!CWZ&PL7aqSL%S8qDt7`L*xK^VI;yI~l+vpji@Tp3>Ijr8=b`o?U{u3`WjHf=g# zdWR-nkZBHp$nDMH_{UHg+*kJo!rKN#R>!J&G?H>Qj|@xr26iVi@(E?C^D3QhIQ z^c5YiL}>Bwkk|M{Al-z$uOiI-CVJ-wkgj}7|=j;=`vM%8AnIo5Cg ztnw80yeH}iPfuRM8hYl@(vJ>NPp-)-vqlzXrRki%R#vQxp85)7F*-Jmyn=Q=iZA_z z%5Zu|sDW4oK1e!{tV&j+Abcaus(P}UbSw2IP~#bK}rTB4GcIkZzTLiM6!3$dPFWBG89;Bf0pRU>t! zrXR%e;oakZLY6^&b3O%i^V!;HIptS;^g?VUxj7%Zw$1RhkPeh|duJN^mG|yJ*Qv1w ziTLJHi_-n9RWhsPWROY_#7OT#;}VuD?2U}&k>i`H>)CaHY>m51HSd2V!i#C6FO4DjhI!%$?cay>PR!GcBky&Y?eENq!ipit}0p`S~*v!o{`079gUN#_Dax&(jIz z$y@J%J!r|xHU+AiNw~}P+a#gMLJ;A7K;xIlh=*+4d zNU)FYtK#~WV;NdOf7)A2EwH;c4>B)K!{PUem46$+oXnNHB<(Btk`I{;w_u>QBWP1xP-bwe* zmg@Y-vsPU&%#!kv(5|(;5{dmVt5?{V>Q6Je)`_c&3Y8H}Pw#*q6Rp}yjWk)*qmNx4 z_b@NTkd%kj zCRCrQymHb9HwZX7P5Hqq(2`l~h~r`m?O2aMaYe!iKV+sMW$Ar3{fZtLbLaU!ttW4o z7pKb!By>G1_rO00&KLsX8%Z}sVTKcmL1^=iYAp99-jH51VqjkOJ*%`4So|UJEdFFm zX^+iA7m!5GAu-@@2o-PO(0ZeHlyBc&K+txE0OIVQ`v~oKBtFu^1T0S|KGF2Z!H`$f z?>L_#R- z3fMf{W(f+815}KeHV0uyNNF|XRw*r%R zLA3yqLU<jkrmLFq&r6nA)&HVqug{Vrc}6N+Ls8 z`3;g!Rn*=~3pMl*q-xu6Mg^yIjLOj3j}AE6!jh#}o5{s9m`Uo(TnUQq6)fpy8lK05 zW7T2G)Gu7e8fvjLR9A zaSTk)kBF>DCnYc4FC8EK7Mbj1pgN4ol!7avQx;)aQHH7t=?v~4Q~5J9c)nGINq0(N z=zB#vm07t_OL}1x_8pU=G(Y(-v2}^sl`W)*8^QB#15EN~`Ac|%@@4EzM1*G$e z9DY+^eXJ46R=G-jhVkh`e-~RK#b{75z$1|!8&-SaIe);dWw#|Mi3Ku*?R^iv40YuhDMW# z!qAWR2BTgj)-shGzYaNQ_qWA1yGbFYg$)BKlp=;yqBPDmX!u{rvW<$izy7vpD9of&Tf{cmv^Kfse z(0uMD!~l;g>jkQC%b3+7Yhc0ig^G!gCbFNWqS9r;hb^99uL{%;J;gRB$|`M@xW=hp zdfzGpE4VFKiy@Hj7h8n+GKIY3!}r3kGlRSE9D^ov=lFbqB)~y`H9v7kQ}~ zcxa&--)_o|s+awsk>}3+jeBjE3AHQ%?DXSpc)Fu+4zus2eCFtRGi_!qq$^Nu%Q!TQ zug`a$Sa1~Z#%N4Q*wWGllF0X;K;)Q^-VcHg%!3H8Adrmnw@~~F_f&QD!fqGLrp0JF z_D9Lz{WPc&D54*|@ZBYuIk$(dAAREId&U-pl8(rckeIb;busTkX&Evoyp@uyCV1$4_Gn2-oJUDq;^!bpgg0|) zF?%UB9fBTEQ>@5G5B%j6%G~hpQhsJDrgeh%fHz#QwvfAY{7&O>5+Pb2Niu>z*X3HEes9o4tWK_r$rEzXSj@QvIWK#_3mgqF667U*EQ(|bvh^FNB#%Gp$R zOMrEI|N1Q!J}VL_Cv-hCk8ajDg%VW^t#$&c)O0@w3X?3fa2id_(h4ex;v#;Qqf#1* z&D2EqntEsz?JYFXKs}F{U`o1t4voX{dk=l)2HKJXx_XPU=pWCROEIELu>xDNP~WX_ zq@mv(hbQBx_D?QrFkxLCU0P!s?oOY40*@Q+`e&^&F~z`_`j~epT0wjdTR%tQ>+$O^ zXdw*^zx-^B@bJ+5tkd63Fg=T!H6_m$sEVIoV88o_p{+#WsNe?Lp@ka*4WzGjOCi`m z)~rzfJ`!K~uC==O+p@r#B}1n~Kuvi_?eiNtY|V9%%4h6LXXbR@s|xE5%FQcl;oR@F z6@(o*ra5R<5X+_#-jCJ&!)5IF*_E>7S(<(FkopfTgn_cf=ivDp0)GkYr6r?yLEg?fn@O$FQ=kV7%!kc-5kmJVf(p@-KKNH}78qiiP)$OV!Vjj_HE?ZG3S93|8V z1QBcuJOR{=)LD~H!tjz#-<;Hsk6Z__AP@xk&&)8#`FU#t1k0gF${71~k0{-FWH^-v z8YjvPi=fP%xh6uK+jv((=5^wj_IT-GWHE8H*F45Z+tQcap~e>=j{pX@{Z3^e+rreq)0zz9{TG&wesSh|)h@1TCv>g%uq!L3J9S$ii4wO|yZjDH|&{aV|wbf37B>MWQlNnOOY{r!U3 z9HeHY%n+eSG1p=HTeRe7aCx#!x(tgf7wlRwgaNhXA7PXdrX$3d{eh4Pyo6beOeob_ z!DgsM_dt+JTp8o)*)nV+*RF_{XEtwwP%lLNV2-EZFXm z>Wgr#0AEIR#Psk0a-FGZxnr$;HK{GRhLJzyOVz8cP6ROBeIcPs8ukOk6>PXcQuHz! zT_Du7HjdU9xeWNMO7Qn!(Fa%Nqtyg5>cFTEK01(mYzY-U z_tBx6wj{D`O2s+wbRoDK^KS+p?CQ~my*UEA?6I!Kx!!zh8H9)J7g>dh-;KSYbnB-_ zeuDBr&rJ<$2WPgh!GFgFcp<&=%LMEomk>%nYro)O{lRzYb>F4TIGCK1g?EpU#c~&y z$za^Dg!0Dln=O&in6f-c201pPx|`+mN(H|5g*^gAdkF^i=Y@Br$d5=sFpyam2K#hL zn%XGn%Y#zgWk8i6yHigrMm*{5-?1I_ABaQ{8 zZuDcdw+QDxs*&&#G)8szL(@Yi?7)A}pSIqSg=tq3o`U-tO>*X(=%o1PS_t~6Tw8)d zE!6t`+$-e|#vI5g3$vf#HSs58Y~N^p+fikQ@z{NK4H3 z1iStE#{a`h0QcA1-l>oyX565^v6^Y&Lu3!t>nkE2Dc|f_muJ>MU?+ zqvWt$$-H@X1&h+5*2V(g|A6csMyDf2FreDLNq^j#^Y}#uLq@g^%09bB-mAP{*qV5|Qs}XjU z5QGIMC~!J_)|}++%6BGql-wa34|Hb(g5!R9s*&6wLr&1yAza)@V@K5G{r1%W<2m_e zIbMQR117ssWFK5@R@||`jq{t57ZR7BwlDT zl#^r`aRAX6f&)5fGSqLOC)ff@17>ARjiSf=**OW~$z8m7WFa~)-Ah$-b*1a^qb&2$bOnl_^qlVCzbUXf0sw=W-Qm&hzRrxv~ z$LpSG*mO>=`_IMR9TZ9~ZE3&0=?$uKF8dx9eO@sQbXw=x?(rQLO0GZtlSWq$`)4I- zAx;(A?N|He2^h*$Qf=UAkl|EqXSVRB9?DbVO8@6w`WMF_B(|#jgtq8}HDNJbSY#V$ z#SL;4tuz%l>wuCDc%=gut1(K|AR6M3G*L|Do|O)WwjT`rIpTmH=LwXnfk9kAXPJD%$TcnE?CsI?2h#|-uAk`=X}RYqgFjBjfN@G9aQvQKl11G z1ZR$1AHI}Nts~8mv|X(ECpbP0E>!OL)%F|YYhN@n{f&lO7MsqYqi=cuHT|s&u0B4R zz;3&V_34M`QA=eNLS7v80%t@1I2hFbEgZe-c#w z2I?qH05~U#Q@=!+P32r(nQ6bZSW^p}dpL?5)IQM+MzJm$krA4O?M+KsQWz!M| zD}!Y(dz1t;V$Wh}usP%sk>~=H3n2*YmyXTW*QALmohw+!T7gk0HA(o-;6X$upf%vb zzCjr{O5=y*B5og2@k?s!+1CaeM4uF*O8Gs#*xiw_C|_xj68CdG*heC}=y($&w5bY2Fx-QL4kLJ! z>>C-kx+-cd_94+RJHFiY!M)lZ6m3R zo=g&{^S!uoxIc0Jds+&jlxF`6^{NJlC(VB|E&YGTldP+ai{<|vRLx3%gU90SGD})& z*jxNsw3@;90k$gdf(a@_3FxG3{Igeamt$t^7c(WVAn#s?1U|?9EDq86b;e zWqug~hyAJOJf-tY$*;ojEY`Wr^D=GixJa#BsbR49x>`srivp%M$ThSn>kWt&%iQ+- zyjXcE-BQu=Y~unV{oeu*wn_berO&)nfkzufEXZPOz-b(d8C z40HzQN_z$vn;krIrs6bIcJxt_tLL!|u_~l@-f8Udc@Jjm_MQHzE zx(`RSRk}(Zft3Hz6OeM@f{>Avb7@#)qRn^6|C|-4NSlOKMkiwHsYLFW-9#02x{(Z4 zPfS!ea6?!7Gk#lP-+@kdi|~06t?vGXQKK~HQ&Fm zoBzyR&Hpj*ToN1mYxx~S-Vb*(cv}lv>*hz4LbbsnXa8kUoZiV)}qW0X-9Wstxbm7S6bO1f6>cj-KPVim4&tU}39zfTjnhZC;orhgLIu#6fEnsyTCFNZwvR6YKxKE{DNIsqrEw*CeY~WgN zvxxGzth)`5t02Dg5A`F8&yA3HGb(K7&6h@nPg(z^F8OP9)O81cb^%tW8lb2BcR5^t zCxHJfPmBzmP5+_Kmi=oi>wjMxhDiWjD4=G#6y&t`5XldbW2-*|_-pkUh0 zrmMfTf>eREq3qHd*4rT;V28XPtEDMel=zaXtdsAh6}FAG6nZC`R9vzyDXME99B4M| zZfC^Yl;D-rGfT4LY7T!CtjpVG*W)#+8V`ooJBR_yO^e27Mdi(_I*_|>=4otQr{Zi` zVu^EqEJIeBtL`B9Q}%Xaj(e3VTSwS28mu_sqGV=OSNG0a<&?2#o3I_#`G4( z3J_fpoYvEm^c6FwI>gVVU+Y8GG8}$K#Q#_ffSUbUae$)vM0yP@m!JS?-rz}KV6(|5 zgrVc1rO8EM7(~_naa!(y+*{`h%$+KNPgYMx1yTXr88_)fEgwCkkL3R-QvyuOms;7* zUbu-?C63X$BA4(M^B%6eJ`7dHT%ePKK27;iPHpr6dRnNsM`I?*s9#UE{By zIgMv9yac$KY{UQi;3;E!8ykRl|1Sad|CrnRpVx4;nzS;iIwqg{X~u}5pr{bjEszih z%Pyp1At3@8HX{iC4HDZ3D+`9j=^4Jcm%{yKQGA^^-T^*~c8hg1)@g0uR zS}}Dmp()mMJD)7en1y1(^k&bqU;KT}wc|91Th#+*@% z+tK@=auuD=){H?yc!gFhbAr>0Qr9u-xxXCcMnmH6ffEZ$Y&$@JRWI={z?uvxNWj=j zWVGWj8k3p*x6_+E780Bm!d&OavaGHNtgd1-5jj(&c-D$6F`R~dl+2vQsVMU3#@@T8 zC{AQOS){Ynm@hR_WjafYDHyQT6yqdlI4)L|j~^Ty7Af-OrQMfOGy_>K%QcO+CA7l$ zaZR1zE~GeEYcg_=3eOuGgtVAxY~5K4Jv0Lq^W6s67MzX6W)37r!2+#F zlDWi*8rYZoT=_m#GY6>QnRj~WrMcHZTT&Zk_V1w^PE4eWVFF8zQXF_%HQ-LD$7-X` zfQBDKxNLFknB*ZasD*S(A>yZ-j#iuUtn_U?t1FVMZ2@xAfa)>3$;m1fdG*+%g6!Pv zVi~~DMBu56fwiaYA7)@8mcrot%Eh=#>=0@P6SAwOY$-F7z|D3uHS*YO&A8V##RRIx z{3+W4J1_bcl+YGbjt!F7XLmLpR~*vcVqS6yz_oWl?kL+#^I zzh-fYY$JX;`OJy|_a5f0w;x`xaI3h3WIki5@q5fQLk?)+U|uV69AWVeu~6}Q#xA1{ zcw5~3NSJ?mf2-twwjH#Aao8V@6!9FGK;w`w{+^#UZNNXnWKLj`2~^;oCv$L+Pk27<|9r-uwfpq2tle-o{ zSvSkl;B0ZFI2QG(#3{v%)IWxkl&GZRuidyk_O&XyBw;!ACI!_+tLla&UBZfdtk#{h z?LOUhqZ1p3gAL>wdOqY>^SP?SgGjetTup)>a4-eUcyA5cHvi#i>YjR;7D%W0)12GFz}|DAZWs5wS0z*IOAB9F?>~KaT3^=# za~^so2UQhN`N-mAVVi%AKB7G%)l^5;&rpDcR3wpsG>8oWKe0j^;1 zt&Z$u`1C{EwY(udEBz$=cv@Vq|2Bz!ijN-J#@4qWwQ0+rsuhx3s5OdD^tsmz+?Ym) znttt@w2mBKCq$TEZW&qPktXc&Jgg5Lrv`q4S}un)fTXox+oIp#3e=2o(N(tDhUAwa7i(A)nu?hWl9Dbt< z;WfZPjN(-ugTMQ&5O9W}SD7A8ZA9#Ppv&*t*@0eu{wtFW+BFqhxYPZ4m_SuJ;lPGB zUt;Vz~24(ZO;>n%p|HQV?e=3!47wyrCS*E9CS6~C6+QACIk@Z>WMv=LiHIK*OY z*c_-S7Z`!|SV5q|iU|f=+Cmr+8se$a=Yr-v8njl8t8njAzbb9Yeml?QLxVn~LP$x3>WJCjim@&oc2}iot5N4SQU5tgkqR&V%vwHJRk& z+_q}vohKLfE0%W7BDwXpRmn_SnHEdwnW^kZ3eDM$&c--6$Y!vGCm<*&Le}!U8u|`2vU3xu-hEX(%e;e;9s4Y_dLBUJ3g)V(|?W;zCNezf%*b! z$LjD(?irKASv)yu`njNT({{T+RiX3}c7s40k$r@MqM4U=zhiamDiJ*NNgF*m;p-*t zMtio=if}Muq23HlVTcd{&5BSC;um~H!M=gcj5`P#kPhbeRWkF^-(yy+wffCrGP$bEPhNN6nUn8bj(ex?Sk@@k?wv$-!AsAkUBy3$jy|{idrN$1 z%e68%+4&UH{`Rl{;p$bzqE>FcDvaRmAheJ3tq3vE z9Ht(G#;o`JRwSw8ov^`I`c)?*(u_M|i!v-TU8g&!Qa;EQi`|m087Gtj&Ascq=the$ zY@;?WJh)tT<_W~cI#_78>x9jXy&}TF%H7jm^E))tYJQG&-eMT0`~(YIl}}uqFFKst z{X1l4NjbmQwUb>wCJdEW+ z5r{S`P>xc*bZ|tX*L?BHlT5yyKYs&Zj}Hn1>4lc8uB!pT4<-VW&XL!dyYkGo9*}09 zl&1Rh5VnA+?!0Zw|J+@@A#yEadmrb~|9TnW;BSAc^tS)nKX~r-zTVh*Ki?wwJZk2^ zr;KdeR=uJC(+D{qSW*H?-IE4;X<%eC@vf+S6U!l|9;^#C>YE9&gcco_T&a-y9*$ z{Ue|kWKo>?q6DFy+9*C-LOGQ?2x`XPIWWc5Lj`a4_6?stPj@faH$>1C#m&^Vl*qx- zxyf#|2vTP|r0a8qUt)KkJX5343x&C-24TlvT^+&I#)E75H|}M)7`<$*Z%Vw$#=_`CY;yqAfLyLvgN4Qhw^Hkado@g z#;AP&Rnv&RZKD?q{$OqI<;!IonA@PT0yr?5iSAsq&h!ng6W!qb*duIO0uI)8_~w)Y zR(s0cKyJ<+*r8n5Gl@Hk568@n$H=Y4MEu@&QIU~b=eC9je59d8Uy}G9UxkJ$({?`A9ft%O_S$VDq*p$#IFRgr{Mgp6JBPS2dmftI zi%m+BUUNcdC@MNscB{tF)KDt=(VZ>gR$uf`d|`vX=1gWPJs~GC7MF_3W$L9Ev5=%B zai*X+h7b6cR9lLu1KQFPS3i!Ud{N%~srI|(p)jmL>d?QrBQUyuGr!3kK1b^k?%H<| z0P69Acv`X>+|F`0AlUaC0*Qb?fA%Iau z9Vz^&Fy>7YN@O-$0_Ma0tHb$5fA_>N>Y=nZFffo#?Q@YJiZ4xV^W?t*(*L@P`on@D z8wTjR$pHu`y#H^T-CrZD04F6CPY2U~_C1PKw3Rp15I;jq&x0VtbSOzl_v}QX31t_G zN>CZ$U9CivkXr3tiDQI^PWKZ{Th9nOUHcK^()#&G|X(j52G5Z4znKA zL}88ap*6-Js7x{Ot1!*Jq(p&)X)c>A)n;4V{+I`HubB%|~6RRh$NCk_3ZF>{5NRZ_V}%Laxc4z~fL+^rM>s znYw+Veyd(~7CugfCXTW_LEtT_Fs07Wn~lfGv%rLntIjvv_)9a=t>YNnu8V$efd`xF zU!eAfMAd_O%G-#9=-^ia3$FU%YM+Pd7C(hOV`TWc2eJ zH!Ya0|78_T)gpEWT1#P=^Xw7I#MAdQPb84&_cc1K7wjF0Hs6*|*s6RxfcqKF3pyAG z!9EGdio;ePYL+ECi;daZRDFhdV;}h_dHgx@OwKk3p2A?^tk6KHPS3TB*AB?#rP>#5 zbnccF+V*2=PK}hO6eeCr;H7QVLf$U*M+7*>NV{%;19krys5x@BtOI@jA5aYBDYA6) zDY=_|r6X8YemDsYa(3CVwC&IbWDxs=*U)rOWlAn~iC45L^4Ba(L_J>>J)hVIoUtkb z&f;F7<CHIjOgt$jacTZ+W7zuq;}cLP6v$yOK+vj}J?Hq1oQ_x}KI=dUQ% z6Y>uf5`xuCAQGA>2E#%p%|bE}O;G%va37?j0M<@9RxHXvz6!CH>!4E?X(R8cSx2KO zTQ^?y$#biM5v-+^ay%@Vo~GK?_{N@f9uO~iQ0IQeHM>%_GM^yrXZAG{y&r66;GtPK?H=YPR-|8;#& z;0?%R0-Bz~fKG|v|J(JgCi|aVw7+_4e_!Lu*7A!6sD9hkx~)of#y??E86YS;|^E_9lvcFnWxZL9ABHs$PbJH@WZxCU3eaReg zWEHTWV%y!&TFzAEb1KWRyj-0+Z$fF>z$XQT69OBIw#ZaL_ttmg_6QQqtE6E37GX%C z%(cAHVRa@a^2=w|1v}KnUNsr5wMLt5i^a3P?&mII_~>Va7z&2$=z}_z*tJDTcC}*5 z*L+bdDQn~2sox|?u|*ifKHOmKttPN|2JVveDW&NIpB!;ZZ3-p^{c?5Pw3T{VmfYmk z8F94|o~E<5-j;{`ooulk)3FB=*z=1kfvSRFqT!z}7;4PXsGw1gp9W})&{qe6L58Gg zF*hWkq=S9aK$a-3ldc}l88$078xW&nTctp$9RizS#T;3ooi)E?RVR{luIF4_tZf7R zrioq$Lz|hlVFWpmjiL?|GVKE}nMge*4KPX0sfhd!;a9nc)g%0fqKWVrJ*(nh4$>k2 zc!~noW}`Z#A=VN)_#J|O5#>yvJ$ z{>e4wwh<*e#AR}aKf9+(9H&QOLX|WC&tUZA&n9+@^zgcU0#(*sV=_r3i7{rk2r$QK zvi_{{53b9T5oI9ED_~$mC1QL9F&2c4>0fnk_=)#m`6dkUvEH-VpYI0l_GHDSX!L+n@Bhm? z^Ir&%zuW$b(^5l>nAsO@+SR|%b_C^r_v>^~=|$y61*L3@F0dP=7HKXJ%(vbFdj3E@ zl(*LINQ$>+z=It3(;Sjx8*h^|0U|bGn8tj4VgXda{#De!vKeFCpP9iKT8d55$t#jh zs>h2vk=w~lY3f7gG8`&Sr01=#RHhx0QI{Q5f88%TYR>$rb}dP*Nse=u+Qyk!>Z(&c zsB)`L_4(#RS@4Ubo!L8a)?|JNW|pjZarO#HBz=7u?M~*g^y>YLKRr@T^oG%}?Q_MO zsc7d;T2VQhspS0lZZb$-VMQqdva_{I+G6VzrtpV?wIM&WZ zO-lruUqI)$ccZ=Ey*I)Aw%_O79?7@OuyZbn!6-C!mb%PfthUs^X4one3H4Ca5-~!} zj(PHg3Ys*ObbHA0JlJ>m6}siyxrS8*`1^Gkm^VBe<>OFDNEht5yYd7f|9mRcT9~4xJ7J6LmwN?bJ`QFakVv;Rbpb*p;^)aqlTlEXv4H zwo(Mg=0UQRDN0}D1=BFs5SKGWc=={*Xbc)ld(Sm2M++W7O3B?@(M3YW6&`%Lz`JYn zFg%PHF!|kOeUq5(SPTh+7AiL~7LZukgCBFOkKDaj=P+qtW7ls|aleo!CE8gBaOXO{ zdU^I;n_bO+rs=;8PQ}9+u^I^E^yw(WH4R?F@VwAa$X`t3<1_%95NZd2wMp#GgE}|< zD23w9d$JGj6San{eA$r?_DvGBu~nGaU(sCxeU$lwIM(UF6V8l>-IyS*8S$;`L?I8m zeyUKffhus5ep)+u(sTP*5%7P9G61gSxq*x)+w5CG4!aQ@`WXV6+I9l~;(;=uHV~_kN)*&l z8_5C)<++g>X>)kcIK=E^5BoUuhoUxQx0htRqwLT3c+dBI_I|tjFxy>+)A7VANS;7< zKW$k!j4N_Sd4Vn)!)#xifwjWLoq&MK^E7XRuzRb!%vo^5RzoX{N9uWT*V1X zY$4`#WAC22vnsqh^$}UdD>6t5nE37K7H|O28YR3wD4d@~vJZ0_D6FDQLw`wE^m2mx zatvipxVdkC>+kSx@-}R58;8A#aU7@8qN@sE@MRhyT<0)z#E~vr zo}LK=>a8&dp;MTO6PD*#Q))6*?<203pOrnC95%X&@n$sAtaben5ti>$7TO!sxrP{E zhqKNe-6DdmdqD($oW|Ft{7F0dy09xYP6{;CbQ!|7weoY33dZO9O?*OvVvshA+-o9d zH>*2w+bNA9p0i?j>6Mo)*-!bflw~1u5}3AJ=H8gixK0~Odb@o_VX?@%kQp6;b=CQR z8)--31Et?l&4ItC(x_3U%@6-*s4xs)C6>WLx50uJFf)B89So%yJTVI8=*)lnYKrVf zx;cg2rpVnH3}4}nY+M#qQ?z+Ke=tm7f1VJ!?a$*KF48Hmd7!EB>uZDJ*DmvGgmOblwJnj;F5L8+>B015;3IkFoz6TWvXX2 zfWq`zuTzj|Yt=>$pghg6T8Uw+syHt%Ba24t_pjliK(V}M?WKRTr3Zyy%Y)=~WAbCD zzC7eonhYH7XzJ(8J+Z0ayd?PXY<~MnCY)<@OJ3I|4c| zJbj;35vb;8@bZcz>nl^3&}KosWD!-k?5?yFx4t2e^h0k9U<_&0s_q8`(Ut`j-YR*t zqLz%nG)^J@Gh_J1k~JA_sDk)e+9vR@Qh^?hq3a&Y=69a8m;*i3Fvo@iBB_!cqup=U zUtUAad~>xcAxv0*&^@5zFHXj_VNM1w#Sw1$Z;gr#2*u5`fyTV|h9E%k$Mi(r+%x>E z<^ET-#+VZ(HS+hC#Ai~X+Y%RdXjVZH^oP2-ltNyf>QSI6& zXxDMdq@$wJYP&MC;_AA$#|9*QXquLrDIqv^Q8OD5kG2pjoaTprV8dc)O&ozRV%?}> zjj#vNxqq@@p^wnf&hSi_GeZL0LIzTZCgwK8tET3yI7v}1M5iVNw|wR}7|A_z z7N1>yk1iI(sMtW7PIsIoUqX6~aVof8)7i{@{#qm+7u$^A zk9!-A;~QJs#>1E~JHDbuJQA7VZ0^1V%?zPd%$PMK@#c0!D^vKDL`N&~>WBqPFLOHL zQB=WrXueJhoHEvtBh3iiZ6kcYLKjjOfb)3KOl23vOi$k~vgp4i9r)VIP9w}zIwGMF z>zptp_WhUE{4da(qTSa1mHo>H{h!A#{69he-?|fF6VrbjExueeR)yg|_LdZO$R%tX z31o7Sp@=25rdbOuw1Imh%xNcZQXJ1$G`X;xujBUkpVY3luuq(xfZm97*~cU;uYz!4 z$rwDRCdMXwZ_m#z&OSa4BR0Q{{VHUL3KHP%%}aE&(C#-v!7GgGjaTMXy_UcPiL0yF znPmN6hHzt$fRYm$Qro2c#_>Sp003!0@&*;;q9Oo3$73iS8LdKcuiBrdv27S4 zeNIWG8~I+0&{G;0^YTz?7o=v4z0KLOoEKoc!Sa=|L9=~z-m0^+K|rNpJZ#%yVv3SR zR)C9@&=ZGW2A%~ILkbPdGzOyre68q8!!-Sw$RMpeR|(lG(~*L*Smy!3QMa)f zhfG?4)X}=$0;PwBDLPO8({Qwjw5L^-#%F7xgHaEOaqEtc?jp;`wHI0Xd=U_c5=3Xt zMZ*=1MW5!iq8KA+i*f+I_B!1ZX{7qG;f4b+2BLx-WL|3dQ!9W2p2=E7;=3bEpz;`` zq+;(J_xwx;)S-4ZbsLHsH1;mmO0{N3@b*S1e4O}HP27UzdcfT7&!%!_xdiA82En#; zhr65|?zsEqbz24f&=O3T{Q&xz9Zcs5>Z1p!#}$~gda4tff@Ah3$#tW9Ww!dF0LfD? zyIIoY=$pnZmO(UxXp zD-$I2kv%)q(hccE$5#!g8^v`Hn5a5P0|HwLJ$Zt$*B&XmPtt#i+hfCZCIh6JT}bSc z#l;_JbevBgUJwv1lEJ1x#aD;#?1%=j@D+Nsz?pu<0YAetS`PR71*IQv9=Xb>OsiPFtFn5TB5NF!p4LxJzuv?BqV*&|&d zS_`6npnt&K2^2Q137=r}JlGvO!Ia2Ai`&%v-n7JD?~9#luz7a{0mwv(+c-0n%8_6- z&j^d2EcYk!CRuJZk`5H`b}m)3(Z~7tlzpm6-)|pp2J-dMzZWxz_lbti5ZmrzLdW9@ z7Lz@4C)b8@tJZ|UoNd9kkt>ky6=VxL?@GWZN@Vp=%b3P*Omj*=3TpIXOZWsDZJ|m? z2)4>Hm{N#@p!eg{Jt}>I6XdrwqZQHlzs45A!iDOSa}%rL&mkAmzKHI)lG}psu%fW| z{mZ80UsZ_!=W9d$i!?#`s!Z1ZVZUzd{8g8n{-y*l@-Q+tF|ztcDCXZ30|t&}PIN-% z2DWBj(}Mqo$?BZzqHwl5j*YE#PsucewAMlZ7mB4CZwn><|ap2#HZ9?Sjt}Ibh z?xCPWtaKb$ZpNC8!dd>xVy24a7svjpQ{;W_^}?~VI|0q^XKYND9T?B6k92xK+=Ka~ zmP=YClMK?#5JF?V_=hkvd=AlB#Q^3u{3o*HI@Bx z8*a#;=P!DG5^%B*39`LPj@B<5lb;8nn{uQ{2(!Yg2Dt%=`c_~AnsZVi)mCK8l1HZ# z^)R^{W+n>vok*(5`qHlB1JW3NXjHwf-Xc4O;lbuRCYD#yDjcz1)!HZJNP(}5E zy<={SyAmWnTa6c7AAeh~L{rgSI@_s*Tx$vYJ-h~JUZBo#voU21sZpM74eLqs!3Z)e zOh+n+5e;BsLZ^J18A029#>v|qwUb;GPbmV&91|@Zxv7%R{B(}!jYPK6H?ZZroI1r2 zL7f6j>f_x6r%sTH$O{PWb*m2g7L z!^QCC)=_TeWmjezxGAX62Wq8KK>U%4QdWyn{&kl7zoF=FhrGYP^!^$^{Wl=>*na6yaLm{;NUbyE;}w64 z*juKnK7C`8FD%O|F5zhi?*p@_cVL6X;;PG1ey55piDmyH<&X_c>m>;^`oJ8nBM0p^ z+SzU%@$|ZYx~beXe=%~G1;E7|yDR!N zQn|s5SQ!#7BY#K1XpfU@CHk)G)iv17Hw{v;(54txf80zrW-=$oB#I+uLB|+>;W6zd zWPuUcT8rycdS-0dj4u6@#A-w}CXLRUu;Uq-NrBg_PDNFTMA;b@Lio{LT_6r_NSYWS zZTLJ4f1kII&0844m1YO&7zyuOyQq8Lq)9**CEQ%U`8Z>JiDpw|pcY#hz#zOLICC4o z(`4*ULT7FXp;8hA&rcG_QbLdZQ4PlA{%I$Q^H|BGaOTPBr4Ie` z@X2oUDNPD}8sC)HqYwQX(Wd(bU{xv-+Nk9gY^k_{pszj{0bW+-G&RTx-kKkW2!Yu# zz%BHSej)6)ll_mviESEpH{}d*!9d>La`k0?!8~tPyHN@XqAcoBaSO=X*Cif202(Ks z(D7~n_fUA0U=-Z%G&Vef^f%D7PLmXwGYb=FEvGp_#aO9cKQ;0`Ez~+4a^rIK&_C41 z;9jnu_{KD7H}t2=ACUj-DE^vzL}alek->fY#!30@8{2<~KQSl!zw)g9j;g;`q)PQK zldnaWk7{NnIZU2P2!HiH+aENMFiWZZ>R1u{i0I4u+qAy%+4_CvqG@b|{GqGtjTwDC z1+Fvb#m%-hMhVTO7B!$f687sm0~WIlVQmF2tL(Y5GesB4{j4nSlU{Q9(_=`Hfn9Q~ zm$rv%pVW_;PKWc4oo_1NsOGZ-)}k(@Zb4wsehu|^jcmzS_?B#o379|CLVwWU1wB3D zXXJ=q@-ep;Zu8w<=?NfjcbRWUEF4w%J%MB_>XOlf8%I(|@r8lX>NE7=VP@L2Q1&Qv z#Gy=D#XbAM%7l|7m5NF&z|;#zM6PmvJRaAT3wrjarz`x_nwQ>IE-lrlW8{(>pPtj^ zD3=_#WoF?EjUt>E%~k(h8U$t;r>Xrrx#aX_?mpnRrjpdJr6Nma6|BDVI**JpBe{90 zdg)*S3)|m$b5S$YXa`ixjfzTa6p3&HfY+$NWlNScp4Tz+%O>-^-vKL?@+Y)5F(KfQ zPd$~ShodVmQSYMUhQg15oJiO9&Xbx!z0*;mYmubLstxyj-vzfzSlE%_(mH0PVEJg;hYW(8jSXx-OdmtVX!J_{TJ}hsbqn>7iw;IQ zMR6=o`ATSDQBuFK`XM$Ro$GJQYFo~w5zHQ6=|N*q!&%{*6BWHVy{IqxFFPRc>$+AER1 zRkZVMV(vOPeZQkthj_yGZ;08*TcD0Jc8Up5h1#WA?rG!H^RKvMsW|A^7O&pbHA(!L zLSPV>k41R!ZC=1_Bejt@4r2KhGsv~6ZEt*-BV57M!+tZdl3mT1wyvR_kDO}2S>I|v zAwA0Z##5Yg=!vKTGJ1*I!^Axce`V>4*8nADD0DMYr!ty{DcO6z((#Qs-ew5mYE}%O zq8X}p%97)vpJVEgrJ``|kjP(-j@JqY8y$S+xa~)?unm5QFAXolx<{6Q`cI*{-l@$YuZwt+=xv=`2H<^0+jMkt7(i zjCR68bFeDx-VKfMYdi608-umz*P<_jmOvP~t~zHk60>h2gt~~uiD|M*9m_$9crHIS zp~tD6xQffB{G3D2xkEkM8X&;Hri`m0h(;lfZp;Wd*(`@(ZFfO(nI7`IX;eRQf$lJT z=eyW6g|ZGthcd7-BoBd!o)Nb#wzCN&vEhu-%Vc8xX?Xjhj0R#0MWwDgqq?q6ey^1k z=AD(mfTosGc_yLOc3)D~t|qMHW4V>mq4mohDU;Q7sPuNTqvabhs@-Ub4~eDegkb*4>^eL!#9Ef+GYo4(E#%RJ>P)_YJ9|UpEjl1>76EkHKYQ?a9=eMr&W!?e zy-()g28NuM+4t`TbcB!JwJb4KPq=c$NwY~-9M`| z19i>j-qX1??$ECF$fr29!iQ5^`qZ>8eM>qvohLEmYNPfyv=-^aXp@HplXZG-zRx)2 zK_p%8;>nA_cYQEfn?;(HI7QnZ(JJw_Se@X#5?RWTUN=!ElD?sPQbhpn*x1Fu_c*+i z_!v~J$8sj()}2OcgM&D;>|05s6c%h!47ipy9$Z`9uIePkxq+b)Coa}3jSjD4(EX20 zs-*e{BLVb1%#Mx;Imf7E6If?4SWcB3v0CP9FpMOYBrt>{L%J5O=u%*4YHwPqIj?v6 zREB+BO0_FuJgccAg8EMD3I`JRW$xOPi#}lF9b57@#G6+Sk!Y z6Th?uaipf#_qWZ%iKA*bf=;7ohde8 zK0Y8bhATv7Glhiyc7(kg!U%2Xx~!mYt6;`$@Uyj{9VF_}r#0E&em|*Nov?RU-6KBx zuXGMn3kiUb6On%_-{eNn^;N?^S;-PTWzqy^BG!LVB3c+I=MxkRi(WH z2NcK833$1pSlHHbD6_X|!_IJttBm%9#Pg?X;|H+-$lbxxFEO4RbELv??E5i6lv4@w z@HoI=oJlC4xj|=hL2sFdVW(- zq;Kx?BJadjQ1JrVZ=}n;VnEIoQc%;lhLG%3Rr10O0+8d}Ml-&E9nF9_A0N+MYjfVB zPn8i*Q3Ah{Pu5sVvSiKF^WVwqXmIXyWS1Ew9Tv9MInRrTGtuXsv=XoyhaCVJYjVcE zXY;EsxC5mn!|uUb@G=v`>b`Etk!Csl`cV+bN{u&gH%N9h8B?TBiE)`D0@E8{Qa0+? zGRi2I*WQg-0fk0tj>EH7Ia^W zmi*>SokNtoi)8q0vwD!zpO4F0EehV(?=rgEmr z;5Hzu1md1E4CK@_rHsf6td>b`YH{?ykYgMaC*69k?m^f44mQ&NK2y8Yw-e_$4wXM zM{LofT#OLDeDw(KQ}n*9WJkWn0DUfH5cg%NVu|`xLPA~X!OfI|vFZNcbJE-el-G&r zK`Haroo0ty8I}mTN)gwsngKZ_g-tAO^q7ygpSRN7zH5QsgZ~tJ9E@gq!TNQ#gs?w~ zcwM-B^#sO-3F`OBRxW&(H@6S(*P zt~?a1czhYV-gLRjfRv4aw^4O&k=EqMT!z324&VYj| z?J$)r9o{gdEFH!0@pJB9$qmBAia$0yhTj+?5y(`_y`Gb#TpI@1B4N%CYvM2rl)xkE z@9#3kDP)yWoYNOrK2{_@J*+t*Dmk<%s@%kEIF|0m_U-2RaztARlNx3|5u31u{AGx; z8%gDd%>s1wFwpm}?mZCzW)Zc)%MfKiK=Yx5^MQ=>ktSter*q$}RWpt(GN!AV@GF{j zYAgX_%3Qp;P1~U>wh^6aJ2d$xlUvj*?x|~?-N?xLk{aF2#7>G@k-=m6?g)Chb-)!% zo#E9A93mAulfNEEWTkFx>=JbRGS}`M9T#)#RoZPRZZ-kZFn(p*z)^U4H1i}+%N>Cv zn7X-0AIn_is7PFC=cmRGl%3n@FZ2S#45K3}tLXZi=1Dd>%Eu2*%~=b}J+_DR7vxrE zOp#n1Ya9VOM#n@4BH1^3kRz7vk2Wj+_eUi%-muG7lOto9 zAitVl(Y<_*ho=u8e!YCRTHP&v+nC`H}q(dv6N{_AgE5 zSNAR8&d2 z)-Oy1<_64+@HxaQht{-8qUEfbwyPb5w!bX=-SbLDK((i2;y7zW+n3bhvz-9-ejsh!Qs zZfSKDDJKv#c@r?>^vx#>J`7{8K|x2w6^q-5$GxU+!p2cWH{~JGk_moQLK=<5p-wc| zh1VcOTp=ug1~>pP0WaG%lk{CwyS!{h74)j`rXoNMU!}r}(h$RGaq2Y??VtPDGkSeM2ulu{iA0D)(Q9O(tqPB;T5A~sGV@{h5 zwooy$aTaRRD=H`mSM)X)dmu)BhJpxm%9hw;7m32FoZ=m8P2?u1;^-n|NQHr=9mPMz z?N#9Z?jRaMMLoJ7?e?aanh(c*kBR#e#ms`Q*4bFs3jWX|%6`WtM`9mf_=8mUtoy=iG^pHMeHnj)CvQQxSy9q1PkDNHq4$Y6yv?QK_&CA1K^~f3V=w9FG z01?v#PN^XZt1JNbzCODh1MR=Mm;6O=-`2%z5+U0z|r5aUMnT;>+1t`@i)+0$&JpX zNkfhFD-0Xx3;K#~!mz_51WKm$JRHk%n&3$|UVI!R`-y~&KBYiM6e5Z+PWXT!nT#{s z-Q|ex`U7KK86M9VirY8hzj1s zf}trn@LEwS_Q+`5e7@>GScoTU7XHI*WYGUcF!w<4x&=7~*F*MbO|=)vx9>P%8c8nU z+F(kG=p$RHESxHDgV4QWegnA!kv0Ld(nZ#r$OwKck%ra;ySat+j2$(NJkOXg1{iSP zwGp)K-9L$HbP+1wN_+?Ur^s=*k`0PTME6IBuXs%9>@K6Z1Fs-QFLH`ynro)2s8#1J z?1LcxFM-BbR)t(k)1^LDLuC;gnK!6&4-so?WIH1=B)722{>(V5ElqGWbv zCDjA?d~Zhok5b|K$A25B)_wv-ihey+>#r?>|1_5CpONTamNb8r8M?o+T>tBN{#)&- zR9^jZrGe+kV0W-wW3{o!4g9uGSV+=~co(KDu0oDXp&Xhg&dvEiO8tabnT6c>?V4@7 zFo}OBPV$RdK4X{7^})Bfsc~9PV`3t!|G0l$h5MG#Tr41>A@r4|L*87vqe?tVxuCpe zI%Eea7bu5bmvm41OYzZWf_@Vock{G`hITWRCWJczW|J|ih(g4eOqRr(3^=$Wc)u<9 zD!^6_bL|4tMz0kp#fLVka|@i-fYaGd;=+-R`Dsu-UDf=|vG~<+ZykfvMWz#A`)+W8B34=H{pP4SPlgJB}?Zno{yo1y#UOM9sOuABF z&c}fJ$ZF%g1SIZGq?ot`v7?#KAnqo;wN4;r!0l6y1Um_4@b>kyM7|C&BYL)67|)3V zA9E!f-MH;nJ_!!4?J8@Ghd5eHu0mSsv2l`IzJi9$=A}dgACkiO%<}5TR>v}%3o?Da z5z38j(h)Uu4<|gQGRSX6*~o%K!o6ypS=tHT+`KPqm#bjuZXtnF#ehU`h4x2y0mX zc*3|Q{zvMCWbx6y6%%SC)q=_`C>Hl5XE2OPak6u*nFXQnXvQC#x$QiHwz1L4G4JJM z1C#|uNjoK{e*ZEl`AcrkU4vXj)yjt?CS+eRd0q)+itGx02Ks0Rl8 zmX>?XS)qpl?T@_MG{2HQE6+|j|Kpp?EN-w@dAxFiVP!3?ZSm^GZ`zviq-#Irfy0p} z9ivxlH{k_53C^QiJxV`5))hRop--W@4Idyk8LK)e%21Yrfc`JL z{Kr_F(E{?^63)Sx-(xX?%2pPSN>Mblq#iuuM=*{RKrws*Ul#w~-F>gld%T1>o1PJG zp5G&&e+*6;sE=)N@#+ph^OXWyrXIGb@Z-Q;g)U+jr8cKdvniNx^xR6bM$q9%=d+-; zKU+5$d_Qy_-{l_V$WEfx`zR~C{6FU>wQ+(}314r?>aY3Tf4Y(NZ>ap|Eam@-%745n z6J(@7{&I|)Yg}mb_4CWy65v6Hw+l}x!$$_A0gG9+nM)iOty_iqpyYvs`uOIT$iA#f zv#Kbv1{gDCoNON^_VDua1*?fLLE{*M(ccgmcmYF;zK@`-TcBewel#K91qtqq8fW~a zG^Nr*ubG(3URfSaPg0F2Z=6@+Lr3lrkY^2_f>L5T>2r$)sWfn3p zVxrNyC%hoz&&ZQi*Oku_5jPsQEXl{8mZRD0EL46eoO#?xFTc>em-1wZyO;(Jj^Lww zyeRj|Jsm(BoWb3Gfjg|xxy97Q{bi34?dLOAS>(4Udwv@8Sg0n3G4c6{%9#1?^jRw^ zM+g4Oq2E+(9Ae%#%yjdvC8r;AmmrXB%?cT9lxp3X_7fqJ^a;H`;|kVfwPo!GV~X67 zm-w}kjrT=FPPZ}HCH!X2!C~8tQtHKCeIH!Ga}q5#Ksuh~^oEVHn!WuE2!Ht|eGUBS{+g=&@ARC1NCy9XTfb6eRq?AZ@d#ZQw1@~pghS{GHdjCa zW6Fa9DFmqN}r>}!vDS0=(eWL~&1s^r*8m>EArWVKz4b*)VE41!tEydDksPKn%-lI6R-VDapadcd@21Rx) z_#-<4nxS}sn*)mkps#NQJ#3TP=IuJTuiEpdj_Mls!!5;tYF}b$3OgkNCn3P%*^NcUig5DK*<*>PID2_2S#<%q0iPhm6$~!UIJG>A6D%e+ zOkc2vxI~4?%=VAv{hr0xQu3~9g62AnBbXdLN{yd^^o5TSpbDlcXIyl;@~&th*PI z_QS0!nh^`pFh&obZ1Cg2^n_4vH_apB&r5kI-Tt!oFswVXDd=a&pTk%ZyCf^6%uMM* z#~?L4nsd2H12y2fMRdQFp{IhWn57O~H$Ac|PR*<2+;D%>u0Nyr6NQV0gE~USd0^w< zs%Z7E6~~vu5{FfwWHp~8_!4*FkMDx;A!tkb32cF2et$%GiM%3Xek99ttdCh@>w87I zZ%}AYYOpAn&rZo#jxAv3Zzs^s57jy9cY)5sGE#;qCDjR2Qel#H)zPinHC~p{6hbFm z#oak2VGeHHG>_OSsu-f7n_m6b9h|@Z=N_W6{`h@u1wImf`zHB6ITHNMsPmsLSpRwm z_($`s{=-{o9^)%j_guz~j>LvS9v5mTU+ycRy^^pHnY;m+0$HG_&Bj&=pDv*R*eQek zaIKF6VZ*XmzeOB%^w`^Ky;YCLVTXWAwtR|=Whzzb4$lJCy zWN$SQ+OB&2KLI?HH}3Hv9ndXWJv@|9==Z<>g#u1a7+te^bD2d~)KI2V_Kde+2pR{b12<4 z`=Pn>cg&tz0?bg}1bdt)O%2*$y7oRiQ1`*GeESp7RL1(MQQkyFq9|^qq!0c;>8dIW z#&WjzZf#PqSL9_A+`A{Sc+-G)4W6#G=Wan%KZE?*RK7|MH)*%W_$b+uqg1^z2K%Vk zvH`nJj6M>?-FGC!x%ZG0Ycr%M^;GR{@17#_3>Q;rvJWYc?SM7 zOegF5dLFnocMNc4ZX<0TLs#zjp+j@KfS*~n0sDKjt6nz}Gq8?m_w+s^?G3!lA0wTq zLzh$lDlqGfdA7i)cI#^6Fog0C-G zdm|!cm~y>pnxjAeez!P;dMh{Z?2KZ9{q6}u(fq#6BjlI)zg75-x~==0Est@-(+Ol+ z=u(^a?Om+y9|B|dtowL<9Zk@zKofClRKRq+aIpAcBN(*dyp)cAT0aR0%Umcqhn&(W zXFg40b5J8$5mi=Fc|zpEm4A*3Y} zn)xR*d6x3C@J)ZE3pKPVJdS=#BzUh1=ptvAJWfolw?OO=)0c5bhkm`>z}5;#q-9QW zea60*alu-F_8Z#2jR#I=GWab1KoeM!($di_MkclR6GD2B74@Nhas808l$JvXYNkf@ zL`CB4Phh=+y1s5f&AhfJvf-)*Uf7NOeYW$-0sxl&5(h7nnVpDE5^o$V5N~57gQb-` z+e9k{d~9J-bzxvQL(n>YEH&a=l3~nE>RUN^&bmh~p(zqGtdUVPZ4`*jfa7JJa15uU zqjtpxMNF&8qA)Kf2l;r%?J6z@9449)LA4!lCleQ$SL8Sk9n z&tTZ>@1f6|4ChSCR|I&d6VVrT6)9f1!F+amVSa@9S-9ijLGS}Yoe3ep%<|oY27>`pM_=NEDU3Z3aN$AZGciX@BB!z z?Ua?YCZe6y#m8kOx$Tye-g()Um7Ef&LL~#mbL5R;-A&Sb#SE13wDsMGKgof_(4K(9 z(JLU^hGvC3$)~PdyfpwQYudx(thTm$2U2rWtpxA2n+_AvyT$Pt5rUF4>FAWfaR{&E z;>e^tjUF0gIAGkO)hU4ZACGIYDXYUSQqnVh_6h}I2!_P-mlAdx-Wqvf(b_)qaUs>b zj{PuVP1am>PMcbA7oP9&QY;LTk$Xq^KQ+EG1(E(tDZ3;nt03j~Q>3%2MCN8XDvm;D z*jA7Zgw29Za2%WXm&PpifilD~wvdvB8OkJvD*BiCqtVMGhB?Y8+gs0NC7z8d%A%@! zBRa7pI75taVfbdJ_q=fPX8?4?)`T&czB@`5t;J#E10&6FYCy5Sc&O%Mt|%d%2%Q;p z@>j@;Lms?%+X@|0FZI{X%*l%N@640HP*6QVV=xQ)5UUIv8S&sDKtbjgG3`Z=@DicV zaXs})Q6IU`cF2nN2lbZ@`s%W$qCQBX$d05##ulD(jadP%K<$~HgUZL%1wwEXIpc!I zhU#azUhaHSO?se~h$#y3O=C8amb51ht5OpNfAlBc6|hf}Fz+j}PnA<&N-EN5xyK6= zW0jmC)pBz3t;4Wy^dy&>BF(Fd;E3*ahL`<}vJJ2rmt(@{C%IP+iu%Fj;zmDwJ7yHr zo~%k5wrJYGb;Npb5^FM<`>JDFW*$Ab2DRc$sNNT{xKydMko!Z^s8%)kLdB6Kf}T4` zk=jnVSgNF;`qbHCWr;Y5uOo|dd$H76V8JPOOWaU`oZY;sYWOC|!Cg6ZfxMB= z`{0QWbnWm^L9mdwls$mWNjiv0;2ys6AIewoO==ANKtQgbKD33XBqx5Ff(Vuf2c)?x#AM#aiP=y{ zCJBwJ&MYEU zXQdDewql6i6o#LiUi%(*1(EoSh$T#k616vCD9ale>)R-bc;R=Puu^%DRrsgw0Kb6uZEm?`oiDK z#rS^CtCjFA-8nBXp6GFW1|4Sq-dJ~VHiNmpL^avZLF_4I+twE?L=+7?FxvC3PC9g( z@vg|Uo7{V5O^->qrP1K-$~-6@e(r~wY%}N8omgkh{xj!{PC(0y2lRwN$yYzk>cbPJBNIZwr zMpL`FhlHN2vrZ&Di?j8=a9Qs^2(3g0fD+Rf5C%xo@%TBwM9?>8!U<1(l>@hpmqxzA zG-HPisF}o~=~2`3DGbI~#gqW42GK=93Y5n(#qvLP6VcDN4fY1NL=22gluc1hFGwsH z3(#B)m>Yi#XPm@EiR>^khgwaMH|0sJg%|F)QX?5KN35$8T!=(8;~j>F)JS6YdF(h; zAjs`_UqjQvPYR;Z<*BrT7Q4d)yMy5D;8dW9)yjJRyx%c$r%t=lw7$}EgiqAv%4m)^ z8_0_gHFdrw=eMGEL>43)P8UhVc2G4&%A&1vAZ3MDWD&&$kkn8tmFOn~(2?)qKjr;K zK)|H-bNzsM`N~u~G^Sd98yy~g{yC)eWTehK1&d?>`@pfDT3gm&%_pm;sH;FqSi%j8 zMN&i`US6@D+ERv9PYz#xQ%=O5aOQ>T@?2jUwsrQNdV9p1S8RwbD$iLfi4>#HBB776 z2=7fbUfoZwEmq~^!#y0?Yf;c|+KUglb8H%|tUDB!W~(fzoU%h@96Oq4U?uIuqhVMY0@*n~T74`g-AUjpU}a+{evEtS9SI2hQj;PhFNS-6qS$F`XZxhd%^Aw8}`F@B(Glc=c<_E$znXyKr_ zafZFhpRo0qh((gu^J{RprZT$ z&BgUELczrN|FC5K?@dpo(y%1Rm+CKTogp3F%`PCM?-$I@IJ|w&FJjxcpMw(x^RQ__ z*%E2}1cnF;-lwPY~?!LxQ@f zHgSMasH{R8MHPLgU-1_~?O`LaP*s_>$DB*LVoro<2w_l}S%j>Rxyjq3K4H5m5Wr*p z0lR9g`_htDi?{2p0ZDv4A^kD2-9fw_uVBmvnez8;{{v0*z-ID#x%>cF3!$ z(nfG)X*_)3^T9~Q8jgC%=RR1Wa#kz9aA~B0OHA8efdg4KkH{V(jDi-jsc;)M#N-IB zzvd$h23*U0E5F+;(C=hVwE$g)ykRFGlCFa5zOX>}CBljVR!lF!%EiskE|N+Q)|J3^ z+^{^#P2kGF|8{}I$JaXv{rv2+bJ#`f$G^k$+_uLsCfxLM8RBr`-$-wiq@9(tFGk4# zJkXdCnTyxvsP1)GZK0-Fjd{l>|F)9sOphz5LBf&)h@SpX6{G)EAT znZAE|%}jkyNsh?%QxzE`wTI+By%J!etzexU_oV-g%V9nSj-nN=d{GSeiJZ6Sh?n*{ z?3=5B9^}#Hu3qQc}@wZOd>Wh4&f3vQ!5^Q0N6+-(D7%*A&MWjgpFc-;Y*DP=+ zNbc_fZPP5zZ9UI!Nj->z6I!JE#!zoWs0<5k;z~1R15KPMCsnp<=n7aM z5#i70qaH#GN^$9`W9>z1e}#di$e$Z(WM{MuhjHJ+K$&K8}sUxr}NlZ=s!x3S;Ut=P#XBLsX9m z0yFYPc7qjdJ+A|J@(F~6&kkRjAoFDuN*yYc0{m+l|JFc`toif2{-3F( zq%p}@(_JuCoJEO}d*P}x>=tD;Yo7;Q{g~8Kxn7;r8KEP~Q(s-!L?mHz+#EH%$Px z?uQyHfLi(kY1B}{aKrpXv zO8=8(M3h@HNb~DkUwM&Ny;FF~D$jx(R#STN^*M~)l1G_sz2eE*$L^J>1!y~nkr9a5 zaY$R-Asdy#0-~#*wwo~CPNvi&^BN)%9BvsjF1;>Gc@RnWJKzpLb8{xR(57=$*-b$wbm6KBlcTl zMS@R*@~wWhLq)MDQJ_j{GoJ5xNXi>vQ*x0A7Y8P1B9^g}D7#9Uk9+Ff8b@YNYEUqh z7iURF=b~gC1$cVHm(}mKg_J{x^-Qnw!d)YhvAB2hfUbq;b~fGswS&MpBA*Oue<_LN ze++k&6IX?~tqGp9xVIgkZgFtI*@;1RuEr|JO(_L@lAcuMYsr8p*nJsKoPbps#H3pQ zpJY~-^BiRiMk8WQthw*z5Zk?Rop3NaJkvF{hyBqGDabs)+S|G6D7K0oVcxP>T9R-{ zycwMCd(h|k zoKP~@22X~%I;*2TcZR-k&hLT(XY`ZblR--7d+9vn#fASH8zyn^ z$1l~JB=C3HtWJf)VrNRNp0U(?-E>_2VJvLi-*6RQjQqZAs{LaDDa!{3?z zG-bWf`XRF_w!3033kMTElZZafE+d2shy@u#Z{#`;z|XoTgfN0tZ?};juz;Q|6P<~| zm$eALCHHV2`UK)Mh{X0h$_CBacEYy|a{tv^(1!#oh=gcHyg}rkx`PesKq#auzP5C} zExCQJ$4^!1_qrB-6-DzyudCcJ>f}-9#jK@ld&v*!HB7bS6>RXkDO9G9$e-1$5LEl0 zj9=SOa1PK;*1Jm|m|aQ!)~-7Spahu961ScfsqveN$qN1@oBl%V-@O#D;_EDaa@-@w zP!vYT>d=TSZ%k_l4oYSu7Z*5t_;x>Q3ZMnODF{Th9)ute956 z%6;w_b@M+M8Ols&EF4`pe;}2hxlRZ!V67!yt&BA^uQ5y?flB`_7bi7GyjeggwHYt- z$ck{)=&xBHR_9$-J4DX6kP~PZWNyh;&qUJ|L+<*PL>QxE-Wsp+Eq}Fws0Dywd z+!Eo;((d?DD|fu~(OiJ$Eezj=wI;@VO;A)4yv+9j-H26u6I!t;0Z&v9jBOUztymLj z7h$Io&c%j3L02#y4>6Xu(fDY}8H#Rs72&=2q zeNTan8cgZhiWx-K;PP2V>cCd$-b_^jKM!cy?3O%k_$DDeh4|- zLq3+1)#c1RJ@f=><;7pJ<@${?jAgTy&>}AAldt|(qvjsG<_i{4t)p}Mt*AVUSh}c( z0-&Pbv7}i$WjC1C^QP}>aYqZnYrfZAeD}yf26j|{Ukz<9L&v%%P3yn9P}8v+2#jy; zSe;ng+WZPJ%$|MbT#l|s)H%|r4j!a0CC85P7JK46 zi7cB+a3py5=taO)Wu%-tKDMtX)T`o_<>aB#Bi%lTRCOi`#*1dey=X;)Ql`1=1)0X4 zYtS8VMAc>BJQsa$HhJnS>jJ+=+j<`s^ool;sX1q( @ky-e}JyiYEtG;7E6YRYXr z^(mMI+N0FI?TzzR)Adzgj2L+E%>`FZ(NZgX#7|~D>yhxP7O5+Uvw%K2bU7o%jRp4YV#?Xj%B>;w}^iXVU|S zuUHLcX&!Sst(TmJL>CQ6sqW`>RC9=|o^6QAv2D8V2##}3pR*`8FlnIDWcBkjRV|mI zQlqlRyclCg1{@4*@Glj2238&PY(0PVYk4n)j_hG?ia`IkG9Qny05SHkaDKd2B^%ok zFukMwS~L^!F@u_vcea$krLLPS=(hn1g(b~<6&_KXDwl(FDk_08@BiG*<*eVF@I=xa z(SpC8?FqyapH}jdgo+MR7QDg>hJO#c{~IeLZg8 zYtEPrD{qhmDR0CF!I%8R7<))fu-wRhe}n>-Bk~wdEnmiUVSlPK4G7=l9f7a^712B8$@mfSmi(${Ji8~G`P(Oa(|07k!B^B*)?4<+!Vz|SzAkYR zw6x--{3S^*(()S+KCj>&rDw!!(^B9!5&pd{v95pypEvYBg*w0GtUy*z`l^5-N+rPH z_3z4A-Tss5DETiT>wiymOyHI8V?YR+Dj-$p91Ye$;D&^vw~%caGOru@@sBY5VRl#Pb1`%=IfZ^Ric}^gpUSt08Rg-0;~aV;NO#U4!NP$ z`qj8}mNL(pOaz?X3)a%8(q;BcJIXM+DIyZNo>D7|sy(`db~h(pjGW4`_&~r-VbgI( znL+etfGv4D8{vnEhjzi*-kUcAOk-VEa&H)i;T0G293mma5{-r5Pt?}Vg}QoNM5pQr zKMWNLsEsBxaQTlz%_)~a&f}T1&It$Ep%k4)SKvs&r`5ZPer43y zvx^mV_l}cvEIi-)YHFpP?N|D`Nco)Gxhu<@J5^X?PZ9r{@HINwp=|-oN`+?+O0A3# z#*&+Jusd?Y*N``+xk^+_9B0RPNg?AL}zN^KyPO6WD79EbTf6L z{r6GQI{^O2!RhyW#KqFonOd5bYI1z4j&+)OmU#~L-Wdk+{tABQK#G2pp7u(nMs{*) zVQie5j)HbpT9$JAK#GQHL`GVM?vqr(0r~-25n5sa+DVdWVbalIQU2kT)2F`-aDIoK zSRiZJ4Iu2k0;EBPf3su*sB3?dm;Rp^kcKXXN&u?|Cuc*OKXgL>9Ps?Jr27lI4@h6am6 z5+NyWkkKvWrPJJj)!KTPa7kkov&{Tg)B&9V+6y;O;lX=cT$Bfjh>aMjL3Yg9v1G0O z#rRzlWvZH$YZ^qp?Ih~@dVA-l0pXJC5CE*jr2nef@+FH>6~#qJnZtMGUYH)qP(8p* zJvX!jK_=MUjT(r2EI_q)(v7^V>M}JzRf1`~D(&9l|GSDt&>xMgr_Cn%q;)&l) zZ!wvE8#0QC=Q$dik!HaPwX8!)lfG$bvE1ob*aDrlnrnehO=YE8x$BG`Y6I}3VW{CL zI~Q2SQbAzP82XmGd(b5xj2E}RdPmP0dtT7a+Gf+n1DMXV?b7=$-4{I$SMp{3UprkN zA!5e;TV#5iFQY3G{gJRiCkOhvMHMCrU#Dcb)<~KRV{y3Qz9{4~1`7iSeu8}Rq>oph zGDvwmfv^)8-|Ah^LR-Xf@;J1gLDi@VUxpLHR`>>`MDwE8hfFNOCNblHBTXO=93w~y zL(_9$LU|-fU?{R>3!^?j|IBm0dxTRSyTx@tz;OTq?(gQg|2g0kT}_=l{~BTyf8rsr zngDpn2A?Li3g2eX+5BQiBvfF_0+rdLl?_SUl}y+d#9t7{>GGYQ{kF??r9pE5!o*;; zZ-E}>=|bJ)H8kTbN9!F&n}!!nTl$^A7Ta2wbAVtf45%~Rcc=`w#iCDeP~0O0kp@q~ zbec7;Zk2zGS>sc0yLUs9Z14&rSG=%a5gP_uYWcBls6_^poc^ zn>#Wl)iW)CINIsq_TAW%8g=HjO;d(Bxv7uEX#k|8ZCrNW?ie~Pr4K47lKAIn_3U~0 zVe8ycLz1?;6>QbXyodCi^)E5!3Pt-$=NT<#M@(v%f%4gYRM~QTdi~e+m+FuEx2ovN zd;PBG&WFK%)y$SBcw)P&9sv(qdk2oG$&an7In1*MN%hSfXGS#1BfP%X(=F({rtTlF zJw(SA@n~Su^)_=qk_GX?Il$w0F|}rN2BYP#h^|+l>=gR%!e=aFYelh$b&7q!%e0;l zKdY8;^r|c{iBWtV4U?PIB&1eQ>87;emPbQ7bN3)@;_%NH`nOs7AHr4zUg>@Tl#GrsT^6y+$<1Cl z+I1mr(HIbHWYmPa^!-rk6`N)6$F_1%=x^WorMyFjT+#g6t~STp4ex8R^)K;(sCL|5ePU7se;^Vv&EPF=nOqf+kMo+S;M5;Vz8@g>1 zG>Kg`)hpr?)Nf|El;h8aN95+hcgBTE%V!!B#8goaFxz%N(cYdqrL0pH!LaU6g8F%_ zwMJCBe2i||5AK;Slpx@d0bh4j5;(jCw>QL;rkV88T&!@xzF=HuKZsu)d~K0S&4j^8 z!RZieXTs$JJVKW4Qgwp6s>P9?w58!|ejQs{!&_^wt-kQpP<-u5U0H#} zmSmg0;YodZ$o}}4e0Y1e4seXWPT8T{}9a0!|YMtzLY;Va+a!{>Pn z(cz;?jvl%D)Z(o}mmM=k{`C2UlVPQ@4FnqAM>XJmYz zu}>QY=&_>as?P=CnLP;T(sr z6h`$Azg#eCCVZn9%m*u@-N1Xbfoo!38_9J;f95m`y**D_MDwGBKHLwyid8Rdp+^4d zk6flBKHNfOa(hrPTb^R&oeAmU#M<#TlD?Z2p}?t9r+~yl88@}9mD$M}of~k)(0z}Z zW)&krlsf-a75c#TYrs;UXVYjhLWZ}AQ|h#=b}Kh#PB8h%#5%*zU4690Gf(ln;1w2^ zJ7O}RcYWtqaAl2(ws!Ltd0ag3p}Dayajr((yon7}JGa?(_(f#hZc1#LQ3y79l~tr^JY{4)dQA)u|Yw`vV_HbH@hNo?a9<^@o<; z50K})?9b3dgBP@xfSYXw3Kx;X;!>az#H#01cKFvMELnc! zm*9%sq&Bk+ddHcyW$CnLDVkD<4~vq2qa=Wp`oW&SVB{;pB4$0Px%qkRt>V63gZ~k9 zbuFDIa1o}alh8VXZPEIXSl$fwn~|7uqG3GZg;k`B=t-+g;b^ullH~Y&##EtH_;RA+ znf?a2wx1}9v$I(0g^7>97|;Af#y!TnfIWrn$7u{AoKyihFpVaQnYWgX+MtndM;sHK z7W=%nShv^@d7*prMv{m?*}B5~FG9w);G^OS_CaK6Rect)jbbLa*r>w0d#p6Pz)I@N z{YGaYuULFgkr6YG3Br~tg!s9K1g5fjPJYcBte}lQZ)|1R!FF@xpk#&IBCVioWt2YYw;9u*q)d9z zAvMipV`6=Qv=y3#RZb-uCA)P;C0ZHOXKC>_@V@o}jzk*dvB}b$ou_!uT+>}gjzTJy zZ2vybm~Uzm1nI%W^`GnN&a9RjYXlm=gb%Rm zt=6;w?|`KpKW&!o*w_!JIZDh=KqTx$f*IXLvo$Ro&~zWE<4;Rd7zI zO=s&xuxWQLnc_8GYyXastdkw&X{l@Bbyhlu&kb8MCF5pa1@&VQk*vE=C%R!OLT_Hl zB0P6H$(cwZCj#6KuD@S~7!eX2$v52HtqJ1G{@tht2}GwI*EtIhbddav0`Aso9rG5K zNdc~z93T@UE@ql~C>x!LYuG@ji?^{IlIBW=>x~l(SMxq0Y>Y~nO{N~@Q6pK4Mf}{^ z408hM`LRuP)~#xLTS96@$=x$5Q+PwDR@|Bc8eRS*jiL1O2zExMa4EL3Gvr`>fRPyE z6ov#;5{q)q?mjA6CCk(Hp4`_%)xM6YlN3ez4ou^8h-1D%-;$RxkGxfy&$7_Uwlsp> zRNMS#g{3DlHx^2vDjas?VBK7QpFdqWOt5CHS2?joN(|ha&@z`+?=o6JGJ$>k4oZKx z*hD`}&rK)+qALl1G8k!G;{7)*E+*K?cVy>N35tl@feA=);*F7A&NQrQQN71ndQscd z5Hi|Hz0Yf8&=vQ{W#%--;=io6C?|8pt6lTc0v3+M;#677zs$xx1Me_an$?6_TcuWF zsm4crZB`%Rb!vfjr_RV0(xRxPZk@ZTV&BRrNI(AUQoClvp0O4GTtLaDl=W-oc(PM3 zseVzSKZG?H?R6VQv<-IR(j^qMLMC!c@g1h6!_aK6*y{N1?Cf&?QhtmjE zyJkWSv0gP{aUQN)op#B)<=Bam!$k|!+9Na2+pGfe7NZBu5=$C4vcPOTfitc-bdcJi zpg_@+qOZ?9^mGqns6Uc33b^H0o&u*tI8T6FHcrno}+@Ddx`AQg_VWM*06x+~}& z3OIugJ`aQ(ul|LRh|~*XPix|}nhz*4DxC2w5ZO`-Cu70-Ms!IsF2}DQkMY*e$`j?l z;U|4aS}h44#d++%M9e_4>4nj;X2K6bkQ;XQfVDOTc&mC;acH+omz+q3B~vzgaYCEI zY8!W5A*V0lsGat%ncA_qSV84;h5Q};6z@ip@wlP6Thxp+lysd@jy}DmEULY5thYeu zLg2;^rJbf>zN^YuL5EptP`#4MJxW*O5`LZ($8$>oLSw%9A(yL>M^)vmQHyF{jfx(! zd(yazV(;DVA23FKpj7%9M-?op6h}J|J(i?#9=viAIgKe(ImNW)*Pi!CEzFwvFJrMx zX(p>f&&-H%5%u{NQd9I4N*}=>nV*5KS*K1@KxP->zUAdA91f?9&ZVVtWpqoU8z%3* z%E6=~baSs{y(sz4j8Ft7SpvuaaSL;5;Zwd7Z|b6iQaR}no#8B9(FyRpT%jlV9JXP8 z|IbJlV?JM`gW-tA;YegmsMTmDr>~~}ePBDrDr5CZ@{OJ3iwbbdX zb?MA;1tV7|$TWPgUNY4(bJY(dWY*1xpuAV3>Pp=%GQFc6I=D!OMxX6kTghq9@P-7V_kIlRJh;Mj70sfCZ@m!|TY;(6ty)F*4dqWY z#$UQGcMy(TaI&=>eQrA?Ja3%AC`=FX$W*z&p* zP+LoBg!Pue^RfUwdm0~`Lsj*vzi2|tMINhj`cGp*Cw(!#ule6t=~Ee+HynQ!|J33& zWDw;^k3G>0JY-f#+>WUOYGcxq0cKCOmb)z?*LM#Z2}1 z%TV1HF+!89pW#<>hrAQ;=}wLK?r>9eFO&UsMA`MpjUlRT(aIWMK_kNsttvqr3R=ve z+Sw}BDD&glujme2VwJ0fNNTMcNa^y_X3j{TlbO56;IhngtkWFz>LmJbIYOMVbXdz!_t%ooN3Tuazk)^YH1j^EF+a0)-s=C^s{U@B8uA`| zIsm)TAi!>v`+wIuN!nTd(Kr3klB!#KVGp4CEG4x!YODzYuE+`zAYgIV=IY1*al1;M zFDnvpgAU0#&aqKj+Stdq1=c$`Kz9gSQa)HybO?+Uxc~S`7IOqZjx@ce`&f8BXKf_z z>ku>w;%{;?bKhQYUS@D|KQEEve;{`Q@r5CF;`Q-)3lFgyTO`U+PeP^ubNaRm2nvkM zbJiS!p@Guinj0U(S>T1{gebwV;b3wT8+_h(Nibd}sJrOTGg4huOk7MHV)Y%snA~Bk zK?6;4@s>7wk)EvITboS-yw(u+6=)~%qC58$ueW|VIan6bqi;7n;Dvoiu8eW{XReiD zZ6RpZoPt^F@9!rpLLxZ83UauuSFCE)MoUH|nbr3tc+U1Gb|W-v^6}xs*1^h3cQ$P{ zDGO-Zv?^6+OBLj%I1`mrRnb&QJ1k0^NuAK zXMm|etM+4f7)(sZwB_*p;SSrjcE`+iFi+*lYBthyVV5+5DW{*^e$x87{m*MV;R>rP+zs~q31olEd{!tGE6bdUx*%Vu-gU&#lho(ZSqbXtk| zv(wI*@#OfBnNxjvLew05>6VdPl@;p>Y;tyJ-LSnHnUz$jI<)DYth>w3i#%YagK@Rt z$c5!fEfy2BvEK)LLB`6u1ui3_WCpi5PJ)ZHJzzfuB1chgHOEZ3hJ-y}56mqWmn$7Q zDi0}t8RUhZC+ZbGQ*10EY-j`-5a_%E@dh} zAqn|5m`Q-1d=#;7usB|ld*1Df&7JS(5I`4UlaL&4puKkb#MtgP%$I3FG5jNx?7AmW z;umHB((!_+yC{sWo-cB&(6A?x|_D&w}YDi_}L=gSp1=j11%X4uABgVfxRqovZy`E7ElfCN4*! z7WmT^Jzx9TzA;3-go-hI^2ab*^96ZyYUY@lp;(*D9C=sSN74c(4jq1hjls6gA|5-CHyX|e>(3z^>iMdZEnjia=V*AcS4uIw^#V_c+vIRM?9M>w0>}m}X^5_{a`xKR_fMB9GkZ)5d$=q=?GxbYe)@Tt(;H z%L#CdK}Px`gf+A7mQXwFS~V)S1GiGMzjLFaf7|h?8&1zgd&&6~2oDm+66BQ#aW`@# zkbJ=DB!=X^k; z9!AmUTZIEJ!a30mqA2$QTp#m9f@ic`v7g3=}|Z225tdNFsFS)D&yn~Ohul{I|j%U zQ-Y*^gf@u!Teo20o=wD62IhmfF>&cAW#!<%j!x;P5IT0k$(Ih-*1pKDhYcJ(G$XB%* zZnhIHrHQRYHJM?JXJ6bBJz)nG9KG)P}faN zp(c@UvR~-ywYc1?W6{&1Z&jWG>vfzR)?4&dpO#Y@@MfM+)ieuPe0md|GpsthXS-#K zv<;_<<99Sx?+$ix+_Jz(GewBjyA7esJ}C?mnW4p28@ZC<<4U3D3YvJ_f>r07uxD1{Gs)5# zBW|BoS^>OJMkn>|EW;A80uGE(+>l4ui(m+akq#3mjIvuiQC9+40C9jE;=2?k<{9ym z9{i3t1J<@P^WjSJ-Wo;sszy|Ntk#EhzaH%%3SgoWoLAGhM7fNQE<&L zrb6#efRwQGs`U=%NR0@MFU%-!K21$4>#xK9gr3DtmXT9ZUB7OBfQu zT#ej&^wZsJh2+em(1tUU7LJB83tS5qnti7svs>hQY0ZS%Nj%*no^w4s74cRePJjfYm#;E zUh}2j=;7SZlTZhD4bu2k-G^ZB!P`^48CThy%Avcnm8z>vQEQ&+Hgs3OB|hN6kYF5C zmvq3X)4Dg)f0WC<`*q5Fus8d2wtRtyi^SYvfFn<`du955(N4?PlIJ3DA`3C_@P)oE zn!-V7iIQjR9PcybxvUuCjapuH8tDx;`~cKq%Zh4x|CxKTPExu8EaHc`xtiR9Sie{? zV9B7lZ*W5~x^CSH8VOjVC11pGrrl2n-0N8u5;|GrI6Z%SO_a+Z$}7g7=+2^?i7EU_ zN>gbRd4GrV9cGd8Fs7hE#>e-*US#rJaxxDg_AFo#<+=F&v+c|(WSQu0f>2;2CzXV4azU^l*5Ii*Y4(S&=o;k9@0 z|Jox=7<^&?0UZ4U;LGT5AN~IXJN-|F)_*#7G$_hS_cNgU!8-lu*_`)p@lbB3IWO^8 zPRtS+ZbZx`nTYd&e5aQ819;K`_FF&ch{85y3_O_aH%SQXFX^j*RNp(ND4~ypFbEi8C4!)H&WPABz1^CoRp#}Q{5|| zQ@dI8)VAERqSu~?1^2UpT4D;yRO6qY-jUjASd(?gW zh`AdY{)uSNfz~LTabEc0mL2u z9dQ=GbOLM{0e}2M5}`8jn{t6iZaEu}Fgu&{k-doo_XyM^(vko3lPGNrl@dGw&LxTC zaszP{GKG9UqFiioKgg9r$hDcEB@$sy5^n_WUg~A~_4xD9l>OGHZB8CK!A}<`+jdY) z4pl%8(lNKs{=hsYF;&zR>v;Y)1*>K;)+s=kmAdq1kKqub%MFq%WO4zs|js>lf;eVXLm?)l1Vd z*CN3uW=C#xx!#q~x5AVum|UHX#$R_wW3;z~mGG!wfR9NTT-|@jz3ooubl$>%Cq5lY ze}-i!40Wawq6-Qe zq(}b?tr&pp^P98l^#6h}C1L$nOv=k63!;3`&L<_IN+G@mhiNsSm?{XuW5GA7gnk#1 znUZraVlZ%$S7cIEoYu<_MSIHDh2dEcTEsOioH~ zeI&p`(-=JByIYs-hezG5^X=Q_ecMLnl9#sqH(R@v6tFr+WST&2Hap|VL7oc*Y~zYi zp`Qp@#HZt^IXdt}C(wh~ah%vZ8t5Gtk=RHqk}Tx$rNu z2;!UJkH+$2l{ zWckSbrV_~~TDyPIbNp7L@jC2c_y7X?{}?}#?O)M7AqU_`zJsgX2geSGDj=eoE|>~p zp(y5E_saWe#sFRP#CI@vOc$DeVP+2Bp}Z@U-|i6!AuA6R!|Q$k^89T4i;fHuZ%C%F zthMy;rL?g0WvHsE4T$WTAW{y-#9&VeE7_4$c&!Je63de|kdXM+QfCM@Z$lQ*4_ zEr-!CtifRFr4zCc6<%0yZDCn?OkVM4Dyl9#4kJ0N^9TRlpxzCv+{)B*)NIb(5}HVT z95rq`{{<*#7>pZ08a*xGiNdw|t+X3|ds zYrqGb7TcX6wm(0zEv42G{-I>zddVus31%Kq^)O7K@+tNXbdPl;!}X#nG_PCSrPmx4 zPbwJdnP}DIoAS7LZ(TKt`ymUw85eCm`Zxt|bPnWD-aN1Ti!4`P-7qh+afxYR&F##`i6xrmfh#Jmq;N*F>h2L9opB7EOgf!rS=(BMMBYrg zDEkO=K4tw3$bL96cXgQlwAyRLJvh?9dI>mJSc?e=B~tHxf(y9NfwBo-FdKH0f2XW59`W&tKa4)hsmtsw8r35nOg6n(#AURrHc z-vto!2!Iw?^Z#GP@!!Dh0j0*DDP13s(h)vzRiwtCG(bPT|0AU<3gWYL)}u%QP*hwOVJPh{IU>cjj1EPX~jOFOjQg zQ<8XcxY9u6?(AYNiNxa{{=TAN+I9h13}x%eCL^=}Z)Ym@*$emxO6^Jzcfzm$N=m#T zzealQY;B*U(y7YhpleZ4t<#wg2szs;S-Gbv(azbLh{Yt4+DdnLFfSWkqZP=)+dS@mHS4Y46*oVQPl@6;gq z7R`Y{hZ9|sdI*<0%2Y|cxek9pZmikg8T(7*bhzgX`CKZo4BXL-YSn`Yk|xvrZs~*r z|7&)RTP*9Q!blEFe+_lP?K-k*MBirdcV-TY57DxjwdhY;5R%Hrxe&wXmggVJ*tEclD-eG99!ge9AiLlQHcfcyXjA4B`~15e9h19#Rjtz)t&^D?|MVLB5S< zEtVD|#*C9YJQb8W1o?IOrX$I=;{Tc6>tSORuK~Rc1)y&EKgcBfhl0=fKT&eZJ-;n~ zGi7y(80iW~E#u;pv>YYE`|-BHOHouE!agf0PT6Es)FD*mZA6y6qe>8vzILW2C^9g}M4A=O@(nV&xC zva=XDnN$JVsspC3xH4Wx5si8uGaamQO<|ET4utrVY>|)Qt?>9>z(z_swlWR-EEZ0S z+w4MO$o)21H(icDiTR|gn~Q2;bc*_d^~D)~q5rK*4$-^Pas}V(7#5!P4B@&TLjZVr z@N_-dcUR!#k0W6OkC*6>AY)q;y>}ul#qLj?!1!C@xIEmXVp+H>4}uri0_RB6cH1XV zU;KQ2K0?PtW6W=}tpf29O#87heohv3fM}fF`v&VC4(_tBjXcj+j`jF-5QMz$=k|%O z$4Yu1pZ^)Af$0s+sPPt#d#p6qKl0or$zzBzUk`28?ej@<;QW}-myneTgjt#ZmrSAd z+8ExVm@MrObu^={3&X&e9|*PS#usmYksbfevNI_i-M@A2F#wMW>%W<0{~H|U|I9Iz zF*Gu@ku>?w$ct0_ZPz27r<91 zaYHt2OR9(HaU0@FIFvbgZ~m?y{o2&r&FzrC3-kUTJj`vVb+{ZT_SNk^SuVQz^^aw+I6%8GS95c_I&vu*st(Ej$= z*&7eObctIj874_5Pny~qhOi6MX?JB)%=|o#Y{!D1E9(xa8P{{`EiHsCR=ZJ3`zSuT?Wykhrs)^|6JGUpBG~JR?VBN#bE>E|>Jgyt!tG^@I@w-_<~^ zr;P|c#<(!spV+^`ku72(wmItYsK9R1`Am|%FN14k!0~2-i(mugH4Rx{t{z@7 zS4WEq2AGGSF=U2u9gB{UXav(~AuUsY=@}OWH%bHdL7-1#@U;V77OB9CN=y&kv574z z#*kdnj7dq}gv6ub#j;Izg)NM+weP-yM#3k0D1fqCVO9xt(QFRcq>)oRsui6ZPnhLY zH;k9Y_#r`kn9+tbeXiAou2qHKt?)ZHn7F_fSd@x66P>vKOHuo~TU)x!0wsn90>Z%i z`vbi{5QhJ_6AM5n{I;zBXXRR<>E(^GfckFd77sfX01Esml!(Xx(iaty2viWs4>Vpt zGc?zNTQbPRK>y5s%){dyupfgS*Sd*F&C*^1#C^qdW-(WXKB&>tm~^p7c=vU z4H>ddahJZ&QC16pTiE4%(Q%X!c(nE9#uDh42Xh4YId));hrsYrpts<#4Ic#OzuROwL|8zsYsCR}!yC$?f-wUJ4?BX-1SIWjz{A+mYQZvIX^TzMt;(Us+!Rl=cD#cnzN*m4NIxl zbLO0$w8r^^y)dvguns6v@$SSymLyO@S_D_KxY8_<|7Q?Z;LvmF##wDvB?8saP! z!~-y!jIdahHXFJ2bHpnVnBnD%6?#DdetEfO@chW&OjV4~Wp!q;9js--n0=8go7Nbu zxyh5|Tc1lbX013xv?pL3!L5%NA7<)FD+7D%$0OeRCP}VET!CUgXRO((Xm|$K(u=xS zU7{pav5^(?(ok)-c+%Y7=nM^?GMS{siHyFG;S1*I(u4UEhwQP@SG}cB;1R52tUA&B z>87`xs=K;bi}YysVZE#z5pA>t5jXDhDD9<;rrh8Nyy@b!eGMavI!lILJI{&`0!%~G zU41S~e@1{Q%qKWW-U+ZhZr2-3V^5eWDwN}r^UwQILUwpbD`W^w`gYXeW_Ohp`x`8C z+vMsFL1p!?_m!pBE32I@!pIww^8&Tnr+JD5kTu#yI#aL4UYX=fSJkP9z$25iapu9a zXx@geOywGMa%Nu+4wLVZ8sfK8HMKQ%w3quGI;fLmFao!nKV&K`49)PK$rx9&#zpE% zQ1FvxHrn&XBme_R7UOY`%Xpt^HYmgHL+IVz(QKH!K=&~QBeFHbXwk;2 zObu_hjW1%CEXW&(yyUo=eSwMK@Kf`~hjji9VRcFIAJAL}v_{L3UrDO$4p(H@VNgDL z2}N&#P#5u{KuNeDg@w5ntu#VSvC;x{h)h~yqyt~Ex)f8~R|A#%?60|Dsi%u`B+tux zO|jJSMEkIGDjD1~gcLMfg6JjsB0ai-w)Wt$-b1)qUnPgL17E?uEnE?CvAoLieMG@q zc}Rv(I%@~&1iQm`*Hjr8Ghs5{1q8{~u11xycnh$!PFL&*Ki2o&3F(yvCD$a$uKpXYG%rU>M{(P!>j_gkAEt zG#&WRU18BM=u+6IbsCBAoU7m(DVH`ICts=@8lg>@MAzPtg(hq--C=FV>&3=;_x&c7 zz&GwQ4N|1tqyvvbVkc%~kO9N;h&{g9Eh7e=<*!_kA8yIwQO!HqXoC}M&UZ;h%X!;^ zLbfrc!2PQ)Y-TMj_L=;rv$9OnKKewAjitPlTb!Le>1_w(s;CqPRKZ*wXJbAAH49qO zz($53hg~zct%LA{-OExPUHT2Rl-9ml$6N?hh~kYQ$rq-MsP)$R8Pir?vTtvUPZHry zqFR?sJg6HLLc30Z?n%1eb(k|1bEZ=dVdnw{*U>tNVqLNpMNpe=VWG`N&+-=;%3pKq=3LC`9v{!8! zp4emvr(EP)qnIZ$lySzaqXibg;qxRUwqs~t>1G`ve;gy%h7Lkm$+VE64zC>@Dz`P`E=>*RlMI5^xhMwpsm zxx6wF|E$;8KjvnTY!4#|bOFHhIQ;p=92`Us~_Fv26dT?)}sD!--9 z6n>tdq9s>Y33khor#M3e{t;LFO0dN7{6I7G@eVl-a#o6 zs}+x0F%+lELGjUj(=vKK^j?1xj1!A<{Z8$acC!B^`tZr|Fx;tdYFd&GI(y+?D zAHfi16R;sIsoe8H(kD@iHr6pYc|-cqLCR*xL`rRau}%kdM+kM#M`;3O7#jfQwY zpX^IyU3}1ocs;&{mJGrgkdrZfS3Wss37CfoSa`yyC}jSDZje^mBf|=fUdlzIZj&7J-I%L;?z+MuLSx4He%ewuk0q13bl;cOz4&j0Y{xBJvTOMYo zwkA>jT6ynJZ?aEnZ&YmFy+7U5L3B!baqriC*KztT@C*_0dc}W|vqf6t@9D&TEvNsn zo1YJtr3;B4{CNkt=c>Tu!~Z&iJ9Gq+%i15wYrj5tvi12x=tR=2W^S58@&mX9%>2W> z8}#j!H+tfeG-f#w7X}xp`TcN5xvtjBg3n7$Lh? zw{oS$?f{CA~^6PPZ99+c~AM{$890kgwU5HMEAKPXRWkf>#6-y|vo|wSH2UmJcPGX(p1ZVf!i&GtOa^ z{yyt<6a;)k^k%o-n{mLrHIhL9Y}J!IQ2KE1qngCQ)}ITg-*4)6E)!iT;0^Tvbkl!# zX89-P=D)JH06mVSndiTZ3;vB5`D0M8{7(WG2pEmpz{5*}uuMuMcAim0Xed;x;>r@! zHpXgPqroFJD;6?3!0*wteQpumDi;Yov*qDF%UOPMoQH3NA4sE535`r*d72G!Yoe3tffEZ5uzT_%uVh&tYY_!spjjE7b6%V~(Tjm*toIj2LcMQ4F z0az{@hKoK;BD&m_%8tbHqaYlRnu$CnqPb<$niKU;@XSK7sy^#4hAyD3+l;#B@pXqP zk&k9Bx6GPXZh02H*qf|9=`|<(S|M&a&@_^#GC%5cEby>vlm+=Z&78ts{aqBq(gY*w zeFqW)?u+4@pZ(jExi~wk(n$48A8a=hZ!Ss)O;7++6j7wnP5dH_X@;AaSE&Ppo2Vf0 zTYX`l5f*rb*!=fTFhL^1!vot!FpHJ3&F8&Xm({D(ZWzSb;9CSMu#;aoJy47pn?*LD z7IZZ_L~mr>*vg|2%>b>fB|!c_ zcnO-An40{SwEQQ&OIiE(a`HXMuFX}KP7S38yB(E8F1J&VA>g}c8JShuBgY1BcT5M% zoaKW4_SOu#1j9ANV;+q8Y5{-%Ec{?N`7`~}JJtDqYO8JwNY8-ud-MPhDh=3`!`2Xp zIr>+gyK9LbwI$59O`uZ07LvX<#Sf7%tj%L~oE6wIWvg)S$W)|?Q(02x>FSX1dgZqP zSEVavNoBfn^Ab~D4EwL=>oR?1s;xSa9?gJSA{M4JRhw0}Rxvqn!%<%UkzdCxvu`Hc zO+DwAejTM&oGS)0kjJspf)_CZZmx9Zb2U;j8j6~oE zV~HzrinEewZmsZB=T{lKpM`BE*v7X$o*k?pPH(U$gG z?6Pg!wr$(C?JnE4ZQFKrvCDRs?XUXG`DV_{jeFxv#Es0zHzWVdckTV|wbrwq-#!Nl zAV&@yL8T#@BPA>$o}fUC$cwvXFbo+G8p%tV5`C?{fJmrvXI_C)44TTHl>OtwXVCU% z5zyJ7YZ8mQRrnt2)E+`SJ(YSey+qyKnmw%Nl7M4mZ>k_E%Ew&~P`Wa9d>S3t-F3C7)=i*g$bF=$0CO8LrLeRIK~Ev z!IlFr6Na4`&6vI+^NP5I>MkYf)sA%9GbT{38y0O z2V%acak!i0VlnA6b=X(yOL)N6c^_ok~QH#M}?MYMzSg+W(ywyfY zwtQnIgDgJ3nz4}4EiMxrQ@rwLPBo?O8v||U2cc@x6qc(G%3=qjMM90yRbL7@SVX8Ts ziFQ!WWj2N3xjbfe53$m6ivf{_rZ)iG;j=u2s%CO>BV*e*a1LI*2p}pJ0PFh3RR`(m z?d?urf=UwfUQ)vwk*HM;0OP%!HQbV=KrQ+9F`aied!I&jNr5^~qLB~FrgRVb070cT zm0`3MDa_7dWwO9KATZbhqnOXeM8c$pmo$JI4(Xe>6RMl7qiWh$oxF6bP)%r}YiwX3cBS?&x!PNba5)cP5Ld z(os|nD-M;=MOHbM$YiMDH`)lDBN42YBxm`WbjuJ_M<_EScRwRUZzmPgH(1Z=8D>lM zS_`IkkP9dq#*#oQM2qEBdHk;JY#;Ee0Q+&TtV5&6(c`6?YI3%_>3tw_(oXklw9{_9 z&_QQs$Te5lzutz1jJoDCB4k_2`}1e(;c6{PC7k@uK}%~mPtq7{akqr05U=X(8SoNc=Nejliiz&BKQ^=9+f`bZ}! zn8J`5(6(*)1v51)-RatD#Xk+)Q-Kt_VV>S=8l$NWG9X5-%cE&YG%_IIO@uXo~dZgjBL$Z-Gox4#3eRNw2{4LL=eIWySX%(mM zg3e|v<|OULeqQXyJxyAxP|^T#VT|k5W4oj$CRsZZhcK9K^31%Z&^o3}k&;IA#1>}z z;a0?_4-o;Uv;=rx3Qf)T*e?q|d;f#jrJK1oxSuJAb*%d1=UJen;caKEc9th?`my9#Es!#)A_h`XA!~&2pK44B0cS9&=BD&al`HBGFm#1idJdvC3QU+%L{s}qYkfNX`9>_i1LvfWS* zK;~Ry+^uwtCqm{ZUTc7Z=5|U%1hNSB@maKqxOQmmJ_4lwd8ONMt(~-ygK6EwZQZ2W zcuZLD@w9!*bbLcsz$7U!8sZjcA}J&ryO5Y6MZY3WmrN+6aC~Ebn4KT6U~~!D;1#gV zwVt?OR)lGj`TA;SVH>LMi&86N{GWcG)SjS1`rp!pod1Om?SC@m6zu*(yZ_gPXLPuf)G{VHmzVQ(H-Ok1@=$DB3@0yWqqIi*(Sc2cjY)#Q zHxBMTAt)0ll#oA47~&sU25s6F48|#gE&6HJWBgT5?>PCoTwJ&!kkNB4T`7e{FS3Cc zAF?CRSTJn&?a+H=rETV7T}YICs1QK#Bi7ER% zY>u{NAbtXs9pFKZ&SjQnXUUGlf4^NF`mbO%XDAcMXoob!FI&z9@7Tm0(23bq=3nK^zCxV#=-EK+0icCzpGNe1YsqTNFqDLG`4rZ}F zVG~+gu(VZ@kqznm+OiDio4s?Fb#dZU zv@nSIbatfgHK1prFsA#3Mm9SZs|?r2`^yj<$+%I%9x~DRLICKtO?nF%ZGMl_1TG%0 zHU*YmnZ{@2n!zw2=_i#kyUc_d(&9Znk4X9was&vK;+8X{kCY3>?MpD;Sk)|AL!_R* z&+v(aWB3?b7-wc&Wnc!8V-9jHN%XM;4wEv6pe0EK{adb#I-B3Wkca;sMSJ|`+PS`i zxd8UxPh0*YpzVxJtm#w@tX)k0OM?G5mOZU4JpZrG_wNZ5Nd(=Ov|1*Ewm8Uf)KS4o z94JydS+G7R2~`X7N5u|k>v+*-!)kP<48=o$-aDG_9o!hl+T#faE}sYYCwc6wbPEKt zvQmWa*yY>I4ENRDmMN*<=fhnsz|2l2dkp@1^k5sN7;K?}cBBDy3}6)1hbQzEg$ZGZ z#6u6lurf4Tvb&UzA74n9=e8=5TM~115!@cgyL`EuQ5)KznB*6GjNG*aHkbon#O&gF zgrTSpg|I@DAf)r^(yxqt@GviB+O--SXeejmSQ#j1({932>)bjWk3!X)_)i}l0Ulh9&_nPrKB(B6Pl zF+I$;Tj=7i@L2=miPnFanm9$f4oqK3K}p{*#NRCF^L9+kw^}$aiH;Z4_p)UQvr3_} zfsobL;>BN*s60V*1WO{wnmCAz3);VH!ixp zJZc!lk9oB~T3qn^c$~p_t*Yk+O_Sfy?v@+cW}Wy_rV6SUQ+>2j3l+azCN(rV43bIS zY{gnsVY(W+iz1CSXgq#UK5MUt3*9;L=1}4q%p~h=;wui0>jmt?;xZ=XAN@z z>y-fv-&cxmfoESawagTE16nr-dAr9QpB{!gyO0*m{7tOlg}D*2e3rm*aXhlH zL3HbH*Lj96ZZ7o4%9PT*2$;~`is{V(%KSX6U_pq}Kqzin*7AJaADd%MaSdp&+Uv*( zNP_QTCw{fT_k`pX$+mhT7iShkmZhZckY-h(%u9JbXQAiycBpglbJ=+__l8?c6M8#b zCT)c+&&EJ@`SsH=Gjw6(*r4_()hW_SWqo<115h_x--!-!tXan1CY3=;&S?I^aa>mNhK7en0A7@^BKFy6#+q#pSu|-{_Gtho@|lOJ#kjo`MN!o>M1Yt zikPL47i%s_QE6#cK(r|C)V)@zuk1~23bQlZ$ZOyWlY{9uENR6o&EZtHL99$lXJ#b9Vhu+7j*Y)%DHkF*g`muafWKoN6hBwkgg^4e$N!+W9cv>Y?06m zPR1QTfp?BEr5ppwH%$rpHQWp2c>M9(I>sKSz28Ef2|<%{mII-y@MZ`hf;&e@@^~?B z;*O5po$Y~$kjnibRJ5++zBRv;vcC-L1j~S2nT8^&(OC+#h%EUN1~`3xlKtKoXQ-wW z-%~Iq_4)i8hhnC?e78Lu=BxLD^b}Z~y>27n$ArTe2G9MmQTVHliauOB=8fWeM=LKp8s*KMOPplW!Izez-CKDYZn_!@e^B zPu+*OQ~^=AlkXIm{SUK4!~WRO!>2%BZ*u--yp%yP;zI~NUP=>Q)xgf{8-Sc4GN5N- z-r~Ilz&}6Z29+pzk@{%ce+QQqEt&y8WAk2(q7|K>9qvgrKQs0yM%M0GIX-tp*ew@e zZ7bf`yzr1=%vL_fL|j$0F{5q>Nr=L`&T<12ZT7?o+CN6szD1ULez)qvmL7hgSmjvKdv4Z*uM&z{iSWJ(Yme1ryiB8gpGuc2%zVDG9GdRs%(@@)>s*t@-Fr z8#;3lgN;>lvMojR?xuSz_M_D^@1@bCrrVE(ZlN>UbKI(Cm_eCAxNB&lR$Hi|lQ3<` zJftEERn1NLj_)zXaYL3wC`#Y5U9so-h+Olwuw2V$4Br|6%$#95^dg6K@zcivg?jwf z+=Xi??pabldFfLp2{Y|nR0Yq%JK4waNfdNXYa#z7Fqi^xv3Z`zdS**3CkHs@g&3mromzjpeGmWoU zmc?^-Q(Jyh9rHV2twmeJx0#T_VD9w~g!0{4chNyTdzoQ94H+xt(2(A5uYu$O&B1L4 znL)nmjDWyQhkVL5H=fkOQUiPy+TKsfc7KfgZb;0@vn;v@Zkw@jU7saU&$;e*tdd}* zAcv=5#&ng#k?QS+1VOg&HV+;SvXPSCWzPZVwEOy%?VUr(ZD|q2!fR=)I7B3buT}95 z#CA`>O;MXnC%Pi5k@kYPMLWMmX^XH}ng-MWcxKQl0*+!f4-2B=*m+8&1~oaC=a|~V zTRf00wBo*rG*E1KLLx8dj5rK54hw4x%I2M7r8hE*N^7c&Yf>4IncwECV14p0LUuCL zrhPtvwITB*#Jb{ zYWK#iNGi)W)t}HO9Ncw;@w*bO*l0!mZq!L*Jd@zzp`1xrH|xmVGfndAK-;vlmWB3T z?|RR2?{46|n1a6C+@OGzr z%_qRFif>c_QN;jtt4s#Dpj-=Zacqcs zy(@zPYaJV=#Jt^$u5p*2QT?S%yp@GwHxto1CL*hS+hppY*~qPRD0myxsaiLUvyQsS zFaG6~4xg8J3SJ1|g&s&d-*IXJawPnyGP4CYTPyC{nVad3+>3D zHSnQ3m14gbt$~s=N-yfZMP42at}T`r!BAaY660sXV!WHVG&#ptUK6qXJIAE!!sQut zu>VnIt9XXqN=cyeA3=m(n%HRbs2IA<9ix_|4?cEvsO6538Q* zxy}o`Gh!$sJSEQULbNAPd+77J*gXuQALAiXP=Ku4>&913LSC(rd%+^TKojmLur0b_ zJN=NOL0G&|5N}L}{@sh+dP{O8l13~FpNp~=?)F)KSKX7d3F2LJ=x3gZq ziyiX+W)t}zdEtLy&i>P7_OCkq|54>o9G3<9CfiL@z7^~RpxKS}x4Q?%p(8T?h=vFO zZZ$P;8n-@8?;p~;q2fkIg!|j+tg-;ll8(xUtF5T4)a|ahti6hr13+V+Aq?*Ze`FHR zOBoTs423RlaWalXP8cU9PtkfrTPv8~m zwd-ghz}bdMCLqmWa7n&^VnLfole)1+Dm9t%USZIdBgYlLwQWBRmvGzLbQ%T=aHn}8 zRE|`~BBC+D)IE4(*CsFUxop;~qyDEPQ4(WlNKV;w7O~9yaXC;0wRJ2`~+DGA&NnC&e z965w^IX8npIYycZRmbL&MIe2u52!Kl&IrhHn->XHxkoh-6F<#z4mFhV;5NjDEHVTk zrL0bx5m8b>v!JFNuT}&t`m3R)GOyy|@?QkHe~*)y`@cMczq9@yaR1A!|G)08s?9%! z4osX)9RKINZB|=V!!kks@=0Qa0v_TopYwquxKP%rL={Hp;D=}m79H-8CI!aHFrH6` zpmEVV>!E{N_7lMKj4^!Z-%o_&eco&Q3i$eY?EdbHV~|aaGgnWp+F2 z*ZU5+1K$%uL~`dXspV6Pwq%Rkd|`HL6Huz-^D#mZhAn~vgowDqGhzD?xHwOaCH;y7)QP5PE?Se!B{ zO{NWHb)@%_Y^KvWFjFb2vKMYmMzVF6>cV5BS|lX#+uxBvGAfdr!eaud#=`B5V?i>= zv@J`U6+waHA)HFe+D$T>a`Gm4YOAu*vzLyTS!z+t7H|Gk<##@9S=^tPY?6=60r+7$^f~_z289@=p_c3DVFx8uj_=p zEm$N;<*sJg9r`5n%-{bF6}KY0c==G@it^|Qffj3(sl9^a?Jp(pCap7=n>dE4t#tte zP5t5AO8rD~tk-}1EQoq01*$imk*h5-MedFs3!bH3O+sCFRYOlccLY;lQ9ii8^a9WB zt;FBKP<;d)>h(R_8&Z)h&6g!2Wv0Uo5yUmYHmS%=8(->x0Idf~i9p??4_^2x(&K+K7nO?hsFIuzYS;Kig4i zDg8Vb4f=<0<2C)jG2;rZIYVM)(~Kjg>YWvAra3@616_;W*LR1735|@)xP6$@AZ(yX zEhCwX;Hs7zV%satL0P|Vw%S0DliX?g#Hn#2$(HSb?2 z;f5PAW^J<8AC$Q?-2Sdx=0ZWofQ}Kh(O}p3vw%Lk!#7Tc_IlC3X7(;_MZmM!C98k9KKc1^vfcs$^y$1=RY1+WId2BBvC`*mbLq7S-U% zrFOGn-t0GTUgUS_LwL%4pni9Pm%89G@3FAkXa+2l zM4abO5Mvh`Z2w}wOg#?&*S^KyiHyM<;=1PVi3|li005zX^KtI-ZCg&KVsC8VY@%wX zYVch)Ftj%L>t+5QLZxAKD0k&0gikVvjp?Hhu`uDJQ0^iAI26Em5O{DvR02W*g=>Y> zO)N(jy~}QafVF@turd`2II7r|096rz%{=w~mVoA#?^koPBvrVfjSY=WwaCR(x0_p{ z_5Hfc`wWq$fOMYIW*hQ3iuYhNc9okEFso#}M8~&PI^1^B z^2hudVRbcROS=O^3)OSV;x_7@+lD&;*9Li#Dy*wyy-3G$0+^1wc!{qXIULj>0vc}e z4DBiR(ZK%vDor*IEjK|nS@B&GvIFR}Z4~^fW1X6&oYYNJfRAm|K;!&N4)W|cXHNHa zFtBaZ@ZJ1ZPt~hGGN1E4s8`IAr)ESTD0>iE@pF7YYS66_nr;dQA40Rbbe%wymU1$m2 zcLY1AXgPaffyk()4uwFsB6mi-tG%)&+!Vu9P(W>r-olm)jxElr7z>lY%!~}79tc9_RaB1Kl z7R3w+gd(fw40BLATvft6e(*$>;NCBa0`n?WMiQehG1dn>Y1O1B!+6rmqbv$){w9{D z!C8v0)T?{~VHVQ+27t#M-H5o%LWV|{G9p5X3_#RODKIq4C%pwl*xpdoleivq@Uvl| zT0ArZrd(&t+tOdQH8JSBYEP`6nkJUAR;`?C>Zi=!)7VB>Ha5LR6dO{ANR?5xDh#Es z(WC?kZl+a_LbD1H8`jxaP%KzV=YBjPNm`MZs7!Kpf9J>7)ZJW8IFdHG(Mu%ui%R6o`0}%J0b^iudmN$vs<1aIn?bWi z1|!!l0VUc!lo-X%1*D?8tCKS%2x`B-#t;o^W*`e(`V^-xdy(NmMAb087VN!Dv^8=3 z$#H~{f@W%P=#1jfb#Tt#p9@j3QWg~i!*sN8m~?Cgc( z;tkKZ;gT?>k*`e)tu1$6qn1V0Z~0+0dkh1|RFtwEI!fL?J(YJDyozV87>ei62tUbV zJ@%44B8v~K(dV4Ak$mN_ z1J@|=DO_y0-7hmlUMtO8Z|di3EMjWgYo2dHG;F*#ml^c^gvKe5Lxob0!T1vg)^!Qp|qVwYmdo8qu8UZ zZM%)vWFeNO8_&bc5!RN6so434R_vect&XF5A}>6f&AMunr$RdzUUy#|) zIj1AMA@04?Fl_OrpBk8#Q1j(CB}P`#V$qbErA%czdC{4L({2Sf(_v9aBXTu9v;MjS zU-k8q9v9ATBs6U{rHz>~O1H5%wiFnNOP*9^`w@6NTp_5?cXhJGMofz^rJLYr|U8+_aXjp_=-U${B(FU8&NpZBxz){Y-?I-_=A4Ak4xY!x%TnD+SldSB64PVnjlV|yhw)aUTn#lZdE^S%T z)?_y9In}l6vN1@f3)IMpDCQ8QhJGzCUx_@C0n%Q;gr^E_%?^O3gICv%vUkMa_QXqx zPXb@A2z(B5V^6U^auuqpnX8}iV`J-=Jp<8{F0dryek1pu81Qs_Zc1<#$?bjI$~o?D1C97qf91 z$bIf)dzpL$5c`+o#Iy^-s{eH0T$;J&M*5siH}otTTd*GA!5(8g-d0U5J1`vUClEXr zD9jKdvUxrZ{NBzuSje#HiGeV7g+`ZRp_Y|zEYJ2%nAXH^j&7w#J~DM05vIM8pf?Bm zVTZb{+7p%tk`xnes9KI3T0E?(oVDB?1uf(NK^y!|f&XIMR~+kwTN8ecTbL=(*&ZKg zqW#zuMm8{8Y$?YNkinuGdpNTfyfL}k;g08+!c64myQ+II{EH|i$0U}_<3W%%RcLpB z9@(I6xUsi;X7_ZD2Q!aprKb&BjeVn)FxIbcsDZ(O+@Y;#CU%hL$OGA0@amU|5o}%_ z#+fWKQ@K47B#q*3p6Pu;;eqBl+z}G6*){3@92k;9fCTlBag-=1seT2?jJX$)7`6o{ zjYAQN;BQ1%Lc%b{S*rHz(5zh__21~wV(PUbA|0^jYu5bZFyN$^)eZxY+9o#q>f@P5 zj-3#d)-4>qm!0k>dkyTKS0cGG0YABstP?6T-h=`8dmWqwSO*k|Dm(Dr3y z#bsop40HLgk_up>3`6-jh6+y*F6P*S?xnk-bCuS3qIJn~(MCn`u!eQY4p}Xr!}Al- zh4%oW!wjBew`JUN=D_H%CWkzK!j00lPr(!jlbfsT@kVGVZkhL^J{nfq*k=yX_xIEK zy2HU3G%DC<)_`I+GnBWS_-9KUSPhVVNLn%O0!&PzXt4fdP;}^@nT6#lO*70cNVU(w z9BpEsarjYE3d=(jlTJ}qWmxy~;?R@|g<%4$fk%`cdBzw#sqyBxp&zZ`kk%w~sj*pF z*8%3MW>n1qY9?Srjwytql7~38h65 zre#6Iy-#plo1A+zx-z|VU?anx#%abV$G{t=auo~%0s`7$5|E;Gd55zfzEu&Q2j(N< z6_s+?u5a!XvgQlKs9o89&>@Mk?S=@N${CHa>zZ`q&yG709co#OQM779fT_&@e5r;D zKx5^qz0;%qB`mpz_2GsXHI(OYfCLSy2DEEFKL10#y3TiqdqrE?Q2#3wU zBqtts1Ron2b$R3?2)G;?q_qi!Yf>Sz&m-N%&mu9xV}#hvud@#+cv`3-}+Zq zt-ocU0tOxU$?qcH(6{j-+rOC=sM;x;JDM06OWPS3{WB9tR+O^)Hk$Y(mE9Y1F+UAd z#4U!)lZB@SA1X#kmCT}MmlxSPVP9WP##|U4U$dA!KT81{-B079H{U^ zO!5y4ycgGo{DYX`rGR-@3!buafpqq^Dvx;dL7r?EVT`{dKp(c+Xb%3tFY>C(asJ}K zOvwE-NR6Pt$w`y+-79oRD>o)qp-3htdLb~FR=+2s0nM+mjy9HcKl?!Q;FEHCVc2Hj zLB%HJ&IuPcM=mcn$FV@xbrbcqqKm53;karL48CWe15Sb9HO~(SIapak|{~5G2TdXm-0E$N6IG{ibrxI z&P}8R)8b(~;?V=aE8*pJoX3F0LQT&ay)fV+`a}pAslL}Zt)*E$M#rHws+p^Bp532u zi^JO-F}uRPg2_e(W1R`E-#CJCX0&jwTrf=tyN_wB5>y?rgD$uamXS-E71_e2 zeezfg#FEJO1oQaj)YOy5+9O!Tw8hZ9{Q>jei@>Bl@)i5v@gevfAIkq`eEfft>x8~T z$Jyln4PB>XRVbs?Td87&UlStJsDeOD31TQudE?Q*wH&{>O27ISjrbsOFX4R+mh_4! zP{!A{ZLr@9e??3I;*DrxFvD{^!{cUp?ECfbfCT`i){r(F5uAvTH9_dVfRV-E&Kl_S zV^&MO+1{Ukz$e6eAN0zJYsYeZE23F>y%qh)GX8Ajn~jKj4dBfj@xi4H}(QoA7CVVotT3uGkbHks(3bin9brivY zJqRRp_w{I^UYV4AR-)9d;3(3r?N~v&W}ltlwdugdqfp*~b%9N582!1?#vCdYLW9@k z@!{m>_UwDLvoN~b*}Xe+d3`Yx`vJ$H&H9q*=dc*swSeF|eT9vCe%ia;sGEE84Y2#n zcj}++9(K1 zPc3ATn=qP3-&MSUQfJ7;##fmt1xuqiss?1t6%!e?pov2vm)r$u)*+4r^7)<6KtrQS8!7NNB8^d#?}I=hW65E3(A>xP1|rTdA{Wi- zyXD*xxCz#@WKB~iTb}tff(mYl;lXwFpk%>|EdCSzhsoNxi`}v4j4W^w!FLbD0rNqG6S(Y{iqO_mXu(xBHY$gh$;ftWtoM(*NODFe$^7OYC8{d(Lle6kLByzHS(ArF*NOBLT;n>A^z#=6=H=((<>Mc}&yRgNfHYt# z$izC_;3oqkY(@Eq0n&})T1RBwpKzz=xZ!WaxN*;6L!-pF3C}@8rNqn_lnUYl9ndNm zEyi;s=ytzFrJNoFbpsa9VwUHXl`3s2Nmf`b*V#zKU!j&+v>H>+wK&Z*7pR$W;4+-m zTG?`0=eT<{tFucA3Ic%{WDTSE(U z+8{aw5K%JB;VK*Irwy!fZwpe0=_ff9uP6;(`ERQx>=9BQtY-+dq4?nD0%8dQY(K#amS?{zZUnmaj)v57#q`{(--q^w3iJbW2Q%G17L!b z?uP)KCzefMm)V03w?I6W;08k@QRh1gAa3&sq9g7h-gLW?H36#ycRd1tfGkL33-Jph zMju@AEsk6rAlM!!kl>u1m^=L-qx3`Ok(}lw7q4}N)9d@PPyE>%3Ll8jG5ieX5Jbzk zK;{#jntQtN`5aYS>J$CZckkgBMbpo$>#=AN726$j%NQeRo+>YQoa3Ja^#My{10E0C zN+9Uj1an(E#S_U0YLGN4uL}n13V&~vCK9;^>W{50K+_L(U69K!BI6XlVMqTsX`82D zngz)&=9*p0Nam>9w?x#$=~fJ5q!UHnm?M}A9ce$Hbtslsn>r^Nu7?^Bb%)O+7^gOb zzt25Ja^JoIc8~#2JP}wX7{|dNo&?q&!t3P2uN%Aqf=_^JtP6h2*+l>Zaf5G{KdUGg z2QB5T(?-OATZ9kNPOue^4yP!b+sw=5s03bcjc-CQ)`c#-D{xsj8_0`q2Pr`69v3PY z2g)!80;edDYY7);foF^WXU``d1Xdq}FLm7lPCO9k9m4B6i^DOBNC)LcJQL_m05Tr= zk1yf8dJh~KZu%ksgm?Jc-~wC0T7>ZFU@xdXJ?9XNgNSH5JbcSPg4A=E1BgFE+%M(C zx4eFguEpU)CMdf!xe&)M%EAVeVI{(QIFtW4vpcDH3_@#AD?dvY5+v+7$QtDY=saXjuMk5_yN*L zKMKJO$ODiNpqZL9TFT66b6Z3NzQ?C_l~viKD(JB*tt+|h%3EbR59~V!Y?=w5yA#rn zMIIWA4#(0HX2^v~>6nIfXlmQnP-+g_r|EmB7$zvve_)*Va7s)TS+sfglWe*goD4hW z98W=YP)QFO=r=;|G8lln1rVg+jxmrY5({-32lv+|OF3=y5G?iXwCe<1yoW%Tb)LO!#$OUs z=5v8Rp0%9L@tgDF$QCk@@K8bRGu4!AXU|jn;r_yCv_5}Nh?Di2W*NNG6p75o2}jrb zg(`$h!!QJIc9J4yslWtz_Rz2!f!N!Y=Om>&M6b-?$Lp)?Q?IS#spix0Xmu#_u(bC& zT6}i*v{VZBG1gf8Kv(O>t)BEsIe6m74W?kXD?K~ylr5Nj`bX7%q&Zk2&rAr=h!b<(zoJ}|mgp^>owOB84#kf$YxtMKJ^JckA@LC$aG2 z&OE}O&4O%62d%=qC-0y4Av`rDFr%>Z0vegu7$Txqc8XbV6oXboC&aoWmnGK=ap&s) zg`)BI5Eu{3uSH?Y2SYX8jxGw&0s~POMWGA z(}e_Z#br}SM=kz+yYlih-S|g3gm>@PQ~c%1l1lB?hpx)X^+-Gp9dI9g`yimt4HL{0 z7yphKMcHodpJ%h4uVA{|yTe*c-`zgo-&1fjn7Gb61n={J$HI1!BZeGW=ZPiS zW*Z*N<&2x=~*~L#g5xh%hNFg5#&gA?B^s`ZUR-un@PY2Hk zbo?KV>!%s$2S39J$7vm(d4JP7zSPXY>;jtAHTf1%Tr+i!6@nSYmGLgn&g{L(_he0{ z8ob-OSFnp^O*%R6w%oPZ1PL8P0(I=TWuQwGAQxgAHnDFLjMUXpiV)~UFai#Ngp#8m zu`p1epu+!vH*63}3U}<09tSCceXb_2i?rYdN$)x3mIICL{Fx7>vB8w~N(()GFiGv3 zHJ#*Q&^)!<64`b)?A;zzuRWndYhq3-l*({mT$Yee8B&4a$iN(%?*XeYsJ-;PbPl;h zIdkc3NnHVZb;eGt+MRIVDvibl(dhU*F)EHH58qFW#&QE(5$xk!G0VQOv>=hsj-YPs z37ym}k(JLi&h9KiE9^svgaP=9zdheW^t3C(^*Hotd_`#t%SmhY*@!>Saq1K{`l3Oh zH^)*lpB8tcz6LV;?@zH`9-vhW6htAwt~~4kUi( z?6m;-N+DM}^pTBpqPX5P0sA6Gr^gM2#J4BKB z;~1tkY_;+6pe&BiTOYa2Ib>TON|P;pOTLb@e5C&h!C zTHCgK`qcRjPGS3X|3j`%=UA|h13a5@Q!RPUsqf-8)$j-9aup3Nszl>{t)ipeA2QW0zB7V!!Y(#Y_jsutXvWg4Fa5a6 z?f50S#$!R}E~4ATMK_is#ondb@*1qm<+3shuyrX$ei64ccoxl^NpP1g#y`-WOPe=$ z#m(O>e=;x*W136wR=jl-2R#}e3^v1GpXyO{;ovkeeE&A2Lo)RW$jqcV63nYItC=Z_ zmyItox~0#Xt^BO(v1sP*^(@UOmCi1H-9-dvw`#gl(fb(TC|INhN`lNcV~f=uRxVR_ zA5z+uXg(eo3@288ff8t@BDlytaUPdhfEt4!Dmtf3D4~X=$Fu|ZE)x9s+TTGU$lB@$ zPtuJLV59(bg%EnivwF}>vt$)WgdA(#qTFr zLCVV7snbX4a_yh?vVuoKLfR^TCVY}Ski)Auef+BY4Q#mZGZA`hNA5CRQlh2M3{fQ| zL|w$(EKGK_8FI^2ZC6Eo;FR}sT&mcD5?O$iEh(an`=J(8Etnd*mp>k=qU9^LkiDcV33jUWURu$L$Y+)XPjC}O5Z!D#Itl< z;rKTGF@`#T6Mi_r4uZG)OSlx#7t2pp=b)M1(h$!Cq=a*MW9v)mr5sU$iA10Wfk1Ll zfL%oa0Qxx#w--@MR5%q;P6%hbbazMr`-#6K(|7`T%6^%(%`ho~p~={j!Kg_TmENnS z!&7obXkE2o_uvpx&d97yc^Hp}7-g`783_t3mfqkKontrc(I`5mjz9*Wn$;qIRTV7Q zw>R}j{CmN?OpT&fhUle$!c{nO$tX?BTZ=R~BtRKGIUPwP<%3(>sK5SH?FT2DcJr*T zB9ff4#|xq=sG{;U<>XbQ!AZg&P*(6bRf0<*@8)%jUS}FyFQJ|>XZx86y(P%?vFlGUd*PYN}B%;T_QUyEniXaTxA2$ICY)-~|+kU%jkxTA{)M0~R630=8P9iZ(w`CfsB- z4X;|hseythBB>KyJBPe*ttZRBik0g@CtAvmbMZ0$urtiYlyy#@_*n?{V5x{q38 zY$kTC&aLTg-CO}HUCU%@uc1gS+crSQG}2NICQKp{&xEvzFIW~<`A0fPMHhg(BwQy$ zy)Yb(<)*9s;20;gq0Y88hRzblBw_y-g&3Lhf*yq!MQJQim_*X$6YFz@cK#@_r%Dm4 z?w)!P@-bl9Y~ff zT)jkoj0t-GpF;?f$};s|1Oc|}Jsfgzw4A}HLHXuq;1^prLJ6&o{_}|hwR5h04_|l^ zt!FCH=1i_yiP1J_kiKsWi zAW7b=gD4!Xv-yX=YaC3+oSr;6GFHTH+@NxA*YN+qP{R zUAAqzx@>mYw(Tz4`0CwfpRKqzVt+So#ER!fuII;ED@V?pIWa~=yGR&|vWi(QiWL!) zY|w8)_~y;|G2TS&PC=3+2ivBF=;u6pP$|vf%ay=6qXnOc7|s%ffs^4!DaCy`qL0_p z6_k!YCq2qIOtnlj3S6(N0!Y3KgTs4BI81d=eQEn2zw*M}oNvmXrP1C7bD3|baMhY^pLf38p*khk$M++`O6U)8qxIRAFVr%a6r|W1vWirjsP-z}d+lA75R)MSb%=Bqlq!G8xuMC~x~$mFmMcN< zKByxr%j+ckIQj_`!sbt+w5Y1Bap;JIiv`n3)H%Fh^*AwNp)@H|66WJlaWyvw>zCP7$xhrhh8BnwWf`mvYXS$;^nhv%r4oNJde#&Ai7Pryg$Jy zp}1NHHX1kTcc84eP?4vcs8Y^ZW2sW)rXx9wQi)`L>QlKjhAr52Qh%G^$#m9?D;etr zH6VUk=Z!1Xg_6q6oA9Mqg}b?|<~BLDWAkrm96W%&H~Ji`8F#g;<>pX>nT`lJkB|27 zojTS|EFQq?9i!HXDQIzIZZaTo>E*n1>%uM^7t|;kH*B7% zv(6`hjy5vq7D7U&Oh#gCFpVhpj|jrUR6t-Coazm$cI92m;Zhe zX%4B>hC^%}U1GYWLy~*c8j&$0-S!cwLv0;h(sFigp0yY-?MZ1`j2_VYzKA2S9EEe$ zF=-vuQA-)`JSns{2?6ZnFa@P(opXn!wu+M1&Igq0AEkymQ;D18ez|@>l_*g-o9QN) z7fu{`BNr!AK`L7*Dyuyl3Hm0)<(QGDb2gXuVUCX;O|(`dqn^LU_Gy-@N{58bS{$y| zJMVVdhvBwhy zhaLgNxf(EO*B(H10nu7Wo;WeQ;c@Ap6w;mKshK@Q^q^sRrv%y-BImx`gwvr-URL-_ zS+?2}!eQG-4SJ738wJlB$2y1>-j%_)HI>;4uy+M}%y;&v=#&{ov(F~ATRz08yx=-y zl%ZWd)H&w?@MxjEihnx2<@M-}>2QD|+rya!nPEUn1^+0F4xQ-V$YnYgO7DaBLBX&D zwReE8pmQTe;Ep4}TR0SQ45n49FRxC3Bg%?jSqde^n?0;Kw8VMap=kG3<_)pexRYUP z;p#zqY1yOOIBz$JXqsdZ`90Kca{3I2OvWM9y0cVMbIoVl>4+L%G<(aCo3Q9n#|B07Phq%fn@a=h$ zf(llzXCAw%U>I{9r>}fS_J4kNGpTI0W#P`}FgN`^A=Z2otL|KE>kAO5 zEq8Fg53g;Non}YIOKp zCa{s_jwdEnS!{n^w=>%+Er+2|if)~C+Q||S<3Klc)ABER>k+7fdo{ny{&ZYU25?DG zya*`|tp+k$!@jytel=_T=?`jF{>wR@<+WNwY24>GJay)lN%U1{AKj$q*U@nNe)<&CD z6=+L-u93>FwKfCT{3%qxlEm-Ep#p+4N)@Q0AMYm4v@^ZEcF6m&#jE5ge%LGm5yfZ$ z0ejE={>C7$wpR)(h+$Yx(l%?1G4|0_g@FI3VFWiS6EAH!_M1Mm%uXyvZ_ohW#Bd)T zrwA|0-UdDmLqR#;k;eGR*p<4_ggx()3_ z#V=)?r1Cr3z5d4=e7rN5qz*tdcd`T!jAo`@6|HG6OAA|H4GvujOSbGiBhl|1Bb<*@{t7~-i(pT-p zOG-1p-(@Gy6oTR`V=%mNM{3=$&w~=Ns=*_#pan0T=-wZWn$72&)i&Nt81b%UJo>1M zn|)#yf}vK6cJ{Ag^#vnQ#JuknS(h*m$`cLUtP37P9o*V17VG)*;P41*c&O;DY#9#ax&z!#2vJyuQ9+Yt9YB) zfugJGn)~SSzS3ZKa^OH}$)Bv~P)OWK%eVx?3)0DvEbyQ8rCqomxcq&ep+Ai1q&Nz(z(zcz7oAsmaMw=9o|ARWSY%)K5u$?t}T zxJhX>uu=2#A<5UM`YxCn8$g(ZSmk2P9EiEj zxTl>{9UP-yh#PW`yArluVm~i4U~$~o4FnCi*ydtU`Z-;H7=^SsRKQs45T*lJ!Y6cXdG~F!KBRgQCkTmlt)EpD4!&r zN8-%D7{(szvm>&bb3RF`Sd&uAM4ykrs6ZN=?uKV_6?sq8Zlq6OM(g`i=gMe!=>Lef zU<7O{Vr4$qANe-&g-NiW+n7d$UA?l$(TTe)aUgpXQuCl;C&)egwcme1@0J+T{Dc}@ z%*?!kjUwcFGoaFs9@FlX)pHY8c#caJ=HH!}92B6o0P9$AVD6Ym%Ql`DgLkJ;9Q%9= z;8V8$)+#sbcEf}7w71Ur39v29PE#q>Vixa~Pi0rn**hMPBbMm?v-7kDiqE1xJmJo` z#?1go<=XDMs4TpPosv}m$MMk&i^rG4q!GhhISR+aLi%Og2u!4##&u~)wH1iE^#c53 ze-A8wn(ir3Ng=T7Tk+(5+o~8bX>>RZpbn`QaQ+V+5Em6YQb(DW+PUb{=RzshW1f|q zX9hH4+~uZIGr-X~FoPG?NR|HhsPr1-DAr;t^$;v;dydqyLLBVj42mCmT0LE0b54v(89jASip>GpnXEHh<)){?#sJ9vpo23YL!$Jv^JxGYmBdN3L9fc( zG(*7UmVi1kd3M3dww8Ro!WsIAGW0L0q$g1y^y^tWuo-?Y*u3oE76K=YSnX-@@N;Ye zLzuNTMd8*0Cs{_FBL`k+UCx{4lUt!jAZem~nXtci1leIs1z{&bxLd(PdIu2zacm)+ z*&m1J!=X#YK?B;IkBs&~4ICK_8j%*ap-b92k`F=iy%8Jt}|w?M--!U0^6$z`Xd?#u9PRd{SWn3;JlX6p%TR?E`0>t*Y zq(usmk97(@F_~W)vj-zCq`RYnvA&ZYKm${l`5C_>hVHE*=Z2)iS~o(MqPiyS#@#X% zS-QuB9OH&y!%TBQ_p@NfI}91PtMC0&!+Am^WQH=9=9O7D!V_=^#5QOJ@*`znZedqr~-B zerCynh)v+d3lyAN<93g5ZWA4Cs1e9Rp*+3z#ulna2Qf1wKuxc=_miGfJx4>bGO8QU zhvy>!^@s^wTxdu?=K!9&DBvl|5j~mMafOts#i11d?<-!QcVk<)r2$W^3X%*N3kB}A z5JrdPG9F@Ox>UxD4<;59*sB>^=eh|dF>3Y3e5w*OxBi)}dj;yHsz`*z3Sp{hboN@C z9t$*;G97PFNfKXKSk~sBFe8dCl*0h1H?hmbtI0R)+D66RPU?9~Am$_#$0&h3+ z9QBzPu8R8npl=sUJzqbjer`~UGDoPlLM`8ao0}gSqLeiFSUlAKuFf6r*@&n}Q$Y5_ zfB;_DmaHDZKc2$PQe<9M6xA2fM{(9iTBZw8Ug@9)e-wN%DIV2LVD&Oc|@9r30#;z}e3P!J5PUD|;je4(scPYoOdcPU z>|~ou~*E{_ndU%!i*|GefH z*Iy9kSdlTG+fnliFYhi^`{(Vne5Iu_<*~>FJ$GMtXp4j4?Pg`~ z81^Njt(#KS3h>i`lHYVa*sgAUEf4pXWbOEDbeu7kjA4P#Q!vpS;fYM=93x1gIOOO| zG^z>@eK2L9GCPh7dmyS(zXb(LgyjR`Ii$%!BbuR`qzVs3v9W(9aR<1U0*(`7WnS>K zrDkj;L2xyZI};6#t0A9z`mgZqy&vv@lnHDSdsm6+L4ZT1j(e1r4gHWOp^K&`D`tPp z@g7*58|5&tYv8wp&=kn>A!&y_)P+19m8di282QTZd?eh~ix%VAW0;)lmADhUPGzCpgXKXm*Oypg|SWqK;wJFfL2cP(CO2KcA(^4y$gk zzLU*}h(DhmWX+&6`z0Az8*v2(wi_>VZB=OUfHAG`b(7V&fC#33rF{1zDz7_!;g13> zzP{*`{x4=+tD@I5|6wcxYa(REcCvtLW1|W6mm~x#kAk$i1aa*Kh#cKQ%FZEtZX;%C zddwV{J}1%sJFBvybqFhnCn#nO^?D|A254m_;~nApPYGoy=@1BYSS5Q%>0yf`sgiyX zV@}yl_+JjB3-Zc0iZR!_gT_&*eV$oR0*G6*l|@BbFjobUj!W<0Hs>vkb=z}8K1x^^ z*QlOlG8rC24(O!v`jU0)!A9nyqH1&DXlF8$wF)jgQ7kb)Abi2h_G;(YW?J0b|Z45k_@v4 zjK&2H#vB2)!Tr6cW5`tH=#5U}OZdQ8TH6Ma&zr1}D9b@0IdV5hBMRs0-{Pk@9wlfI zVZ(}@*hd9$ma}rby!_+apzeq@ex(i!);$#?`!%Y9ztaehZ5olgvR*mM7o2ExC5%Yyy)~qr&=2(>im*dyF?D%DK7B%P zF?EGxKbfHC?86t=qFV&#A8$N(vWxK$OmV@)6$&}mV8up~3pVzpzc zcKmEI>2CYQL$hoitHXa@3mN7kMul&FJr$PVlcF-$Jwhr#q&J4qXR&jL-`RImiv?OQ zQ}&BcjH01bgYVq158d6xl<1J$M_duEO0G%mv?(s2n{bgjSn0+ST~fQ_8dcMBOLBaC zeMg`ZCuf*TJl-v#g}OBEC!5CCZ`Cbd_>kQib8E&8@cnDf0QY&zn&O_{DS%HIkka`x zzC4qL?$Z?58FGu)Ls9vmz17UDGX0q++h6#D;x}wa93g_Y6NqjQqo*vNPAFmlL^k8eA%XJkO=?15HG)6aW zJ1(xh0HSh&M_=yRYTrW=AOLu!6;2Q`PM2q})cV1_lPKqh$q{*E<4-6g!>!0~xn;)R zL@E1o>Qn`h2;l5UJj{`8hj(m{D^{*k)g848jKd)fUmO?8``0OoB_J14cX6_gl7Qs^ zJ%C>|EH2F0`^yr2`~--bxg65dH**-4i3Zz5FT`0O$l5B(7$;y*GJYLG{$gkw{865A zZrC*U5sm+z|1&}h3O2$iy*04DtRmLNz$>EnT&r^(xhr)2d6%wN>yxpe?1hdhNlIi+wVE@AH2O# zD3qMvBygkUB+x+}4lr#^G=?{QzcFPlPy(w^LWJs@CX08OFnOg;fuAwRH@Qo9@A!nO zLk=;kZAi#uEtgde3%*0M7FAvrimaLG+8!)m`N3CUf%ajR1}q0- zv%jl`$@18qc8|B#cdY={ckuvCx5(@29+-x1W#B(C9#7^yq62*iR=s8YFKUd(_4s|c z`3<_#B`bmCV?y;oeJob*f7IVU8~~krGSRF~4nz~nDbJ85)Da{j!-tl?#rANWWl{*E zcOGW0zmHm%e_39w>xrFDlW8Fl@2e`3Enf+2nC@YiUE-`+D0~aXUp=OMq9Bl*qmpv5 zQbqpvLHlj|Mj6xD2sh_*4=)m|nsO=4G>kh?0{k zW}Q2f(f_tKe5DDG`)PH%!(;CnHFv`0^xM91urE~G{b!0@;ps4`L>={~{Q^(8LnLu+ zxG_5EIlW*}&r85B>3GXz3g#A(UE@T-5M6~iEC3z*)HQF;+`Z`v;MFqGWa1ZYB~?W6 zu#vCOu+cdzVslkVhC1hn*B^I36AS~wYtn4SVSc(;2=QjZ&*qq{1AHBZy#Q&+ry-f3 z5N5NF`gIW^y++c~t2+nh7hpvpY|>PiXG#cdAn)5Dvwh^pj!x>=iw9=r&uD0fAV%f4 z`HW-L5OlpFignQFSrgo2n;qS{u@JubQW0zd`)+{n+2E^dLA>g(0*8)c<|8F%^TBPw ziUD7jc*&83t2WHRgyXY~_}nP9^)Uspp@jx{OyxgA6`&PGB<6>*gS>_*8Tg&Zal-{U z4dAB{g9-(Y1WOIT4}Q__5o8Ws_HI**XIe=ZR%0NB%mJ>uYXNY6=Cra(PAbp5fsV2h_LiB%=Z?+PQ%dA_#_T8G zF15yx!J#88C|jQmX@4Us)B08R=7(7AZ&?{mX>{!>EjXgEjE;^M-IJDosx1$H1;scN zdmW1^s?1%4RBimJh?%JKOc=1~tRkavUP9r@CyTs~)g2b!?o;6YimaqOgKVxwy>f`! zCSw~+tzg|+j1Hxk6y{*q2_e&z=S5?l?7kAD8Yw1of^ky`ae++t`7Z^6f3>zrZFP}| ze0Q0^ewWKK{FeoS|5h5Ctk5Cb&kvvFG{x!w4N>DKEP@ubg9%A2pCPV{fSiZ?2m2V2 z_Lk_D=vsmKTR9n$*DqG^oP)F=FTZUwdox|*;-}AV-yiJ#T|hC}oR%w1v(0tGJ!B&2 zjI{)TF6D;FZWxx?g#a#|qw0*zZo_|!0lB>Kb& z3l6S!iU(s)4-!ihN|!*TM+7IpAy|YIqz<%sPtc*CmrtZ(#Zg@7oAI$+K|i2Q*(etI zcPg$8RE3o?`R;bq)*bZ)4cfoMsfDDJM9##P?wK+t3d9I;LX;vgplim}V;&aC*=7H7 z>cbEj_5!+lriwEA1V2&tEf$f!ZuT>3@ozA^cxLbjtZax_(IRvNyOHm zfzZuD6H8;O7w<7Tp%7(lyj)Vi%=8ccm#SlPH^9HQlO@!>!FPVohsrmRsrY|6Cr01p z%8qu{jxN?FbbtF%wfk$DzK0aQhyE^^r1G~aW?m&)nkH0XVJdflPGot}crciuqUJPn zcm!#fE*ZB{6MeVl^z^~;8b!Sf^F6q0F^p+zC|kM&`FYmWwyeACyX@?%iO<)M53(PX zeU_L*`n(Wq^KpJJ46Pt77gIQIBkPBPh^UFR!ut2&aedq*^htW;Na(bnv}E*M1jO6W zACPKx8iW1WqtQJEy6F@K%T<#G4P?yzb0J92%Hle3D2KM$sz8TU)v#>^p#i?v3?*XO z{Fo^2l=tk>xQBTw8*4+0nEn`I4yMmkqzCQHeclo25ZvQ*&Ls}%LuFlfBbU%3-Bh3@ zX;ltN_M3)fGCOG4NF&YI9h)53y2Z511tGKEvKl(_X0fA~v1F0cRMJqPLw#NJ8!hDz z;pN-MU`eYvmXb}Xz*{htJ=%AhxDrKG?OC5KG{2F8#&)Mgh#OcHsIMA?LQXE|3DrT3=7RoO3zAIOED-`Y8q5lW@G|Q_WX)#e0!*t1v|cX^f+L zTzy{`#qyCQSLb+Qs_38BD8iFlV-&pR@rpT>I17-x!nJ0%G(qR=LwY=Ot6tmd@gmcM zIxt$n#xe5j`GDZ`Nr2!CFgotP>;M5{WfzZaW~zK{JHCmZbhsiBYit>F3;Txlbs|em zt^_NjP7P9La0=yx+zmC7e6f-Py<66Is#7a3#jn2YU=I~3mep0ljRCCUb5&ip0=}x} z^TbZXp13`>hV_q^h(zEl8x8>D8@LlxjvjXD9d?jo{dy2x0Xr+H55EChppY)-9Wujb zWhl8F?xB+&I-kH@&?x7$KZ1KO^oHkR(5O!ud>jl~0%|mnbX(5mfR$B| z#?9}zm<#s&lO^9VrpS)Lg(}kp5JdpxBsF3{g;I!Y-0MKtZlzlwCoTC zka>ZS$>p`IB3nGm*MKd~xK9${5rwP@3AXTwd0{&mT09oMEU>_Cjxr^h`o;5XMzQQb8Ot!uq6}K;1K7m*eLP@{knQemyczo z&hU;rI~lOR+fZ@yr7;PjRC-T8Wvd+8LM6!efbRye2AUV=WmCCIc!j(8XHcIqwgFH8 z2WJ^!J;jQFm44-~S*lp7kBsG@hAao#SOjs@)?WPVFMbpEge39MdrkF}r7J*G@T6we zz5?UDU_5pyBTg`v#oM*#aKd^D<1yfp0~u;URdh-Ffk*}&xXz?_CEs7 zAfR97(O~kwy?P40Lyu|V-?`Mgk4}uON$Rmy>P(opXMs&r>YEu@^x9;)l1P0B245iFsuPmiv@KJY?SzLzoB|lF!yigN+mraFH2Vjh& z=>gOxy?*azvk9L@ye_$$B)oPsMC_;h%q;5FmB3eJZftnI|G^``r^E|}%r`W@L4N5~ZPPhzbo$7mR>t2>5{DZ@^qk08 zph%VCM7X+}r(H7q!_;~1dawZ0OoZWi*Zealr}s%%*uKjy0M;DqN}{MsWF5ZiA}6T0 zdE1(%tt9G26WIt68h+KN0tIEUX@!pwmvA>CYD0d}$OJHC`Rk@@ zT##+VY@4ZS5;ytrJn*EQu01neH9%!{#z70b-bmJY+bur|1JfTiS|(+5h0T=XH8h^U zGv|9>ef86JxcpK148t>6b7DiNF!9JTt2aTKiH@)EEBqd<{!Acc3F3a9GX~iKL)s8p z>0ZVt<>&_7Vkm~*!Joa6{VdZH0Zj{izg3u7pp=Y3Qai&rkVfkLUm8&VGTSd#tQ^AM z&L-(M%Kv{y_`gVSRw?kv_3@+oz(OKd`jNMzBeA($qq2rWA)p07#9bEiT#qy@YimXE zMY5-{KLfoh47CK0930(tZeQJPcc3TGpni7KZ#P^TH7CsO!3aZ#GtuC|Me4N^gbuw+vS2$9SBF>%8HnXVXCi>+AmUuRA-*W{a=>V@-wQF3p>9$~;cUnUK_0X3wi*d4;6bgwH$u`roHg*%j= zIxOgF0JeEi`)&nFL~!oBtHyN?Qz;um587nP^K*E_=93$Y^%Qz?nAkP^RUlkmxIB>3 z5<2l~d30t=&&A6|d(KYzBoO_SgU*BGRszi+kWe-yzG|a0&?e#*z@SMyWfz`v9TdAj zVoCJO?YW>#-mUaLZy^(u2UeKXg$>+45tgck+0AtMZ!5{0x8sm%N;z=Vc} z$B#QzQ>E5`3e}DjVcKwRA>YR0zH>&QZ%sK|HJ_C*AleETT_%6DF?}&mZ?RFGY31Uh z>YKuz6a1xw^?XXJvD8lM9JS_RtSTJZ?xN&^%1yFourak+p%BMQ#mKqTyx{zxx9YGUi9KEy^Zqw0yV?{8nX>)paY zEZ3uVpAO&JuZtB|Br1tY&eq^{*vlQ-H^yGag}4A{g!dmcnDt z&~~ynJ>!DI1FKK!Rt-{37oEsD#{~@-HYDmubunv#ab&oWmrlpyX~m&4`NN6PQ7c-e zEU%#qg16Kbm^}9Yt9^ZFwS8*$$h?Iu;lc#-%fh|{iPnaG(&eOcxg#}T7?^bVxkC^| z^djQ(=)=&Y;a0d#=*7u5Leg18Ff@~nN_2bPQ2T(i3DWRWz(e9v^K1I!NWTAa?E0%~ zRHK}`u;=^8g@pg(hs1xm|9+D`8hm$&n%Ej!*qYjXdyvB410sJLkoX?>dt3a9o-?)z z4%qcJ-Kc5eq-}l2=p`wZl!YIwjARRQuySOv#hjqIqO~F*O`a`lqVxA(R#uDdW62xU zi$IbJ`2YBW?c}K!kr#^tJYZ9ViBts?q@cy({*=dicZ#9Q>)y^Dl|4GTl%B5hc;4*T zPXB$Ep5EbRb~iO#(*^LOVut}w8@Qvw0O0(lPZuu|BZP?lEj;Fg5e&7m!GoR{{k zZKMBiTpQNDEp=S2bz}GtKUGNk^7!^gDp;F$^7wKq_rM`N-je~H_a@XfKX@!L)ad8I zf-)!9QZi+clLk(H2VHWebWy|Wf-`S^v^0sR(~E@8__X=UfVAd1M>^IlW4JPH;_QGH zqR_{XS4ZS5CZ?x);gf|{Nz;4v-puE^4V}>FY(PrOm162Ljn*xSDVdb2nWn)Jh=`#mD6%T^>!*%#P)- z4;OiCPkN4FY{o6~ap-*K0ru@$0M5n<>GQIpcq)IGWka8T1qWsBt0gR{YqVd zKj5MkdF>=u?5t6&u5ii$+bmw<%mE`|(=@}cl3v0P$9jf75YI(JndYBzak1qn3b*7a zf;o>P`l+kzOwOzDt26(kmSzj4ol#fcCqlAn8p`?j;-P_az3ic#(k9(2RtjdNAa_`H z(c(8%;wpFcXjt-3E}Zz~msOEvZ6^fS?Csm5X4l;9vGY$D_^fzF;B9?d&fGcH5|65w zkt+?}oGgh~0~YT&IJLe(aGkFw%Zt#89Ya26M~x8^gj7`8RQtB5@nUUMCyl=1 z8|}3=>U~F$)bTdzRP;c;*3_1u=4QAHFS-$hu*3YT8AysaN_cE$cdo>AGdJ)MWFd_4=f1`l_yN z^Y|pIK{M6FBV>b)MKg|R$Cz~u^LoWZvr;3DpZ9*bPlPT>nTREi4HU0rg+!u%Pvo~Q3zbU3W!4H< zJgijW${JgdX{aT-L^rq;uARnLEyuZJM?Pp4H_e$=9SAqOCN_muE^}(tC}~ldoRQW) zwyAq1tJX}O9tt(*f}=q)--#XoY5HnUL0(fu&Aons9=w;qNtCFbD3COD{WRC zU4p1L)vo-Iv}&5voD8>K9M!}>lQlatZEDhNz9cx)MLUC$te7@^a3Iurig)4DfMeI< zD{Ou>J``rt&Ul}mUw zZ~SvPVN&IZd;MrSIq2COUgF{^(h4*RiQetU4Zf&5wLQ zEoL!q0Og3U@+CgY9eG7FJFBv^l5hS@uJm=P+bU@cv0j2FtAEfl{`k%e?puFUu3;ur z;l)1~p`9HkE!9q99tqbMfOV=v7*x78`{>%hNU1{mfm!KPN)$J3nN}SOH;ay95?O7m za#l7kjW0!xw9gD?C~9I^FM)o41jBk-0;|jh7hxNlxGISHYWq4%Nvi?VXnR7fKQAcX zmrjnJ*y2){wT{>lE!tVy9A=Y7;rDCm*6YeG`Iw!-HnC7@wZysf3}&cm8nIT08=tY( z+mfBxOf5Myv5;yd8soUu$&yz^vsw|6)w^U>A{kF|YB5<_6BwtiAqK`L_atA498|b~t<+s4v1|CR4aNXU zg!A2PW>I;X0Ef?AePCV$>wPj^qU*>VP9JTy089kuTc;8PVBy*{yrZZ*Rp3s=B@BUV zaLVVp0q_9q9=?~3ZE!)tXCU8ROaXOZvlp!i@Kcd%Azhzne8K=U_h_boGVq)o31eUf zgpKK3RU&ibUfs`jh5%3m>1(qA@C@PFY`ba%=E%HMH8P^GaDA4q@j>u0;o6|D8UtWl zgzG&m3*cnJYh`RIKGiJxefUzZ2kM~f%$b1g09bEW&+B!2BHTa)Z(P?sw;f$?0Nnol zYwRxY((4X;&~7liJ*jIqZh)`BRE97z2ZXKws++f!=$buM?qJNW5T<8N+#a@Tg?9kl zUObJ&c+yf9jLdurWaY0L;fxRrBg0)J;iEq%RxO|F`YsifwoQxK4K>@ROX{0`i&ahS zE~;$iE<&no)-GpNwgac4RkjnN_wErzsjbv5QsKe7f&>F@i`s>1_F+ zaze=40V2<=)cv{qWL-dKH>ESNW;>?dXo}BFBYV>ZXrF+O`x@@>z7S&9YS++RV8b^* z+kbb5%s*qXN8(gH55OYn55xq(kt|0hLu0AS17 z<(o;!;JHHbD>b@F7U~+GH8U!z@Mju@Etj2ASfH;kvSg9oEDMZexbO#TpuASRR zk8g+}=q$h4=_E4_#hq-_P(-IA#gLEz^UqX~?QHY$9drDyRl&jcECc$+vwi$hz{jpZdFyXl|)Kf()Ovh*kva-{!in>?LoAq0kh>FqW5VGm_LmCFkpj^ z8GU&AM(A1Jw*7um02AckL^;2%ID<6UZvpFsK~}J8)4*&Qm4-4927Z1xncw4O1-cnD z1(5oY@h9>u4g6?1Zaszt{Ix#2vZ*2X;HUAFlx>^|hJu_0J$RpQJ56_c2H*-5X z2S+?GHbd)fKxOy?;FoeZfg+l^pkuW5H$yi&#fKI2H}4tp9^x;+5+Lyh$F7djr<|+z z$In~HAIJ6w{LB8hfu>=m1-3abWBSCU5xqjb+;@(#VmZ)lR*iAH_VkY`6T#An(oWEb zyegcs3ddz0wD!0aKZs&TBJojU=D-_v+$?Uhy+?Ld<~lUBsW?z}$@ORIJt+cReXswJ zG7;_>#bfT3br2@yj54Fz+Vl*Dbm}H3vOPF9VjldOZ;^o^g~q)&J<3A9w*f5d%^g3j z(n9smc1#+Sms_sBTbADE>tW?s4XI$f*slsR4<|$IBaz+R*C3eIzn4>?Lufuoi0fKe zCc4TsJ;}rb0!1O0ts2vZ`t<|3CAAI|_Q9=8%b)WQW<}@FE9t6VAlypON`wUZC73xx?jU^O~rA)oSqg#74T)v^V{>ulFn94r)q8*-mFD6fUi*LSI6t6fP|i z<&(5|!duYO^12T)Inq#nyvha+Wv9s|rIA@7 zg)^eL@^1_2cU!_OS=yem_RYWj8pHKtQ`cGbKk#FdW#d7f>p}0<$mg{`^W8uV)9u8% zaGe`jWT&GK50b+nbO^ohHQ|XNQU}(TR*=Jj+8vSuz~7$3h}1&Lza}$p&dc@ zShrdobz(TGyN3Y;+gCPdetUMG4JI4Dl&|gms};|Z(>1-+bL?t*kzA_|u&g;(5>4sB z1WqPZ(BvO!#@$|oH3#_J%>j0lNs|mJfMt8>=F~Sy{AEUt*vO^6sCPd%BNrRAdj^-X zu|KTX_KE?g>;!X*6EIF?#q>EFiy#9MrS_Vg<7vZ!uy4xD$9iv3bK^}lX&Rd%Fa5mk zBrw|VFs;pS+ETmZ$*2ybhhD7F+)qgVjwf-VQc=6_5LET|5nb&622X!!I*M4E{4b8a zO~7CKjGg2EKxtA%=dW}Qj}QeuzPVPnrq&so{+Xx|5{i+cghki_{CeDTt4;`K$Ri5%mTf?^R&rir5gn9>Idzy$t_7Vr4 z7*7&$kHLkiF5FsoH@+cjOeV zCR-MiKdf!{AY=i{ARCY)BCXZ9>q*EQjM4i5Ot0i9S?-DjsBt2AH<>z)55+vNNnnAw^_l_j_F6^h29c^kM%-Ye!gOCVb5&dR?gu z`HgOk+ry~YCcKYLyDy1WAURsGQ%(o|TVwKP-@+JgA0FuS(c7Ff&Q7tjqxAF=bf)B}coxW~GJo=kn zyq#Fatv^dmgmeWKoWJ#sH|E=zw!3^^Aa_7mZ5kbxMWHHCFL%3|ansz*_u|8c0WWY+ zD)yRs9KV}kWwkNd9q{2Ir3ZWU&(wQXWV{j8v45p)#TFus#cU+T5oH_fwe8krQe3DB z6tb(d^>pN?3M&qJa841wlw*@i%noSZjF-{w8p*v+7s-`kAqw*rRRB0 z#{^f$UOe)z$^0Zx)ThWZ1Z8g**BGwYT2g_)jV_XFgKSk3o|93L>9Mmf$ub)&$J}fh zw_d()f=hHbn$4N>?edI%wt;b^4<&=m>0_)r(#OGq&B>>#{px-^DN)WaW(yaiEK|66 zpKO*Hd}eWPD20noRJwUwUeMigM+P)q6w<$zLvjhoAg;V&F%MjQNnn2A0*h43{LRDs z3~>Hw7WR23#mrm3+{0bd(u%5WW#2To225K`+o!QRZ8o&--NI{>)KhssUeE^Nm_Iv&3?7~_(2hr`MSa) zbA*b?p}ZWA#GAFN(Mz(wZUNpQr~QK91wVf9LNc(<2WVoHY*jb4;S5g2)|Tx}R@Qd0pX{yd$ynx&lW5%rf7Lbj%vo^o)#r&oS6q)I zPr=C^!SxW(t7mImAj)>n>~75N=Y@#6uz^g%4VAP^uLM6pO?3sitspf#7S^#`!@Sot zb_+-`95>z!@?V3gl)jPMcV~j=Q^OVy;n4J#oQJj+$6|b#{$_;HV`-=18g5|=r%3Xa zd6Z>C2lZZVhfNMIzGNm}Ws48w0K22*)^=0qr9fk=-7!Rv`tFQF&;x1Tw@W|5-`I{T zDsZuic5z_ZbcKQfq+_T1jO~2RLhH7%rX%GdK7%8{xqrq>-j0rbjGf>AVo<)S_UkBT zSye$9U>F2kR3Klkq74r3x%>KA)l-O+q;24-R!jaF!pr-k)>0=o3G8t7Nd-B zOa}a4WUT)Kld5+ALvsBOL<*byvm)akm{j)qTgKW(Z+S@wl9%86hTWqa8=n_mQ3O{a zIiRj+NMAao0|d3kZE~{-xI4}_GMr%O8sMG_!>ncwGav*wu_OKEV(Qb?)YYu}>)jJv zAF@G1dpH_;&7Mg}wI<*v<|_*NNM8>P3tJk2m3S|&2@DlOfq`;AP6$Y0BbAU<$H@Po z?H!}@+}G{l#*J;GvF*lop4hhSMo(uaW$SgWYN7A(5yIdMwF5=#V;5zZbvj1L5$8NUA8DQ8xr5j5IZ(TaVcQ%++N)CyW$o zu4<{7Il2TJ*XB-)Huwz#n;h>vsFY`aT$2H>lwEBV;2Pvhv{EWH!m=sp3{}% z`@-3|Kuv18z~~^H25CzidBZB)JvcimjH9+{rGXsC3rfd0Qb9A`(zj&N%uy^Ht%5>_zk-dZgR?em|tDG(XZI9u|2yi{EE?`&ZDgJosZF3EL#h?VU<<~3qr@@ zXcMz^`tZ*8!d4xXDO6{-Z_8q36cX1KH+On4S6*Ai7BH6&i2>27Pw4Z?oRkp9qw@JY}|eieokEb z?%$099F)7uc2Th?Qugv!)K=>@@*2Oyxu@Em`M5WV%(mh8rVt^p0 zPuOtoI%j3p#Ay{~m}iOJ`=Q~gXEhY5!5Zh&_))Q1P-o>fzqq8O-Ru(*>g>}OGVL-; z@nl;ruv#HuMWGa={?7pCw9@w{w1c+*=`D0diO-yO==Emj@P)+jcpru4Ee1Xo`ZX14 z5h2C@f)>Xo)ia*DwFWyc|r;Z2#ME_Ro>#pS2+9R3FA7=If6sNui+flx@_0^4t8;X)*P9nCmj#?(#jG?|EVwnIFM0d&I?nnye)$ja8wNY(fDFm!L~<@wdVV&qNy(Vo;L3C=tD(x-snSn zbPOx!Xq*0!IWE^ooAQu6Ys*NR)(``$eaaO)ZtG~9o`mKQA?tDhOAKtxjSaB_)$?gBJ=C_Ns<}-L;FrJx$#%U z5Q{r8%KPTeHrNz?Ax*P-O$8p#TlVWa8dK`K?%qE@{Mgd}a*vku z@%mR9q32+r1{9#1y!ct*AcoYT=i|rypRj;Mc4+Ml{eZgWNypP%br01ZOW2bkxJ}2} z%ad~ku(%7C`RvqBTYBfn$3TM{wZRM;bg7*EpFW~VP!t-y;9x#b$FQago-f{dIF(>{Ur z@rp0}dJR2xjPt%pSj8l~+9UBxZP|7l&ha0cTX`lDq;G_l_SN~0=;|FMbsb&aB zWP#oHMC)L1T=R%dBf<}hw}tyj=;`ejo?5f0Jz16CYCtkR!=d;K5V$D)aZLZ&L(caA zLD6j4wLj2rzx~+UZa*|%?C!&Kjz5MyFEh(i7+Y6L_r-AWu6 z!9!yZ*A+I*Yvr~Bcm6iXHp;sJCmp3z`KLm){1dk@9bB(Ma6t{7CE*ZCU|^SezJ$qRNyG#UC|zRFZ(b9x&8J?`j>-$F4mW8bk8( z$K6eUJe|OIav&*+|=mmw$k%mBHnP{(@6{Y=;=6Lo=_wSDLKnIq(LOUA`aKxK&ECm z#p1vQH-(7=McTv@QWeflpc0~bi%$J=!J&g1DWxG6kg$VNNd~>GCvF-U7&(Hr8aaa6 z-b9`Heu5upp$K;0O8-@$h1VHSfISq_1?KUy%3je?&R}xrJ^M*7iPljmyC7qSME9tC z8MHM{HnDy6B7Q`*;CEDPKngYt#5PNk;WvR2Yo|j!pkMt;>h8KjTB2B0$9r^He!+x9x?9`9% zM)hMq>hDzTmx3k}rawHnSC*0k{r$6seDcmuHXq@qD6_3Kf4HOfqH|;+^!bo!g-}@X zc(FiqXG)i9aqac!j?2~Z@vz7`<%l2T&Y_RBR1NGrh7dO+yD^|Fn|TIuQ@02ad^01j zscVekrZy)>nvPsOnzaRr5zo$QPYR9eB3JKhk_%>@IO*wRcd7#mb5 z(#<|P$*Di2km?ij%E=K*lkKT~!`|BT^NUJ;Tb4NT;kJC8B~fPBJ1(s;jP`z3kz%Dr<@=S$#hbD8iP6-(gnis@-UiEWY#6C zTT-$kwlEcNZ%>x#+=ilF@tMIAG||=ZMaiDGT+sxdN6N|GDr+qm2`daJ)idp z#<*z7y0-{B_I{|bX}O^Mb-bw&;}x`@;p5v$?OuP7qGNy*Z-0Rw3e%GG>%oGM_%Put zvADoSN}aE##8wy^3Vn`5u#uiOb2ina*f1;w3(Pn#wWTsP~ibKaPD*q~S0 zo;}D+iZq#G6k(${C_a~N7+I{6czvSbDy!QNaxSG|k~8yS9EFg7l!F;pm7ZcffMp#w zk(%N(OS7g$ASW4ybXHRp{Xnt|siLOdiwb^?(__RD6L=4cV+sxfpn`aY9pMV>w*Cm6 z`(c|K-BVW$XGOHf5PhYzl&vo16Deh#`1y2?1b8f0Afh!i#3?L}HTY*hN}xNq0&^gi z+dBw(NCdXPL2F8g8(18BaJI!j1OS?2A#8G`7DDs~!w^`E@>K)`D#K#f{R$og1d?qE zbjR}cJ=F%)7U$AP#PDCvR!U#CMevfb+kivz?9^{{Nzeya`uSIQF|AgmS)Umj2SYuA}EzAE7Hvjf~&wwQ9&$~zG2bR4!4%>M;HyptAJ`& zp);4JW6|k&?@}VG%v3$>du&Y~Uo$9j3{9WdvQ2QTK%aUs)D9?3lj_Wujw=xMMk6}r zIhu>IOug%+>yAB`6MiW6*iI7^5qiQnT%Si_hqok6lkc3T%^G+lGfU!TtmI5OrOmQ1 zJk#(T4a7(2?YZoq%8JG{Vciq$}JXI(L z0{qB_Fr{Eqsy>q@dE7 z7t~5p`QMbz4vuEdMy^&4_DsJkW;0U}EAKx#O8>2L{%2z|s|{9KejYwqR)$HpcmeqV z>MF7FePs)pjBIhf)UDmA?HJa&O?6JwZO$7QECwva?}f#QHJ}KJij~bMD47SH+TP50 zxqG?Mco%n>AIXXpqg9z7a=@xySyu-b+GM?8NnSFgPI3bpn>3Fb+Lh-TmN%PHyTkN; znPGbTqL{Fndfm2lpq=SO)Ref)YQAFUMeAsWBMEUHslR`hf@E9}CekTN6AQk3yVeZl!%#t1zqkrR@AKFi1$8B{^qUCV3ZEHrsNDuhb&-m5QPWd@cYkb7&Z>s z*RTqNX*T(j=r7Eisq0L@S6SF6zsOc#tQET4Wg@*5n(@O%C}@fI3^>GD`In#+A18%p2Kk z^~Y#b=SMuFa^cmFQqqhB;U@@SR%s`7ucLp3uz^1d1%p$Lrp_56a%%C(_Nd7vaBXWN zeJec!f0Qm06zQ!95V=Y=h7)gKgUl}3Z%?)sl%1}au*_sVl2)D4Rd`BwEX{v`TB187 zk0h7tB1Y$Y%VOrUXmmtec8R6B%{mDRSXw;hI3>m8~-)??(O+VNFSp9XooJ0KXtoH+E)~rsHyrtQfWn|mG_9woad*Ww1C#?DGh~zhFiW@o`pCgVwor2lUv{eooWlrCBhNhhb}53-$|XGyqk_b*8!RwIq~eWed!BaNZ}XF` z>ck%1a#OdZa*BBk6UPWFc7Cjfyd7B_0{yMjh!!2HDo1X1>j=fg(vIsLw%$1*u{nqj z(J*p0F89ljf^llajB0(0Vd(H`ZqO)u5>s5=QMk@*D%cd=$)_1lEHaXEl4x$-0qYr@ zz9tjSbKV(0VW)E%=1iF)H1Gq-0)sK@IU?nF65`RJ`fh{k9&X_Q^0@A~OZSYySEgL& zTA&?f{dRK56B*@8oS&PD+qi*G#nXPU*8bc%vB^Rs%*$R+ji+&~E+5W^UHo zt+w!V_o+tg2bj3&tw+b#m$<`^50VsYALLNBYj{Qmw7<2#hxjWOaK1 z2V6`IX67iHAL?i?zaE^t1S5-mNQA#&)$gb}f5s}8&)D-`o468Bsb7exQd81~7ChJC zly&UK)f&=L7Wle;6D`}st?nhBa8Mv9bmTHOcw>}m68K#+;Iyb&Mrh|mNeRivI7Mwm z9Nu`VVZkyGU$&hw*B|yGj~sa=Y0?3kHGaBVSNRo2;67TX1}L&+W$6Nt1Q{y6srS9 zfQpho+Ge{;-h7rJ`XcoUKg7I#_cISW#(~5bo#gi!cGf60`Og+Ja`_zcHZ&84oAgU> znhjr2(%r2uNaAuPA~umB&6`Xosgd%Np6+3^Fk+V$Io#)=SVJj}yF(I$+^$+WS7yGL zK;w`1)*^Y%TdP)rkhO;KCS#(^aQyH9DCo zk84?YO-$XGLGSMr$(Vh&^dxf}JHnO`Al+h zUBHGn9K5PDkwW)eKM!j!W%KKk0#39lDx8{08+~nr)-m%DA}iazHrf92UeDh3(obM9 zhIYaaB)%Gqd4I+eYZ7DN=bw<}NfOwN&$=A`24{u3TI*S>S09@eV~6GrNl*f2E>OT>yydU7sGk6iP&UN;oyxg3#ni>``E$mlTAQP=+%$i!_v)FQq zVdfUGEfwLj6T(*^O{NiC5Jde^%Q=xv=|k($I3(E~KMF^SqnMzY@@3HY{wZPnO)vA8 zebo^LJ#Y<(I`MZC#(!P0GK$h)fTeFUpRPq5Ia<3V)e1;u?s?OngZcVGvTVSXjbd>ZP|H_0vNj7y^mJ`P^fq2 zj;9Ty!jn{82V#6kBZPMvNIQnWpQWp2Dbc{^1oR6Ea*tgv<&cJhnPPOz9W$-+*7>P% z7+oA8>dlNVYPySo_}`4qpF_D=4BrU)-8+fDnNWdvTE8>_`hsU4zpK$qS3iiyga5vDtw=jD^auyk>OX7cL-&ln0D%<%2^g@J3(E3=H zWj>Nu!|IymK3QtTUD{~^=<9L!2%q^zR^_?=%Tt5XrpZR9Nsmw0SPFBv1!p0AUaLV* z-+rNze}(-s5_W{ZxNFNq4;Co+0c+2A`->6}77^B~pJRHq*S}oN!CSi#v3nV^+r5@b z@DTPliLATCgw0i>_9Jjjd=d-cCrLOaB#MOdjxv$vC_bHaGPt^}K*_bwR0yW9N~Ww7 z{!Co`KB^K^vq?rL_At?)3~F{OQk*<8l4@#&PVt7_K8~nU5WT`eL=7F+ICBEuJO4VzcvP zl1O?-Qw0!*&PN!OOcQEytQfDQ=>%A_lXbsp2{AlknfLeHSZ)VQ#e$dVl-Jp4v!Une zx5OQ(Vp{OWhU}nA2Wf18f<#c~Bc$TFa3w$FP@84)(gfitpM+Y%+@ZZB1O;B9&WehE zCfX$#!aR+9Cj)ec%;i>1P!U z7_c@&`78?vE8lT0j0fmSu_%uyHGn=wC>R0rcgv& z7RP=D`bPQ&rW~2gmk5|HQ6cBc`$~QnXcs6yL&*>Y`+=?z2z`~7mB@uOi{vSC#HL+6 zKkAZMi6*a-VZRbjJ5+#Hx{C*=qF7KONjl^ftulqGy+tBdK=m#r=1DfW&`7Sxu+&Io zG0iF?fclHDagOaaSi==G<>Vg53qS)%%MJC1RHQN~w*+#D3B6cPL1S&j5> z;^Y5xrndwzuFxlh(Jfvehzf;y^&;cAXSJ*MfV)|X~u^Z z!m+;3f|6@m*bjN!cD5>NqHu}JbSeGvecu0!i|VUaZt9y!g@}Slk%bCtZExp@X<|kA zVYbX_TzWodC6_lwfMV&L39HVKdH_;!4j|u`{}G;&aHmC->(WW>wMknA3}Pyy=pk)Y zKPJ=q6Z&_$QG*kJL^OYSG+dsV!#phc*lDt)r9M6@~=eroYTcVvpXGV+vQm;?}Dl8(~^hc#n+UN|)1n_J~et4#bnk zTQ(BiqqH>&!?N8Ifa3d0N+Tn|wMGhpLOaNb>izGa@S9&?W@=*U_|GPZsHx*0KJ{PT z^xrk=AEVG_m2sJV5O;9CG^Tn{@U{0wvIR$%hg&KAN9DlY1 zTG}T05@jt3r-4c>LMSJ96^p49RUn*mpgdY-MZJ(kjf1LMa_qRkYsnN>J%DEvsz@u; zznt}P>uy-pzLT%DBg$}?!h@mjT^wuf>Sl676$|jo#921a7S~r7^EHF7U*Fzc;^@$t zJ1P$P9kD4XrHINS**Nb728GcwEMYnVR|9wM2e;)9rCect5{VvckKo{Lux1N7Aoi;ph{)>SbjqY$N(HdJ_elKDm?pO1OL+!T4d-K97cujwu{Mx2kc6p*L{GzHEGxd$_ph#08p++_V z$TLB=GIRMp3r{9}F@HA*S{{kZDa*)#w|MRxtN$*bt(nG=8loOb)X)09SBb)j&pQaQ zTW~T>EQR*=BZO%}!e()8w5=t#YLrzjSW-?|z1(NLNVZJb=32w%GcMEEgcpob4a+JL zDlV&iYQx|vZblWcC^5|*vPm=g9TnRVt5l!IHH&@0*cdp_a*9Ycaa5WU57rMQcM0?5 zrPu_%UZwscI4gD0uo7xI_jm(3K+&zHJk%(a@I`Tut~3nj!*veu2Ih>ptRmDP9bXNI zKW$5ZPLvPgC!L)C8Z-ffnO~3V<}`^X+jQHZN~RdUgOp`)&J17-h_HZr3^G>Hm7xhy z&NExu{P^#H^P6N*=mCWf+8Td111g;UZr|&#N)JqqM$RA>ABb@w`fm*~kgEax`zNFm zWgXC2P=?4n z`BM*gdL+z+z{d$ptn9u0;%EEznb_bf1b0tAirt2t371&^vkxiwj~}g9p9&ULB`_6n zGIK6Ik%rsR;x0XpjqFtr$#_r#am8DnI8j%HxDW2#n5h{7Q+e!nZh1EcB~%ks4YYL{H%zJypUAX5t;-k_rc*4=UrSE~3`9cI zHVi#)9MA=DW6f0PH+wE`YulD1&A1<@r{$-gU|gzsmWOnlF5fdeEx#;7-UL(N&&4KL z>}wDi1o;(+LvW3@jBV4BH7I}R!Lv_5u8WP~ZI?U&F8hh@oqx#8!@e$J4Jeyic=T_M zVBke|#9!yI%44r0gA&u$qOhA%yN()gECZbXg8VmNeivc|pY$JpSK5Riz{vj1u=L*m z^AAywKY`_+Fj0|L1ZP3XxvuzB_@0uey8_1N%9xn~dUgPX!*HqS_yUW;UT4nzYR|xn z^$H{bB8eL&4lB%r=8@FO=3u_nCH?$*^#uLSr%wM9d(}ZfW*A=JMxat3$NS>e76I^# zQY4;0XB}#PEZMv)+3%7gfHhvjgyCqAw6W>XCY+&XYO z0@@Nn7ZJLqhCIzFe`c~ZWGQkVVMYF>Y@LM-y}YW-gkmBNu#+vt zo~YD{4-;xeRVlUT2F#-Tv&jX9Zfd90x$(Bb>_1R1{cy(~0z;c+Dn}MOLgiv~=`m7A zjX7ZPL_QuM=24WG9XNlTYG!{HH5y8`?A3=8EwB-cBNJX9wlY`CEs4B2rJb$OOr|`# zR8BfR^o>%TLKa=tNI>9H7wf9%qNnAobhKUJwlYCcz*6O`*#pK{F@rxf-=7;Ep8rVu zfh^ed?d|%+@No0>o{Q7G$94m9+<0k-VPdr{hHqgA@VQ}zJLoWy@xQ8!r{$@o6%dry#b15*>%A89RPvY5b+6V%6_Tv{2XOQjV+Zpk@^kI1H z7o5rdeg^DTCo0A9dclq6n{L7A_4cz}K_bm#Bcv1pN`hNT9ahF^ZcUv#w-Hl})-_;6 z{$S=>NImmQhwc`PhsGt&Yt^5 zcoU#at7GkeA4CKf0auqRHC_F+c>#Xwe6y2AoMB$bikA!hZ2V;lrNnu`L%2!?>{=wo z?YJLUF``>3ZdyH?XcQpw5@GW=JV7D(NUWj%wM0`!?8uPAZn^^6R-E^!V&&Q^PXxtZ zswS);w!<~mA~dX}WAWIrEo@wpf& z^ToxKUuX;p^;x1Nk+C-nUQROSGpAEW)Ec`fie|^qYOZun+=WFQzG+gcn)4W<(*=!m zo=;&ci}wcsZ>=2T*_MKoBc^<*8_Yxu)?2WHlYOG>6J*oM&ZA=z9R|IV{8sHTw;4&= z*5F?r4deM@d+)uivV&wdbs_tiIc}-VSrn@IrTF?K)7xawIuZ{`od=s4huk*ud1Se{ zSj1Fv@18nSAO6y9TP<~caRLGS7Ua19{}Jr^i~EL#D=}lxgbWZ8XHdcVr~4KXQDKR^ zTRXl;M#|W7AX-LypuYHgedz38OT zrWDu9S!;Es$O3=LHe6o#ktsBnvmS2QV5Hdo7kea9={B#UW3MohJ>EPLXl*VS*U|Z* z`R&E|A(&|GyKIim?xeK5|Qz@UUL4@pYLG=KsO#Ii7%w@n-})*ZssR&A4! zN(&!PWL$3;_*1#^J3&#iAa?uB8!-Xl-2885pQis^jpC0+^FM|He^I0OqfhdW@xZ^w zKh24g_P^_wVXH5Vrt66!va+&P1y)g)VD|YksKnqjp)%q;dz)@tjH{cL=a5(GB!M77 zig)}N#%GKLIEN!<=KQ(1Z?BEddxxz*-d&>H;VFgctl5IZJX+nFiYDz5FBY~L1D61o z_rqEPl1${_<1a3pX08Ks>A97<#aHCuxr|fm14*Y!98j*lVh4*7jG~>WX6q-S942cB9Qt=$j zrstY@k$DLo@GOQzUgkea|v__ zvl^_Ssdv25t`KkUD%m=;M5K24RtjQOC`m$Mb#yevlmw64*vr!GU}FZfoXPUd^G{NG zjpV_1Cr!4KUD#+N^ILk(%$Z{@@t2>L!y!ZPkUxxS! zBdFG>To?1z8u4wP6@>weyig5ii?++c7ov!6M&fiYqLAu{4kjATdOO5FLtl)}gNpJh9qwlCr16&o)~M;VQ$6Ehso3oFy}$)^obx|{-&ZR2Cn_dD>5 zO@ph9r`HJL)xm>thUUdoDa1937#*3b{bHNmAeX`BWtv2}2EV>}ITpt-!A|Zo-YWaT$DX1~@ACf65 zW_AwlpdF##ecnHohW-juWflbp78C-iGy;M^68(3CO55PPC@L7CwBWEa900+sMDG2w z5qG2mEr1jT|0hY(J8%xnmAQ+lDbJY+*NL&ISMZGoWYh`bQ%tmFcM|8YIG_^#rgC6yLd8SeL1SLLSH1&1kppk)VSmh_ zmtlVU%Cwf0QK^Ou%L_jEW+1=469+_y1g*HRcocEWx9z=Sc&#&s{q~DGR!^eL2EjGf zfKftw6Wp@YQ7o|H&lJ{;%1W*R0$0gsS zoJplWKdZxy3H2gxhoJ?exx1O7^2YaU{$RZS^(Zj<@>^~Fljs?Tk@4_AFeUAZReo%k zx2LJ`@_-4jqm0ZT7B}}!0Mi+_!6W3y{vtdug6sO6ILVPZ zQPl%yW=h+@%bwX0y<+)Bp8T0a6}VT}RGY|*ISQcgr5zlO=Z0VuG$X?s9nnZrfVN(W zDhm4a6i@3d?=T85p=Y%q8WVPSGp}c#`)c^D6ILB&hU_@$bGu+?%~#!q>ZYFCUzr(Z z;Y}6a`8cHcuVhYUIuGgzv)fgdgF@F4?ylu^+CqV$ljytt>hOo7IJ6&AjP>%WuA&}BY#tXIY=;{@E&(sEPlP?98&l+AHk374 znv>+gi4h#=TsY2(#dQ5;2*k@-Er*WB(62&HvsYfrstP0vO4NeMyWM+kVtEcw{!!8A zBjquYD~02HWbp!A$+6q1Ozl;I?(OI81uMv2MT{M_;@gPH3@xE25#DFzDLM!eIn21` zS#y|t5M>Mt_@6h+avn=9bY4Bpwu?5n|rRs-?MSLnGr>h)D~r5!jxX`(JJ& z44Khm(5dBfFo7kx?|&jriy6`#ht0Wo(1+bJRi$P5EY0ltjh|m_DoMAdL3Y{xfaT+- zjoUe_e^QvVAt*P2!r14|#V;!rZm+Q6D^;O;quX@|^dvZvpAoulXqr}%m;Zz&I*?)( zmi1iV$XAKL;~+$^3m>!j9Xb~-XW6lx z3cvo7b)f%V4a&x03*WD>%9LD0v zC$$Q?;THURPRtnC3bwX+e3=9LNuU;7WEP>TC z4*TPE)8qr$-?U~dLszo$ahrT-B7B9_T~)8}Ssmy;#&2?eVnJ%~4Oejzt0<3P?$#bi zEOo`zK--qYg9zgoGW>wpg2N|i7=6oNgQ@ZJG38I`)bH-E4?J~oHVC(haQ_F96;KTN zFS!0iWMxtPk12gAb_;+yJREKpk!gdAS|SM#T{RFzIf7H(cjH3AN$Ngv73#|17(Ie= z2;0PX*MK!QLoahJwFeKa9(kUv^#|V}pT+b=oI&1~cbY&gF|byI4Nk|haD-CC37m8W zvN#@y8w9_&5URpqgsn0z+bxbzY-ql@eFZ~K-(#Teg|pQK-0Rd&!f))$efbheX+Q1k zB@d?PI33cFkOxz-VbikIN#yEpXV~nvq8{{3YcxFfFp*yft!`4frL^4v5v?ks&7^iR z-%xx`_4}Eo7jT?0uak`|MLmBF#_Ak4STANZu{P|it2dfU7knQzX7r{L0glxdE)!8) zc?|4~vx-It>2CR0i>v?i6FRzo6#+n#!zS*m!qUotL#FQQyVliWm}m;%9^ejnO-MFv zxKO9dAH(QM1SNeL*E=}SEWjPdjH*+h1>Ew_3Li9VHx=v3Aoeh~4;Fb^m5g?x4QU3X zX}om>#Swo9-B;lpXOq;MtqRyUR_hG@GPV*(jPMBDmJi#p_l_&al6v5V7XWa*S}Y<* zvV|Uny%%OhJZ?O%w4i}U7+iijs#GGhzODl{w%MI)LmUl*_a_0)KOfG2f}!zVbOBXH z)w-H;ry{kVjz|?Z88N-;v-tgZalVxNP%f*9SDXKpaiaDucXS>Hxn_1)2J9paLUpzD z3SqL6eR?*)$lc!Gi1>_r6&GQq{EO=+QXHHi60OE7o@7hJHM}7$5#^=#Q^)gA(YyQ& z?6Er{eU1j?g@hf72KbA0CRgV0sXJthv)qwRaug^W&iV;yg5)>mJ9G^$H_sz}M?G1V zE{zL)bXJGyEsRMnxOVcpk?uFNu=9fn8U%ik{YU%hyor0>QG3vX2_=g(F-|vJ|LM44 zzMIK7f(+mi)EN3dE3$w*x0Siq|Dedy3|Iw;Yk)j=F^6=HtF$T{hUHjliR+3!NeMq7 zzexsFrLwDYlmZuYB#LIt04#{?st4v$Is9~G@>NJR{^082DRi;CLYLQ9lFmtr(a39_&G`i`qyaqZ(3?%`#GZ~Jp zHc^4h0`@TA9sGbf0qy|6T2U+2nn>$CLnDn2Lg(Iu{5Xs5PBvUvp3K#39iGTxvWX^T zt(CWA^0Vb`=2lAS?Hx{GyKf9>i{ddt6sA>VE8(6P_wZVTLPAQU+VXAYcd0i)grTmM zVj{xVln`MrR~g!i5$h52Weqm!IDSjm+JJzK=3@>fmq++!2S|lvtHO;uM^4eI`K}jc zhSxko`NY2K_zIsSOoNG~Vm_G%S`S>o09G`$&wC4l_{aEP1qV9`zlzdg)feZN8{;FZ zQ6#9;6$R}jL=JoQDZOeGvC=K(SCLlEiFY9kAQa?H^Jm|_K-p64sF1%JyL;dQGQTW) z$6e(2)_K2zAt>^hwUcXQY?!Ki0n)#yU^43phs1KDH5uf8bcCeMVMlJtE5eC^tsZwB zJ|6pJxx=?|sDA=iebc=SKG#$!46dF~K-Z5~1KiF*A$SfNDPuXiM&Vo(_s^IBotRpw+L6^1Ps4Rl9_J5PUPp1T00hlH)KmW})yWNDV}~nA$yKR1Zj@%mfK& z{g&MCgoo0utDiMzYrN0(Ih@E4=zP9eZY6$4R1hzYhi|npN(PKUP-(+gxSwmw8-f6a zeyM|Kr#sglT(n!f!b$zCH;c`GnKJ1S+G>E_jV4-J!>j!en1Jx3l&=Lkp20P2*{{g8 z4A86_MtA-byx;8e@Oq6Cztz*+<(I@CgsmU!Ds?1yRi3kf*B>wIlMf|J<~Yyuuu^Mv z<)5Ao+nx>4zd4R8JL-y9%UT^cunoXxAp*rhxpBUKmKjeAoKODVY`GRfucjxvf@lOt zNA3;zS}XNyp6$dMMIFAr9>cku{ADQFK?4p%as+v&!wZd6_S86fK5h-zvdq-#&cOP8 zHq6XA-WP6SAQ{fJ4_E?ELjk|Ie@e5v9}D1(J8=;!muWK4_cINYgCjn zSAcM62gRY?PvyD0(Vn7UmaeDIMQ);N^Ap6%_`8fb%FD60l*x;4afPrds$)h-HwaOx z`iG8S83fKF%>0kbOrMMnA;o1qvq^>*gBSa;P2^M}B8RQ&6h8K`zkD!pP2isyM>E5= z+NZph4Of+;D)I`9*G`7885FJC^%(d@K=z6m;gtT1fI+v|D>hSD8GKwUei+THz1LZU zaX#mZZk3XU)FchO&FC&Rgio7hS zLiRguwQ1JI?D9s@Muslt8kDW3#z3uviaX}C9y3>MSciM16~M&!1qKojbnhH&4!<)- zVoTz>`DP023h3$rvostRCOQ=d5So&GRUV)e-I02v#^F^$j5S$8nT^kdZdBaSVX6OCNO3ty4vAH#mK=rT6sG4+~fKgpxk61BG_yAGEeb^uKM8Xs@p=37*XhHdW8x$y%5Wxf5K8 z_M9~NTb8lCECm#(+I?I&Zk=*1t!?B=LxHfy$ja#KJUm-%Jp47q)0sv5`gmgVPVHeN zV$ssY7;}yA$k7;zSNta3@(xs>*i+pVQlURzwvqUR9{IEIZV#Y)&IOi<1aWPogB%T9Dt%-4*6ezsz2b(+gKo%Df_7H*%TipKC8Ma~;IE_ znIA#xi&f^1YFfSUSG3u7PCOE|NDocR8zB3|H~At3adNL|y8++Gn%fHDJRfgtaShSl zQYEFsqK-0lhG%I?p)nN(DjPy01`K-*aA-NvvGCnHx_y(hn!&>yQCM``rP5<~(Le`v z7u=SOvOEMHa+)PJ+q|Nin-15tTuX8)>R}u#OWi9sG)mq1xLfL1YA}}pjxs;tT@;Mo8Fk@l8Bk+w-1F7EE`4vkCW zjeFznPT}q}?(Xgmjk`NE?(XjHe)x7~c4lW!oS2RCqoOM6=Np;%WFysz)GWsEErC`|$!4F3KaGO_%jf88AjihUY zpTn-0m&2~QOB%uML3zhO7oiYNY~85ShH42KSdsGcm#EL3dxMmRRl46_Z};Q7GI;fq z?(eTBt?>w7-%r%B3AgGaSf1pFI7hZpg@BBe^mv6L z3{}u>pXzAe&wjz%@x~m>&D`7Tu}5Zje+ERB&!QAs{h2E&DZ0+tz{fcV2pr{kyr^D^ zDHzd7jKaeQYST#5bRn>`F|#mHi?6)N*n4G(s-(06Gx6{lW2tP-v4N2t%0a=7=(;;v zUKD&J;YU*jduRgN;87naG$KS^bQQ)@aNp9I7$_k1g&Ve1ie^`Q8^CY7|CmP`bJfGM zL=Xjq>jP|Z&+4#0CyMtw5QUODx+xsbC_#uMD{Sx>qawE=dPnr89ZxIOtV$$oP{EbxhaL2mJ+1R)J(BS=}dY1D&Ikhypb{5J<6SujL7h=|ENxs@rj)6_ERuFhhQNz zMrw*D_Obt+pA}j+qxFXWyC2eg)S$Xvb|6Gag{7`86rsvy@l%!v-bK>zm4Skq7*P?mAD<=|`p^wh!*?hv-q`H=oMpqQIKNpf z%bCyYV{mc*VAS^4D@3s8%~ZE1sVK+lvRn3;Xk-fT#z2qiQYBS4gcKb~Mz-}w#inEy z*;JO-Xp~t6E?^ya2{`h5EzE|~PRi-N%(A5izgTgc*s#lOww1p`d(AbWX*e7X#k@0> zv6NXEF8y$f5~!+yap#x=F_r|{aR%nCjAQ!<+ASi~4m<)A@x@!Ls5~b)!k2<0XJ#Qm%;?a90W;tLJP#GeW z>iaPc_QJ7ET#(9yQd5JKuc3i0#!sm3oiEwzoRpdQEqRYSbAq2*sA8u_k7CjKBv3(W zFqs;lo?Tx^UQ;+AHyIJTv}O?DJavFgw(KLScxmDvow~eXR`M-GmST>X)HHzlPK8BT zDK0{7yV(yt;BX|IIxQ{!WDt2VVfKg9th9o`yC|~+m>Lagj~kVfoBgsx5pi3DIxN8; z>0Bcgt@EyYzRml;*(8m2(>}U>9r>xE{pXnK{|`dZ|5_JK)^t=-#UA>6MM~{sgqBDH z!>KH+&y)r!X8lnk(ZdQRDFMY8gW=Abx-5Y(HkO*ji7J?jVScGnz96M(HE%E=HJ`Un zVkVL-m0YPzcsBs4>v=Dt>v>f;dbw&kF_ys+N>=G;yzlwy+12s+%KdtC&g=blGy)04 zzRe+T8QcQ3%7`NZ1Nila%AEvn#i6k zem2l_^)TGwsS!Tk1sOV2ChVJ_=|Ws0pyuvZ0o2t-QzOG217{_U2x`*&)GRCp zTo_%+8BP}g%1BErDYbP$iL`s+QN*)uhGWjP;K$OELn-xp*K`1rhP`t1R;BgdW-5<=i-ks{f~#^V zs)vnAG?GTXmeflf6d1NPvM9=2=*^83MoO-|;(5$SD!$P;Ua0En>Esnsb6u#R z`Tj6?h=rx2N6ZjXoO}274Ey0VQ|K;a(#g6BPZJkwsXNkehBth$>wq_Q8Ywz5VN{^N zAsWGu#1$w=Sy~*&TmJ^@Aqu%uk9s z%A;r?tI2-15S^g!@#-B5VMh**e~TdPGM0?y5wp-CPwOyP+CX5l?abl?H-8$=kC4gi z-UvZ_v1YG;u8)vKOJVl|x=k}d4c;Sq89s}^E0#^=_=G3_CFZvHge5^Gv(R(#35&z~ta#%&88RhQ9| zqRLCaW0|S_0hnm0ongF9!ju&`j57Cp?|bze>)N$cAlT%PB~hqMRi<|IZX ztz-yd`m1MAEpoS}DFr8N176lqJ;v$Cr_LQXV`(Yn;%X(WwY(t2wA1&gzQyt%0f=Q~ zg7UTHF`&q4SCDqwD+DJBJEh?Pw6x#~=;Ii^G3E2B(9f&G{6as=FNk9D+7SdR?IDT1 zMM$gTc_U-WeC0rWwJxf5TERQRV>Q8T#JfEX@xZ71KPhA-!>&fy5YDw zJ1^dTc9iiSa3fjg=?bnM7Za_|JYxtH1}YUvf%CddX)>_V08jUmhX}8On;jm@^a1hW zR{LaG&DElZ|G6k=N>Rmav#nAnMAKBjDN?~%CO0nZzwyyxfd-b6vL6-y5G7weV560= zKjwo;_*H2)bKifORV-K1@K8LlNxI;K4SUpe!Gno%DdYht@_kJkdnJ3Ua9 zTwMZ^4@3W;&kAG+v+&A@;R6ptf2}VB#7?uc*Ea}csd5ED$PTF&?pMKQ3Ej;Op8Qh% z4Jet~H6JkG*aF11!jI$C*6NFEcZES% z3EQptg|7;3g3#0IK_DCiWz5wpMnnZ(D%^4>bOzso0EZ{EPB96ve%u}eY8UFUCfq>w zNk>~d>yrU)7U|*kY7WfN=&oPEyxKroHG2i3HH)kYh*GW}SIH-^m<~uUtw(5@+JsmW zU1j^JS?TXAN{NsU8*RW#p{Iw^w2Q{Rqwct?Y}tFd6!9eiTTg158MupgPo_k?v z#`Vq*xI&bK_{`IOAiN8Qat?8a3t>M)Ikl}4pQ8&K{)waD32IjZ z4poDN&WbY%fd9t~qIN}PY31i$g8)w@zMz0q&paI(8{|;KY|2blAM`nT#@t3f^*LSE z+{S?73VOyu<#xmaBu~DVxbCk1&-&St`iEzQDmY zH+dW_d^99ay$dfNoI#8^d$PJRPi>Y%yG&nJy8>&Zt2AA4U6xe0W`G_qSBSh;6-T)q zC^e&5!d|zeyyld$I8A=nuDYO8vNWm;&3SOl{xCiAU9dsTkR?#Hxc9U@XruBT)9&#( zMp!B_fN;hCPFE}|xa6R(?1Qv^Y>DsT-!6_dwnE6WzAlZK;DCUX{x63U|Bfp8?=77F zJ>XWTtSjOwe+{^`!$D-|Q1BRYFbzMR)@BywKnh9Z3T|T4*wN)qW$b+mhc8-}iSCCv zhOl)rr-vpSDOisDJLSYo@v^-hh9N&;bUo!K*8>XHjWP;YSy~>~qHno34=-#!-|k?2 zM)d@Qnew+ZkO;;?^x1t*4Sp&1Xd#7t_oNMBxBDI)2!t`d=g`*1$-Oet=HqH*I=t zM>#qfnF_P0&itL9dc9H>+q_lZ2xfD`>?#AI z;9AXNhB0w0lmfX_39=gfr5p`yXN>^^W5wfI7BiuhM1?odCN(@wE&DK2$7uy_q{+MJ z?;IMiDo&*1FzpA)Wm7oyND?S@;gIZ$b*Co1C>kq>WOx}=ezYEz*`=ICmn9ObGk2K) zNUL;o@i&1io?hn1Kt<*R!4sK0aZZqIf{g+?Hi>XH1?4$0e562SGrBeYIkJ*~DSFyD z%XslWr3Erg)C)hSIi1qwY^8eI<`6aLqhHo6q|CXw>cTP9ub=D4CA^@ssiI9K%JpWb zG_ZdOp?VcvdZ!HpTzO!vyUO>@)xpA(hOVL@4dTnmXP4xM-g&jYT{PyXZTJpPeM=65 zFY~)0ifD6{6&z}h<$%vTb>8`i5+7z{|FJx)zOFlGHU6tQBXO!hOKqoBE?rd?-7@f+ zj}K~BsGzqwIJ(yr+_cnzXLEyI|CqB-&0^bmpO>yfFPUWKAWOXhpeQZSW{;_WFytyHShTASTYy2BmmBj6MW;v|gHv0-Q@m+F zeaqC9ouKcvBb@&Q%sXe~ljeoyP1A8z%Hi;+>gspYuvp9xNhj%(MVN31Fc@h+By^5{ zKkQT|vmv;W-1~R2YCe=loC(yX2w=Dc+On8D;HJEHcyxTh-&tLePyW^)Jwb1MSk$*t zy;DHv_%K4nMw}P8={FublF^?~xinBkF24IS;e;$?4xbas<<_LF;x5H9GFMg=$fi8Y6z znBd8d%~;ho;$-$oI)brDekTaVp|oUJ_uLbfrnn1Eh{mJ}ig)A-X!O2@0D+;WX)f5R z^;<;mC(nZ_>EK<%g$eu!DmL_0*pbxcBFr7dFBCmKBSto852H5C`uMk@r!VN2s`FPZ zoFe`~Y~ox=*^Xzoa(-2*J%VKj7vo7m%c;+w0Mm$h+PN^AJh zt^o(V1R-P(9X~+45wDjzy=0Dhwo>LCucuv{Ia^rp1k{bTFmK&*dHs@6^|!`pa4+M2 z%2CPBv~C#f(3z#hf_a%yKfEm5$Dtvq)6k%y2~|)r^^DVR6WY=(g78c0To6i`i&Dl@ z50+ibZ~)8|oYZ&iV6Ae^=d4^jICJe5fWfly*~n?){-%-)_i7*=VV4;@M3uh?Rd+Lv z01cuB)Jm?LNe{#KaZ*x22$|G*w5Y-dIVxxj4Xfbbqxby@@aNj>=&X5k#IAQdMpSrZ z@4C2cQ;NRwPc&~jIaBBu%^Vk4KiB?wN|Bwdzp!PN68L+0TmVJC^8{0cVcRNbrall2 zOY|shWx2qC5USEbxlOSDPGd;V^_0P`6;A$#zAztuSkJk`0>?td`P3UoMSu&{8`GX$ z(CGpMn+?O4!;9ZYE%5RJbl4#0SV$!k6|}Rc4mKlsXqozQ;BWNeaNnkfA0I&)yvP9GYo?YHU~r>F@H;E%$K_V?auaeXf>QphdDt@| z{*j3;zmsI%<(G0*?e$1td*)=AqGET4AL8yQNc16-xIpUpm*K zkGqn}(pft!3QT`+MR_0T)|eiuz|(m5MDB=@-sEZtDt+Zvu`?PQ(!5~d})RkIHrNGpR*&? z6HTRQ&gjG{%*GHT%tsg^^(HK_kbq0FLllmh07A)@%@enAa!(q~VfqhfAugeri8a zyo3{7I0p=0j-2gI@Z^A;8ar-L_4Zh0H8P!;ehZy!4-OcbXDr9!m1uF$ejP~A4VgLq z3NvLQzLEmuI>C79%lgl_DSWL%>7Ea9c1is}%lh8IEvjP%5oHl%YU?{#K@f}Ho%;S4 z&glhrcB?ZtN5#pYRS)at^Ks3l&Ki$Lk7%oORx1*~eAbx=40mAW$a$Q!Eof&ih<G#1WMqE8@9Jwy z5M$%O%n1q_OO*66MjI&7)ZQY-;QlZ)m9cLg;kKVT^W`#i-yS3*>gmh0J==rr)cpB?FC9uafEA>#TiNvh%U&%JhT{D2eLhh!Q2 zMk010#q5H{Yx*?ABOoGr)2%1m8F6y4!e%>JQP(8^R^-g166eI)l!Z-CDgZ|$gnXVC zM27IpgiFezx@h|)@OvlthUDh5!$l_PpO`JY*E57{Az^o2kp)kAvERyEXx8DqR#alx zguCF=@I~$&Ef!RQl`3EPf=m&M6wrbGtl1nFWZy0||wk1TKmK90CgV7|BjoE6U58KM$2rFq$ zqm-F2a=;OzHGTGe7&N?kYNwsxhmaQX-Rgjv+uotRgPpOc3?ACeN>s)utT#i*=|O87 zxgVeCJsCi#7DaD~F*yMF{(6{z=4~a?H#i~tq4>Sib_5+NtSUZ12L(|wl?QiDX^U>WwHiwZi zPBM(w2WkSpEy8!BOE2C7!-!B9;CtdB70U1tx8wO3h7L$v)M zfZrp$dre`YPUMOQba{?Te1gO%7t1+84^EN^+n6;ChVp&9AG@TVb#7aFtVi9fds%SM zpjRFmI&&(ZzA~krUPy!Xqy}yj9spYsePNE8wr@deHX$QNA)Vb#t-ntt1Ydr1>__SD zcK|Icns?kgV;>F(YKWPOX@b>jspqg5?dL_5|C~z#C&s;>JWt^^hPWr>J8cV}8~vSq zmMU|(W1Ytwe!$L{gT#Z3wGAJlSmsy^_yi&0!DahJ*`qFGVbdLxbgt`CRjpdoL z^THmrgk%BnCQmzjvCOU&{(a;q+|3>N@k5$tLk)N79=22Kwi7R3PvZ_^Chq1X-*e!;IM8~ev~~wYTa+ylJ=nbJZ1Evho=$scA36; zNyy9qS?do%PAYFG#sjOyvOb-`WKLv<_~LQ09h1D~h)$o#8EFXx%Zg0?AJk@3>EOhJ z+wH*U_VlsFMHaLEci&LtN8ETUI~%4UQop51uKyg_K10Yf_-$D&-@Y&^djM|Z@3ig&fu29l#sNBd@@x7 zJe(XDP4>uWS(f?Vkx9-eu4o^cpqsQ&4Y#4rx2#n~V$0)#tIF)9B-C?_`6qTSG_|e2 z)f4165WV7#im|~3%V}l_Apfpp+y$a%)R%v%OMVy>oLBRm5c2JlqI(K4<_9mHFCl87 z4W%>fikmwpD_StXSLG=)@KYK9D`ggpL*G}6mI@uGU;6Jei=1R$YjUeJ>e=uO9(q9Ms!Y{JYR zlfY2*6KNAIA8>Myii7=2P&O_*K5JS^k|X_Qf0fpFlb3{{b9JjG6rTweCLHC18Y(_yn@SL@_adOKHGL zOl(fHtuqQlzUn-Ck>ql_1$renNFVD@M!++c?V0-QmAdThrf5NH+1nB!eB&w|c=GV?J$$)OY^14iPoY_Zs*QAZomd+cc;|<=o3k7` z*ZEOUYXWG@;fmdDXEx)+Z+%Sm8QjHKiTZ9oNq9yD^ia`Te@qRFG=<^}lzA^u@1kK3 zoU9}2T>|8LQUSCN9& zcik%o!xo!`6WnlcTX2#)L}67A%-4qJn@`v(rweXbFZRuUyG1%>uRr~Z2I(&WSq)1o z!{%3%seVBz{!;++e+Zy)sG5aPPBjR zVnkb~SyxoDv;CSkpT`L)KUUB{7f=ZNK_|}2C+keByn z{x?>0Z%jOa|NO6k;I)UAl?HAA-TVb_(6dQNTta#M=)12TRda5!{|<0q>Z`)=9k9@^ zbCcvH6BR8pDRO5B0ondZ*GWtbF2|P5{hB#fL5!JXW_{NU=f3VFnox+EZ|#3Bg6(2L zT&WB^s0L1bSiREQO5xBO3Q1JfFl`Wa12zt*y?gURoPVV-)w{KzA{eOhB)wFQ)I@2% z)KL7~K@&RUx9qMyVa18$rq`{qf!?0WTy59gT)V-!|Fvny;W04?;j$>BH9*t1HrF0% zkyiHM`S`Hd^YPSIe7*5e!1}A}ad#^}^t5&RLf5k5FmUlMFMnU>?KNJr0{Sz=bswJ^ z6E(K65gTJM>Qy4WKj$S^*0E8DuNTJ64&%=FPktC@O2TBkzXLWOQ($-iW>K{O_H4Fz zvB;R>4%R^73TAa$B4MsvT^Q-u9Gzjn%%SBGYbJUeNF*9mqFoRfMrgTQkaQLqGeiP| zv7+g}3TXdQwz-1G#sPgr)y&uDKc!*(J$(M6JQ*7q0Nno_Q~uusuD``og&eO`{|~f` zj!|t^(aYwI-k;yr1i3}zdIp8T$=@m5b|l$x*$I2!X=!_UzuY=ebn~=KiJM_B$H#C@ z2w$(C9}u>nZh;IfUzTo|P*bvw6gY}OcGo+EyW6Tcp~pzHXPhh)>>p{qsi_OID~jZ0 zTs%h~u|>CHG>0-<6wsfRImO*b@~N4c+v9UC1Kim&)Ws9oR+45)%JO*TrLYl?v=}CX zhAZqxz2+~L8-;hMulhvwt$;vylCy;`V{ zPmvyQIEpAa9W_?3;jcZkR`r7+RO~*UgYOTe5y%AD!{RqjTD`Ck&+{6k7pYO>)f%PT zGUN4{ke%h&ZICNjyX=}ltL$18Ryc&|6P5Y^cb^4wrKPRF+lvZWNYSh%b6oGG{@Tr( z3<`f%ZCd4x3T14`OAl3~)z*F7Z$b844)BhGsgiL1=(Fq_PviJ~>oYENW#YaQ2Lyd8 zt+iE6PUAD@K`QrJv(|eo9ki4*Kee08TP^H+%y5f~INVDooAi z&b=4`EZ1er)lQQxq10&ynD%{F=AKzO)jz>+a4|-X?=4a&7WhmJGuq{v1j}vOGAfsU z)lHQv#MUR2?Y24XHVkvHJA<2Ng_kw==!VOqyP;u)bwHP=bW5STFcs#7V54&|6&YYb zqm#aglk_m!+NrHbuG?EOr%Ic)V$`(M+060c7`42H(`mYwCw83_JI5xzkPWS~S*>em z7c9Dle830H+g*U?d`B51ix#5p1Q!emaTwLZDn26+`JlqDHWZ#fdKbhNqWN*t#@8#W z$J~F21YIU6_$Q0R8Nzp$6!WU-NNH03i9rgqegiUs2K}O)!!Cp>7sKL zzGBr}&AM*C#IvdNV)hUI)g8=D7M|N0NyO zYu$hgABUSSap!aCvF&0Z7mnIAo=|yehCo)u@8k`uB-uw8Q+BkCB?cE^JNFPa-Ba9;j*g{B~dlt|s@fU8P zabi@f4C2P3C-nW=3gS9$QeqUh!4VQ>6G&+F;O`dNq<{Mt(}us=KEtzLD)e8Ovi8;X z@%@LH@^=iQG{D+I&{)|KVCnD=+u1_Jzi%ymTi3xT4e@goQV(?3&yzREBPOX2QtK`V zLFAEX0>xj-1ei3Dzv1h8s-PN1Y(qZfN0`D$%s-J0XN__=SbI#Q67qN9gSx`$^rF#Y z%J)0Q*3%;B+}n=(o<^YHji`cL)y&PX(wf-X}~x%f9q&t?5o zrURW;_Kh&2bHZttY;8bws%v2Ab384f#b)NVfD1g-FQ}JH#;U!Yw+dPd1I+HL2?1KB z!!>8DLsf(+ci~aP%rw>Zua39PSkSkDm07x#ID|^SUhWA_`xmrm2U~@n>19;vOPF2) zu@+nr(s_3qt&s2SnOwnc0ZOucB=UT30cLbY^<2p;FwAc+63pl5{ zoh%+(OCV)%vZaJ?1%w$dJuZ=vsDRg*o6fjkrgxS8VG8!NPZi~>m>%6(jg>@kvQX)g zBmIT=Urcl#y0$@uU3dUV&+p_v6?cjicRsTeIvMh^%FT^CTW7y()|(Cn&7b4GQ*#Jc7CEqcc5D^v7jl^6vAE*0UIEG60v6r#!zH;fx3EK z(v&_@9^#e|P3z9DHE0@g zxj7^`jUwt{M1r^=DAFO|24ONGvQi$UQV;%?E*4iD&qOgm(`K$;b@`AUS25=4hf6$n zYAOrM;n>FC%5ojm0P(gu$RrbazHU(351825)oZ!li*xk-;Kcei3JD3R*-w-S{5K<0RFL#=^IC zZG&bH(D-}L$g=flu5%Kd`Shd%cLXPxLt&DIJ!=`LYtU0PqCA0|49!bX(E_jKpwPxh~}ktn1kyu{g0%4G&lo+9xoob z>JU3{(B}LcOfQ(3BSUfRMB$awAS>j2U#(7|i+yy;1&7Q{!2Fa(#f*&Vk-2JFyj5|o zW?GF_K{lhvr>(1-_!Q8eqQLV}n1O^)5_&a1dT=*Gqk;JE5Zoe1Alp@YOl!BXB*|oN zL_r{Lbb`NFV`E_sL$rRNJWZi{CjHz;3Dl2xa$7;l%o9S^cL#1^yf#gS!WwD_679cp{6pjpujXvb2|OQvUY@5%v6gAi z6C}?)-kC0|^fJbo`T7bQg;M+_isbpH>>i}swjo(L_Y9MJ8Ks_>_hZ`4eetxAP7+u! zh_4%(C-?KeU=IH3&pQm1fiS+J{QXM~#s7bcawTIcTT6XMV-=f!0y8q>tiFb6q#@JW zr6SYWdI?J_uM!Ozl4b@pB^q#KF!Han?DkD9cDvcO_39?fdrfL8KZZA;UsQGvIPPn1 zY+K=(%lIEGuj!dzQ9dLK}dl_gM_=rsBcp$95r3ZpjLI z9AWTB%qbtP``Usk{VjwvtcMO5>_G<<6rQv8z9O-|dI>e*_>mfb{|8s)vDOtL-@+Z0 zxhFY*zf&g)UC>&#`Ph_0*`}dxWrY*I5SfoK>{(lJ&~e@j8e6~ zecX_F42F_B%^bZq`I%8;+~nJo0arCd6sWP9o!)#J%x@&uhs`?DYGjvB=kNQKzFu$T zfnd!CxVF1>Pb5@D*-6@IXL6{%;}oU(N1cTiIVA$}eQg-v;hNRja?0cE7Bl)S9j2%G3hpkOqgklk2An__*hIOZ~hY+1ak0K_% zzYJr0C%8|Tz*o~@7*VuT9r8SKPVzn)-5l!jf5PZN1%BsZBowP%*=ttcI(Qc~$7p%> zN%vTzv#a~P)%QJ(aWek(>?76>(yo5T5FBw?S+P3rhiVL_S%QdqToJd-?!#GYV{WO) zxR$a*rBzCK9|$$ToK}QW-cGBWl{|d^I;@R?CA!HmYr+3KrPR9%TrH`e5e(oe1L zZ;MZ_WWC*OJ^i-+=R`$y^IPvk#u!^q)F4*}odgc5quG0JJlpQdAyLjjUfwl5n0 z<^Cw((S%4Q6^z=ra<;29`$I3Gms=fz?NCeR(@2H(m1F7bj9;J5D-ZPh6Iv`^3;=`_ zvW1XAQSm3$#S!q}kneq^HiJeHoUv=WFb3F66J-Mhmdk{_L!$k1t#)em+MMxn7xX}4 zA#+FZyYb<~Nb8*TN@bnOLaCNp;)wubjfKiJ4he6c>qOa7YXK_>K`Bs2_}RB9UfpXY zbyhro6umXpZ>qQN!5v4iX+rAF>NI7i3DgMSX^UD`1B|z2Ds?KRX1hsb0JsV>ONl%M zUArTEXrt(YZ7xvNVBkFExo@HkE#L9tm8=m9Q&AO$&ru|{$TMV#{C&ab?O6I{C|gm! zM_zzUT$Kc;W7;Ma@br*MZsF-j>wzhPbcjh5fsswXYQ288j21`EFsLy0mC%DjDV2+k zXtL4W>o$~+Rv6P1R;ub_SjteU+!?O=LMeO?#JVrQd@m7GW3J-go%DFis=swd@p)l~ zQpsFN1~{j>3wU`QVE0F7Ez`~omO^d_qNz?vAh6hg%h z7D5+*B7gk?Ov1Y==O=s-J2{gp+{#O06F@VAq_p>oDpqPcj1?@Dhm7!?GfWGCdyd>0@Nm#pgJcf z!g)KL;d%G*LTwiNfpc1$LemYlc(w#)R&o;ztTwuCUFnil+4T^LIkL(8f z+4C0^awQBM&O8m_smFbuM)RYiT=euU{KJvu^Tq+Zg( zq2pSv#uog=$G>^$umHg-;-CNlHPip+CKG=joBr*X?XUUi?+2M0u%1fush^#UdlPF~ zf>4O~Kgyv{P=baHZw~aKfb℘*r2A+*uq@MOj#wSVE&0RFF00krT}anv`=IFbLc5 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 QF^Ms0P58ORD=by}3u+AybN~PV literal 0 HcmV?d00001 diff --git a/web-designschema/libs/com.inspur.edp.udt.designtime.api.jar b/web-designschema/libs/com.inspur.edp.udt.designtime.api.jar new file mode 100644 index 0000000000000000000000000000000000000000..44f6d5a24b5c84060c6bccfc2e11bb61def47471 GIT binary patch literal 101129 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 literal 0 HcmV?d00001 diff --git a/runtime-scriptcache/libs/bff-engine-core-0.1.4.jar b/runtime-scriptcache/libs/bff-engine-core-0.1.4.jar new file mode 100644 index 0000000000000000000000000000000000000000..fcfa913205a68e546519930ee7bdd3b8e794bcc5 GIT binary patch literal 80940 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