Jelajahi Sumber

Merge branch 'wrdp' into 'develop'

Wrdp

See merge request o2oa/o2oa!2606
o2null 5 tahun lalu
induk
melakukan
fbe95e461c
100 mengubah file dengan 3566 tambahan dan 545 penghapusan
  1. 25 1
      .gitignore
  2. 10 0
      o2server/configSample/externalDataSources.json
  3. 10 0
      o2server/configSample/externalDataSources_db2.json
  4. 10 0
      o2server/configSample/externalDataSources_dm.json
  5. 10 0
      o2server/configSample/externalDataSources_informix.json
  6. 10 0
      o2server/configSample/externalDataSources_kingbase.json
  7. 10 0
      o2server/configSample/externalDataSources_mysql.json
  8. 10 0
      o2server/configSample/externalDataSources_oracle.json
  9. 10 0
      o2server/configSample/externalDataSources_postgresql.json
  10. 10 0
      o2server/configSample/externalDataSources_sqlserver.json
  11. 290 0
      o2server/configSample/externalStorageSources.json
  12. 38 0
      o2server/configSample/manifest.cfg
  13. 18 0
      o2server/configSample/messageSendRule.js
  14. 31 0
      o2server/configSample/mq.json
  15. 4 0
      o2server/configSample/web.json
  16. 18 15
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/factory/AttendanceWorkDayConfigFactory.java
  17. 6 1
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/jaxrs/attachment/ActionExportHolidayDetail.java
  18. 26 1
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/jaxrs/attendancedetail/ActionReciveAttendanceMobile.java
  19. 3 1
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceDetailAnalyseService.java
  20. 17 1
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceDetailServiceAdv.java
  21. 28 1
      o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceSettingServiceAdv.java
  22. 14 0
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceDetail.java
  23. 28 0
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceDetailMobile.java
  24. 21 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/entity/enums/DesignerType.java
  25. 3 27
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/build/CreateConfigSample.java
  26. 0 168
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ClientInit.java
  27. 5 18
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java
  28. 4 4
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/JpushConfig.java
  29. 73 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WiDesigner.java
  30. 197 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WrapDesigner.java
  31. 21 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/PropertyTools.java
  32. 26 13
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/factory/FormFactory.java
  33. 5 4
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/ActionApplication.java
  34. 5 4
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/CmsJaxrsCipherFilter.java
  35. 167 0
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/ActionSearch.java
  36. 7 0
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/BaseAction.java
  37. 48 0
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/DesignerAction.java
  38. 11 0
      o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/ExceptionFieldEmpty.java
  39. 71 74
      o2server/x_console/src/main/java/com/x/server/console/server/web/WebServerTools.java
  40. 0 28
      o2server/x_organization_assemble_authentication/src/main/java/com/x/organization/assemble/authentication/schedule/TestJob.java
  41. 15 1
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/factory/PageFactory.java
  42. 15 1
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/factory/WidgetFactory.java
  43. 3 1
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/ActionApplication.java
  44. 10 0
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/DesignerJaxrsFilter.java
  45. 213 0
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/ActionSearch.java
  46. 7 0
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/BaseAction.java
  47. 48 0
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/DesignerAction.java
  48. 11 0
      o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java
  49. 16 1
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/element/factory/FormFactory.java
  50. 3 1
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/ActionApplication.java
  51. 10 0
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/DesignerJaxrsFilter.java
  52. 172 0
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/ActionSearch.java
  53. 7 0
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/BaseAction.java
  54. 45 0
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/DesignerAction.java
  55. 11 0
      o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java
  56. 55 0
      o2server/x_processplatform_assemble_surface/src/main/java/com/x/processplatform/assemble/surface/jaxrs/snap/ActionTypeAbandonedWorkCompleted.java
  57. 19 0
      o2server/x_processplatform_assemble_surface/src/main/java/com/x/processplatform/assemble/surface/jaxrs/snap/SnapAction.java
  58. 16 0
      o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Snap.java
  59. 11 0
      o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/SnapProperties.java
  60. 7 2
      o2server/x_processplatform_core_express/src/main/java/com/x/processplatform/core/express/service/processing/jaxrs/taskcompleted/WrapUpdateNextTaskIdentity.java
  61. 23 9
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/WorkDataHelper.java
  62. 2 0
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/review/ActionCreateWithWorkCompleted.java
  63. 65 7
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/ActionRestore.java
  64. 95 0
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/ActionTypeAbandonedWorkCompleted.java
  65. 69 0
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/BaseAction.java
  66. 19 0
      o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/SnapAction.java
  67. 2 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/ActionApplication.java
  68. 10 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/DesignerJaxrsFilter.java
  69. 3 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/collect/ActionValidateDirect.java
  70. 149 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/ActionSearch.java
  71. 7 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/BaseAction.java
  72. 48 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/DesignerAction.java
  73. 11 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/ExceptionFieldEmpty.java
  74. 2 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/ActionApplication.java
  75. 10 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/DesignerJaxrsFilter.java
  76. 259 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/ActionSearch.java
  77. 7 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/BaseAction.java
  78. 48 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/DesignerAction.java
  79. 11 0
      o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java
  80. 106 129
      o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/ActionSearch.java
  81. 8 2
      o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/DesignAction.java
  82. 6 2
      o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/ModuleType.java
  83. 6 12
      o2web/source/x_component_process_Xform/$Module.js
  84. 20 0
      o2web/source/x_component_process_Xform/Actionbar.js
  85. 43 0
      o2web/source/x_component_process_Xform/Attachment.js
  86. 25 0
      o2web/source/x_component_process_Xform/Calendar.js
  87. 10 0
      o2web/source/x_component_process_Xform/Combox.js
  88. 25 0
      o2web/source/x_component_process_Xform/DatagridMobile.js
  89. 25 0
      o2web/source/x_component_process_Xform/DatagridPC.js
  90. 5 0
      o2web/source/x_component_process_Xform/Documenteditor.js
  91. 115 4
      o2web/source/x_component_process_Xform/Form.js
  92. 65 2
      o2web/source/x_component_process_Xform/Htmleditor.js
  93. 11 0
      o2web/source/x_component_process_Xform/Iframe.js
  94. 13 1
      o2web/source/x_component_process_Xform/Image.js
  95. 38 1
      o2web/source/x_component_process_Xform/ImageClipper.js
  96. 26 1
      o2web/source/x_component_process_Xform/Label.js
  97. 38 1
      o2web/source/x_component_process_Xform/Log.js
  98. 17 1
      o2web/source/x_component_process_Xform/Monitor.js
  99. 11 0
      o2web/source/x_component_process_Xform/Number.js
  100. 119 4
      o2web/source/x_component_process_Xform/Office.js

+ 25 - 1
.gitignore

@@ -13,7 +13,31 @@
 /o2server/commons/
 /o2server/jvm/
 /o2server/local/
-/o2server/configSample/
+/o2server/configSample/appStyle.json
+/o2server/configSample/cache.json
+/o2server/configSample/centerServer.json
+/o2server/configSample/clientInit.json
+/o2server/configSample/collect.json
+/o2server/configSample/communicate.json
+/o2server/configSample/components.json
+/o2server/configSample/dingding.json
+/o2server/configSample/dumpRestoreData.json
+/o2server/configSample/exmail.json
+/o2server/configSample/logLevel.json
+/o2server/configSample/meeting.json
+/o2server/configSample/messages.json
+/o2server/configSample/node_127.0.0.1.json
+/o2server/configSample/person.json
+/o2server/configSample/portal.json
+/o2server/configSample/processPlatform.json
+/o2server/configSample/jpushConfig.json
+/o2server/configSample/qiyeweixin.json
+/o2server/configSample/query.json
+/o2server/configSample/token.json
+/o2server/configSample/vfs.json
+/o2server/configSample/weLink.json
+/o2server/configSample/workTime.json
+/o2server/configSample/zhengwuDingding.json
 /o2server/*/src/main/webapp/describe/
 /o2server/*/src/main/webapp/WEB-INF/
 **/.settings/

+ 10 - 0
o2server/configSample/externalDataSources.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url":"jdbc:mysql://127.0.0.1:3306/X?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8",      
+		"username" : "root",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_db2.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:db2://127.0.0.1:50000/X",
+		"username" : "db2admin",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_dm.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:dm://127.0.0.1/X",
+		"username" : "admin",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_informix.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:sqlserver://127.0.0.1:1433;DatabaseName=X;selectMethod=cursor;sendStringParametersAsUnicode=false",
+		"username" : "sa",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_kingbase.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:kingbase://127.0.0.1:54321/X",
+		"username" : "system",
+		"password" :"krms",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_mysql.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url":"jdbc:mysql://127.0.0.1:3306/X?autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8",      
+		"username" : "root",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_oracle.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url":"jdbc:oracle:thin:@//127.0.0.1:1521/orcl",
+		"username" : "X",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_postgresql.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:postgresql://localhost:5432/X",
+		"username" : "postgres",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 10 - 0
o2server/configSample/externalDataSources_sqlserver.json

@@ -0,0 +1,10 @@
+[
+	{
+		"url" : "jdbc:sqlserver://127.0.0.1:1433;DatabaseName=X;selectMethod=cursor;sendStringParametersAsUnicode=false",
+		"username" : "sa",
+		"password" :"password",
+		"includes": [],
+		"excludes": [],
+		"enable" : true
+	}
+]

+ 290 - 0
o2server/configSample/externalStorageSources.json

@@ -0,0 +1,290 @@
+{
+  "file": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "processPlatform": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "mind": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "meeting": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "calendar": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "okr": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "cms": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "bbs": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "report": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "strategyDeploy": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "teamwork": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ],
+  "structure": [
+    {
+      "protocol": "webdav",
+      "username": "admin",
+      "password": "admin",
+      "host": "127.0.0.1",
+      "port": 8080.0,
+      "prefix": "",
+      "enable": true,
+      "weight": 100.0,
+      "name": "251",
+      "deepPath": false,
+      "###protocol": "协议,可选值ftp,webdav###",
+      "###username": "登录用户名.###",
+      "###password": "登录密码.###",
+      "###host": "主机地址.###",
+      "###port": "端口.###",
+      "###prefix": "前缀路径.###",
+      "###enable": "是否启用###",
+      "###weight": "设置权重.###",
+      "###name": "存储节点名,对应存储名称,谨慎修改.###",
+      "###deepPath": "是否使用更深的路径.###"
+    }
+  ]
+}

+ 38 - 0
o2server/configSample/manifest.cfg

@@ -0,0 +1,38 @@
+{"node_127.0.0.1.json":"节点配置",
+ "appStyle.json":"移动端应用样式配置",
+ "centerServer.json":"中心服务配置",
+ "clientInit.json":"客户端初始化配置",
+ "collect.json":"连接到云平台配置",
+ "communicate.json":"消息配置",
+ "components.json":"组件配置",
+ "dingding.json":"钉钉配置",
+ "dumpRestoreData.json":"导出导入数据配置",
+ "exmail.json":"腾讯企业邮邮件配置",
+ "externalDataSources.json":"数据库配置",
+ "externalDataSources_db2.json":"db2数据库配置",
+ "externalDataSources_dm.json":"达梦数据库配置",
+ "externalDataSources_informix.json":"informix数据库配置",
+ "externalDataSources_kingbase.json":"金仓数据库配置",
+ "externalDataSources_mysql.json":"mysql数据库配置",
+ "externalDataSources_oracle.json":"oracle数据库配置",
+ "externalDataSources_postgresql.json":"postgresql数据库配置",
+ "externalDataSources_sqlserver.json":"sqlserver数据库配置",
+ "externalStorageSources.json":"文件存储配置",
+ "jpushConfig.json":"极光推送配置",
+ "logLevel.json":"日志配置",
+ "meeting.json":"openMeeting配置",
+ "messages.json":"消息发送配置",
+ "messageSendRule.js":"消息发送规则",
+ "mq.json":"消息队列配置",
+ "person.json":"个人信息配置",
+ "portal.json":"门户配置",
+ "processPlatform.json":"流程平台配置",
+ "qiyeweixin.json":"企业微信配置",
+ "query.json":"数据中心配置",
+ "token.json":"令牌,密钥配置",
+ "vfs.json":"虚拟文件存储配置",
+ "web.json":"web端参数配置",
+ "weLink.json":"华为WeLink配置",
+ "workTime.json":"工作时间配置",
+ "zhengwuDingding.json":"政务钉钉配置"
+}

+ 18 - 0
o2server/configSample/messageSendRule.js

@@ -0,0 +1,18 @@
+/**
+ * 统一消息推送执行脚本,使用在messages.json配置文件
+ * 方法返回boolean类型,true表示满足发送条件且接受对body体的修改,false表示不发送
+ * 变量body表示消息体,每个消息类型的消息体可能不同,是一个Gson的JsonObject对象
+ * 以下excute方法表示拟稿状态的待办不发送消息;excute1方法表示变更或者添加body对象中的modifyFlag参数
+ */
+function excute() {
+    if(body.has("first") && body.has("workCreateType")){
+        if (body.get("first").getAsBoolean() && "surface".equals(body.get("workCreateType").getAsString())){
+            return false;
+        }
+    }
+    return true;
+}
+function excute1() {
+    body.addProperty("modifyFlag","1");
+    return true;
+}

+ 31 - 0
o2server/configSample/mq.json

@@ -0,0 +1,31 @@
+{
+  "enable": false,
+  "mq":"kafka",
+  "kafka":{
+	  "bootstrap_servers": "localhost:9092",
+	  "topic":"topic-test",
+	  "acks": "all",
+	  "retries": 0,
+	  "batch_size": 16384,
+	  "linger_ms": 1,
+	  "buffer_memory": 33554432,
+	  "key_deserializer": "org.apache.kafka.common.serialization.StringDeserializer",
+	  "value_deserializer": "org.apache.kafka.common.serialization.StringDeserializer",
+	  "###bootstrap_servers": "服务器地址###",
+	  "###acks": "指定必须有多少个分区副本接收消息,生产者才认为消息写入成功,用户检测数据丢失的可能性###",
+	  "###retries": "生产者从服务器收到的错误有可能是临时性的错误的次数###",
+	  "###batch_size": "该参数指定了一个批次可以使用的内存大小,按照字节数计算(而不是消息个数)。###",
+	  "###linger_ms": "该参数指定了生产者在发送批次之前等待更多消息加入批次的时间,增加延迟,提高吞吐量###",
+	  "###buffer_memory": "该参数用来设置生产者内存缓冲区的大小,生产者用它缓冲要发送到服务器的消息###",
+	  "###key_deserializer": "key值的序列化类###",
+	  "###value_deserializer": "value的序列化类###"
+  },
+  "activeMQ":{
+	   "url":"tcp://127.0.0.1:61616",
+	   "queueName":"queue-test",
+	   "###url": "服务地址,端口默认61616.###",
+	   "###queueName": "要创建的消息名称###"
+  },
+  "###enable": "是否启用.###",
+  "###mq": "消息服务类型.###"
+}

+ 4 - 0
o2server/configSample/web.json

@@ -0,0 +1,4 @@
+{
+  "mock": {},
+  "###mock": "使用Post模拟Put,Get模拟Delete的模块.###"
+}

+ 18 - 15
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/factory/AttendanceWorkDayConfigFactory.java

@@ -13,6 +13,7 @@ import javax.persistence.criteria.Root;
 import com.x.attendance.assemble.common.date.DateOperation;
 import com.x.attendance.assemble.control.AbstractFactory;
 import com.x.attendance.assemble.control.Business;
+import com.x.attendance.assemble.control.service.AttendanceSettingServiceAdv;
 import com.x.attendance.entity.AttendanceWorkDayConfig;
 import com.x.attendance.entity.AttendanceWorkDayConfig_;
 import com.x.base.core.project.exception.ExceptionWhen;
@@ -23,7 +24,8 @@ import com.x.base.core.project.exception.ExceptionWhen;
 public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 
 	private DateOperation dateOperation = new DateOperation();
-	
+	private AttendanceSettingServiceAdv attendanceSettingServiceAdv = new AttendanceSettingServiceAdv();
+
 	public AttendanceWorkDayConfigFactory(Business business) throws Exception {
 		super(business);
 	}
@@ -32,8 +34,8 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 	public AttendanceWorkDayConfig get( String id ) throws Exception {
 		return this.entityManagerContainer().find(id, AttendanceWorkDayConfig.class, ExceptionWhen.none);
 	}
-	
-//	@MethodDescribe("列示全部的AttendanceWorkDayConfig信息列表")
+
+	//	@MethodDescribe("列示全部的AttendanceWorkDayConfig信息列表")
 	@SuppressWarnings("unused")
 	public List<AttendanceWorkDayConfig> listAll() throws Exception {
 		EntityManager em = this.entityManagerContainer().get(AttendanceWorkDayConfig.class);
@@ -42,7 +44,7 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		Root<AttendanceWorkDayConfig> root = cq.from( AttendanceWorkDayConfig.class);
 		return em.createQuery(cq).getResultList();
 	}
-	
+
 	//@MethodDescribe("列示指定Id的AttendanceWorkDayConfig信息列表")
 	public List<AttendanceWorkDayConfig> list(List<String> ids) throws Exception {
 		if( ids == null || ids.size() == 0 ){
@@ -55,7 +57,7 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		Predicate p = root.get(AttendanceWorkDayConfig_.id).in(ids);
 		return em.createQuery(cq.where(p)).getResultList();
 	}
-	
+
 	//@MethodDescribe("根据年份月份列示全部的AttendanceWorkDayConfig信息列表")
 	public List<String> listByYearAndMonth( String year, String month ) throws Exception {
 		if( year == null ){
@@ -64,20 +66,20 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		if( "0".equals(month) || "00".equals(month) || "(0)".equals(month)){
 			month = null;
 		}
-		
+
 		EntityManager em = this.entityManagerContainer().get(AttendanceWorkDayConfig.class);
 		CriteriaBuilder cb = em.getCriteriaBuilder();
 		CriteriaQuery<String> cq = cb.createQuery(String.class);
 		Root<AttendanceWorkDayConfig> root = cq.from( AttendanceWorkDayConfig.class);
 		cq.select(root.get(AttendanceWorkDayConfig_.id));
-		
+
 		Predicate p = cb.equal( root.get(AttendanceWorkDayConfig_.configYear), year);
 		if( month != null ){
 			p = cb.and( p, cb.equal( root.get(AttendanceWorkDayConfig_.configMonth), month));
 		}
 		return em.createQuery(cq.where(p)).getResultList();
 	}
-	
+
 	//@MethodDescribe("根据年份和节假日名称列示全部的AttendanceWorkDayConfig信息列表")
 	public List<String> listByYearAndName( String year, String configName ) throws Exception {
 		if( year == null ){
@@ -88,14 +90,14 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		CriteriaQuery<String> cq = cb.createQuery(String.class);
 		Root<AttendanceWorkDayConfig> root = cq.from( AttendanceWorkDayConfig.class);
 		cq.select(root.get(AttendanceWorkDayConfig_.id));
-		
+
 		Predicate p = cb.equal( root.get(AttendanceWorkDayConfig_.configYear), year);
 		if( configName != null ){
 			p = cb.and( p, cb.equal( root.get(AttendanceWorkDayConfig_.configName), configName));
 		}
 		return em.createQuery(cq.where(p)).getResultList();
 	}
-	
+
 	//@MethodDescribe("根据节假日名称列示全部的AttendanceWorkDayConfig信息列表")
 	public List<String> listByName( String configName ) throws Exception {
 		EntityManager em = this.entityManagerContainer().get(AttendanceWorkDayConfig.class);
@@ -103,9 +105,9 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		CriteriaQuery<String> cq = cb.createQuery(String.class);
 		Root<AttendanceWorkDayConfig> root = cq.from( AttendanceWorkDayConfig.class);
 		cq.select(root.get(AttendanceWorkDayConfig_.id));
-		
+
 		Predicate p = cb.equal( root.get(AttendanceWorkDayConfig_.configName), configName);
-		
+
 		return em.createQuery(cq.where(p)).getResultList();
 	}
 
@@ -129,7 +131,8 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 			isHoliday = true;
 			dateString = s_year + "-" + _month + "-" + (i<10?"0"+i:i);
 			//判断当天是否周末
-			if( !dateOperation.isWeekend( dateOperation.getDateFromString( dateString )) ){
+			//if( !dateOperation.isWeekend( dateOperation.getDateFromString( dateString )) ){
+			if( !attendanceSettingServiceAdv.isWeekend( dateOperation.getDateFromString( dateString )) ){
 				//如果不是周末
 				if( workDayConfigList != null && workDayConfigList.size() > 0 ){
 					//遍历所有的节假日配置进行判断,是否法定节假日
@@ -161,7 +164,7 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 		}
 		return workDaysCountForMonth;
 	}
-	
+
 	//@MethodDescribe("根据节假日配置计算一个周期内的应出勤天数")
 	public Integer getWorkDaysCountForMonth( Date startDate, Date endDate, List<AttendanceWorkDayConfig> workDayConfigList ) throws Exception {
 		/**
@@ -181,7 +184,7 @@ public class AttendanceWorkDayConfigFactory extends AbstractFactory {
 			workDaysCountForMonth = dateStringList.size();
 			for( String dateString : dateStringList){
 				//判断当天是否周末
-				if( !dateOperation.isWeekend( dateOperation.getDateFromString( dateString )) ){
+				if(!attendanceSettingServiceAdv.isWeekend( dateOperation.getDateFromString( dateString ))  ){
 					//如果不是周末
 					if( workDayConfigList != null && workDayConfigList.size() > 0 ){
 						//遍历所有的节假日配置进行判断,是否法定节假日

+ 6 - 1
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/jaxrs/attachment/ActionExportHolidayDetail.java

@@ -6,6 +6,7 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
@@ -126,9 +127,13 @@ public class ActionExportHolidayDetail extends BaseAction {
 						attendanceSelfHoliday = holidayList.get(i);
 						if( attendanceSelfHoliday != null ){
 							row = sheet.createRow(i + 1);
+							String empName = attendanceSelfHoliday.getEmployeeName();
+							if(StringUtils.isNotEmpty(empName) && StringUtils.contains(empName,"@")){
+								empName = empName.split("@")[0];
+							}
 							row.createCell(0).setCellValue(attendanceSelfHoliday.getTopUnitName());
 							row.createCell(1).setCellValue(attendanceSelfHoliday.getUnitName());
-							row.createCell(2).setCellValue(attendanceSelfHoliday.getEmployeeName());
+							row.createCell(2).setCellValue(empName);
 							row.createCell(3).setCellValue(attendanceSelfHoliday.getLeaveType());
 							
 							if( attendanceSelfHoliday.getStartTime() != null ){

+ 26 - 1
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/jaxrs/attendancedetail/ActionReciveAttendanceMobile.java

@@ -86,7 +86,14 @@ public class ActionReciveAttendanceMobile extends BaseAction {
 				attendanceDetailMobile.setLongitude( wrapIn.getLongitude() );
 			}
 		}
-
+		if( check ){
+			//是否在范围外打卡,默认否
+			if( wrapIn.getIsExternal() ){
+				attendanceDetailMobile.setIsExternal(true);
+			}else{
+				attendanceDetailMobile.setIsExternal(false);
+			}
+		}
 		if( check ){
 			String distinguishedName = wrapIn.getEmpName();
 			if( StringUtils.isEmpty( distinguishedName )){
@@ -240,6 +247,12 @@ public class ActionReciveAttendanceMobile extends BaseAction {
 		@FieldDescribe( "操作设备类别:Mac|Windows|IOS|Android|其他, 可以为空." )
 		private String optSystemName = "其他";
 
+		@FieldDescribe( "工作地点描述, 可以为空." )
+		private String workAddress = "未知";
+
+		@FieldDescribe("是否范围外打卡")
+		private Boolean isExternal = false;
+
 		public String getRecordDateString() {
 			return recordDateString;
 		}
@@ -316,6 +329,18 @@ public class ActionReciveAttendanceMobile extends BaseAction {
 		public void setCheckin_type(String checkin_type) { this.checkin_type = checkin_type; }
 		public long getCheckin_time() { return checkin_time; }
 		public void setCheckin_time(long checkin_time) { this.checkin_time = checkin_time; }
+		public String getWorkAddress() {
+			return workAddress;
+		}
+		public void setWorkAddress(String workAddress) {
+			this.workAddress = workAddress;
+		}
+		public Boolean getIsExternal() {
+			return isExternal;
+		}
+		public void setIsExternal(Boolean isExternal) {
+			this.isExternal = isExternal;
+		}
 	}
 	
 	public static class Wo extends WoId {

+ 3 - 1
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceDetailAnalyseService.java

@@ -40,6 +40,7 @@ public class AttendanceDetailAnalyseService {
 	private AttendanceDetailAnalyseCoreService attendanceDetailAnalyseCoreService = new AttendanceDetailAnalyseCoreService();
 	private DateOperation dateOperation = new DateOperation();
 	private UserManagerService userManagerService = new UserManagerService();
+	private  AttendanceSettingServiceAdv attendanceSettingServiceAdv = new AttendanceSettingServiceAdv();
 
 	/**
 	 * 根据员工姓名\开始日期\结束日期查询日期范围内所有的打卡记录信息ID列表<br/>
@@ -336,7 +337,8 @@ public class AttendanceDetailAnalyseService {
 
 			if( check ){
 				try{
-					detail.setIsWeekend( dateOperation.isWeekend( detail.getRecordDate() ));
+					System.out.println("isWeekend="+attendanceSettingServiceAdv.isWeekend( detail.getRecordDate()));
+					detail.setIsWeekend( attendanceSettingServiceAdv.isWeekend( detail.getRecordDate() ));
 				}catch( Exception e ){
 					check = false;
 					logger.warn( "system analyse record date may be weekend got an exception." + detail.getRecordDateString() );

+ 17 - 1
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceDetailServiceAdv.java

@@ -24,6 +24,7 @@ public class AttendanceDetailServiceAdv {
 	private AttendanceDetailService attendanceDetailService = new AttendanceDetailService();
 	private AttendanceDetailMobileService attendanceDetailMobileService = new AttendanceDetailMobileService();
 	private AttendanceScheduleSettingService attendanceScheduleSettingService = new AttendanceScheduleSettingService();
+	private AttendanceSettingService attendanceSettingService = new AttendanceSettingService();
 //	protected AttendanceDetailAnalyseServiceAdv attendanceDetailAnalyseServiceAdv = new AttendanceDetailAnalyseServiceAdv();
 //	protected AttendanceWorkDayConfigServiceAdv attendanceWorkDayConfigServiceAdv = new AttendanceWorkDayConfigServiceAdv();
 //	protected AttendanceStatisticalCycleServiceAdv attendanceStatisticCycleServiceAdv = new AttendanceStatisticalCycleServiceAdv();
@@ -282,6 +283,16 @@ public class AttendanceDetailServiceAdv {
 	 * @throws Exception
 	 */
 	public void pushToDetail(String distinguishedName, String recordDateString, Boolean debugger ) throws Exception {
+		//查询外勤打卡配置
+		Boolean ATTENDANCE_FIELD = false;
+		try (EntityManagerContainer em = EntityManagerContainerFactory.instance().create()) {
+			AttendanceSetting attendanceSettingField = attendanceSettingService.getByCode(em,"ATTENDANCE_FIELD");
+			if(attendanceSettingField !=null &&  StringUtils.equalsIgnoreCase(attendanceSettingField.getConfigValue(),"true")){
+				ATTENDANCE_FIELD = true;
+			}
+		}catch ( Exception e0 ) {
+			throw e0;
+		}
 		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
 			List<AttendanceDetailMobile> mobileDetails = attendanceDetailMobileService.listAttendanceDetailMobileWithEmployee( emc, distinguishedName, recordDateString );
 			if( ListTools.isNotEmpty( mobileDetails )) {
@@ -292,7 +303,11 @@ public class AttendanceDetailServiceAdv {
 				if( scheduleSetting == null ){
 					throw new Exception("scheduleSetting is null, empName:" + distinguishedName );
 				}
-
+				for( AttendanceDetailMobile detailMobile : mobileDetails ) {
+					if(detailMobile.getIsExternal()){
+						ATTENDANCE_FIELD = true;
+					}
+				}
 				//获取打卡策略:两次,三次还是四次
 				//根据考勤打卡规则来判断启用何种规则来进行考勤结果分析
 				if( 2 == scheduleSetting.getSignProxy() ){
@@ -305,6 +320,7 @@ public class AttendanceDetailServiceAdv {
 					//1、一天只打上下班两次卡
 					detail = new ComposeDetailWithMobileInSignProxy1().compose( mobileDetails, scheduleSetting, debugger);
 				}
+				detail.setIsExternal(ATTENDANCE_FIELD);
 				if( detail_old == null ) {
 					detail.setBatchName( "FromMobile_" + dateOperation.getNowTimeChar() );
 					detail.setRecordStatus(1);

+ 28 - 1
o2server/x_attendance_assemble_control/src/main/java/com/x/attendance/assemble/control/service/AttendanceSettingServiceAdv.java

@@ -8,11 +8,13 @@ import com.x.attendance.entity.AttendanceDetail;
 import com.x.attendance.entity.AttendanceSetting;
 import com.x.base.core.container.EntityManagerContainer;
 import com.x.base.core.container.factory.EntityManagerContainerFactory;
-
+import java.util.Calendar;
+import java.util.Date;
 
 public class AttendanceSettingServiceAdv {
 
 	private AttendanceSettingService attendanceSettingService = new AttendanceSettingService();
+	private DateOperation dateOperation = new DateOperation();
 
 	public List<AttendanceSetting> listAll() throws Exception {
 		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
@@ -109,4 +111,29 @@ public class AttendanceSettingServiceAdv {
 		attendanceAppealInfo.setEndTime( endTime );
 		return attendanceAppealInfo;
 	}
+	/**
+	 * 判断是否周末
+	 * @param recordDate
+	 * @return
+	 */
+	public boolean isWeekend( Date recordDate ) throws Exception {
+		boolean iflag = false;
+		Calendar cal = Calendar.getInstance();
+		cal.setTime( recordDate );
+
+
+		if(cal.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY){
+			AttendanceSetting attendanceSetting = this.getByCode("ATTENDANCE_WEEKEND");
+			String configValue =  attendanceSetting.getConfigValue();
+			if(attendanceSetting != null){
+				if( (configValue.indexOf("周六")>-1 && cal.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY) || (configValue.indexOf("周日")>-1 && cal.get(Calendar.DAY_OF_WEEK)==Calendar.SUNDAY)){
+					iflag = true;
+				}
+			}else{
+				iflag = true;
+			}
+
+		}
+		return iflag;
+	}
 }

+ 14 - 0
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceDetail.java

@@ -336,6 +336,12 @@ public class AttendanceDetail extends SliceJpaObject {
 	@CheckPersist(allowEmpty = true)
 	private String archiveTime;
 
+	public static final String isExternal_FIELDNAME = "isExternal";
+	@FieldDescribe("是否范围外打卡")
+	@Column(name = ColumnNamePrefix + isExternal_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Boolean isExternal = false;
+
 	public String getMorningOffDutyTime() {
 		return morningOffDutyTime;
 	}
@@ -1170,6 +1176,14 @@ public class AttendanceDetail extends SliceJpaObject {
 		isWeekend = weekend;
 	}
 
+	public Boolean getIsExternal() {
+		return isExternal;
+	}
+
+	public void setIsExternal(Boolean isExternal) {
+		this.isExternal = isExternal;
+	}
+
 	/**
 	 * 清除对该条数据信息的分析结果
 	 */

+ 28 - 0
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceDetailMobile.java

@@ -159,6 +159,18 @@ public class AttendanceDetailMobile extends SliceJpaObject {
 	@Column( name = ColumnNamePrefix + recordStatus_FIELDNAME )
 	private Integer recordStatus = 0;
 
+	public static final String workAddress_FIELDNAME = "workAddress";
+	@FieldDescribe("打卡地点描述")
+	@Column( length = JpaObject.length_255B, name = ColumnNamePrefix + workAddress_FIELDNAME )
+	@CheckPersist(allowEmpty = true)
+	private String workAddress;
+
+	public static final String isExternal_FIELDNAME = "isExternal";
+	@FieldDescribe("是否范围外打卡")
+	@Column(name = ColumnNamePrefix + isExternal_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Boolean isExternal = false;
+
 	public String getEmpNo() {
 		return empNo;
 	}
@@ -270,4 +282,20 @@ public class AttendanceDetailMobile extends SliceJpaObject {
 	public long getCheckin_time() { return checkin_time; }
 
 	public void setCheckin_time(long checkin_time) { this.checkin_time = checkin_time; }
+
+	public String getWorkAddress() {
+		return workAddress;
+	}
+
+	public void setWorkAddress(String workAddress) {
+		this.workAddress = workAddress;
+	}
+
+	public Boolean getIsExternal() {
+		return isExternal;
+	}
+
+	public void setIsExternal(Boolean isExternal) {
+		this.isExternal = isExternal;
+	}
 }

+ 21 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/entity/enums/DesignerType.java

@@ -0,0 +1,21 @@
+package com.x.base.core.entity.enums;
+
+import com.x.base.core.entity.JpaObject;
+
+/**
+ * 平台设计搜索业务类型枚举类
+ * script(脚本:流程平台脚本、内容管理脚本、门户脚本、服务管理的代理、服务管理的接口)
+ * form(流程平台的表单、内容管理的表单)
+ * page(门户的页面)
+ * widget(门户的widget)
+ * process(流程平台的流程模板)
+ * view(数据中心视图)
+ * table(数据中心自建表)
+ * stat(数据中心统计)
+ * statement(数据中心查询语句)
+ */
+public enum DesignerType {
+
+	script, form, page, widget, process, view, table, stat, statement;
+	public static final int length = JpaObject.length_64B;
+}

+ 3 - 27
o2server/x_base_core_project/src/main/java/com/x/base/core/project/build/CreateConfigSample.java

@@ -11,37 +11,13 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.x.base.core.project.config.*;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.commons.lang3.reflect.MethodUtils;
 
 import com.x.base.core.project.annotation.FieldDescribe;
-import com.x.base.core.project.config.AppStyle;
-import com.x.base.core.project.config.Cache;
-import com.x.base.core.project.config.CenterServer;
-import com.x.base.core.project.config.ClientInit;
-import com.x.base.core.project.config.Collect;
-import com.x.base.core.project.config.Communicate;
-import com.x.base.core.project.config.Components;
-import com.x.base.core.project.config.ConfigObject;
-import com.x.base.core.project.config.Dingding;
-import com.x.base.core.project.config.DumpRestoreData;
-import com.x.base.core.project.config.Exmail;
-import com.x.base.core.project.config.LogLevel;
-import com.x.base.core.project.config.Meeting;
-import com.x.base.core.project.config.Messages;
-import com.x.base.core.project.config.Node;
-import com.x.base.core.project.config.Person;
-import com.x.base.core.project.config.Portal;
-import com.x.base.core.project.config.ProcessPlatform;
-import com.x.base.core.project.config.PushConfig;
-import com.x.base.core.project.config.Qiyeweixin;
-import com.x.base.core.project.config.Query;
-import com.x.base.core.project.config.Token;
-import com.x.base.core.project.config.Vfs;
-import com.x.base.core.project.config.WorkTime;
-import com.x.base.core.project.config.ZhengwuDingding;
 import com.x.base.core.project.gson.XGsonBuilder;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.LoggerFactory;
@@ -57,7 +33,6 @@ public class CreateConfigSample {
 		List<Class<?>> classes = new ArrayList<Class<?>>();
 		classes.add(AppStyle.class);
 		classes.add(CenterServer.class);
-		classes.add(ClientInit.class);
 		classes.add(Collect.class);
 		classes.add(Communicate.class);
 		classes.add(Components.class);
@@ -72,11 +47,12 @@ public class CreateConfigSample {
 		classes.add(Person.class);
 		classes.add(Portal.class);
 		classes.add(ProcessPlatform.class);
-		classes.add(PushConfig.class);
+		classes.add(JpushConfig.class);
 		classes.add(Qiyeweixin.class);
 		classes.add(Query.class);
 		classes.add(Token.class);
 		classes.add(Vfs.class);
+		classes.add(WeLink.class);
 		classes.add(WorkTime.class);
 		classes.add(ZhengwuDingding.class);
 		classes.add(Cache.class);

+ 0 - 168
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ClientInit.java

@@ -1,168 +0,0 @@
-package com.x.base.core.project.config;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.BooleanUtils;
-
-import com.x.base.core.project.annotation.FieldDescribe;
-
-public class ClientInit extends ConfigObject {
-
-	@FieldDescribe("是否启用.")
-	private Boolean enable;
-
-	@FieldDescribe("center节点信息.")
-	private List<CenterAddress> center;
-
-	@FieldDescribe("网页底部说明.")
-	private String footer = "";
-
-	@FieldDescribe("网页头部说明.")
-	private String title = "";
-
-	@FieldDescribe("APP使用协议,auto,http,https.")
-	private String app_protocol = "auto";
-
-	@FieldDescribe("登录页面配置.")
-	private LoginPage loginPage;
-
-	@FieldDescribe("是否启用webSocket")
-	private Boolean webSocketEnable;
-
-	public ClientInit() {
-		this.enable = DEFAULT_ENABLE;
-		this.center = new ArrayList<>();
-		this.loginPage = new LoginPage();
-	}
-
-	public static ClientInit defaultInstance() {
-		return new ClientInit();
-	}
-
-	public static final Boolean DEFAULT_ENABLE = false;
-
-	public static class LoginPage extends ConfigObject {
-
-		public static LoginPage defaultInstance() {
-			return new LoginPage();
-		}
-
-		@FieldDescribe("是否启用定制的登录页面.")
-		private Boolean enable;
-		@FieldDescribe("登录的门户.")
-		private String portal;
-		@FieldDescribe("登录页面.")
-		private String page;
-
-		public Boolean getEnable() {
-			return enable;
-		}
-
-		public void setEnable(Boolean enable) {
-			this.enable = enable;
-		}
-
-		public String getPortal() {
-			return portal;
-		}
-
-		public void setPortal(String portal) {
-			this.portal = portal;
-		}
-
-		public String getPage() {
-			return page;
-		}
-
-		public void setPage(String page) {
-			this.page = page;
-		}
-	}
-
-	public static class CenterAddress extends ConfigObject {
-
-
-		public static CenterAddress defaultInstance() {
-			return new CenterAddress();
-		}
-
-		private String port;
-
-		private String host;
-
-		public String getPort() {
-			return port;
-		}
-
-		public void setPort(String port) {
-			this.port = port;
-		}
-
-		public String getHost() {
-			return host;
-		}
-
-		public void setHost(String host) {
-			this.host = host;
-		}
-
-	}
-
-	public Boolean getEnable() {
-		return BooleanUtils.isTrue(this.enable);
-	}
-
-	public void setEnable(Boolean enable) {
-		this.enable = enable;
-	}
-
-	public List<CenterAddress> getCenter() {
-		return center;
-	}
-
-	public void setCenter(List<CenterAddress> center) {
-		this.center = center;
-	}
-
-	public String getFooter() {
-		return footer;
-	}
-
-	public void setFooter(String footer) {
-		this.footer = footer;
-	}
-
-	public String getTitle() {
-		return title;
-	}
-
-	public void setTitle(String title) {
-		this.title = title;
-	}
-
-	public String getApp_protocol() {
-		return app_protocol;
-	}
-
-	public void setApp_protocol(String app_protocol) {
-		this.app_protocol = app_protocol;
-	}
-
-	public LoginPage getLoginPage() {
-		return loginPage;
-	}
-
-	public void setLoginPage(LoginPage loginPage) {
-		this.loginPage = loginPage;
-	}
-
-	public Boolean getWebSocketEnable() {
-		return webSocketEnable;
-	}
-
-	public void setWebSocketEnable(Boolean webSocketEnable) {
-		this.webSocketEnable = webSocketEnable;
-	}
-
-}

+ 5 - 18
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java

@@ -62,7 +62,7 @@ public class Config {
 	public static final String PATH_CONFIG_PROCESSPLATFORM = "config/processPlatform.json";
 	public static final String PATH_CONFIG_QUERY = "config/query.json";
 	public static final String PATH_CONFIG_DINGDING = "config/dingding.json";
-	public static final String PATH_CONFIG_WELINK = "config/welink.json";
+	public static final String PATH_CONFIG_WELINK = "config/weLink.json";
 	public static final String PATH_CONFIG_ZHENGWUDINGDING = "config/zhengwuDingding.json";
 	public static final String PATH_CONFIG_QIYEWEIXIN = "config/qiyeweixin.json";
 	public static final String PATH_CONFIG_MQ = "config/mq.json";
@@ -892,15 +892,15 @@ public class Config {
 		return instance().messageSendRuleScript;
 	}
 
-	private PushConfig pushConfig;
+	private JpushConfig pushConfig;
 
-	public static synchronized PushConfig pushConfig() throws Exception {
+	public static synchronized JpushConfig pushConfig() throws Exception {
 		if (null == instance().pushConfig) {
-			PushConfig custom = BaseTools.readConfigObject(PATH_CONFIG_JPUSH, PushConfig.class);
+			JpushConfig custom = BaseTools.readConfigObject(PATH_CONFIG_JPUSH, JpushConfig.class);
 			if (null != custom) {
 				instance().pushConfig = custom;
 			} else {
-				instance().pushConfig = PushConfig.defaultInstance();
+				instance().pushConfig = JpushConfig.defaultInstance();
 			}
 		}
 		return instance().pushConfig;
@@ -1050,19 +1050,6 @@ public class Config {
 		return instance().logLevel;
 	}
 
-	private ClientInit clientInit;
-
-	public static synchronized ClientInit clientInit() throws Exception {
-		if (null == instance().clientInit) {
-			ClientInit obj = BaseTools.readConfigObject(PATH_CONFIG_CLIENTINIT, ClientInit.class);
-			if (null == obj) {
-				obj = ClientInit.defaultInstance();
-			}
-			instance().clientInit = obj;
-		}
-		return instance().clientInit;
-	}
-
 	private byte[] bindLogo;
 
 	public static synchronized byte[] bindLogo() throws Exception {

+ 4 - 4
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/PushConfig.java → o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/JpushConfig.java

@@ -3,16 +3,16 @@ package com.x.base.core.project.config;
 import com.x.base.core.project.annotation.FieldDescribe;
 import org.apache.commons.lang3.BooleanUtils;
 
-public class PushConfig extends ConfigObject {
+public class JpushConfig extends ConfigObject {
 
     private static final String O2_app_key_default = "9aca7cc20fe0cc987cd913ca";
     private static final String O2_master_secret_default = "96ee7e2e0daffd51bac57815";
 
 
-    public static PushConfig defaultInstance() {
-        return new PushConfig();
+    public static JpushConfig defaultInstance() {
+        return new JpushConfig();
     }
-    public PushConfig() {
+    public JpushConfig() {
         this.enable = false;
         this.appKey = O2_app_key_default;
         this.masterSecret = O2_master_secret_default;

+ 73 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WiDesigner.java

@@ -0,0 +1,73 @@
+package com.x.base.core.project.jaxrs;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.gson.GsonPropertyObject;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class WiDesigner extends GsonPropertyObject {
+
+    @FieldDescribe("搜索关键字.")
+    private String keyword;
+    @FieldDescribe("是否区分大小写.")
+    private Boolean caseSensitive;
+    @FieldDescribe("是否全字匹配.")
+    private Boolean matchWholeWord;
+    @FieldDescribe("是否正则表达式匹配.")
+    private Boolean matchRegExp;
+    @FieldDescribe("设计类型:script|form|page|widget|process")
+    private List<String> designerTypes = new ArrayList<>();
+    @FieldDescribe("应用ID列表.")
+    private List<String> appIdList = new ArrayList<>();
+
+    public String getKeyword() {
+        return keyword;
+    }
+
+    public void setKeyword(String keyword) {
+        this.keyword = keyword;
+    }
+
+    public Boolean getCaseSensitive() {
+        return caseSensitive;
+    }
+
+    public void setCaseSensitive(Boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    public Boolean getMatchWholeWord() {
+        return matchWholeWord;
+    }
+
+    public void setMatchWholeWord(Boolean matchWholeWord) {
+        this.matchWholeWord = matchWholeWord;
+    }
+
+    public Boolean getMatchRegExp() {
+        return matchRegExp;
+    }
+
+    public void setMatchRegExp(Boolean matchRegExp) {
+        this.matchRegExp = matchRegExp;
+    }
+
+    public List<String> getDesignerTypes() {
+        return designerTypes == null ? new ArrayList<>() : designerTypes;
+    }
+
+    public void setDesignerTypes(List<String> designerTypes) {
+        this.designerTypes = designerTypes;
+    }
+
+    public List<String> getAppIdList() {
+        return appIdList == null ? new ArrayList<>() : appIdList;
+    }
+
+    public void setAppIdList(List<String> appIdList) {
+        this.appIdList = appIdList;
+    }
+}

+ 197 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WrapDesigner.java

@@ -0,0 +1,197 @@
+package com.x.base.core.project.jaxrs;
+
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.gson.GsonPropertyObject;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class WrapDesigner extends GsonPropertyObject {
+
+	@FieldDescribe("应用Id.")
+	private String appId;
+
+	@FieldDescribe("应用名称.")
+	private String appName;
+
+	@FieldDescribe("设计Id.")
+	private String designerId;
+
+	@FieldDescribe("设计名称.")
+	private String designerName;
+
+	@FieldDescribe("设计类型.")
+	private String designerType;
+
+	private Date updateTime;
+
+	@FieldDescribe("匹配信息.")
+	private List<DesignerPattern> patternList = new ArrayList<>();
+
+	public String getAppId() {
+		return appId;
+	}
+
+	public void setAppId(String appId) {
+		this.appId = appId;
+	}
+
+	public String getAppName() {
+		return appName;
+	}
+
+	public void setAppName(String appName) {
+		this.appName = appName;
+	}
+
+	public String getDesignerId() {
+		return designerId;
+	}
+
+	public void setDesignerId(String designerId) {
+		this.designerId = designerId;
+	}
+
+	public String getDesignerName() {
+		return designerName;
+	}
+
+	public void setDesignerName(String designerName) {
+		this.designerName = designerName;
+	}
+
+	public String getDesignerType() {
+		return designerType;
+	}
+
+	public void setDesignerType(String designerType) {
+		this.designerType = designerType;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public List<DesignerPattern> getPatternList() {
+		return patternList;
+	}
+
+	public void setPatternList(List<DesignerPattern> patternList) {
+		this.patternList = patternList;
+	}
+
+	public void setPatternList(Map<String, String> map) {
+		if(map!=null && !map.isEmpty()){
+			List<DesignerPattern> patternList = new ArrayList<>();
+			for (String key : map.keySet()){
+				DesignerPattern pattern = new DesignerPattern();
+				pattern.setProperty(key);
+				pattern.setPropertyValue(map.get(key));
+				patternList.add(pattern);
+			}
+			this.patternList = patternList;
+		}
+	}
+
+	public DesignerPattern getPatternInstant(){
+		DesignerPattern pattern = new DesignerPattern();
+		return pattern;
+	}
+
+	public void clearPatternValue(){
+		for (DesignerPattern pattern : this.patternList){
+			pattern.setPropertyValue(null);
+		}
+	}
+
+	public DesignerPattern getScriptDesigner(){
+		DesignerPattern designerPattern = null;
+		if(DesignerType.script.toString().equals(this.getDesignerType())){
+			for (DesignerPattern pattern : this.patternList){
+				if ("text".equals(pattern.getProperty())){
+					designerPattern = pattern;
+				}else{
+					pattern.setPropertyValue(null);
+				}
+			}
+		}else{
+			this.clearPatternValue();
+		}
+		return designerPattern;
+	}
+
+	public class DesignerPattern extends GsonPropertyObject {
+
+		@FieldDescribe("元素类型(activity | process).")
+		private String elementType;
+		@FieldDescribe("元素ID.")
+		private String elementId;
+		@FieldDescribe("元素名称.")
+		private String elementName;
+
+		@FieldDescribe("设计属性.")
+		private String property;
+
+		@FieldDescribe("设计属性.")
+		private String propertyValue;
+
+		@FieldDescribe("匹配行")
+		private List<Integer> lines;
+
+		public String getElementType() {
+			return elementType;
+		}
+
+		public void setElementType(String elementType) {
+			this.elementType = elementType;
+		}
+
+		public String getElementId() {
+			return elementId;
+		}
+
+		public void setElementId(String elementId) {
+			this.elementId = elementId;
+		}
+
+		public String getElementName() {
+			return elementName;
+		}
+
+		public void setElementName(String elementName) {
+			this.elementName = elementName;
+		}
+
+		public String getProperty() {
+			return property;
+		}
+
+		public void setProperty(String property) {
+			this.property = property;
+		}
+
+		public List<Integer> getLines() {
+			return lines;
+		}
+
+		public void setLines(List<Integer> lines) {
+			this.lines = lines;
+		}
+
+		public String getPropertyValue() {
+			return propertyValue;
+		}
+
+		public void setPropertyValue(String propertyValue) {
+			this.propertyValue = propertyValue;
+		}
+	}
+
+}

+ 21 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/PropertyTools.java

@@ -1,8 +1,12 @@
 package com.x.base.core.project.tools;
 
 import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 
 public class PropertyTools {
@@ -32,4 +36,20 @@ public class PropertyTools {
 		return defaultObject;
 	}
 
-}
+	public static <T> Map<String, String> fieldMatchKeyword(final List<String> properties, T t, String keyword, Boolean caseSensitive, Boolean matchWholeWord, Boolean matchRegExp) throws Exception {
+		Map<String, String> map = new HashMap<>();
+		if(ListTools.isNotEmpty(properties) && StringUtils.isNotBlank(keyword)) {
+			for (String name : properties) {
+				Object o = PropertyUtils.getProperty(t, name);
+				if (o!=null) {
+					String content = String.valueOf(o);
+					if (StringTools.matchKeyword(keyword, content, caseSensitive, matchWholeWord, matchRegExp)) {
+						map.put(name, content);
+					}
+				}
+			}
+		}
+		return map;
+	}
+
+}

+ 26 - 13
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/factory/FormFactory.java

@@ -19,7 +19,7 @@ import java.util.List;
 
 /**
  * 分类表单模板信息管理表基础功能服务类
- * 
+ *
  * @author O2LEE
  */
 public class FormFactory extends AbstractFactory {
@@ -37,7 +37,7 @@ public class FormFactory extends AbstractFactory {
 	public Form get( String id ) throws Exception {
 		return this.entityManagerContainer().find( id, Form.class, ExceptionWhen.none );
 	}
-	
+
 	/**
 	 * @return List:String
 	 * @throws Exception
@@ -51,9 +51,9 @@ public class FormFactory extends AbstractFactory {
 		cq.select(root.get(Form_.id));
 		return em.createQuery(cq).getResultList();
 	}
-	
+
 	/**
-	 * 
+	 *
 	 * @param ids 需要查询的ID列表
 	 * @return List:Form
 	 * @throws Exception
@@ -70,15 +70,15 @@ public class FormFactory extends AbstractFactory {
 //		Predicate p = root.get(Form_.id).in(ids);
 //		return em.createQuery(cq.where(p)).getResultList();
 //	}
-	
+
 	/**
 	 * 列示指定应用的所有表单模板信息ID列表
-	 * @param doucmentId 指定的文档ID
+	 * @param appId 指定的文档ID
 	 * @return
-	 * @throws Exception 
+	 * @throws Exception
 	 */
 	//@MethodDescribe("列示指定分类的所有表单模板信息ID列表")
-	public List<String> listByAppId( String appId ) throws Exception {		
+	public List<String> listByAppId( String appId ) throws Exception {
 		if( StringUtils.isEmpty(appId) ){
 			throw new Exception("内容管理listByAppId方法不接受appId为空的查询操作!");
 		}
@@ -90,8 +90,21 @@ public class FormFactory extends AbstractFactory {
 		Predicate p = cb.equal(root.get( Form_.appId ), appId);
 		return em.createQuery(cq.where(p)).getResultList();
 	}
-	
-	public List<Form> listFormByAppId( String appId ) throws Exception {		
+
+	public List<String> listByAppIds(List<String> appIds) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Form.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<String> cq = cb.createQuery(String.class);
+		Root<Form> root = cq.from(Form.class);
+		Predicate p = cb.conjunction();
+		if(ListTools.isNotEmpty(appIds)) {
+			p = cb.isMember(root.get(Form_.appId), cb.literal(appIds));
+		}
+		cq.select(root.get(Form_.id)).where(p);
+		return em.createQuery(cq).getResultList();
+	}
+
+	public List<Form> listFormByAppId( String appId ) throws Exception {
 		if( StringUtils.isEmpty(appId) ){
 			throw new Exception("内容管理listByAppId方法不接受appId为空的查询操作!");
 		}
@@ -123,9 +136,9 @@ public class FormFactory extends AbstractFactory {
 		Root<Form> root = cq.from( Form.class );
 		Predicate appPre = cb.equal( root.get( Form_.appId ), appId );
 		Predicate p = CriteriaBuilderTools.predicate_or( cb, cb.equal( root.get( Form_.id ), formFlag ), cb.equal( root.get( Form_.name ), formFlag ) );
-//		p = CriteriaBuilderTools.predicate_or( cb, cb.equal( root.get( Form_.alias ), formFlag ), p );				
+//		p = CriteriaBuilderTools.predicate_or( cb, cb.equal( root.get( Form_.alias ), formFlag ), p );
 		p = CriteriaBuilderTools.predicate_and( cb, appPre, p );
-		List<Form> list = em.createQuery(cq.where(p)).getResultList();		
+		List<Form> list = em.createQuery(cq.where(p)).getResultList();
 		return ListTools.isEmpty( list ) ? null : list.get( 0 );
 	}
-}
+}

+ 5 - 4
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/ActionApplication.java

@@ -12,6 +12,7 @@ import com.x.cms.assemble.control.jaxrs.categoryinfo.CategoryInfoAnonymousAction
 import com.x.cms.assemble.control.jaxrs.commend.DocumentCommendAction;
 import com.x.cms.assemble.control.jaxrs.comment.DocumentCommentInfoAction;
 import com.x.cms.assemble.control.jaxrs.data.DataAction;
+import com.x.cms.assemble.control.jaxrs.designer.DesignerAction;
 import com.x.cms.assemble.control.jaxrs.document.DocumentAction;
 import com.x.cms.assemble.control.jaxrs.document.DocumentAnonymousAction;
 import com.x.cms.assemble.control.jaxrs.document.DocumentCipherAction;
@@ -46,7 +47,7 @@ import java.util.Set;
 public class ActionApplication extends AbstractActionApplication {
 
 	public Set<Class<?>> getClasses() {
-		
+
 		this.classes.add(TemplateFormAction.class);
 		this.classes.add(AppInfoAction.class);
 		this.classes.add(AppInfoConfigAction.class);
@@ -77,7 +78,7 @@ public class ActionApplication extends AbstractActionApplication {
 		this.classes.add(SearchFilterAction.class);
 		this.classes.add(InputAction.class);
 		this.classes.add(OutputAction.class);
-		
+
 		this.classes.add(AppInfoAnonymousAction.class);
 		this.classes.add(AppDictAnonymousAction.class);
 		this.classes.add(CategoryInfoAnonymousAction.class);
@@ -87,8 +88,8 @@ public class ActionApplication extends AbstractActionApplication {
 		this.classes.add(ScriptAnonymousAction.class);
 		this.classes.add(DocumentCommentInfoAction.class);
 		this.classes.add(DocumentCommendAction.class);
-
+		this.classes.add(DesignerAction.class);
 		return this.classes;
 	}
 
-}
+}

+ 5 - 4
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/CmsJaxrsCipherFilter.java

@@ -7,13 +7,14 @@ import javax.servlet.annotation.WebFilter;
 ;
 /**
  * web服务过滤器,将指定的URL定义为需要用户认证的服务,如果用户未登录,则无法访问该服务
- * 
+ *
  * @author O2LEE *
  */
-@WebFilter(urlPatterns = { 
+@WebFilter(urlPatterns = {
 		"/jaxrs/document/cipher/*",
-		"/jaxrs/permission/management/*"
+		"/jaxrs/permission/management/*",
+		"/jaxrs/designer/*"
 }, asyncSupported = true )
 public class CmsJaxrsCipherFilter extends CipherManagerJaxrsFilter {
 
-}
+}

+ 167 - 0
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/ActionSearch.java

@@ -0,0 +1,167 @@
+package com.x.cms.assemble.control.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.bean.WrapCopierFactory;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.base.core.project.tools.PropertyTools;
+import com.x.cms.assemble.control.Business;
+import com.x.cms.core.entity.AppInfo;
+import com.x.cms.core.entity.element.Form;
+import com.x.cms.core.entity.element.Script;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+class ActionSearch extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionSearch.class);
+
+	ActionResult<List<Wo>> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		if(!effectivePerson.isManager()){
+			throw new ExceptionAccessDenied(effectivePerson);
+		}
+		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
+		logger.info("{}开始内容管理设计搜索,关键字:{}", effectivePerson.getDistinguishedName(), wi.getKeyword());
+		if(StringUtils.isBlank(wi.getKeyword())){
+			throw new ExceptionFieldEmpty("keyword");
+		}
+
+		ActionResult<List<Wo>> result = new ActionResult<>();
+
+		List<Wo> resWos = new ArrayList<>();
+		List<CompletableFuture<List<Wo>>> list = new ArrayList<>();
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.form.toString())){
+			list.add(searchForm(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.script.toString())){
+			list.add(searchScript(wi, wi.getAppIdList()));
+		}
+		for (CompletableFuture<List<Wo>> cf : list){
+			if(resWos.size()<50) {
+				resWos.addAll(cf.get(60, TimeUnit.SECONDS));
+			}
+		}
+		if (resWos.size()>50){
+			resWos = resWos.subList(0, 50);
+		}
+		result.setData(resWos);
+		result.setCount((long)resWos.size());
+		return result;
+	}
+
+	private CompletableFuture<List<Wo>> searchScript(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoScript> woScripts;
+				if (ListTools.isEmpty(appIdList)) {
+					woScripts = emc.fetchAll(Script.class, WoScript.copier);
+				} else {
+					woScripts = emc.fetchIn(Script.class, WoScript.copier, Script.appId_FIELDNAME, appIdList);
+				}
+
+				for (WoScript woScript : woScripts) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoScript.copier.getCopyFields(), woScript, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						AppInfo appInfo = emc.find( wo.getAppId(), AppInfo.class );
+						if(appInfo != null){
+							wo.setAppId(appInfo.getId());
+							wo.setAppName(appInfo.getAppName());
+						}
+						wo.setDesignerId(woScript.getId());
+						wo.setDesignerName(woScript.getName());
+						wo.setDesignerType(DesignerType.script.toString());
+						wo.setUpdateTime(woScript.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woScripts.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchForm(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Business business = new Business(emc);
+				List<String> formIds = business.getFormFactory().listByAppIds(appIdList);
+				for (List<String> partFormIds : ListTools.batch(formIds, 100)) {
+					List<WoForm> woForms = emc.fetchIn(Form.class, WoForm.copier, Form.id_FIELDNAME, partFormIds);
+					for (WoForm woForm : woForms) {
+						Map<String, String> map = PropertyTools.fieldMatchKeyword(WoForm.copier.getCopyFields(), woForm, wi.getKeyword(),
+								wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+						if (!map.isEmpty()) {
+							Wo wo = new Wo();
+							AppInfo appInfo = emc.find( wo.getAppId(), AppInfo.class );
+							if(appInfo != null){
+								wo.setAppId(appInfo.getId());
+								wo.setAppName(appInfo.getAppName());
+							}
+							wo.setDesignerId(woForm.getId());
+							wo.setDesignerName(woForm.getName());
+							wo.setDesignerType(DesignerType.form.toString());
+							wo.setUpdateTime(woForm.getUpdateTime());
+							wo.setPatternList(map);
+							resWos.add(wo);
+						}
+					}
+					woForms.clear();
+				}
+
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+
+
+	public static class Wi extends WiDesigner {
+
+	}
+
+	public static class Wo extends WrapDesigner{
+
+	}
+
+	public static class WoScript extends Script {
+
+		static WrapCopier<Script, WoScript> copier = WrapCopierFactory.wo(Script.class, WoScript.class,
+				JpaObject.singularAttributeField(Script.class, true, false),null);
+
+	}
+
+	public static class WoForm extends Form {
+
+		static WrapCopier<Form, WoForm> copier = WrapCopierFactory.wo(Form.class, WoForm.class,
+				JpaObject.singularAttributeField(Form.class, true, false),null);
+
+	}
+
+}

+ 7 - 0
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.cms.assemble.control.jaxrs.designer;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 48 - 0
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/DesignerAction.java

@@ -0,0 +1,48 @@
+package com.x.cms.assemble.control.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("designer")
+@JaxrsDescribe("设计")
+public class DesignerAction extends StandardJaxrsAction {
+
+	private static Logger logger = LoggerFactory.getLogger(DesignerAction.class);
+
+	@JaxrsMethodDescribe(value = "根据关键字搜索设计对象.", action = ActionSearch.class)
+	@POST
+	@Path("search")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void search(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+							JsonElement jsonElement) {
+		ActionResult<List<ActionSearch.Wo>> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionSearch().execute(effectivePerson, jsonElement);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+}

+ 11 - 0
o2server/x_cms_assemble_control/src/main/java/com/x/cms/assemble/control/jaxrs/designer/ExceptionFieldEmpty.java

@@ -0,0 +1,11 @@
+package com.x.cms.assemble.control.jaxrs.designer;
+
+import com.x.base.core.project.exception.PromptException;
+
+public class ExceptionFieldEmpty extends PromptException {
+
+	public ExceptionFieldEmpty(String field) {
+		super("参数: {} 值无效.", field);
+	}
+
+}

+ 71 - 74
o2server/x_console/src/main/java/com/x/server/console/server/web/WebServerTools.java

@@ -178,85 +178,82 @@ public class WebServerTools extends JettySeverTools {
 		File file = new File(dir, "config.json");
 
 		Gson gson = XGsonBuilder.instance();
-		if (Config.clientInit().getEnable()) {
-			FileUtils.write(file, gson.toJson(Config.clientInit()), DefaultCharset.charset);
-		} else {
-			LinkedHashMap<String, Object> map = new LinkedHashMap<>();
-			/** 覆盖掉配置的参数 */
-			com.x.base.core.project.config.CenterServer centerServerConfig = Config.nodes().centerServers().first()
-					.getValue();
-			map.putAll(centerServerConfig.getConfig());
-			List<Map<String, String>> centers = new ArrayList<>();
-			map.put("center", centers);
-			/** 写入center地址 */
-			Map<String, String> center = new HashMap<String, String>();
+
+		LinkedHashMap<String, Object> map = new LinkedHashMap<>();
+		/** 覆盖掉配置的参数 */
+		com.x.base.core.project.config.CenterServer centerServerConfig = Config.nodes().centerServers().first()
+				.getValue();
+		map.putAll(centerServerConfig.getConfig());
+		List<Map<String, String>> centers = new ArrayList<>();
+		map.put("center", centers);
+		/** 写入center地址 */
+		Map<String, String> center = new HashMap<String, String>();
+		center = new HashMap<String, String>();
+		center.put("host", "");
+		center.put("port", centerServerConfig.getPort().toString());
+		centers.add(center);
+		if (!Objects.equals(centerServerConfig.getProxyPort(), centerServerConfig.getPort())) {
 			center = new HashMap<String, String>();
 			center.put("host", "");
+			center.put("port", centerServerConfig.getProxyPort().toString());
+			centers.add(center);
+		}
+		String host = Config.nodes().primaryCenterNode();
+		if (!Host.isRollback(host)) {
+			center = new HashMap<String, String>();
+			center.put("host", host);
 			center.put("port", centerServerConfig.getPort().toString());
 			centers.add(center);
-			if (!Objects.equals(centerServerConfig.getProxyPort(), centerServerConfig.getPort())) {
-				center = new HashMap<String, String>();
-				center.put("host", "");
-				center.put("port", centerServerConfig.getProxyPort().toString());
-				centers.add(center);
-			}
-			String host = Config.nodes().primaryCenterNode();
-			if (!Host.isRollback(host)) {
-				center = new HashMap<String, String>();
-				center.put("host", host);
-				center.put("port", centerServerConfig.getPort().toString());
-				centers.add(center);
-			}
-			/** 写入proxy地址 */
-			if (StringUtils.isNotEmpty(centerServerConfig.getProxyHost())) {
-				center = new HashMap<String, String>();
-				center.put("host", centerServerConfig.getProxyHost());
-				center.put("port", centerServerConfig.getProxyPort().toString());
-				centers.add(center);
-			}
+		}
+		/** 写入proxy地址 */
+		if (StringUtils.isNotEmpty(centerServerConfig.getProxyHost())) {
+			center = new HashMap<String, String>();
+			center.put("host", centerServerConfig.getProxyHost());
+			center.put("port", centerServerConfig.getProxyPort().toString());
+			centers.add(center);
+		}
 
-			/** 写入systemName */
-			map.put("footer", Config.collect().getFooter());
-			map.put("title", Config.collect().getTitle());
-			map.put("appUrl", Config.collect().getAppUrl());
-			/***/
-			if (centerServerConfig.getSslEnable()) {
-				map.put("app_protocol", "https:");
-			} else {
-				map.put("app_protocol", "http:");
-			}
-			/* 上面的无效 */
-			map.put("app_protocol", "auto");
-			if ((null != Config.portal().getLoginPage())
-					&& (BooleanUtils.isTrue(Config.portal().getLoginPage().getEnable()))) {
-				map.put(MAP_LOGINPAGE, Config.portal().getLoginPage());
-			} else if ((null != Config.person().getLoginPage())
-					&& (BooleanUtils.isTrue(Config.person().getLoginPage().getEnable()))) {
-				map.put(MAP_LOGINPAGE, Config.person().getLoginPage());
-			} else {
-				map.put(MAP_LOGINPAGE, Config.portal().getLoginPage());
-			}
-			map.put("indexPage", Config.portal().getIndexPage());
-			map.put("webSocketEnable", Config.communicate().wsEnable());
-			map.put("urlMapping", Config.portal().getUrlMapping());
-
-			/* 密码规则 */
-			map.put("passwordRegex", Config.person().getPasswordRegex());
-			map.put("passwordRegexHint", Config.person().getPasswordRegexHint());
-
-			/* RSA */
-			File publicKeyFile = new File(Config.base(), "config/public.key");
-			if (publicKeyFile.exists() && publicKeyFile.isFile()) {
-				String publicKey = FileUtils.readFileToString(publicKeyFile, "utf-8");
-				byte[] publicKeyB = Base64.decodeBase64(publicKey);
-				publicKey = new String(Base64.encodeBase64(publicKeyB));
-				map.put("publicKey", publicKey);
-			}
-			for (Entry<String, JsonElement> en : Config.web().entrySet()) {
-				map.put(en.getKey(), en.getValue());
-			}
-			FileUtils.writeStringToFile(file, gson.toJson(map), DefaultCharset.charset);
+		/** 写入systemName */
+		map.put("footer", Config.collect().getFooter());
+		map.put("title", Config.collect().getTitle());
+		map.put("appUrl", Config.collect().getAppUrl());
+		/***/
+		if (centerServerConfig.getSslEnable()) {
+			map.put("app_protocol", "https:");
+		} else {
+			map.put("app_protocol", "http:");
+		}
+		/* 上面的无效 */
+		map.put("app_protocol", "auto");
+		if ((null != Config.portal().getLoginPage())
+				&& (BooleanUtils.isTrue(Config.portal().getLoginPage().getEnable()))) {
+			map.put(MAP_LOGINPAGE, Config.portal().getLoginPage());
+		} else if ((null != Config.person().getLoginPage())
+				&& (BooleanUtils.isTrue(Config.person().getLoginPage().getEnable()))) {
+			map.put(MAP_LOGINPAGE, Config.person().getLoginPage());
+		} else {
+			map.put(MAP_LOGINPAGE, Config.portal().getLoginPage());
+		}
+		map.put("indexPage", Config.portal().getIndexPage());
+		map.put("webSocketEnable", Config.communicate().wsEnable());
+		map.put("urlMapping", Config.portal().getUrlMapping());
+
+		/* 密码规则 */
+		map.put("passwordRegex", Config.person().getPasswordRegex());
+		map.put("passwordRegexHint", Config.person().getPasswordRegexHint());
+
+		/* RSA */
+		File publicKeyFile = new File(Config.base(), "config/public.key");
+		if (publicKeyFile.exists() && publicKeyFile.isFile()) {
+			String publicKey = FileUtils.readFileToString(publicKeyFile, "utf-8");
+			byte[] publicKeyB = Base64.decodeBase64(publicKey);
+			publicKey = new String(Base64.encodeBase64(publicKeyB));
+			map.put("publicKey", publicKey);
+		}
+		for (Entry<String, JsonElement> en : Config.web().entrySet()) {
+			map.put(en.getKey(), en.getValue());
 		}
+		FileUtils.writeStringToFile(file, gson.toJson(map), DefaultCharset.charset);
 	}
 
 	private static void createIndexPage() throws Exception {
@@ -300,4 +297,4 @@ public class WebServerTools extends JettySeverTools {
 			FileUtils.copyDirectory(p.toFile(), Config.path_servers_webServer(true).toFile());
 		}
 	}
-}
+}

+ 0 - 28
o2server/x_organization_assemble_authentication/src/main/java/com/x/organization/assemble/authentication/schedule/TestJob.java

@@ -1,28 +0,0 @@
-package com.x.organization.assemble.authentication.schedule;
-
-import java.util.Date;
-
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-
-import com.x.base.core.container.EntityManagerContainer;
-import com.x.base.core.container.factory.EntityManagerContainerFactory;
-import com.x.base.core.project.logger.Logger;
-import com.x.base.core.project.logger.LoggerFactory;
-
-public class TestJob implements Job {
-
-	private static Logger logger = LoggerFactory.getLogger(TestJob.class);
-
-	@Override
-	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
-		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
-			logger.print("run at {}", new Date());
-		} catch (Exception e) {
-			logger.error(e);
-			throw new JobExecutionException(e);
-		}
-	}
-
-}

+ 15 - 1
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/factory/PageFactory.java

@@ -10,6 +10,7 @@ import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
+import com.x.base.core.project.tools.ListTools;
 import com.x.portal.assemble.designer.AbstractFactory;
 import com.x.portal.assemble.designer.Business;
 import com.x.portal.core.entity.Page;
@@ -74,6 +75,19 @@ public class PageFactory extends AbstractFactory {
 		return list;
 	}
 
+	public List<String> listWithPortals(List<String> portalIds) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Page.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<String> cq = cb.createQuery(String.class);
+		Root<Page> root = cq.from(Page.class);
+		Predicate p = cb.conjunction();
+		if(ListTools.isNotEmpty(portalIds)) {
+			p = cb.isMember(root.get(Page_.portal), cb.literal(portalIds));
+		}
+		cq.select(root.get(Page_.id)).where(p);
+		return em.createQuery(cq).getResultList();
+	}
+
 	public boolean isFirstPage(Page page) {
 		return FIRSTPAGE_NAMES.contains(page.getName());
 	}
@@ -88,4 +102,4 @@ public class PageFactory extends AbstractFactory {
 		return null;
 	}
 
-}
+}

+ 15 - 1
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/factory/WidgetFactory.java

@@ -8,6 +8,7 @@ import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
+import com.x.base.core.project.tools.ListTools;
 import com.x.portal.assemble.designer.AbstractFactory;
 import com.x.portal.assemble.designer.Business;
 import com.x.portal.core.entity.Widget;
@@ -69,4 +70,17 @@ public class WidgetFactory extends AbstractFactory {
 		return list;
 	}
 
-}
+	public List<String> listWithPortals(List<String> portalIds) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Widget.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<String> cq = cb.createQuery(String.class);
+		Root<Widget> root = cq.from(Widget.class);
+		Predicate p = cb.conjunction();
+		if(ListTools.isNotEmpty(portalIds)) {
+			p = cb.isMember(root.get(Widget_.portal), cb.literal(portalIds));
+		}
+		cq.select(root.get(Widget_.id)).where(p);
+		return em.createQuery(cq).getResultList();
+	}
+
+}

+ 3 - 1
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/ActionApplication.java

@@ -5,6 +5,7 @@ import java.util.Set;
 import javax.ws.rs.ApplicationPath;
 
 import com.x.base.core.project.jaxrs.AbstractActionApplication;
+import com.x.portal.assemble.designer.jaxrs.designer.DesignerAction;
 import com.x.portal.assemble.designer.jaxrs.file.FileAction;
 import com.x.portal.assemble.designer.jaxrs.id.IdAction;
 import com.x.portal.assemble.designer.jaxrs.input.InputAction;
@@ -30,7 +31,8 @@ public class ActionApplication extends AbstractActionApplication {
 		classes.add(IdAction.class);
 		classes.add(OutputAction.class);
 		classes.add(InputAction.class);
+		classes.add(DesignerAction.class);
 		return classes;
 	}
 
-}
+}

+ 10 - 0
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/DesignerJaxrsFilter.java

@@ -0,0 +1,10 @@
+package com.x.portal.assemble.designer.jaxrs;
+
+import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = "/jaxrs/designer/*", asyncSupported = true)
+public class DesignerJaxrsFilter extends CipherManagerJaxrsFilter {
+
+}

+ 213 - 0
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/ActionSearch.java

@@ -0,0 +1,213 @@
+package com.x.portal.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.bean.WrapCopierFactory;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.base.core.project.tools.PropertyTools;
+import com.x.portal.assemble.designer.Business;
+import com.x.portal.core.entity.Page;
+import com.x.portal.core.entity.Portal;
+import com.x.portal.core.entity.Script;
+import com.x.portal.core.entity.Widget;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+class ActionSearch extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionSearch.class);
+
+	ActionResult<List<Wo>> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		if(!effectivePerson.isManager()){
+			throw new ExceptionAccessDenied(effectivePerson);
+		}
+		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
+		logger.info("{}开始门户设计搜索,关键字:{}", effectivePerson.getDistinguishedName(), wi.getKeyword());
+		if(StringUtils.isBlank(wi.getKeyword())){
+			throw new ExceptionFieldEmpty("keyword");
+		}
+		ActionResult<List<Wo>> result = new ActionResult<>();
+
+		List<Wo> resWos = new ArrayList<>();
+		List<CompletableFuture<List<Wo>>> list = new ArrayList<>();
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.form.toString())){
+			list.add(searchPage(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.script.toString())){
+			list.add(searchScript(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.widget.toString())){
+			list.add(searchWidget(wi, wi.getAppIdList()));
+		}
+		for (CompletableFuture<List<Wo>> cf : list){
+			if(resWos.size()<50) {
+				resWos.addAll(cf.get(60, TimeUnit.SECONDS));
+			}
+		}
+		if (resWos.size()>50){
+			resWos = resWos.subList(0, 50);
+		}
+		result.setData(resWos);
+		result.setCount((long)resWos.size());
+		return result;
+	}
+
+	private CompletableFuture<List<Wo>> searchScript(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoScript> woScripts;
+				if (ListTools.isEmpty(appIdList)) {
+					woScripts = emc.fetchAll(Script.class, WoScript.copier);
+				} else {
+					woScripts = emc.fetchIn(Script.class, WoScript.copier, Script.portal_FIELDNAME, appIdList);
+				}
+
+				for (WoScript woScript : woScripts) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoScript.copier.getCopyFields(), woScript, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Portal portal = emc.find(woScript.getPortal(), Portal.class);
+						if(portal != null){
+							wo.setAppId(portal.getId());
+							wo.setAppName(portal.getName());
+						}
+						wo.setDesignerId(woScript.getId());
+						wo.setDesignerName(woScript.getName());
+						wo.setDesignerType(DesignerType.script.toString());
+						wo.setUpdateTime(woScript.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woScripts.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchPage(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Business business = new Business(emc);
+				List<String> ids = business.page().listWithPortals(appIdList);
+				for (List<String> partIds : ListTools.batch(ids, 100)) {
+					List<WoPage> wos = emc.fetchIn(Page.class, WoPage.copier, Page.id_FIELDNAME, partIds);
+					for (WoPage wopage : wos) {
+						Map<String, String> map = PropertyTools.fieldMatchKeyword(WoPage.copier.getCopyFields(), wopage, wi.getKeyword(),
+								wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+						if (!map.isEmpty()) {
+							Wo wo = new Wo();
+							Portal portal = emc.find(wopage.getPortal(), Portal.class);
+							if(portal != null){
+								wo.setAppId(portal.getId());
+								wo.setAppName(portal.getName());
+							}
+							wo.setDesignerId(wopage.getId());
+							wo.setDesignerName(wopage.getName());
+							wo.setDesignerType(DesignerType.page.toString());
+							wo.setUpdateTime(wopage.getUpdateTime());
+							wo.setPatternList(map);
+							resWos.add(wo);
+						}
+					}
+					wos.clear();
+				}
+
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchWidget(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Business business = new Business(emc);
+				List<String> ids = business.widget().listWithPortals(appIdList);
+				for (List<String> partIds : ListTools.batch(ids, 100)) {
+					List<WoWidget> wos = emc.fetchIn(Widget.class, WoWidget.copier, WoWidget.id_FIELDNAME, partIds);
+					for (WoWidget woWidget : wos) {
+						Map<String, String> map = PropertyTools.fieldMatchKeyword(WoWidget.copier.getCopyFields(), woWidget, wi.getKeyword(),
+								wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+						if (!map.isEmpty()) {
+							Wo wo = new Wo();
+							Portal portal = emc.find(woWidget.getPortal(), Portal.class);
+							if(portal != null){
+								wo.setAppId(portal.getId());
+								wo.setAppName(portal.getName());
+							}
+							wo.setDesignerId(woWidget.getId());
+							wo.setDesignerName(woWidget.getName());
+							wo.setDesignerType(DesignerType.widget.toString());
+							wo.setUpdateTime(woWidget.getUpdateTime());
+							wo.setPatternList(map);
+							resWos.add(wo);
+						}
+					}
+					wos.clear();
+				}
+
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	public static class Wi extends WiDesigner {
+
+	}
+
+	public static class Wo extends WrapDesigner{
+
+	}
+
+	public static class WoScript extends Script {
+
+		static WrapCopier<Script, WoScript> copier = WrapCopierFactory.wo(Script.class, WoScript.class,
+				JpaObject.singularAttributeField(Script.class, true, false),null);
+
+	}
+
+	public static class WoPage extends Page {
+
+		static WrapCopier<Page, WoPage> copier = WrapCopierFactory.wo(Page.class, WoPage.class,
+				JpaObject.singularAttributeField(WoPage.class, true, false),null);
+
+	}
+
+	public static class WoWidget extends Widget {
+
+		static WrapCopier<Widget, WoWidget> copier = WrapCopierFactory.wo(Widget.class, WoWidget.class,
+				JpaObject.singularAttributeField(WoWidget.class, true, false),null);
+
+	}
+
+
+}

+ 7 - 0
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.portal.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 48 - 0
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/DesignerAction.java

@@ -0,0 +1,48 @@
+package com.x.portal.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("designer")
+@JaxrsDescribe("设计")
+public class DesignerAction extends StandardJaxrsAction {
+
+	private static Logger logger = LoggerFactory.getLogger(DesignerAction.class);
+
+	@JaxrsMethodDescribe(value = "根据关键字搜索设计对象.", action = ActionSearch.class)
+	@POST
+	@Path("search")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void search(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+							JsonElement jsonElement) {
+		ActionResult<List<ActionSearch.Wo>> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionSearch().execute(effectivePerson, jsonElement);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+}

+ 11 - 0
o2server/x_portal_assemble_designer/src/main/java/com/x/portal/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java

@@ -0,0 +1,11 @@
+package com.x.portal.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.exception.PromptException;
+
+public class ExceptionFieldEmpty extends PromptException {
+
+	public ExceptionFieldEmpty(String field) {
+		super("参数: {} 值无效.", field);
+	}
+
+}

+ 16 - 1
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/element/factory/FormFactory.java

@@ -2,6 +2,7 @@ package com.x.processplatform.assemble.designer.element.factory;
 
 import java.util.Comparator;
 import java.util.List;
+import java.util.concurrent.locks.Condition;
 import java.util.stream.Collectors;
 
 import javax.persistence.EntityManager;
@@ -10,6 +11,7 @@ import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
+import com.x.base.core.project.tools.ListTools;
 import com.x.processplatform.assemble.designer.AbstractFactory;
 import com.x.processplatform.assemble.designer.Business;
 import com.x.processplatform.core.entity.element.Form;
@@ -31,6 +33,19 @@ public class FormFactory extends AbstractFactory {
 		return em.createQuery(cq).getResultList();
 	}
 
+	public List<String> listWithApplications(List<String> applications) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Form.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<String> cq = cb.createQuery(String.class);
+		Root<Form> root = cq.from(Form.class);
+		Predicate p = cb.conjunction();
+		if(ListTools.isNotEmpty(applications)) {
+			p = cb.isMember(root.get(Form_.application), cb.literal(applications));
+		}
+		cq.select(root.get(Form_.id)).where(p);
+		return em.createQuery(cq).getResultList();
+	}
+
 	public List<Form> listWithApplicationObject(String application) throws Exception {
 		EntityManager em = this.entityManagerContainer().get(Form.class);
 		CriteriaBuilder cb = em.getCriteriaBuilder();
@@ -47,4 +62,4 @@ public class FormFactory extends AbstractFactory {
 		return list;
 	}
 
-}
+}

+ 3 - 1
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/ActionApplication.java

@@ -8,6 +8,7 @@ import com.x.base.core.project.jaxrs.AbstractActionApplication;
 import com.x.processplatform.assemble.designer.jaxrs.application.ApplicationAction;
 import com.x.processplatform.assemble.designer.jaxrs.applicationcategory.ApplicationCategoryAction;
 import com.x.processplatform.assemble.designer.jaxrs.applicationdict.ApplicationDictAction;
+import com.x.processplatform.assemble.designer.jaxrs.designer.DesignerAction;
 import com.x.processplatform.assemble.designer.jaxrs.elementtool.ElementToolAction;
 import com.x.processplatform.assemble.designer.jaxrs.file.FileAction;
 import com.x.processplatform.assemble.designer.jaxrs.form.FormAction;
@@ -45,7 +46,8 @@ public class ActionApplication extends AbstractActionApplication {
 		classes.add(MappingAction.class);
 		classes.add(ElementToolAction.class);
 		classes.add(WorkCompletedAction.class);
+		classes.add(DesignerAction.class);
 		return classes;
 	}
 
-}
+}

+ 10 - 0
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/DesignerJaxrsFilter.java

@@ -0,0 +1,10 @@
+package com.x.processplatform.assemble.designer.jaxrs;
+
+import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = "/jaxrs/designer/*", asyncSupported = true)
+public class DesignerJaxrsFilter extends CipherManagerJaxrsFilter {
+
+}

+ 172 - 0
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/ActionSearch.java

@@ -0,0 +1,172 @@
+package com.x.processplatform.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.bean.WrapCopierFactory;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.base.core.project.tools.PropertyTools;
+import com.x.processplatform.assemble.designer.Business;
+import com.x.processplatform.core.entity.element.Application;
+import com.x.processplatform.core.entity.element.Form;
+import com.x.processplatform.core.entity.element.Script;
+import com.x.processplatform.core.entity.element.wrap.WrapProcess;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+class ActionSearch extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionSearch.class);
+
+	ActionResult<List<Wo>> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		if(!effectivePerson.isManager()){
+			throw new ExceptionAccessDenied(effectivePerson);
+		}
+		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
+		logger.info("{}开始流程平台设计搜索,关键字:{}", effectivePerson.getDistinguishedName(), wi.getKeyword());
+		if(StringUtils.isBlank(wi.getKeyword())){
+			throw new ExceptionFieldEmpty("keyword");
+		}
+		ActionResult<List<Wo>> result = new ActionResult<>();
+
+		List<Wo> resWos = new ArrayList<>();
+		List<CompletableFuture<List<Wo>>> list = new ArrayList<>();
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.form.toString())){
+			list.add(searchForm(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.script.toString())){
+			list.add(searchScript(wi, wi.getAppIdList()));
+		}
+		for (CompletableFuture<List<Wo>> cf : list){
+			if(resWos.size()<50) {
+				resWos.addAll(cf.get(60, TimeUnit.SECONDS));
+			}
+		}
+		if (resWos.size()>50){
+			resWos = resWos.subList(0, 50);
+		}
+		result.setData(resWos);
+		result.setCount((long)resWos.size());
+		return result;
+	}
+
+	private CompletableFuture<List<Wo>> searchScript(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoScript> woScripts;
+				if (ListTools.isEmpty(appIdList)) {
+					woScripts = emc.fetchAll(Script.class, WoScript.copier);
+				} else {
+					woScripts = emc.fetchIn(Script.class, WoScript.copier, Script.application_FIELDNAME, appIdList);
+				}
+				for (WoScript woScript : woScripts) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoScript.copier.getCopyFields(), woScript, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Application app = emc.find(woScript.getApplication(), Application.class);
+						if (app != null) {
+							wo.setAppId(app.getId());
+							wo.setAppName(app.getName());
+						}
+						wo.setDesignerId(woScript.getId());
+						wo.setDesignerName(woScript.getName());
+						wo.setDesignerType(DesignerType.script.toString());
+						wo.setUpdateTime(woScript.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woScripts.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchForm(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Business business = new Business(emc);
+				List<String> formIds = business.form().listWithApplications(appIdList);
+				for (List<String> partFormIds : ListTools.batch(formIds, 100)) {
+					List<WoForm> woForms = emc.fetchIn(Form.class, WoForm.copier, Form.id_FIELDNAME, partFormIds);
+					for (WoForm woForm : woForms) {
+						Map<String, String> map = PropertyTools.fieldMatchKeyword(WoForm.copier.getCopyFields(), woForm, wi.getKeyword(),
+								wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+						if (!map.isEmpty()) {
+							Wo wo = new Wo();
+							Application app = emc.find(woForm.getApplication(), Application.class);
+							if (app != null) {
+								wo.setAppId(app.getId());
+								wo.setAppName(app.getName());
+							}
+							wo.setDesignerId(woForm.getId());
+							wo.setDesignerName(woForm.getName());
+							wo.setDesignerType(DesignerType.form.toString());
+							wo.setUpdateTime(woForm.getUpdateTime());
+							wo.setPatternList(map);
+							resWos.add(wo);
+						}
+					}
+					woForms.clear();
+				}
+
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+
+
+	public static class Wi extends WiDesigner {
+
+	}
+
+	public static class Wo extends WrapDesigner{
+
+	}
+
+	public static class WoScript extends Script {
+
+		static WrapCopier<Script, WoScript> copier = WrapCopierFactory.wo(Script.class, WoScript.class,
+				JpaObject.singularAttributeField(Script.class, true, false),null);
+
+	}
+
+	public static class WoForm extends Form {
+
+		static WrapCopier<Form, WoForm> copier = WrapCopierFactory.wo(Form.class, WoForm.class,
+				JpaObject.singularAttributeField(Form.class, true, false),null);
+
+	}
+
+	public static class WoProcess extends WrapProcess {
+
+		private static final long serialVersionUID = -8507786999314667403L;
+
+	}
+
+}

+ 7 - 0
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.processplatform.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 45 - 0
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/DesignerAction.java

@@ -0,0 +1,45 @@
+package com.x.processplatform.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("designer")
+@JaxrsDescribe("设计")
+public class DesignerAction extends StandardJaxrsAction {
+
+	private static Logger logger = LoggerFactory.getLogger(DesignerAction.class);
+
+	@JaxrsMethodDescribe(value = "根据关键字搜索设计对象.", action = ActionSearch.class)
+	@POST
+	@Path("search")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void search(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+							JsonElement jsonElement) {
+		ActionResult<List<ActionSearch.Wo>> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionSearch().execute(effectivePerson, jsonElement);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+}

+ 11 - 0
o2server/x_processplatform_assemble_designer/src/main/java/com/x/processplatform/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java

@@ -0,0 +1,11 @@
+package com.x.processplatform.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.exception.PromptException;
+
+public class ExceptionFieldEmpty extends PromptException {
+
+	public ExceptionFieldEmpty(String field) {
+		super("参数: {} 值无效.", field);
+	}
+
+}

+ 55 - 0
o2server/x_processplatform_assemble_surface/src/main/java/com/x/processplatform/assemble/surface/jaxrs/snap/ActionTypeAbandonedWorkCompleted.java

@@ -0,0 +1,55 @@
+package com.x.processplatform.assemble.surface.jaxrs.snap;
+
+import org.apache.commons.lang3.BooleanUtils;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.Applications;
+import com.x.base.core.project.x_processplatform_service_processing;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.exception.ExceptionEntityNotExist;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WoId;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.processplatform.assemble.surface.Business;
+import com.x.processplatform.assemble.surface.ThisApplication;
+import com.x.processplatform.core.entity.content.WorkCompleted;
+
+class ActionTypeAbandonedWorkCompleted extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionTypeAbandonedWorkCompleted.class);
+
+	ActionResult<Wo> execute(EffectivePerson effectivePerson, String workCompletedId) throws Exception {
+		String job = null;
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			Business business = new Business(emc);
+			WorkCompleted workCompleted = emc.find(workCompletedId, WorkCompleted.class);
+			if (null == workCompleted) {
+				throw new ExceptionEntityNotExist(workCompletedId, WorkCompleted.class);
+			}
+			if (BooleanUtils.isFalse(business.canManageApplicationOrProcess(effectivePerson,
+					workCompleted.getApplication(), workCompleted.getProcess()))) {
+				throw new ExceptionAccessDenied(effectivePerson, workCompleted);
+			}
+			job = workCompleted.getJob();
+		}
+
+		Wo wo = ThisApplication.context().applications()
+				.getQuery(effectivePerson.getDebugger(), x_processplatform_service_processing.class, Applications
+						.joinQueryUri("snap", "workcompleted", workCompletedId, "type", "abandonedworkcompleted"), job)
+				.getData(Wo.class);
+		ActionResult<Wo> result = new ActionResult<>();
+		result.setData(wo);
+		return result;
+
+	}
+
+	public static class Wo extends WoId {
+
+		private static final long serialVersionUID = -2577413577740827608L;
+
+	}
+
+}

+ 19 - 0
o2server/x_processplatform_assemble_surface/src/main/java/com/x/processplatform/assemble/surface/jaxrs/snap/SnapAction.java

@@ -69,6 +69,25 @@ public class SnapAction extends StandardJaxrsAction {
 		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
 	}
 
+	@JaxrsMethodDescribe(value = "对已完成工作进行快照,并标记为废弃", action = ActionTypeAbandonedWorkCompleted.class)
+	@GET
+	@Path("workcompleted/{workCompletedId}/type/abandonedworkcompleted")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void typeAbandonedWorkCompleted(@Suspended final AsyncResponse asyncResponse,
+			@Context HttpServletRequest request,
+			@JaxrsParameterDescribe("工作标识") @PathParam("workCompletedId") String workCompletedId) {
+		ActionResult<ActionTypeAbandonedWorkCompleted.Wo> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionTypeAbandonedWorkCompleted().execute(effectivePerson, workCompletedId);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+
 	@JaxrsMethodDescribe(value = "挂起工作", action = ActionTypeSuspend.class)
 	@GET
 	@Path("work/{workId}/type/suspend")

+ 16 - 0
o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Snap.java

@@ -44,6 +44,8 @@ public class Snap extends SliceJpaObject {
 
 	public static final String TYPE_ABANDONED = "abandoned";
 
+	public static final String TYPE_ABANDONEDWORKCOMPLETED = "abandonedWorkCompleted";
+
 	public String getId() {
 		return id;
 	}
@@ -108,6 +110,20 @@ public class Snap extends SliceJpaObject {
 		this.setActivityType(work.getActivityType());
 	}
 
+	public Snap(WorkCompleted workCompleted) {
+		this.setTitle(workCompleted.getTitle());
+		this.setJob(workCompleted.getJob());
+		this.setApplication(workCompleted.getApplication());
+		this.setApplicationName(workCompleted.getApplicationName());
+		this.setApplicationAlias(workCompleted.getApplicationAlias());
+		this.setProcess(workCompleted.getProcess());
+		this.setProcessName(workCompleted.getProcessName());
+		this.setProcessAlias(workCompleted.getProcessAlias());
+		this.setCreatorIdentity(workCompleted.getCreatorIdentity());
+		this.setCreatorPerson(workCompleted.getCreatorPerson());
+		this.setCreatorUnit(workCompleted.getCreatorUnit());
+	}
+
 	public SnapProperties getProperties() {
 		if (null == this.properties) {
 			this.properties = new SnapProperties();

+ 11 - 0
o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/SnapProperties.java

@@ -22,6 +22,9 @@ public class SnapProperties extends JsonProperties {
 	@FieldDescribe("工作")
 	private List<Work> workList = new ArrayList<>();
 
+	@FieldDescribe("已完成工作")
+	private WorkCompleted workCompleted;
+
 	@FieldDescribe("待办")
 	private List<Task> taskList = new ArrayList<>();
 
@@ -183,4 +186,12 @@ public class SnapProperties extends JsonProperties {
 		documentVersionList = documentVersionList;
 	}
 
+	public WorkCompleted getWorkCompleted() {
+		return workCompleted;
+	}
+
+	public void setWorkCompleted(WorkCompleted workCompleted) {
+		this.workCompleted = workCompleted;
+	}
+
 }

+ 7 - 2
o2server/x_processplatform_core_express/src/main/java/com/x/processplatform/core/express/service/processing/jaxrs/taskcompleted/WrapUpdateNextTaskIdentity.java

@@ -3,17 +3,22 @@ package com.x.processplatform.core.express.service.processing.jaxrs.taskcomplete
 import java.util.ArrayList;
 import java.util.List;
 
+import com.x.base.core.project.annotation.FieldDescribe;
 import com.x.base.core.project.gson.GsonPropertyObject;
 
 public class WrapUpdateNextTaskIdentity extends GsonPropertyObject {
 
+	private static final long serialVersionUID = -597948505960097189L;
+
+	@FieldDescribe("后续环节待办人")
 	private List<String> nextTaskIdentityList = new ArrayList<>();
 
+	@FieldDescribe("已办标识")
 	private List<String> taskCompletedList = new ArrayList<>();
 
 	public List<String> getNextTaskIdentityList() {
 		if (null == this.nextTaskIdentityList) {
-			this.nextTaskIdentityList = new ArrayList<String>();
+			this.nextTaskIdentityList = new ArrayList<>();
 		}
 		return nextTaskIdentityList;
 	}
@@ -24,7 +29,7 @@ public class WrapUpdateNextTaskIdentity extends GsonPropertyObject {
 
 	public List<String> getTaskCompletedList() {
 		if (null == this.taskCompletedList) {
-			this.taskCompletedList = new ArrayList<String>();
+			this.taskCompletedList = new ArrayList<>();
 		}
 		return taskCompletedList;
 	}

+ 23 - 9
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/WorkDataHelper.java

@@ -15,11 +15,13 @@ import org.apache.commons.lang3.StringUtils;
 import com.google.gson.Gson;
 import com.google.gson.JsonElement;
 import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.entity.dataitem.DataItem;
 import com.x.base.core.entity.dataitem.DataItemConverter;
 import com.x.base.core.entity.dataitem.ItemCategory;
 import com.x.base.core.project.gson.XGsonBuilder;
 import com.x.processplatform.core.entity.content.Data;
 import com.x.processplatform.core.entity.content.Work;
+import com.x.processplatform.core.entity.content.WorkCompleted;
 import com.x.query.core.entity.Item;
 import com.x.query.core.entity.Item_;
 
@@ -43,7 +45,22 @@ public class WorkDataHelper {
 			throw new Exception("can not create DataHelper job is empty.");
 		}
 		this.emc = emc;
-		this.converter = new DataItemConverter<Item>(Item.class);
+		this.converter = new DataItemConverter<>(Item.class);
+		this.gson = XGsonBuilder.instance();
+		this.items = this.load();
+	}
+
+	public WorkDataHelper(EntityManagerContainer emc, WorkCompleted workCompleted) throws Exception {
+		if ((null == emc) || (null == workCompleted)) {
+			throw new Exception("create instance error.");
+		}
+		this.job = workCompleted.getJob();
+		this.distributeFactor = workCompleted.getDistributeFactor();
+		if (StringUtils.isEmpty(this.job)) {
+			throw new Exception("can not create DataHelper job is empty.");
+		}
+		this.emc = emc;
+		this.converter = new DataItemConverter<>(Item.class);
 		this.gson = XGsonBuilder.instance();
 		this.items = this.load();
 	}
@@ -53,11 +70,10 @@ public class WorkDataHelper {
 		CriteriaBuilder cb = em.getCriteriaBuilder();
 		CriteriaQuery<Item> cq = cb.createQuery(Item.class);
 		Root<Item> root = cq.from(Item.class);
-		Path<String> path = root.get(Item.bundle_FIELDNAME);
+		Path<String> path = root.get(DataItem.bundle_FIELDNAME);
 		Predicate p = cb.equal(path, this.job);
 		p = cb.and(p, cb.equal(root.get(Item_.itemCategory), ItemCategory.pp));
-		List<Item> list = em.createQuery(cq.where(p)).getResultList();
-		return list;
+		return em.createQuery(cq.where(p)).getResultList();
 	}
 
 	public Data get() throws Exception {
@@ -69,7 +85,7 @@ public class WorkDataHelper {
 				if (jsonElement.isJsonObject()) {
 					return gson.fromJson(jsonElement, Data.class);
 				} else {
-					/* 如果不是Object强制返回一个Map对象 */
+					// 如果不是Object强制返回一个Map对象
 					return new Data();
 				}
 			}
@@ -80,13 +96,11 @@ public class WorkDataHelper {
 
 	public boolean update(JsonElement jsonElement) throws Exception {
 		if (jsonElement.isJsonNull()) {
-			// throw new Exception("can not update data null.");
-			/** 如果是空数据就不更新,避免数据被清空 */
+			// 如果是空数据就不更新,避免数据被清空
 			return false;
 		}
 		if (jsonElement.isJsonPrimitive()) {
-			// throw new Exception("can not update data primitive.");
-			/** 如果是空数据就不更新,避免数据被清空 */
+			// 如果是空数据就不更新,避免数据被清空 */
 			return false;
 		}
 		if (jsonElement.isJsonObject()) {

+ 2 - 0
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/review/ActionCreateWithWorkCompleted.java

@@ -9,6 +9,7 @@ import com.google.gson.JsonElement;
 import com.x.base.core.container.EntityManagerContainer;
 import com.x.base.core.container.factory.EntityManagerContainerFactory;
 import com.x.base.core.entity.annotation.CheckPersistType;
+import com.x.base.core.project.annotation.FieldDescribe;
 import com.x.base.core.project.exception.ExceptionEntityNotExist;
 import com.x.base.core.project.executor.ProcessPlatformExecutorFactory;
 import com.x.base.core.project.gson.GsonPropertyObject;
@@ -79,6 +80,7 @@ class ActionCreateWithWorkCompleted extends BaseAction {
 
 	public static class Wi extends GsonPropertyObject {
 
+		@FieldDescribe("已完成工作标识")
 		private String workCompleted;
 
 		private List<String> personList = new ArrayList<>();

+ 65 - 7
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/ActionRestore.java

@@ -1,10 +1,13 @@
 package com.x.processplatform.service.processing.jaxrs.snap;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.commons.lang3.BooleanUtils;
+
 import com.x.base.core.container.EntityManagerContainer;
 import com.x.base.core.container.factory.EntityManagerContainerFactory;
 import com.x.base.core.entity.annotation.CheckPersistType;
@@ -28,6 +31,7 @@ import com.x.processplatform.core.entity.content.Snap;
 import com.x.processplatform.core.entity.content.Task;
 import com.x.processplatform.core.entity.content.TaskCompleted;
 import com.x.processplatform.core.entity.content.Work;
+import com.x.processplatform.core.entity.content.WorkCompleted;
 import com.x.processplatform.core.entity.content.WorkLog;
 import com.x.processplatform.service.processing.Business;
 import com.x.processplatform.service.processing.ThisApplication;
@@ -66,14 +70,28 @@ class ActionRestore extends BaseAction {
 				if (null == snap) {
 					throw new ExceptionEntityNotExist(id, Snap.class);
 				}
-				CompletableFuture.allOf(deleteItem(business, snap.getJob()), deleteWork(business, snap.getJob()),
-						deleteTask(business, snap.getJob()), deleteTaskCompleted(business, snap.getJob()),
-						deleteRead(business, snap.getJob()), deleteReadCompleted(business, snap.getJob()),
-						deleteReview(business, snap.getJob()), deleteWorkLog(business, snap.getJob()),
-						deleteRecord(business, snap.getJob()), deleteAttachment(business, snap.getJob()),
-						deleteDocumentVersion(business, snap.getJob())).get();
+				if (Objects.equals(Snap.TYPE_ABANDONEDWORKCOMPLETED, snap.getType())) {
+					CompletableFuture.allOf(deleteItem(business, snap.getJob()),
+							deleteWorkCompleted(business, snap.getJob()), deleteTask(business, snap.getJob()),
+							deleteTaskCompleted(business, snap.getJob()), deleteRead(business, snap.getJob()),
+							deleteReadCompleted(business, snap.getJob()), deleteReview(business, snap.getJob()),
+							deleteWorkLog(business, snap.getJob()), deleteRecord(business, snap.getJob()),
+							deleteAttachment(business, snap.getJob()), deleteDocumentVersion(business, snap.getJob()))
+							.get();
+				} else {
+					CompletableFuture.allOf(deleteItem(business, snap.getJob()), deleteWork(business, snap.getJob()),
+							deleteTask(business, snap.getJob()), deleteTaskCompleted(business, snap.getJob()),
+							deleteRead(business, snap.getJob()), deleteReadCompleted(business, snap.getJob()),
+							deleteReview(business, snap.getJob()), deleteWorkLog(business, snap.getJob()),
+							deleteRecord(business, snap.getJob()), deleteAttachment(business, snap.getJob()),
+							deleteDocumentVersion(business, snap.getJob())).get();
+				}
 				emc.commit();
-				restore(business, snap);
+				if (Objects.equals(Snap.TYPE_ABANDONEDWORKCOMPLETED, snap.getType())) {
+					restoreWorkCompleted(business, snap);
+				} else {
+					restore(business, snap);
+				}
 				emc.commit();
 				emc.beginTransaction(Snap.class);
 				emc.remove(snap, CheckRemoveType.all);
@@ -159,6 +177,46 @@ class ActionRestore extends BaseAction {
 			attachment(business, snap);
 			emc.commit();
 		}
+
+		private void restoreWorkCompleted(Business business, Snap snap) throws Exception {
+			EntityManagerContainer emc = business.entityManagerContainer();
+			emc.beginTransaction(WorkCompleted.class);
+			emc.beginTransaction(TaskCompleted.class);
+			emc.beginTransaction(Read.class);
+			emc.beginTransaction(ReadCompleted.class);
+			emc.beginTransaction(Review.class);
+			emc.beginTransaction(WorkLog.class);
+			emc.beginTransaction(Record.class);
+			emc.beginTransaction(Item.class);
+			emc.beginTransaction(Attachment.class);
+			for (TaskCompleted o : snap.getProperties().getTaskCompletedList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (Read o : snap.getProperties().getReadList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (ReadCompleted o : snap.getProperties().getReadCompletedList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (Review o : snap.getProperties().getReviewList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (WorkLog o : snap.getProperties().getWorkLogList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (Record o : snap.getProperties().getRecordList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			for (Attachment o : snap.getProperties().getAttachmentList()) {
+				emc.persist(o, CheckPersistType.all);
+			}
+			emc.persist(snap.getProperties().getWorkCompleted(), CheckPersistType.all);
+			if (BooleanUtils.isNotTrue(snap.getProperties().getWorkCompleted().getMerged())) {
+				WorkDataHelper workDataHelper = new WorkDataHelper(emc, snap.getProperties().getWorkCompleted());
+				workDataHelper.update(snap.getProperties().getData());
+			}
+			emc.commit();
+		}
 	}
 
 	public static class Wo extends WoId {

+ 95 - 0
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/ActionTypeAbandonedWorkCompleted.java

@@ -0,0 +1,95 @@
+package com.x.processplatform.service.processing.jaxrs.snap;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.annotation.CheckPersistType;
+import com.x.base.core.project.exception.ExceptionEntityNotExist;
+import com.x.base.core.project.executor.ProcessPlatformExecutorFactory;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WoId;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.processplatform.core.entity.content.Attachment;
+import com.x.processplatform.core.entity.content.Read;
+import com.x.processplatform.core.entity.content.ReadCompleted;
+import com.x.processplatform.core.entity.content.Record;
+import com.x.processplatform.core.entity.content.Review;
+import com.x.processplatform.core.entity.content.Snap;
+import com.x.processplatform.core.entity.content.TaskCompleted;
+import com.x.processplatform.core.entity.content.WorkCompleted;
+import com.x.processplatform.core.entity.content.WorkLog;
+import com.x.processplatform.service.processing.Business;
+import com.x.query.core.entity.Item;
+
+class ActionTypeAbandonedWorkCompleted extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionTypeAbandonedWorkCompleted.class);
+
+	ActionResult<Wo> execute(EffectivePerson effectivePerson, String workCompletedId) throws Exception {
+		String job = null;
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			WorkCompleted workCompleted = emc.find(workCompletedId, WorkCompleted.class);
+			if (null == workCompleted) {
+				throw new ExceptionEntityNotExist(workCompletedId, WorkCompleted.class);
+			}
+			job = workCompleted.getJob();
+		}
+		return ProcessPlatformExecutorFactory.get(job).submit(new CallableImpl(workCompletedId)).get(300,
+				TimeUnit.SECONDS);
+	}
+
+	public class CallableImpl implements Callable<ActionResult<Wo>> {
+
+		private String id;
+
+		public CallableImpl(String id) {
+			this.id = id;
+		}
+
+		public ActionResult<Wo> call() throws Exception {
+			ActionResult<Wo> result = new ActionResult<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Business business = new Business(emc);
+				WorkCompleted workCompleted = emc.find(id, WorkCompleted.class);
+				if (null == workCompleted) {
+					throw new ExceptionEntityNotExist(id, WorkCompleted.class);
+				}
+				Snap snap = new Snap(workCompleted);
+				List<Item> items = new ArrayList<>();
+				List<TaskCompleted> taskCompleteds = new ArrayList<>();
+				List<Read> reads = new ArrayList<>();
+				List<ReadCompleted> readCompleteds = new ArrayList<>();
+				List<Review> reviews = new ArrayList<>();
+				List<WorkLog> workLogs = new ArrayList<>();
+				List<Record> records = new ArrayList<>();
+				List<Attachment> attachments = new ArrayList<>();
+				snap.setProperties(snap(business, workCompleted.getJob(), items, workCompleted, taskCompleteds, reads,
+						readCompleteds, reviews, workLogs, records, attachments));
+				snap.setType(Snap.TYPE_ABANDONEDWORKCOMPLETED);
+				emc.beginTransaction(Snap.class);
+				emc.persist(snap, CheckPersistType.all);
+				emc.commit();
+				clean(business, items, workCompleted, taskCompleteds, reads, readCompleteds, reviews, workLogs, records,
+						attachments);
+				emc.commit();
+				Wo wo = new Wo();
+				wo.setId(snap.getId());
+				result.setData(wo);
+				return result;
+			}
+		}
+	}
+
+	public static class Wo extends WoId {
+
+		private static final long serialVersionUID = -2577413577740827608L;
+
+	}
+
+}

+ 69 - 0
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/BaseAction.java

@@ -1,5 +1,6 @@
 package com.x.processplatform.service.processing.jaxrs.snap;
 
+import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
@@ -7,6 +8,8 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang3.BooleanUtils;
+
 import com.google.gson.JsonElement;
 import com.x.base.core.entity.dataitem.DataItem;
 import com.x.base.core.entity.dataitem.DataItemConverter;
@@ -26,6 +29,7 @@ import com.x.processplatform.core.entity.content.SnapProperties;
 import com.x.processplatform.core.entity.content.Task;
 import com.x.processplatform.core.entity.content.TaskCompleted;
 import com.x.processplatform.core.entity.content.Work;
+import com.x.processplatform.core.entity.content.WorkCompleted;
 import com.x.processplatform.core.entity.content.WorkLog;
 import com.x.processplatform.service.processing.Business;
 import com.x.query.core.entity.Item;
@@ -55,6 +59,35 @@ abstract class BaseAction extends StandardJaxrsAction {
 		return properties;
 	}
 
+	protected SnapProperties snap(Business business, String job, List<Item> items, WorkCompleted workCompleted,
+			List<TaskCompleted> taskCompleteds, List<Read> reads, List<ReadCompleted> readCompleteds,
+			List<Review> reviews, List<WorkLog> workLogs, List<Record> records, List<Attachment> attachments) {
+		SnapProperties properties = new SnapProperties();
+		properties.setJob(job);
+		properties.setWorkCompleted(workCompleted);
+		properties.setTitle(workCompleted.getTitle());
+		List<CompletableFuture<Void>> futures = new ArrayList<>();
+		futures.add(mergeTaskCompleted(business, job, properties, taskCompleteds));
+		futures.add(mergeRead(business, job, properties, reads));
+		futures.add(mergeReadCompleted(business, job, properties, readCompleteds));
+		futures.add(mergeReview(business, job, properties, reviews));
+		futures.add(mergeWorkLog(business, job, properties, workLogs));
+		futures.add(mergeRecord(business, job, properties, records));
+		futures.add(mergeAttachment(business, job, properties, attachments));
+		if (BooleanUtils.isNotTrue(workCompleted.getMerged())) {
+			futures.add(mergeItem(business, job, properties, items));
+		}
+		CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0]));
+//		CompletableFuture.allOf(mergeItem(business, job, properties, items),
+//				mergeTaskCompleted(business, job, properties, taskCompleteds),
+//				mergeRead(business, job, properties, reads),
+//				mergeReadCompleted(business, job, properties, readCompleteds),
+//				mergeReview(business, job, properties, reviews), mergeWorkLog(business, job, properties, workLogs),
+//				mergeRecord(business, job, properties, records),
+//				mergeAttachment(business, job, properties, attachments)).get();
+		return properties;
+	}
+
 	protected void clean(Business business, List<Item> items, List<Work> works, List<Task> tasks,
 			List<TaskCompleted> taskCompleteds, List<Read> reads, List<ReadCompleted> readCompleteds,
 			List<Review> reviews, List<WorkLog> workLogs, List<Record> records, List<Attachment> attachments,
@@ -68,6 +101,17 @@ abstract class BaseAction extends StandardJaxrsAction {
 				.get();
 	}
 
+	protected void clean(Business business, List<Item> items, WorkCompleted workCompleted,
+			List<TaskCompleted> taskCompleteds, List<Read> reads, List<ReadCompleted> readCompleteds,
+			List<Review> reviews, List<WorkLog> workLogs, List<Record> records, List<Attachment> attachments)
+			throws InterruptedException, ExecutionException {
+		CompletableFuture.allOf(deleteItem(business, items), deleteWork(business, workCompleted),
+				deleteTaskCompleted(business, taskCompleteds), deleteRead(business, reads),
+				deleteReadCompleted(business, readCompleteds), deleteReview(business, reviews),
+				deleteWorkLog(business, workLogs), deleteRecord(business, records),
+				deleteAttachment(business, attachments)).get();
+	}
+
 	private CompletableFuture<Void> mergeItem(Business business, String job, SnapProperties snapProperties,
 			List<Item> items) {
 		return CompletableFuture.runAsync(() -> {
@@ -270,6 +314,17 @@ abstract class BaseAction extends StandardJaxrsAction {
 		});
 	}
 
+	private CompletableFuture<Void> deleteWork(Business business, WorkCompleted workCompleted) {
+		return CompletableFuture.runAsync(() -> {
+			try {
+				business.entityManagerContainer().beginTransaction(WorkCompleted.class);
+				business.entityManagerContainer().remove(workCompleted);
+			} catch (Exception e) {
+				logger.error(e);
+			}
+		});
+	}
+
 	private CompletableFuture<Void> deleteTask(Business business, List<Task> tasks) {
 		return CompletableFuture.runAsync(() -> {
 			try {
@@ -413,6 +468,20 @@ abstract class BaseAction extends StandardJaxrsAction {
 		});
 	}
 
+	protected CompletableFuture<Void> deleteWorkCompleted(Business business, String job) {
+		return CompletableFuture.runAsync(() -> {
+			try {
+				business.entityManagerContainer().beginTransaction(WorkCompleted.class);
+				for (WorkCompleted o : business.entityManagerContainer().listEqual(WorkCompleted.class,
+						WorkCompleted.job_FIELDNAME, job)) {
+					business.entityManagerContainer().remove(o);
+				}
+			} catch (Exception e) {
+				logger.error(e);
+			}
+		});
+	}
+
 	protected CompletableFuture<Void> deleteTask(Business business, String job) {
 		return CompletableFuture.runAsync(() -> {
 			try {

+ 19 - 0
o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/jaxrs/snap/SnapAction.java

@@ -83,6 +83,25 @@ public class SnapAction extends StandardJaxrsAction {
 		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
 	}
 
+	@JaxrsMethodDescribe(value = "废弃已完成工作", action = ActionTypeAbandonedWorkCompleted.class)
+	@GET
+	@Path("workcompleted/{workCompletedId}/type/abandonedworkcompleted")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void typeAbandonedWorkCompleted(@Suspended final AsyncResponse asyncResponse,
+			@Context HttpServletRequest request,
+			@JaxrsParameterDescribe("已完成工作标识") @PathParam("workCompletedId") String workCompletedId) {
+		ActionResult<ActionTypeAbandonedWorkCompleted.Wo> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionTypeAbandonedWorkCompleted().execute(effectivePerson, workCompletedId);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+
 	@JaxrsMethodDescribe(value = "删除快照", action = ActionDelete.class)
 	@DELETE
 	@Path("{id}")

+ 2 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/ActionApplication.java

@@ -18,6 +18,7 @@ import com.x.program.center.jaxrs.collect.CollectAction;
 import com.x.program.center.jaxrs.command.CommandAction;
 import com.x.program.center.jaxrs.config.ConfigAction;
 import com.x.program.center.jaxrs.datastructure.DataStructureAction;
+import com.x.program.center.jaxrs.designer.DesignerAction;
 import com.x.program.center.jaxrs.dingding.DingdingAction;
 import com.x.program.center.jaxrs.distribute.DistributeAction;
 import com.x.program.center.jaxrs.input.InputAction;
@@ -72,6 +73,7 @@ public class ActionApplication extends AbstractActionApplication {
 		classes.add(OutputAction.class);
 		classes.add(InputAction.class);
 		classes.add(MarketAction.class);
+		classes.add(DesignerAction.class);
 		return classes;
 	}
 }

+ 10 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/DesignerJaxrsFilter.java

@@ -0,0 +1,10 @@
+package com.x.program.center.jaxrs;
+
+import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = "/jaxrs/designer/*", asyncSupported = true)
+public class DesignerJaxrsFilter extends CipherManagerJaxrsFilter {
+
+}

+ 3 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/collect/ActionValidateDirect.java

@@ -16,6 +16,9 @@ class ActionValidateDirect extends BaseAction {
 
 	ActionResult<Wo> execute(JsonElement jsonElement) throws Exception {
 		ActionResult<Wo> result = new ActionResult<>();
+		if (!Config.nodes().centerServers().first().getValue().getConfigApiEnable()) {
+			throw new ExceptionModifyConfig();
+		}
 		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
 		Wo wo = new Wo();
 		wo.setValue(true);

+ 149 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/ActionSearch.java

@@ -0,0 +1,149 @@
+package com.x.program.center.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.bean.WrapCopierFactory;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.base.core.project.tools.PropertyTools;
+import com.x.program.center.core.entity.Agent;
+import com.x.program.center.core.entity.Invoke;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+class ActionSearch extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionSearch.class);
+
+	ActionResult<List<Wo>> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		if(!effectivePerson.isManager()){
+			throw new ExceptionAccessDenied(effectivePerson);
+		}
+		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
+		logger.info("{}开始服务管理设计搜索,关键字:{}", effectivePerson.getDistinguishedName(), wi.getKeyword());
+		if(StringUtils.isBlank(wi.getKeyword())){
+			throw new ExceptionFieldEmpty("keyword");
+		}
+		ActionResult<List<Wo>> result = new ActionResult<>();
+
+		List<Wo> resWos = new ArrayList<>();
+		List<CompletableFuture<List<Wo>>> list = new ArrayList<>();
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.script.toString())){
+			if(wi.getAppIdList().isEmpty() || wi.getAppIdList().contains("invoke")) {
+				list.add(searchInvoke(wi));
+			}
+			if(wi.getAppIdList().isEmpty() || wi.getAppIdList().contains("agent")) {
+				list.add(searchAgent(wi));
+			}
+		}
+		for (CompletableFuture<List<Wo>> cf : list){
+			if(resWos.size()<50) {
+				resWos.addAll(cf.get(60, TimeUnit.SECONDS));
+			}
+		}
+		if (resWos.size()>50){
+			resWos = resWos.subList(0, 50);
+		}
+		result.setData(resWos);
+		result.setCount((long)resWos.size());
+		return result;
+	}
+
+	private CompletableFuture<List<Wo>> searchAgent(final Wi wi) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoAgent> woAgents = emc.fetchAll(Agent.class, WoAgent.copier);
+				for (WoAgent woAgent : woAgents) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoAgent.copier.getCopyFields(), woAgent, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						wo.setAppId("agent");
+						wo.setAppName("代理");
+						wo.setDesignerId(woAgent.getId());
+						wo.setDesignerName(woAgent.getName());
+						wo.setDesignerType(DesignerType.script.toString());
+						wo.setUpdateTime(woAgent.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woAgents.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchInvoke(final Wi wi) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoInvoke> woInvokes = emc.fetchAll(Invoke.class, WoInvoke.copier);
+				for (WoInvoke woInvoke : woInvokes) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoInvoke.copier.getCopyFields(), woInvoke, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						wo.setAppId("invoke");
+						wo.setAppName("接口");
+						wo.setDesignerId(woInvoke.getId());
+						wo.setDesignerName(woInvoke.getName());
+						wo.setDesignerType(DesignerType.script.toString());
+						wo.setUpdateTime(woInvoke.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woInvokes.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+
+	public static class Wi extends WiDesigner {
+
+	}
+
+	public static class Wo extends WrapDesigner{
+
+	}
+
+	public static class WoAgent extends Agent {
+
+		static WrapCopier<Agent, WoAgent> copier = WrapCopierFactory.wo(Agent.class, WoAgent.class,
+				JpaObject.singularAttributeField(Agent.class, true, false),null);
+
+	}
+
+	public static class WoInvoke extends Invoke {
+
+		static WrapCopier<Invoke, WoInvoke> copier = WrapCopierFactory.wo(Invoke.class, WoInvoke.class,
+				JpaObject.singularAttributeField(Invoke.class, true, false),null);
+
+	}
+
+
+}

+ 7 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.program.center.jaxrs.designer;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 48 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/DesignerAction.java

@@ -0,0 +1,48 @@
+package com.x.program.center.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("designer")
+@JaxrsDescribe("设计")
+public class DesignerAction extends StandardJaxrsAction {
+
+	private static Logger logger = LoggerFactory.getLogger(DesignerAction.class);
+
+	@JaxrsMethodDescribe(value = "根据关键字搜索设计对象.", action = ActionSearch.class)
+	@POST
+	@Path("search")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void search(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+							JsonElement jsonElement) {
+		ActionResult<List<ActionSearch.Wo>> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionSearch().execute(effectivePerson, jsonElement);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+}

+ 11 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/designer/ExceptionFieldEmpty.java

@@ -0,0 +1,11 @@
+package com.x.program.center.jaxrs.designer;
+
+import com.x.base.core.project.exception.PromptException;
+
+public class ExceptionFieldEmpty extends PromptException {
+
+	public ExceptionFieldEmpty(String field) {
+		super("参数: {} 值无效.", field);
+	}
+
+}

+ 2 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/ActionApplication.java

@@ -5,6 +5,7 @@ import java.util.Set;
 import javax.ws.rs.ApplicationPath;
 
 import com.x.base.core.project.jaxrs.AbstractActionApplication;
+import com.x.query.assemble.designer.jaxrs.designer.DesignerAction;
 import com.x.query.assemble.designer.jaxrs.id.IdAction;
 import com.x.query.assemble.designer.jaxrs.input.InputAction;
 import com.x.query.assemble.designer.jaxrs.neural.NeuralAction;
@@ -30,6 +31,7 @@ public class ActionApplication extends AbstractActionApplication {
 		classes.add(InputAction.class);
 		classes.add(TableAction.class);
 		classes.add(StatementAction.class);
+		classes.add(DesignerAction.class);
 		return classes;
 	}
 

+ 10 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/DesignerJaxrsFilter.java

@@ -0,0 +1,10 @@
+package com.x.query.assemble.designer.jaxrs;
+
+import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = "/jaxrs/designer/*", asyncSupported = true)
+public class DesignerJaxrsFilter extends CipherManagerJaxrsFilter {
+
+}

+ 259 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/ActionSearch.java

@@ -0,0 +1,259 @@
+package com.x.query.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.enums.DesignerType;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.bean.WrapCopierFactory;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.base.core.project.tools.PropertyTools;
+import com.x.query.core.entity.Query;
+import com.x.query.core.entity.Stat;
+import com.x.query.core.entity.View;
+import com.x.query.core.entity.schema.Statement;
+import com.x.query.core.entity.schema.Table;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+class ActionSearch extends BaseAction {
+
+	private static Logger logger = LoggerFactory.getLogger(ActionSearch.class);
+
+	ActionResult<List<Wo>> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		if(!effectivePerson.isManager()){
+			throw new ExceptionAccessDenied(effectivePerson);
+		}
+		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
+		logger.info("{}开始数据中心设计搜索,关键字:{}", effectivePerson.getDistinguishedName(), wi.getKeyword());
+		if(StringUtils.isBlank(wi.getKeyword())){
+			throw new ExceptionFieldEmpty("keyword");
+		}
+		ActionResult<List<Wo>> result = new ActionResult<>();
+
+		List<Wo> resWos = new ArrayList<>();
+		List<CompletableFuture<List<Wo>>> list = new ArrayList<>();
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.view.toString())){
+			list.add(searchView(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.table.toString())){
+			list.add(searchTable(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.statement.toString())){
+			list.add(searchStatement(wi, wi.getAppIdList()));
+		}
+		if (wi.getDesignerTypes().isEmpty() || wi.getDesignerTypes().contains(DesignerType.stat.toString())){
+			list.add(searchStat(wi, wi.getAppIdList()));
+		}
+		for (CompletableFuture<List<Wo>> cf : list){
+			if(resWos.size()<50) {
+				resWos.addAll(cf.get(60, TimeUnit.SECONDS));
+			}
+		}
+		if (resWos.size()>50){
+			resWos = resWos.subList(0, 50);
+		}
+		result.setData(resWos);
+		result.setCount((long)resWos.size());
+		return result;
+	}
+
+	private CompletableFuture<List<Wo>> searchView(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoView> woViews;
+				if (ListTools.isEmpty(appIdList)) {
+					woViews = emc.fetchAll(View.class, WoView.copier);
+				} else {
+					woViews = emc.fetchIn(View.class, WoView.copier, View.query_FIELDNAME, appIdList);
+				}
+				for (WoView woView : woViews) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoView.copier.getCopyFields(), woView, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Query query = emc.find(woView.getQuery(), Query.class);
+						if (query != null) {
+							wo.setAppId(query.getId());
+							wo.setAppName(query.getName());
+						}
+						wo.setDesignerId(woView.getId());
+						wo.setDesignerName(woView.getName());
+						wo.setDesignerType(DesignerType.view.toString());
+						wo.setUpdateTime(woView.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woViews.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchTable(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoTable> woTables;
+				if (ListTools.isEmpty(appIdList)) {
+					woTables = emc.fetchAll(Table.class, WoTable.copier);
+				} else {
+					woTables = emc.fetchIn(Table.class, WoTable.copier, Table.query_FIELDNAME, appIdList);
+				}
+				for (WoTable woTable : woTables) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoTable.copier.getCopyFields(), woTable, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Query query = emc.find(woTable.getQuery(), Query.class);
+						if (query != null) {
+							wo.setAppId(query.getId());
+							wo.setAppName(query.getName());
+						}
+						wo.setDesignerId(woTable.getId());
+						wo.setDesignerName(woTable.getName());
+						wo.setDesignerType(DesignerType.table.toString());
+						wo.setUpdateTime(woTable.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woTables.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchStat(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoStat> woStats;
+				if (ListTools.isEmpty(appIdList)) {
+					woStats = emc.fetchAll(Stat.class, WoStat.copier);
+				} else {
+					woStats = emc.fetchIn(Stat.class, WoStat.copier, Stat.query_FIELDNAME, appIdList);
+				}
+				for (WoStat woStat : woStats) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoStat.copier.getCopyFields(), woStat, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Query query = emc.find(woStat.getQuery(), Query.class);
+						if (query != null) {
+							wo.setAppId(query.getId());
+							wo.setAppName(query.getName());
+						}
+						wo.setDesignerId(woStat.getId());
+						wo.setDesignerName(woStat.getName());
+						wo.setDesignerType(DesignerType.stat.toString());
+						wo.setUpdateTime(woStat.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woStats.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	private CompletableFuture<List<Wo>> searchStatement(final Wi wi, final List<String> appIdList) {
+		CompletableFuture<List<Wo>> cf = CompletableFuture.supplyAsync(() -> {
+			List<Wo> resWos = new ArrayList<>();
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				List<WoStatement> woStatements;
+				if (ListTools.isEmpty(appIdList)) {
+					woStatements = emc.fetchAll(Statement.class, WoStatement.copier);
+				} else {
+					woStatements = emc.fetchIn(Statement.class, WoStatement.copier, Statement.query_FIELDNAME, appIdList);
+				}
+				for (WoStatement woStatement : woStatements) {
+					Map<String, String> map = PropertyTools.fieldMatchKeyword(WoStatement.copier.getCopyFields(), woStatement, wi.getKeyword(),
+							wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					if (!map.isEmpty()) {
+						Wo wo = new Wo();
+						Query query = emc.find(woStatement.getQuery(), Query.class);
+						if (query != null) {
+							wo.setAppId(query.getId());
+							wo.setAppName(query.getName());
+						}
+						wo.setDesignerId(woStatement.getId());
+						wo.setDesignerName(woStatement.getName());
+						wo.setDesignerType(DesignerType.statement.toString());
+						wo.setUpdateTime(woStatement.getUpdateTime());
+						wo.setPatternList(map);
+						resWos.add(wo);
+					}
+				}
+				woStatements.clear();
+			}catch (Exception e){
+				logger.error(e);
+			}
+			return resWos;
+		});
+		return cf;
+	}
+
+	public static class Wi extends WiDesigner {
+
+	}
+
+	public static class Wo extends WrapDesigner{
+
+	}
+
+	public static class WoView extends View {
+
+		static WrapCopier<View, WoView> copier = WrapCopierFactory.wo(View.class, WoView.class,
+				JpaObject.singularAttributeField(View.class, true, false),null);
+
+	}
+
+	public static class WoStat extends Stat {
+
+		static WrapCopier<Stat, WoStat> copier = WrapCopierFactory.wo(Stat.class, WoStat.class,
+				JpaObject.singularAttributeField(Stat.class, true, false),null);
+
+	}
+
+	public static class WoTable extends Table {
+
+		static WrapCopier<Table, WoTable> copier = WrapCopierFactory.wo(Table.class, WoTable.class,
+				JpaObject.singularAttributeField(Table.class, true, false),null);
+
+	}
+
+	public static class WoStatement extends Statement {
+
+		static WrapCopier<Statement, WoStatement> copier = WrapCopierFactory.wo(Statement.class, WoStatement.class,
+				JpaObject.singularAttributeField(Statement.class, true, false),null);
+
+	}
+
+
+}

+ 7 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.query.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 48 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/DesignerAction.java

@@ -0,0 +1,48 @@
+package com.x.query.assemble.designer.jaxrs.designer;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.List;
+
+@Path("designer")
+@JaxrsDescribe("数据中心设计")
+public class DesignerAction extends StandardJaxrsAction {
+
+	private static Logger logger = LoggerFactory.getLogger(DesignerAction.class);
+
+	@JaxrsMethodDescribe(value = "根据关键字搜索设计对象.", action = ActionSearch.class)
+	@POST
+	@Path("search")
+	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+	@Consumes(MediaType.APPLICATION_JSON)
+	public void search(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+							JsonElement jsonElement) {
+		ActionResult<List<ActionSearch.Wo>> result = new ActionResult<>();
+		EffectivePerson effectivePerson = this.effectivePerson(request);
+		try {
+			result = new ActionSearch().execute(effectivePerson, jsonElement);
+		} catch (Exception e) {
+			logger.error(e, effectivePerson, request, null);
+			result.error(e);
+		}
+		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+	}
+}

+ 11 - 0
o2server/x_query_assemble_designer/src/main/java/com/x/query/assemble/designer/jaxrs/designer/ExceptionFieldEmpty.java

@@ -0,0 +1,11 @@
+package com.x.query.assemble.designer.jaxrs.designer;
+
+import com.x.base.core.project.exception.PromptException;
+
+public class ExceptionFieldEmpty extends PromptException {
+
+	public ExceptionFieldEmpty(String field) {
+		super("参数: {} 值无效.", field);
+	}
+
+}

+ 106 - 129
o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/ActionSearch.java

@@ -1,25 +1,24 @@
 package com.x.query.service.processing.jaxrs.design;
 
 import com.google.gson.JsonElement;
-import com.x.base.core.project.Applications;
+import com.x.base.core.project.*;
 import com.x.base.core.project.annotation.FieldDescribe;
 import com.x.base.core.project.annotation.FieldTypeDescribe;
 import com.x.base.core.project.gson.GsonPropertyObject;
 import com.x.base.core.project.http.ActionResult;
 import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WiDesigner;
+import com.x.base.core.project.jaxrs.WrapDesigner;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.LoggerFactory;
 import com.x.base.core.project.tools.ListTools;
 import com.x.base.core.project.tools.SortTools;
-import com.x.base.core.project.tools.StringTools;
-import com.x.base.core.project.x_cms_assemble_control;
-import com.x.base.core.project.x_portal_assemble_designer;
-import com.x.base.core.project.x_processplatform_assemble_designer;
 import com.x.query.service.processing.ThisApplication;
+import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.*;
-import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.*;
 
 class ActionSearch extends BaseAction {
 
@@ -29,27 +28,15 @@ class ActionSearch extends BaseAction {
 			throws Exception {
 		ActionResult<Wo> result = new ActionResult<>();
 		Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
-		Wo wo = new Wo();
-		wo.setType(wi.getType());
 		if(StringUtils.isBlank(wi.getKeyword())){
 			throw new ExceptionFieldEmpty("keyword");
 		}
-		if(StringUtils.isBlank(wi.getType())){
-			throw new ExceptionFieldEmpty("type");
-		}
-		logger.print("{}搜索全局设计:{},关键字:{}", effectivePerson.getDistinguishedName(), wi.getType(), wi.getKeyword());
-		switch (wi.getType()) {
-			case "script":
-				wo.setScriptWrapList(searchScript(wi));
-				break;
-			default:
-				throw new ExceptionFieldEmpty("type");
-		}
-		result.setData(wo);
+		logger.print("{}搜索全局设计:{}", effectivePerson.getDistinguishedName(), wi);
+		result.setData(search(wi));
 		return result;
 	}
 
-	private List<ScriptWo> searchScript(final Wi wi) throws Exception{
+	private Wo search(final Wi wi) {
 		final Map<String, List<String>> moduleMap = new HashMap<>();
 		if(!ListTools.isEmpty(wi.getModuleList())){
 			for (Module module: wi.getModuleList()){
@@ -62,72 +49,93 @@ class ActionSearch extends BaseAction {
 				if(module.getModuleType().equalsIgnoreCase(ModuleType.processPlatform.toString())){
 					moduleMap.put(ModuleType.processPlatform.toString(), module.getFlagList());
 				}
+				if(module.getModuleType().equalsIgnoreCase(ModuleType.query.toString())){
+					moduleMap.put(ModuleType.query.toString(), module.getFlagList());
+				}
+				if(module.getModuleType().equalsIgnoreCase(ModuleType.service.toString())){
+					moduleMap.put(ModuleType.service.toString(), module.getFlagList());
+				}
 			}
 		}else{
 			List<String> list = new ArrayList<>();
 			moduleMap.put(ModuleType.cms.toString(), list);
 			moduleMap.put(ModuleType.portal.toString(), list);
 			moduleMap.put(ModuleType.processPlatform.toString(), list);
-		}
-
-		CompletableFuture<List<ScriptWo>> processPlatformCf = scriptSearchAsync(wi, moduleMap, ModuleType.processPlatform.toString(), x_processplatform_assemble_designer.class);
-		CompletableFuture<List<ScriptWo>> portalCf = scriptSearchAsync(wi, moduleMap, ModuleType.portal.toString(), x_portal_assemble_designer.class);
-		CompletableFuture<List<ScriptWo>> cmsCf = scriptSearchAsync(wi, moduleMap, ModuleType.cms.toString(), x_cms_assemble_control.class);
-
-		List<ScriptWo> scriptWoList = new ArrayList<>();
-		scriptWoList.addAll(processPlatformCf.get());
-		scriptWoList.addAll(portalCf.get());
-		scriptWoList.addAll(cmsCf.get());
-
-		return scriptWoList;
+			moduleMap.put(ModuleType.query.toString(), list);
+			moduleMap.put(ModuleType.service.toString(), list);
+		}
+		Executor executor = Executors.newFixedThreadPool(5);
+		CompletableFuture<List<WrapDesigner>> processPlatformCf = searchAsync(wi, moduleMap, ModuleType.processPlatform.toString(), x_processplatform_assemble_designer.class, executor);
+		CompletableFuture<List<WrapDesigner>> portalCf = searchAsync(wi, moduleMap, ModuleType.portal.toString(), x_portal_assemble_designer.class, executor);
+		CompletableFuture<List<WrapDesigner>> cmsCf = searchAsync(wi, moduleMap, ModuleType.cms.toString(), x_cms_assemble_control.class, executor);
+		CompletableFuture<List<WrapDesigner>> queryCf = searchAsync(wi, moduleMap, ModuleType.query.toString(), x_query_assemble_designer.class, executor);
+		CompletableFuture<List<WrapDesigner>> serviceCf = searchAsync(wi, moduleMap, ModuleType.service.toString(), x_program_center.class, executor);
+		Wo wo = new Wo();
+		try {
+			wo.setProcessPlatformList(processPlatformCf.get(200, TimeUnit.SECONDS));
+		} catch (Exception e) {
+			logger.warn("搜索流程平台设计异常:{}",e.getMessage());
+		}
+		try {
+			wo.setPortalList(portalCf.get(200, TimeUnit.SECONDS));
+		} catch (Exception e) {
+			logger.warn("搜索门户平台设计异常:{}",e.getMessage());
+		}
+		try {
+			wo.setCmsList(cmsCf.get(200, TimeUnit.SECONDS));
+		} catch (Exception e) {
+			logger.warn("搜索内容管理平台设计异常:{}",e.getMessage());
+		}
+		try {
+			wo.setQueryList(queryCf.get(200, TimeUnit.SECONDS));
+		} catch (Exception e) {
+			logger.warn("搜索数据中心平台设计异常:{}",e.getMessage());
+		}
+		try {
+			wo.setServiceList(serviceCf.get(200, TimeUnit.SECONDS));
+		} catch (Exception e) {
+			logger.warn("搜索服务管理平台设计异常:{}",e.getMessage());
+		}
+		return wo;
 	}
 
-	private CompletableFuture<List<ScriptWo>> scriptSearchAsync(final Wi wi, final Map<String, List<String>> moduleMap, final String moduleType, final Class<?> applicationClass){
-		CompletableFuture<List<ScriptWo>> cf = CompletableFuture.supplyAsync(() -> {
-			List<ScriptWo> swList = new ArrayList<>();
+	private CompletableFuture<List<WrapDesigner>> searchAsync(final Wi wi, final Map<String, List<String>> moduleMap, final String moduleType, final Class<?> applicationClass, Executor executor){
+		CompletableFuture<List<WrapDesigner>> cf = CompletableFuture.supplyAsync(() -> {
+			List<WrapDesigner> swList = new ArrayList<>();
 			if(moduleMap.containsKey(moduleType)) {
 				try {
-					Map<String, Object> map = new HashMap<>();
-					map.put("appIdList", moduleMap.get(moduleType));
-					map.put("keyword", wi.getKeyword());
-					map.put("caseSensitive", wi.getCaseSensitive());
-					map.put("matchWholeWord", wi.getMatchWholeWord());
-					map.put("matchRegExp", wi.getMatchRegExp());
-					List<WrapScript> scriptList = ThisApplication.context().applications().postQuery(applicationClass,
-							Applications.joinQueryUri("script", "list", "manager"), map).getDataAsList(WrapScript.class);
-					logger.print("设计搜索关联{}的匹配脚本个数:{}", moduleType, scriptList.size());
-					getScriptSearchRes(wi, moduleType, swList, scriptList);
+					WiDesigner wiDesigner = new WiDesigner();
+					BeanUtils.copyProperties(wiDesigner, wi);
+					wiDesigner.setAppIdList(moduleMap.get(moduleType));
+					List<WrapDesigner> designerList = ThisApplication.context().applications().postQuery(applicationClass,
+							Applications.joinQueryUri("designer", "search"), wiDesigner).getDataAsList(WrapDesigner.class);
+					logger.info("设计搜索关联{}的匹配设计个数:{}", moduleType, designerList.size());
+					getSearchRes(wi, designerList);
+					swList = designerList;
 				} catch (Exception e) {
 					logger.error(e);
 				}
 				if (swList.size() > 2) {
 					try {
-						SortTools.desc(swList, "appId");
+						SortTools.desc(swList, "designerType","appId");
 					} catch (Exception e) {
 					}
 				}
 			}
 			return swList;
-		});
+		}, executor);
 		return cf;
 	}
 
-	private void getScriptSearchRes(final Wi wi, String moduleType, List<ScriptWo> swList, List<WrapScript> scriptList){
-		if (!ListTools.isEmpty(scriptList)){
-			for (WrapScript script:scriptList) {
-				if (StringTools.matchKeyword(wi.getKeyword(), script.getText(), wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp())){
-					List<Integer> list = patternLines(script.getId()+"-"+script.getUpdateTime().getTime(),
-							wi.getKeyword(), script.getText(), wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
-					if (!ListTools.isEmpty(list)){
-						ScriptWo scriptWo = new ScriptWo();
-						scriptWo.setModuleType(moduleType);
-						scriptWo.setAppId(script.getAppId());
-						scriptWo.setAppName(script.getAppName());
-						scriptWo.setScriptId(script.getId());
-						scriptWo.setScriptName(script.getName());
-						scriptWo.setPatternLines(list);
-						swList.add(scriptWo);
-					}
+	private void getSearchRes(final Wi wi, List<WrapDesigner> designerList){
+		if (!ListTools.isEmpty(designerList)){
+			for (WrapDesigner designer : designerList) {
+				WrapDesigner.DesignerPattern pattern = designer.getScriptDesigner();
+				if(pattern!=null) {
+					List<Integer> lines = patternLines(designer.getDesignerId() + "-" + designer.getUpdateTime().getTime(),
+							wi.getKeyword(), pattern.getPropertyValue(), wi.getCaseSensitive(), wi.getMatchWholeWord(), wi.getMatchRegExp());
+					pattern.setLines(lines);
+					pattern.setPropertyValue(null);
 				}
 			}
 		}
@@ -138,15 +146,15 @@ class ActionSearch extends BaseAction {
 
 		@FieldDescribe("搜索关键字.")
 		private String keyword;
-		@FieldDescribe("搜索类型:script|form|process")
-		private String type;
+		@FieldDescribe("搜索设计类型:script|form|page|widget|process")
+		private List<String> designerTypes;
 		@FieldDescribe("是否区分大小写.")
 		private Boolean caseSensitive;
 		@FieldDescribe("是否全字匹配.")
 		private Boolean matchWholeWord;
 		@FieldDescribe("是否正则表达式匹配.")
 		private Boolean matchRegExp;
-		@FieldDescribe("限制查询的模块列表.")
+		@FieldDescribe("限制查询的模块列表(模块类型:processPlatform|cms|portal|query|service).")
 		@FieldTypeDescribe(fieldType = "class", fieldTypeName = "Module", fieldValue = "{\"moduleType\": \"cms\", \"flagList\": []}")
 		private List<Module> moduleList;
 
@@ -158,12 +166,12 @@ class ActionSearch extends BaseAction {
 			this.keyword = keyword;
 		}
 
-		public String getType() {
-			return type;
+		public List<String> getDesignerTypes() {
+			return designerTypes;
 		}
 
-		public void setType(String type) {
-			this.type = type;
+		public void setDesignerTypes(List<String> designerTypes) {
+			this.designerTypes = designerTypes;
 		}
 
 		public Boolean getCaseSensitive() {
@@ -202,7 +210,7 @@ class ActionSearch extends BaseAction {
 	public static class Module extends GsonPropertyObject {
 		@FieldDescribe("模块的应用id列表.")
 		private List<String> flagList;
-		@FieldDescribe("模块类型:processPlatform|cms|portal|query|service")
+		@FieldDescribe("模块类型.")
 		private String moduleType;
 
 		public List<String> getFlagList() {
@@ -223,88 +231,57 @@ class ActionSearch extends BaseAction {
 	}
 
 	public static class Wo extends GsonPropertyObject {
-		@FieldDescribe("搜索类型:script|form|process")
-		private String type;
-		@FieldDescribe("脚本搜索结果集")
-		private List<ScriptWo> scriptWrapList = new ArrayList<>();
-
-		public String getType() {
-			return type;
-		}
 
-		public void setType(String type) {
-			this.type = type;
-		}
+		private static final long serialVersionUID = 8169092162410529422L;
 
-		public List<ScriptWo> getScriptWrapList() {
-			return scriptWrapList;
-		}
+		private List<WrapDesigner> processPlatformList;
 
-		public void setScriptWrapList(List<ScriptWo> scriptWrapList) {
-			this.scriptWrapList = scriptWrapList;
-		}
-	}
+		private List<WrapDesigner> cmsList;
 
-	public static class ScriptWo extends GsonPropertyObject {
-		@FieldDescribe("模块类型:processPlatform|cms|portal|query|service")
-		private String moduleType;
-		@FieldDescribe("应用ID")
-		private String appId;
-		@FieldDescribe("应用名称")
-		private String appName;
-		@FieldDescribe("脚本Id")
-		private String scriptId;
-		@FieldDescribe("脚本名称")
-		private String scriptName;
-		@FieldDescribe("匹配行")
-		private List<Integer> patternLines;
+		private List<WrapDesigner> portalList;
 
-		public String getModuleType() {
-			return moduleType;
-		}
+		private List<WrapDesigner> queryList;
 
-		public void setModuleType(String moduleType) {
-			this.moduleType = moduleType;
-		}
+		private List<WrapDesigner> serviceList;
 
-		public String getAppId() {
-			return appId;
+		public List<WrapDesigner> getProcessPlatformList() {
+			return processPlatformList;
 		}
 
-		public void setAppId(String appId) {
-			this.appId = appId;
+		public void setProcessPlatformList(List<WrapDesigner> processPlatformList) {
+			this.processPlatformList = processPlatformList;
 		}
 
-		public String getAppName() {
-			return appName;
+		public List<WrapDesigner> getCmsList() {
+			return cmsList;
 		}
 
-		public void setAppName(String appName) {
-			this.appName = appName;
+		public void setCmsList(List<WrapDesigner> cmsList) {
+			this.cmsList = cmsList;
 		}
 
-		public String getScriptId() {
-			return scriptId;
+		public List<WrapDesigner> getPortalList() {
+			return portalList;
 		}
 
-		public void setScriptId(String scriptId) {
-			this.scriptId = scriptId;
+		public void setPortalList(List<WrapDesigner> portalList) {
+			this.portalList = portalList;
 		}
 
-		public String getScriptName() {
-			return scriptName;
+		public List<WrapDesigner> getQueryList() {
+			return queryList;
 		}
 
-		public void setScriptName(String scriptName) {
-			this.scriptName = scriptName;
+		public void setQueryList(List<WrapDesigner> queryList) {
+			this.queryList = queryList;
 		}
 
-		public List<Integer> getPatternLines() {
-			return patternLines;
+		public List<WrapDesigner> getServiceList() {
+			return serviceList;
 		}
 
-		public void setPatternLines(List<Integer> patternLines) {
-			this.patternLines = patternLines;
+		public void setServiceList(List<WrapDesigner> serviceList) {
+			this.serviceList = serviceList;
 		}
 	}
 

+ 8 - 2
o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/DesignAction.java

@@ -17,14 +17,17 @@ import javax.ws.rs.container.AsyncResponse;
 import javax.ws.rs.container.Suspended;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
+import java.util.concurrent.locks.ReentrantLock;
 
 @Path("design")
-@JaxrsDescribe("设计")
+@JaxrsDescribe("全平台设计")
 public class DesignAction extends StandardJaxrsAction {
 
 	private static Logger logger = LoggerFactory.getLogger(DesignAction.class);
 
-	@JaxrsMethodDescribe(value = "全局设计搜索.", action = ActionSearch.class)
+	private static ReentrantLock lock = new ReentrantLock();
+
+	@JaxrsMethodDescribe(value = "全平台设计搜索.", action = ActionSearch.class)
 	@POST
 	@Path("search")
 	@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@@ -33,11 +36,14 @@ public class DesignAction extends StandardJaxrsAction {
 					   JsonElement jsonElement) {
 		ActionResult<ActionSearch.Wo> result = new ActionResult<>();
 		EffectivePerson effectivePerson = this.effectivePerson(request);
+		lock.lock();
 		try {
 			result = new ActionSearch().execute(effectivePerson, jsonElement);
 		} catch (Exception e) {
 			logger.error(e, effectivePerson, request, null);
 			result.error(e);
+		} finally {
+			lock.unlock();
 		}
 		asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
 	}

+ 6 - 2
o2server/x_query_service_processing/src/main/java/com/x/query/service/processing/jaxrs/design/ModuleType.java

@@ -3,10 +3,14 @@ package com.x.query.service.processing.jaxrs.design;
 import com.x.base.core.entity.JpaObject;
 
 /**
- *
+ * processPlatform(流程管理平台)
+ * portal(门户管理平台)
+ * cms(内容管理平台)
+ * query (数据中心平台)
+ * service(服务管理平台)
  */
 public enum ModuleType {
 
-	processPlatform, portal, cms;
+	processPlatform, portal, cms, query, service;
 	public static final int length = JpaObject.length_64B;
 }

+ 6 - 12
o2web/source/x_component_process_Xform/$Module.js

@@ -10,25 +10,19 @@ MWF.xApplication.process.Xform.$Module = MWF.APP$Module =  new Class(
     Implements: [Events],
     options: {
         /**
-         * 组件加载前事件。<br/>
-         * 平台执行queryLoad事件的时候,组件还没有开始加载,这个时候可以根据条件修改组件的配置信息以改变加载细节。
+         * 组件加载前触发。
          * @event MWF.xApplication.process.Xform.$Module#queryLoad
-         * {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|事件的使用}
-         * @example
-         * var field = this.form.get("fieldName");
-         * field.addEvent("queryLoad", function(){
-         *
-         * };
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
          */
         /**
-         * 组件加载事件.
+         * 组件加载时触发.
          * @event MWF.xApplication.process.Xform.$Module#load
-         * {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|事件的使用}
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
          */
         /**
-         * 组件加载后事件.
+         * 组件加载后触发.
          * @event MWF.xApplication.process.Xform.$Module#postLoad
-         * {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|事件的使用}
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
          */
         "moduleEvents": ["load", "queryLoad", "postLoad"]
     },

+ 20 - 0
o2web/source/x_component_process_Xform/Actionbar.js

@@ -18,6 +18,26 @@ MWF.xApplication.process.Xform.Actionbar = MWF.APPActionbar =  new Class(
     {
 	Extends: MWF.APP$Module,
     options: {
+        /**
+         * 组件加载前触发。
+         * @event MWF.xApplication.process.Xform.Actionbar#queryLoad
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 组件加载时触发。
+         * @event MWF.xApplication.process.Xform.Actionbar#load
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 组件加载后事件.由于加载过程中有异步处理,这个时候操作条有可能还未生成。
+         * @event MWF.xApplication.process.Xform.Actionbar#postLoad
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 组件加载后事件。这个时候操作条已生成
+         * @event MWF.xApplication.process.Xform.Actionbar#afterLoad
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["load", "queryLoad", "postLoad", "afterLoad"]
     },
     /**

+ 43 - 0
o2web/source/x_component_process_Xform/Attachment.js

@@ -1084,6 +1084,49 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class(
 {
     Extends: MWF.APP$Module,
     options: {
+        /**
+         * @event MWF.xApplication.process.Xform.Attachment#queryLoad
+         * @ignore
+         */
+        /**
+         * @event MWF.xApplication.process.Xform.Attachment#postLoad
+         * @ignore
+         */
+        /**
+         * 附件上传后触发。本事件中可以通过this.event获取上传附件的数据
+         * @event MWF.xApplication.process.Xform.Attachment#upload
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 删除附件前触发。本事件中可以通过this.event获取被删附件的数据
+         * @event MWF.xApplication.process.Xform.Attachment#delete
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 删除附件后触发。本事件中可以通过this.event获取被删附件的数据
+         * @event MWF.xApplication.process.Xform.Attachment#afterDelete
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 附件容器加载时触发。
+         * @event MWF.xApplication.process.Xform.Attachment#load
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 附件有变化的时候会被触发,包括上传、删除、排序
+         * @event MWF.xApplication.process.Xform.Attachment#change
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 下载附件后触发。本事件中可以通过this.event获取被下载附件对象
+         * @event MWF.xApplication.process.Xform.Attachment#download
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 打开附件后触发。本事件中可以通过this.event获取被打开附件对象
+         * @event MWF.xApplication.process.Xform.Attachment#open
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["upload", "delete", "afterDelete", "load", "change","download","open"]
     },
 

+ 25 - 0
o2web/source/x_component_process_Xform/Calendar.js

@@ -17,6 +17,31 @@ MWF.xApplication.process.Xform.Calendar = MWF.APPCalendar =  new Class(
 	Extends: MWF.APP$Input,
 	iconStyle: "calendarIcon",
     options: {
+        /**
+         * 日期选择完成时触发.
+         * @event MWF.xApplication.process.Xform.Calendar#complete
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 日期选择器上点清空时触发.
+         * @event MWF.xApplication.process.Xform.Calendar#clear
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 值改变时触发.
+         * @event MWF.xApplication.process.Xform.Calendar#change
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 显示日期选择器时触发.
+         * @event MWF.xApplication.process.Xform.Calendar#show
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 隐藏日期选择器时触发.
+         * @event MWF.xApplication.process.Xform.Calendar#hide
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["queryLoad","postLoad","load","complete", "clear", "change","show","hide"]
     },
     _loadNode: function(){

+ 10 - 0
o2web/source/x_component_process_Xform/Combox.js

@@ -17,6 +17,16 @@ MWF.xApplication.process.Xform.Combox = MWF.APPCombox =  new Class(
 	Extends: MWF.APP$Input,
 	iconStyle: "selectIcon",
     options: {
+        /**
+         * 手工输入完成后触发。
+         * @event MWF.xApplication.process.Xform.Combox#commitInput
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 值改变时触发。
+         * @event MWF.xApplication.process.Xform.Combox#change
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["load", "queryLoad", "postLoad", "commitInput", "change"]
     },
 

+ 25 - 0
o2web/source/x_component_process_Xform/DatagridMobile.js

@@ -17,6 +17,31 @@ MWF.xApplication.process.Xform.DatagridMobile = new Class(
     Extends: MWF.APP$Module,
     isEdit: false,
     options: {
+        /**
+         * 当前条目编辑完成时触发。通过this.event可以获取对应的table。
+         * @event MWF.xApplication.process.Xform.DatagridMobile#completeLineEdit
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 添加条目时触发。通过this.event可以获取对应的table。
+         * @event MWF.xApplication.process.Xform.DatagridMobile#addLine
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 删除条目前触发。通过this.event可以获取对应的table。
+         * @event MWF.xApplication.process.Xform.DatagridMobile#deleteLine
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 删除条目后触发。
+         * @event MWF.xApplication.process.Xform.DatagridMobile#afterDeleteLine
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 编辑条目时触发。
+         * @event MWF.xApplication.process.Xform.DatagridMobile#editLine
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["queryLoad","postLoad","load","completeLineEdit", "addLine", "deleteLine", "afterDeleteLine","editLine"]
     },
 

+ 25 - 0
o2web/source/x_component_process_Xform/DatagridPC.js

@@ -84,6 +84,31 @@ MWF.xApplication.process.Xform.DatagridPC = new Class(
 	Extends: MWF.APP$Module,
 	isEdit: false,
 	options: {
+		/**
+		 * 当前条目编辑完成时触发。通过this.event可以获取对应的tr。
+		 * @event MWF.xApplication.process.Xform.DatagridPC#completeLineEdit
+		 * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+		 */
+		/**
+		 * 添加条目时触发。通过this.event可以获取对应的tr。
+		 * @event MWF.xApplication.process.Xform.DatagridPC#addLine
+		 * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+		 */
+		/**
+		 * 删除条目前触发。通过this.event可以获取对应的tr。
+		 * @event MWF.xApplication.process.Xform.DatagridPC#deleteLine
+		 * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+		 */
+		/**
+		 * 删除条目后触发。
+		 * @event MWF.xApplication.process.Xform.DatagridPC#afterDeleteLine
+		 * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+		 */
+		/**
+		 * 编辑条目时触发。
+		 * @event MWF.xApplication.process.Xform.DatagridPC#editLine
+		 * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+		 */
 		"moduleEvents": ["queryLoad","postLoad","load","completeLineEdit", "addLine", "deleteLine", "afterDeleteLine","editLine"]
 	},
 

+ 5 - 0
o2web/source/x_component_process_Xform/Documenteditor.js

@@ -15,6 +15,11 @@ MWF.xApplication.process.Xform.Documenteditor = MWF.APPDocumenteditor =  new Cla
 {
     Extends: MWF.APP$Module,
     options: {
+        /**
+         * 当公文编辑器内容每次被渲染的时候都会触发。
+         * @event MWF.xApplication.process.Xform.Documenteditor#loadPage
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["load", "queryLoad", "beforeLoad", "postLoad", "afterLoad", "loadPage"],
         "docPageHeight": 850.4,
         "docPageFullWidth": 794,

+ 115 - 4
o2web/source/x_component_process_Xform/Form.js

@@ -25,28 +25,139 @@ MWF.xApplication.process.Xform.Form = MWF.APPForm = new Class(
         "cssPath": "",
         "macro": "FormContext",
         "parameters": null,
-        "moduleEvents": ["queryLoad",
+        "moduleEvents": [
+            /**
+             * 表单加载前触发。数据(businessData)、预加载脚本和表单html已经就位。
+             * @event MWF.xApplication.process.Xform.Form#queryLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
+            "queryLoad",
+            /**
+             * 表单加载前触发。已提示抢办锁定。
+             * @event MWF.xApplication.process.Xform.Form#beforeLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeLoad",
+            /**
+             * 表单的所有组件加载前触发,此时表单的样式和js head已经加载。
+             * @event MWF.xApplication.process.Xform.Form#beforeModulesLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
+            "beforeModulesLoad",
+            /**
+             * 表单加载后触发。主表单的组件加载完成,但不保证子表单、子页面、部件加载完成。
+             * @event MWF.xApplication.process.Xform.Form#postLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "postLoad",
+            /**
+             * 表单的所有组件后触发。表单包含有子表单、子页面、部件时,此事件会在这些组件加载后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterModulesLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
+            "afterModulesLoad",
+            /**
+             * 表单加载后触发。表单包含有子表单、子页面、部件时,此事件会在这些组件加载后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterLoad
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterLoad",
+            /**
+             * 保存前触发。流转前也会触发本事件。
+             * @event MWF.xApplication.process.Xform.Form#beforeSave
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeSave",
+            /**
+             * 保存后触发。流转后也会触发本事件。
+             * @event MWF.xApplication.process.Xform.Form#afterSave
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterSave",
+            /**
+             * 关闭前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeClose
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeClose",
-            "beforeProcess",
+            /**
+             * 弹出提交界面前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeProcessWork
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeProcessWork",
+            /**
+             * 流转前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeProcess
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
+            "beforeProcess",
+            /**
+             * 流转后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterProcess
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterProcess",
+            /**
+             * 重置处理人前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeReset
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeReset",
+            /**
+             * 重置处理人后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterReset
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterReset",
+            /**
+             * 撤回前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeRetract
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeRetract",
+            /**
+             * 撤回后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterRetract
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterRetract",
+            /**
+             * 调度前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeReroute
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeReroute",
+            /**
+             * 调度后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterReroute
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterReroute",
+            /**
+             * 删除工作前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeDelete
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeDelete",
+            /**
+             * 删除工作后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterDelete
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterDelete",
-            "beforeModulesLoad",
             "resize",
-            "afterModulesLoad",
+            /**
+             * 已阅前触发。
+             * @event MWF.xApplication.process.Xform.Form#beforeReaded
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "beforeReaded",
+            /**
+             * 已阅后触发。
+             * @event MWF.xApplication.process.Xform.Form#afterReaded
+             * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+             */
             "afterReaded"]
     },
     initialize: function (node, data, options) {

+ 65 - 2
o2web/source/x_component_process_Xform/Htmleditor.js

@@ -1,5 +1,18 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.Htmleditor = MWF.APPHtmleditor =  new Class({
+/** @class Htmleditor HTML编辑器。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Htmleditor = MWF.APPHtmleditor =  new Class(
+    /** @lends MWF.xApplication.process.Xform.Htmleditor# */
+    {
 	Extends: MWF.APP$Module,
     options: {
         "moduleEvents": ["load", "postLoad", "afterLoad"]
@@ -376,16 +389,58 @@ MWF.xApplication.process.Xform.Htmleditor = MWF.APPHtmleditor =  new Class({
     _loadValue: function(){
         var data = this._getBusinessData();
     },
+    /**
+     * @summary 重置组件的值为默认值或置空。
+     *  @example
+     * this.form.get('fieldName').resetData();
+     */
     resetData: function(){
         this.setData(this._getBusinessData());
     },
+    /**
+     * @summary 判断组件值是否为空.
+     * @example
+     * if( this.form.get('fieldName').isEmpty() ){
+     *     this.form.notice('HTML编辑器不能为空', 'warn');
+     * }
+     * @return {Boolean} 值是否为空.
+     */
     isEmpty : function(){
         return !this.getData().trim();
     },
+    /**
+     * 当表单上没有对应组件的时候,可以使用this.data[fieldName]获取值,但是this.form.get('fieldName')无法获取到组件。
+     * @summary 获取组件值。
+     * @example
+     * var data = this.form.get('fieldName').getData();
+     * @example
+     *  //如果无法确定表单上是否有组件,需要判断
+     *  var data;
+     *  if( this.form.get('fieldName') ){ //判断表单是否有无对应组件
+     *      data = this.form.get('fieldName').getData();
+     *  }else{
+     *      data = this.data['fieldName']; //直接从数据中获取字段值
+     *  }
+     * @return 组件的数据.
+     */
     getData: function(){
         this.clearEcnetNodes();
         return this.editor ? this.editor.getData() : "";
     },
+    /**
+     * 当表单上没有对应组件的时候,可以使用this.data[fieldName] = data赋值。
+     * @summary 为组件赋值。
+     * @param data{String} .
+     * @example
+     *  this.form.get("fieldName").setData("test"); //赋文本值
+     * @example
+     *  //如果无法确定表单上是否有组件,需要判断
+     *  if( this.form.get('fieldName') ){ //判断表单是否有无对应组件
+     *      this.form.get('fieldName').setData( data );
+     *  }else{
+     *      this.data['fieldName'] = data;
+     *  }
+     */
     setData: function(data){
         this._setBusinessData(data);
         if (this.editor) this.editor.setData(data);
@@ -519,7 +574,15 @@ MWF.xApplication.process.Xform.Htmleditor = MWF.APPHtmleditor =  new Class({
         }
         return true;
     },
-
+    /**
+     * @summary 根据组件的校验设置进行校验。
+     *  @param {String} [routeName] - 可选,路由名称.
+     *  @example
+     *  if( !this.form.get('fieldName').validation() ){
+     *      return false;
+     *  }
+     *  @return {Boolean} 是否通过校验
+     */
     validation: function(routeName, opinion){
         if (!this.validationConfig(routeName, opinion))  return false;
 

+ 11 - 0
o2web/source/x_component_process_Xform/Iframe.js

@@ -1,4 +1,15 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
+/** @class Iframe HTML iframe。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
 MWF.xApplication.process.Xform.Iframe = MWF.APPIframe =  new Class({
 	Extends: MWF.APP$Module,
 

+ 13 - 1
o2web/source/x_component_process_Xform/Image.js

@@ -1,5 +1,17 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.Image = MWF.APPImage =  new Class({
+/** @class Image 图片。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Image = MWF.APPImage =  new Class(
+    {
     Extends: MWF.APP$Module,
     _loadUserInterface: function(){
         if (this.json.properties && this.json.properties["src"]){

+ 38 - 1
o2web/source/x_component_process_Xform/ImageClipper.js

@@ -1,5 +1,18 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.ImageClipper = MWF.APPImageClipper =  new Class({
+/** @class ImageClipper 图片编辑组件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.ImageClipper = MWF.APPImageClipper =  new Class(
+    /** @lends MWF.xApplication.process.Xform.ImageClipper# */
+    {
 	Implements: [Events],
 	Extends: MWF.APP$Module,
     initialize: function(node, json, form, options){
@@ -86,9 +99,24 @@ MWF.xApplication.process.Xform.ImageClipper = MWF.APPImageClipper =  new Class({
         var value = this._getBusinessData() || "";
         return {"value": [value], "text": [value]};
     },
+    /**
+     * @summary 判断组件值是否为空.
+     * @example
+     * if( this.form.get('fieldName').isEmpty() ){
+     *     this.form.notice('请上传图片', 'warn');
+     * }
+     * @return {Boolean} 值是否为空.
+     */
     isEmpty : function(){
         return !this.getData();
     },
+    /**
+     * 获取上传的图片ID。
+     * @summary 获取上传的图片ID。
+     * @example
+     * var id = this.form.get('fieldName').getData(); //获取上传的图片id
+     * var url = MWF.xDesktop.getImageSrc( id ); //获取图片的url
+     */
     getData: function( data ){
         return this._getBusinessData() || "";
     },
@@ -279,6 +307,15 @@ MWF.xApplication.process.Xform.ImageClipper = MWF.APPImageClipper =  new Class({
         }
         return true;
     },
+    /**
+     * @summary 根据组件的校验设置进行校验。
+     *  @param {String} [routeName] - 可选,路由名称.
+     *  @example
+     *  if( !this.form.get('fieldName').validation() ){
+     *      return false;
+     *  }
+     *  @return {Boolean} 是否通过校验
+     */
     validation: function(routeName, opinion){
         if (!this.validationConfig(routeName, opinion))  return false;
 

+ 26 - 1
o2web/source/x_component_process_Xform/Label.js

@@ -1,5 +1,18 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.Label = MWF.APPLabel =  new Class({
+/** @class Label 文本组件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Label = MWF.APPLabel =  new Class(
+    /** @lends MWF.xApplication.process.Xform.Label# */
+    {
 	Implements: [Events],
 	Extends: MWF.APP$Module,
 	
@@ -55,6 +68,18 @@ MWF.xApplication.process.Xform.Label = MWF.APPLabel =  new Class({
             //this.node.set("text", value || "");
         }
     },
+    /**当参数为Promise的时候,请参考文档: {@link  https://www.yuque.com/o2oa/ixsnyt/ws07m0|使用Promise处理表单异步}<br/>
+     * @summary 为组件设置文本,该文本不会被保存到后台。
+     * @param text{String|Promise} .
+     * @example
+     *  this.form.get("fieldName").setText("test"); //赋文本值
+     * @example
+     *  //使用Promise
+     *  var field = this.form.get("fieldName");
+     *  var dict = new this.Dict("test"); //test为数据字典名称
+     *  var promise = dict.get("tools", true); //异步使用数据字典的get方法时返回Promise,参数true表示异步
+     *  field.setText( promise );
+     */
     setText: function(text){
 	    if (!!text){
             o2.promiseAll(text).then(function(v){

+ 38 - 1
o2web/source/x_component_process_Xform/Log.js

@@ -1,7 +1,44 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.Log = MWF.APPLog =  new Class({
+
+/** @class Log 流程记录组件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Log = MWF.APPLog =  new Class(
+    /** @lends MWF.xApplication.process.Xform.Log# */
+    {
 	Extends: MWF.APP$Module,
     options: {
+        /**
+         * 加载数据后事件。
+         * @event MWF.xApplication.process.Xform.Log#postLoadData
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         * @example
+         * //触发该事件的时候可以获取到流程数据workLog
+         * var workLog = this.target.workLog;
+         * //可以修改workLog达到定制化流程记录的效果
+         * do something
+         */
+        /**
+         * 加载每行流程信息以后触发,可以通过this.event获得下列信息:
+         * <pre><code>
+         {
+            "data" : {}, //当前行流程信息
+            "node" : logTaskNode, //当前节点
+            "log" : object, //指向流程记录
+            "type" : "task"  //"task"表示待办,"taskCompleted"表示已办
+        }
+         </code></pre>
+         * @event MWF.xApplication.process.Xform.Log#postLoadLine
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["load", "queryLoad", "postLoad", "postLoadData", "postLoadLine"]
     },
 

+ 17 - 1
o2web/source/x_component_process_Xform/Monitor.js

@@ -1,6 +1,19 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
 //MWF.xDesktop.requireApp("process.Xform", "widget.Monitor", null, false);
-MWF.xApplication.process.Xform.Monitor = MWF.APPMonitor =  new Class({
+/** @class Monitor 流程图组件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Monitor = MWF.APPMonitor =  new Class(
+    /** @lends MWF.xApplication.process.Xform.Monitor# */
+    {
     Extends: MWF.APP$Module,
 
     _loadUserInterface: function(){
@@ -9,6 +22,9 @@ MWF.xApplication.process.Xform.Monitor = MWF.APPMonitor =  new Class({
         MWF.xDesktop.requireApp("process.Xform", "widget.Monitor", function(){
         //    debugger;
             var process = (this.form.businessData.work) ? this.form.businessData.work.process : this.form.businessData.workCompleted.process;
+            /**
+             * @summary 流程图对象,是一个 MWF.xApplication.process.Xform.widget.Monitor 类实例
+             */
             this.monitor = new MWF.xApplication.process.Xform.widget.Monitor(this.node, this.form.businessData.workLogList, process,{
                 "onPostLoad" : function(){
                     this.fireEvent("postLoad");

+ 11 - 0
o2web/source/x_component_process_Xform/Number.js

@@ -1,4 +1,15 @@
 MWF.xDesktop.requireApp("process.Xform", "Textfield", null, false);
+/** @class Number 数字输入组件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.Textfield
+ * @category FormComponents
+ * @hideconstructor
+ */
 MWF.xApplication.process.Xform.Number = MWF.APPNumber =  new Class({
     Implements: [Events],
     Extends: MWF.APPTextfield,

+ 119 - 4
o2web/source/x_component_process_Xform/Office.js

@@ -1,5 +1,18 @@
 MWF.xDesktop.requireApp("process.Xform", "$Module", null, false);
-MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
+/** @class Office Office控件。
+ * @example
+ * //可以在脚本中获取该组件
+ * //方法1:
+ * var attachment = this.form.get("name"); //获取组件
+ * //方法2
+ * var attachment = this.target; //在组件事件脚本中获取
+ * @extends MWF.xApplication.process.Xform.$Module
+ * @category FormComponents
+ * @hideconstructor
+ */
+MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class(
+    /** @lends MWF.xApplication.process.Xform.Office# */
+{
 	Extends: MWF.APP$Module,
 	isActive: false,
     options:{
@@ -20,7 +33,62 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
         "pdfCodeBase64": "../o2_lib/officecontrol/5040/ntkooledocall64.cab",
 
         "files": ["doc","docx","dotx","dot","xls","xlsx","xlsm","xlt","xltx","pptx","ppt","pot","potx","potm","pdf"],
-
+        /**
+         * @event MWF.xApplication.process.Xform.Office#queryLoad
+         * @ignore
+         */
+        /**
+         * @event MWF.xApplication.process.Xform.Office#postLoad
+         * @ignore
+         */
+        /**
+         * 点击套红按钮触发。
+         * @event MWF.xApplication.process.Xform.Office#redFile
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 点击盖章按钮触发。
+         * @event MWF.xApplication.process.Xform.Office#seal
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * Ntko控件执行AfterOpenFromURL事件(BeginOpenFromURL方法执行完毕之后被触发)时执行。</br>
+         * 本事件可以通过this.event获取当前打开的文档对象。比如,对于一个Word文档,第二个参数是一个Word.Document对象。
+         * @event MWF.xApplication.process.Xform.Office#afterOpen
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * Ntko控件执行OnDocumentOpened事件(Office文档打开完毕)时触发。<br/>
+         * 本事件可以通过this.event获取以下内容
+         * <pre><code>
+         {
+            url : url, //Office文档路径或者URL
+            doc : doc //Office文档的自动化接口,比如,对于一个Word文档,第二个参数是一个Word.Document对象。
+        }
+         </pre></code>
+         * @event MWF.xApplication.process.Xform.Office#afterOpenOffice
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 在新建Office文档后触发。
+         * @event MWF.xApplication.process.Xform.Office#afterCreate
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 在保存Office文档前触发。
+         * @event MWF.xApplication.process.Xform.Office#beforeSave
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 在保存Office文档后触发。
+         * @event MWF.xApplication.process.Xform.Office#afterSave
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
+        /**
+         * 在关闭Office文档时执行。
+         * @event MWF.xApplication.process.Xform.Office#afterCloseOffice
+         * @see {@link https://www.yuque.com/o2oa/ixsnyt/hm5uft#i0zTS|组件事件说明}
+         */
         "moduleEvents": ["redFile",
             "afterOpen",
             "afterOpenOffice",
@@ -263,15 +331,30 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
             return this.getTempleteUrl();
         }
     },
-
+    /**
+     * @summary 允许编辑Office文档
+     * @example
+     * this.form.get("fieldName").editEnabled();
+     */
     editEnabled: function(){
         try {
             this.officeOCX.ActiveDocument.Unprotect();
         }catch(e){}
     },
+    /**
+     * @summary 设置Office文档为只读
+     * @example
+     * this.form.get("fieldName").docReadonly();
+     */
     docReadonly: function(){
         this.protect(3);
     },
+    /**
+     * @summary 设置Office文档状态
+     * @example
+     * this.form.get("fieldName").protect(1);
+     * @param {Number} type 1(批注),2(填写窗体),3(只读),0(修订),-1(限制编辑样式)
+     */
     protect: function(type){
         // wdAllowOnlyComments = 1         //批注
         // wdAllowOnlyFormFields = 2       //填写窗体
@@ -282,6 +365,9 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
             this.officeOCX.ActiveDocument.Protect(type);
         }catch(e){}
     },
+    /**
+     * @summary 设置Office文档保留痕迹
+     */
     startRevisions: function(){
         if (this.officeOCX && (this.officeOCX.DocType==1 || this.officeOCX.DocType==6)){
             this.officeOCX.ActiveDocument.Application.UserName = layout.desktop.session.user.name;
@@ -305,6 +391,9 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
         }
         //this.officeOCX.FullScreenMode = true;
     },
+    /**
+     * @summary 设置Office文档取消保留痕迹
+     */
     stopRevisions: function(accept){
         this.officeOCX.ActiveDocument.TrackRevisions = false;
         this.officeOCX.ActiveDocument.showRevisions = false;
@@ -607,9 +696,15 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
             button.setText(MWF.xApplication.process.Xform.LP.menu_hideHistory)
         }
     },
+    /**
+     * @summary 盖章
+     */
     seal: function(){
         this.fireEvent("seal");
     },
+    /**
+     * @summary 套红
+     */
     redFile: function(){
        // try {
         if (this.officeOCX.ActiveDocument.ActiveWindow.View.RevisionsFilter){
@@ -636,6 +731,9 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
         //     throw e;
         // }
     },
+    /**
+     * @summary 显示痕迹
+     */
     showRevisions: function(){
         try {
             if (this.officeOCX.ActiveDocument.ActiveWindow.View.RevisionsFilter) {
@@ -645,6 +743,9 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
             this.officeOCX.ActiveDocument.showRevisions = true;
         }catch(e){}
     },
+    /**
+     * @summary 隐藏痕迹
+     */
     hideRevisions: function(){
         try {
             if (this.officeOCX.ActiveDocument.ActiveWindow.View.RevisionsFilter) {
@@ -1122,7 +1223,10 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
         this.afterOpen();
         this.loadMenu();
 
-        this.fireEvent("afterOpenOffice");
+        this.fireEvent("afterOpenOffice", {
+            url : url,
+            doc : doc
+        });
     },
     AfterOpenFromURL: function(doc, statusCode){
         this.fireEvent("afterOpen", [doc, statusCode]);
@@ -1179,6 +1283,13 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
 
         this.officeNode.set("html", objectHtml);
         this.officeForm = this.officeNode.getFirst();
+        /**
+        @summary Ntko Office 控件对象, 第三方控件
+        @see {@link http://ieoffice.ntko.com/pro/show/mid/1_8/pid/2731|NTKO官网 }
+         @example
+         var officeOCX = this.form.get("fieldName").officeOCX;
+         var activeDocument = officeOCX.ActiveDocument //返回一个Office Document 对象,该对象代表活动文档。
+         */
         this.officeOCX = this.officeNode.getFirst().getFirst();
 
         if(window.navigator.platform=="Win64"){
@@ -1218,6 +1329,10 @@ MWF.xApplication.process.Xform.Office = MWF.APPOffice =  new Class({
         }
     },
     setData: function(){},
+    /**
+     * @summary 保存Office文档到后台
+     * @param {Boolean} history - 是否生产保留痕迹文件
+     */
     save: function(history){
         //if (!this.uploadFileAreaNode) this.createUploadFileNode();
         if (!this.readonly){