Browse Source

update

main
wangshaoping 11 months ago
parent
commit
beb4b6276e
  1. 7
      build.gradle
  2. 4
      erm.frontend/package.json
  3. 9
      gradle.properties
  4. 4
      io.sc.engine.mv.frontend/package.json
  5. 2
      io.sc.engine.mv.frontend/src/menus/menus.json
  6. 2
      io.sc.engine.mv.frontend/src/views/config/binomial.vue
  7. 2
      io.sc.engine.mv.frontend/src/views/config/chiSquare.vue
  8. 2
      io.sc.engine.mv.frontend/src/views/config/cutOffPoint.vue
  9. 2
      io.sc.engine.mv.frontend/src/views/config/dataExtractor.vue
  10. 2
      io.sc.engine.mv.frontend/src/views/config/distribution.vue
  11. 1
      io.sc.engine.mv.frontend/src/views/config/executor.vue
  12. 2
      io.sc.engine.mv.frontend/src/views/config/model.vue
  13. 2
      io.sc.engine.mv.frontend/src/views/config/scale.vue
  14. 2
      io.sc.engine.mv.frontend/src/views/config/threshold.vue
  15. 2
      io.sc.engine.mv.frontend/src/views/result/Result.vue
  16. 24
      io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue
  17. 8
      io.sc.engine.mv.frontend/src/views/sample/Sample.vue
  18. 4
      io.sc.engine.rule.frontend/package.json
  19. 31
      io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
  20. 7
      io.sc.engine.rule.frontend/src/views/dictionary/dictionary.vue
  21. 4
      io.sc.engine.rule.frontend/src/views/lib/IndicatorGrid.vue
  22. 34
      io.sc.engine.rule.frontend/src/views/lib/Lib.vue
  23. 6
      io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue
  24. 4
      io.sc.engine.rule.frontend/src/views/lib/ProcessorGrid.vue
  25. 140
      io.sc.engine.rule.frontend/src/views/lib/TestCase.vue
  26. 192
      io.sc.engine.rule.frontend/src/views/lib/TestCaseParameter.vue
  27. 4
      io.sc.engine.rule.frontend/src/views/lib/ValidatorGrid.vue
  28. 7
      io.sc.engine.rule.frontend/src/views/migration/Migration.vue
  29. 19
      io.sc.engine.rule.frontend/src/views/resources/Resources.vue
  30. 2
      io.sc.engine.rule.frontend/src/views/resources/designer/TestCaseParameter.vue
  31. 3
      io.sc.engine.rule.frontend/src/views/resources/designer/Testcase.vue
  32. 283
      io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue
  33. 223
      io.sc.engine.rule.frontend/src/views/workflow/Workflow.vue
  34. 3
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/resource/controller/ResourceWebController.java
  35. 3
      io.sc.platform.core.frontend/package.json
  36. 9
      io.sc.platform.core.frontend/src/platform/components/workflow/WWorkflowAction.vue
  37. 1
      io.sc.platform.core.frontend/src/platform/i18n/messages.json
  38. 1
      io.sc.platform.core.frontend/src/platform/i18n/messages_tw_CN.json
  39. 1
      io.sc.platform.core.frontend/src/platform/i18n/messages_zh_CN.json
  40. 4
      io.sc.platform.core.frontend/src/platform/index.ts
  41. 141
      io.sc.platform.core.frontend/src/platform/plugin/axios.ts
  42. 2
      io.sc.platform.core.frontend/src/platform/plugin/index.ts
  43. 37
      io.sc.platform.core.frontend/src/platform/utils/Downloader.ts
  44. 1
      io.sc.platform.core.frontend/src/platform/utils/index.ts
  45. 54
      io.sc.platform.core.frontend/src/views/FormElements.vue
  46. 4
      io.sc.platform.core.frontend/template-project/package.json
  47. 21
      io.sc.platform.core.frontend/template-project/src/views/FormElements.vue
  48. 4
      io.sc.platform.developer.frontend/package.json
  49. 10
      io.sc.platform.gradle/templates/pgp/setup/gradle.properties
  50. 4
      io.sc.platform.lcdp.frontend/package.json
  51. 8
      io.sc.platform.lcdp.frontend/src/views/Frontend.vue
  52. 4
      io.sc.platform.mvc.frontend/package.json
  53. 2
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/plugins/item/Parameter.java
  54. 9
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/support/FileDownloader.java
  55. 8
      io.sc.platform.poi/build.gradle
  56. 0
      io.sc.platform.poi/gradle.properties
  57. 4
      io.sc.platform.security.frontend/package.json
  58. 3
      io.sc.platform.security/src/main/resources/META-INF/platform/plugins/messages.json
  59. 8
      io.sc.platform.security/src/main/resources/META-INF/platform/plugins/parameters.json
  60. 3
      io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter.properties
  61. 3
      io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter_tw_CN.properties
  62. 3
      io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter_zh_CN.properties
  63. 31
      io.sc.platform.system.api/src/main/java/io/sc/platform/system/api/parameter/ParameterVo.java
  64. 4
      io.sc.platform.system.frontend/package.json
  65. 4
      io.sc.platform.system.frontend/src/i18n/messages.json
  66. 4
      io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json
  67. 4
      io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json
  68. 1
      io.sc.platform.system.frontend/src/views/datasource/ConnectionPropertiesDialog.vue
  69. 1
      io.sc.platform.system.frontend/src/views/datasource/Datasource.vue
  70. 23
      io.sc.platform.system.frontend/src/views/monitor/Log.vue
  71. 88
      io.sc.platform.system.frontend/src/views/parameter/Parameter.vue
  72. 1
      io.sc.platform.system.frontend/src/views/shared/SelectMenuTreeGrid.vue
  73. 1
      io.sc.platform.system.frontend/src/views/shared/SelectOrgTreeGrid.vue
  74. 2
      io.sc.platform.system.frontend/src/views/shared/SelectRoleDialog.vue
  75. 2
      io.sc.platform.system.frontend/src/views/shared/SelectUserDialog.vue
  76. 3
      io.sc.platform.system/src/main/java/io/sc/platform/system/ds/jpa/entity/DsEntity.java
  77. 2
      io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/jpa/entity/I18nEntity.java
  78. 46
      io.sc.platform.system/src/main/java/io/sc/platform/system/initializer/ParameterInitializer.java
  79. 3
      io.sc.platform.system/src/main/java/io/sc/platform/system/menu/jpa/entity/MenuEntity.java
  80. 4
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/LogViewerWebController.java
  81. 35
      io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/controller/ParameterWebController.java
  82. 101
      io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/jpa/entity/ParameterEntity.java
  83. 1
      io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/service/ParameterService.java
  84. 59
      io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/service/impl/ParameterServiceImpl.java
  85. 7
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java
  86. 3
      io.sc.platform.system/src/main/resources/META-INF/platform/plugins/messages.json
  87. 3
      io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter.properties
  88. 3
      io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter_tw_CN.properties
  89. 3
      io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter_zh_CN.properties
  90. 5
      io.sc.platform.system/src/main/resources/liquibase/io.sc.platform.system_8.0.0_20220606__System Database Schema DDL.xml
  91. 4
      io.sc.standard.frontend/package.json
  92. 13
      settings.gradle

7
build.gradle

@ -52,7 +52,6 @@ subprojects {
exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j"
exclude group: "org.slf4j", module: "slf4j-jdk14"
exclude group: "org.slf4j", module: "slf4j-nop"
//exclude group: "com.oracle.database.jdbc", module: "ojdbc8"
}
dependencyManagement {
@ -100,7 +99,6 @@ subprojects {
compileTestJava.options.encoding ="${java_encoding}"
tasks.withType(JavaCompile) {
//options.compilerArgs += ["-Xdoclint:none", "-Xlint:none", "-nowarn"]
options.compilerArgs += ["-Xlint:deprecation","-Xlint:unchecked"]
}
@ -184,7 +182,6 @@ subprojects {
sources {
include '*.adoc'
}
//outputDir = file("$buildDir/resources/main/help/" + project.name)
outputDir = file("dist/help/" + project.name)
resources {
from(sourceDir) {
@ -235,8 +232,6 @@ subprojects {
doLast{
// jrebel
delete "$buildDir/resources/main/rebel.xml"
//
}
}
@ -269,7 +264,7 @@ subprojects {
*----------------------------------------------------------------*/
task jrebelIdea() {}
tasks.jrebelIdea.doLast {
if(file('package.json').exists()){
if(isFrontendProject(file('.'))) {
File resourcesFile = file('java-src/main/resources')
if (resourcesFile != null && resourcesFile.exists()) {
File rebelFile = file('java-src/main/resources/rebel.xml')

4
erm.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "erm.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -78,7 +78,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

9
gradle.properties

@ -36,9 +36,9 @@ application_version=1.0.0
# platform
###########################################################
platform_group=io.sc
platform_version=8.1.30
platform_version=8.1.33
platform_plugin_version=8.1.13
platform_core_frontend_version=8.1.160
platform_core_frontend_version=8.1.169
###########################################################
# dependencies version
@ -62,13 +62,13 @@ jxls_jexcel_version=1.0.7
jxls_poi_version=1.0.15
jxls_version=2.4.6
mybatis_version=3.5.10
ooxml_schemas_version=4.1.2
opencsv_version=5.7.1
oshi_version=6.4.2
p6spy_version=3.9.1
pinyin4j_version=2.5.1
poi_ooxml_version=3.17
poi_version=5.2.5
schemacrawler_version=16.19.11
#schemacrawler_version=14.21.02
spring_boot_version=2.7.18
spring_cloud_alibaba_version=2021.0.4.0
spring_cloud_context_version=3.1.4
@ -78,6 +78,7 @@ spring_statemachine_version=3.2.1
webjars_locator_weblogic_version=0.10
zip4j_version=2.11.5
###########################################################
# asciidoc deploy directory,the path must end with '/'
###########################################################

4
io.sc.engine.mv.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.engine.mv.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

2
io.sc.engine.mv.frontend/src/menus/menus.json

@ -18,7 +18,7 @@
[
/**/
{"type":"GROUP", "order":10000, "id":"menu.engine.mv", "titleI18nKey":"menu.engine.mv", "icon":"bi-bag-check"},
{"type":"GROUP", "order":11000, "id":"menu.engine.mv", "titleI18nKey":"menu.engine.mv", "icon":"bi-bag-check"},
/*/*/
{"type":"ROUTE", "order":100, "parentId":"menu.engine.mv", "id":"menu.engine.mv.result", "titleI18nKey":"menu.engine.mv.result", "icon":"bi-display", "routeName":"route.engine.mv.result"},
/*/*/

2
io.sc.engine.mv.frontend/src/views/config/binomial.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.binomial.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -19,7 +20,6 @@
:editor="{
dialog: {
width: '600px',
height: '300px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/chiSquare.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.chiSquare.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -18,7 +19,6 @@
:editor="{
dialog: {
width: '600px',
height: '300px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/cutOffPoint.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.cutOffPoint.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -21,7 +22,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/dataExtractor.vue

@ -2,6 +2,7 @@
<w-grid
ref="gridRef"
:title="$t('io.sc.engine.mv.config.dataExtractor.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -44,7 +45,6 @@
:editor="{
dialog: {
width: '800px',
height: '600px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/distribution.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.distribution.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -20,7 +21,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,

1
io.sc.engine.mv.frontend/src/views/config/executor.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.executor.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"

2
io.sc.engine.mv.frontend/src/views/config/model.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.model.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -35,7 +36,6 @@
:editor="{
dialog: {
width: '600px',
height: '300px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/scale.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.scale.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -20,7 +21,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/config/threshold.vue

@ -1,6 +1,7 @@
<template>
<w-grid
:title="$t('io.sc.engine.mv.config.threshold.grid.title')"
hide-bottom
:config-button="true"
selection="multiple"
:checkbox-selection="true"
@ -28,7 +29,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,

2
io.sc.engine.mv.frontend/src/views/result/Result.vue

@ -1,5 +1,5 @@
<template>
<div>
<div style="height: 100%">
<div v-if="executeProgress.show" class="row pt-2">
<div class="col-2 pl-4">{{ $t('io.sc.engine.mv.result.task.progress') }}</div>
<div class="col-3">

24
io.sc.engine.mv.frontend/src/views/result/ResultDetailDialog.vue

@ -1,6 +1,6 @@
<template>
<w-dialog ref="dialogRef" :title="detailRef?.modelName + '(' + detailRef?.modelId + ')'" :can-maximize="false" :maximized="true">
<div class="px-2">
<div class="px-2" style="height: 100%">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps @update:model-value="tabChanged">
<q-tab name="discrimination" :label="$t('io.sc.engine.mv.result.grid.entity.discrimination')" />
<q-tab name="stability" :label="$t('io.sc.engine.mv.result.grid.entity.stability')" />
@ -8,8 +8,8 @@
<q-tab name="sample" :label="$t('io.sc.engine.mv.sample.tabs.sample')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="discrimination" class="px-0">
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)">
<q-tab-panel name="discrimination" class="px-0 pb-0" style="height: 100%">
<div style="height: 50px"></div>
<div class="row">
<div class="col-4">
@ -53,7 +53,7 @@
</tr>
</table>
</q-tab-panel>
<q-tab-panel name="stability" class="px-0">
<q-tab-panel name="stability" class="px-0 pb-0" style="height: 100%">
<div style="height: 50px"></div>
<div class="row">
<div class="col-4">
@ -77,16 +77,21 @@
</div>
</div>
</q-tab-panel>
<q-tab-panel name="scaleValidate" class="px-0">
<div class="row">
<div class="col-6 pr-4">
<q-tab-panel name="scaleValidate" class="px-0 pb-0" style="height: 100%">
<div class="row" style="height: 100%">
<div class="col-6 pr-4" style="height: 100%">
<w-grid
:title="$t('io.sc.engine.mv.result.chiSquare.grid.title') + ' (' + chiSquareValueRef + ')'"
hide-bottom
:checkbox-selection="false"
:fetch-data-url="
Environment.apiContextPath('/api/mv/viewer/chiSquare/data?modelId=' + detailRef.modelId + '&validateDate=' + detailRef.validateDate)
"
:pageable="false"
:pagination="{
sortBy: 'level',
descending: false,
}"
:toolbar-actions="['refresh', 'separator', 'export']"
:columns="[
{ width: 50, name: 'level', label: $t('io.sc.engine.mv.result.chiSquare.level'), align: 'right' },
@ -97,10 +102,11 @@
]"
></w-grid>
</div>
<div class="col-6 pl-4">
<div class="col-6 pl-4" style="height: 100%">
<w-grid
:title="$t('io.sc.engine.mv.result.binomial.grid.title')"
:checkbox-selection="false"
hide-bottom
:fetch-data-url="
Environment.apiContextPath('/api/mv/viewer/binomial/data?modelId=' + detailRef.modelId + '&validateDate=' + detailRef.validateDate)
"
@ -126,7 +132,7 @@
</div>
</div>
</q-tab-panel>
<q-tab-panel name="sample" class="px-0">
<q-tab-panel name="sample" class="px-0 pb-0" style="height: 100%">
<w-grid
:title="$t('io.sc.engine.mv.sample.sample.grid.title')"
:config-button="true"

8
io.sc.engine.mv.frontend/src/views/sample/Sample.vue

@ -1,12 +1,12 @@
<template>
<div>
<div style="height: 100%">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0" no-caps>
<q-tab name="scoreRecord" :label="$t('io.sc.engine.mv.sample.tabs.scoreRecord')" />
<q-tab name="defaultRecord" :label="$t('io.sc.engine.mv.sample.tabs.defaultRecord')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="scoreRecord" class="px-0">
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)">
<q-tab-panel name="scoreRecord" class="px-0 pb-0" style="height: 100%">
<w-grid
ref="scoreRecordGridRef"
:title="$t('io.sc.engine.mv.sample.scoreRecord.grid.title')"
@ -83,7 +83,7 @@
}"
></w-grid>
</q-tab-panel>
<q-tab-panel name="defaultRecord" class="px-0">
<q-tab-panel name="defaultRecord" class="px-0 pb-0" style="height: 100%">
<w-grid
ref="defaultRecordGridRef"
:title="$t('io.sc.engine.mv.sample.defaultRecord.grid.title')"

4
io.sc.engine.rule.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.engine.rule.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.163",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

31
io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json

@ -190,7 +190,36 @@
"re.migration.remove.action":"删除数据",
"re.migration.remove.action.tip":"您确定要删除所有数据吗?",
"re.workflow.task.grid.title":"任务列表",
"re.workflow.task.grid.toolbar.viewResource":"查看资源",
"re.workflow.task.grid.toolbar.viewAttachment":"查看附件",
"re.workflow.task.grid.toolbar.claim":"领取任务",
"re.workflow.task.grid.toolbar.claim.tip":"您确定要领取任务吗?",
"re.workflow.task.grid.toolbar.unclaim":"归还任务",
"re.workflow.task.grid.toolbar.unclaim.tip":"您确定要归还任务吗?",
"re.workflow.task.grid.toolbar.complete":"审批任务",
"re.workflow.task.grid.toolbar.terminate":"终止任务",
"re.workflow.task.grid.toolbar.terminate.tip":"您确定要归终止务吗?",
"re.workflow.task.grid.entity.processDefinitionId":"流程定义ID",
"re.workflow.task.grid.entity.processInstanceId":"流程实例ID",
"re.workflow.task.grid.entity.taskDefinitionId":"任务定义ID",
"re.workflow.task.grid.entity.taskId":"任务ID",
"re.workflow.task.grid.entity.taskName":"任务名称",
"re.workflow.task.grid.entity.taskAssignee":"任务处理人",
"re.workflow.task.grid.entity.taskCreateTime":"任务创建日期",
"re.workflow.task.grid.entity.taskEndTime":"任务完成日期",
"re.workflow.task.grid.entity.taskClaimTime":"任务领取日期",
"re.workflow.task.grid.entity.taskTreatment":"审批意见",
"re.workflow.task.grid.entity.resourceType":"资源类型",
"re.workflow.task.grid.entity.resourceId":"资源ID",
"re.workflow.task.grid.entity.resourceCode":"资源代码",
"re.workflow.task.grid.entity.resourceName":"资源名称",
"re.workflow.task.grid.entity.resourceVersion":"资源版本",
"re.workflow.task.grid.entity.resourceStatus":"资源状态",
"re.workflow.task.grid.entity.attachments":"资源附件",
"re.workflow.historyTask.grid.title":"历史任务列表",

7
io.sc.engine.rule.frontend/src/views/dictionary/dictionary.vue

@ -206,8 +206,7 @@
return arg.selected;
},
click: (arg) => {
let url = Environment.apiContextPath('/api/re/dictionary/export/' + arg.selected.id);
downloadIframe.src = url;
Downloader.get(Environment.apiContextPath('/api/re/dictionary/export/' + arg.selected.id));
},
},
]"
@ -317,7 +316,6 @@
<UserDefinedJavaClassDictionaryJsonDialog ref="userDefinedJavaClassDictionaryJsonDialogRef"></UserDefinedJavaClassDictionaryJsonDialog>
<ImportDialog ref="importDialogRef"></ImportDialog>
<ImportSampleDialog ref="importSampleDialogRef"></ImportSampleDialog>
<iframe ref="downloadIframe" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<template #after>
@ -483,7 +481,7 @@
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { axios, Environment, Formater, EnumTools, DialogManager } from 'platform-core';
import { axios, Environment, Formater, EnumTools, DialogManager, Downloader } from 'platform-core';
import UserDefinedJavaClassDictionaryJsonDialog from './UserDefinedJavaClassDictionaryJsonDialog.vue';
import ImportDialog from './ImportDialog.vue';
import ImportSampleDialog from './ImportSampleDialog.vue';
@ -494,7 +492,6 @@ const enumGridRef = ref();
const userDefinedJavaClassDictionaryJsonDialogRef = ref();
const importDialogRef = ref();
const importSampleDialogRef = ref();
const downloadIframe = ref();
const currentSelectedDictionaryIdRef = ref('');
const divStatus = reactive({
isShowFieldGrid: false,

4
io.sc.engine.rule.frontend/src/views/lib/IndicatorGrid.vue

@ -140,11 +140,11 @@ const props = defineProps({
const gridRef = ref();
const refresh = () => {
gridRef.value.refresh();
gridRef?.value?.refresh();
};
onMounted(() => {
gridRef.value.refresh();
gridRef?.value?.refresh();
});
defineExpose({

34
io.sc.engine.rule.frontend/src/views/lib/Lib.vue

@ -9,6 +9,7 @@
currentSelectedLibRef = row;
showStatus.detail = true;
indicatorGridRef?.refresh();
testcaseGridRef?.refresh();
} else {
currentSelectedLibRef = {};
showStatus.detail = false;
@ -66,7 +67,31 @@
</template>
</q-splitter>
</q-tab-panel>
<q-tab-panel name="testcase" class="px-0 pb-0" style="height: 100%"> </q-tab-panel>
<q-tab-panel name="testcase" class="px-0 pb-0" style="height: 100%">
<q-splitter :model-value="testcaseSplitterRef" unit="px" separator-style="width: 3px;" horizontal class="w-full" style="height: 100%">
<template #before>
<TestCase
ref="testcaseGridRef"
:lib="currentSelectedLibRef"
@row-click="
(evt, row, index) => {
currentSelectedTestCaseRef = row;
testcaseParameterGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedTestCaseRef = {};
testcaseParameterGridRef?.refresh();
}
"
></TestCase>
</template>
<template #after>
<TestCaseParameter ref="testcaseParameterGridRef" :test-case="currentSelectedTestCaseRef"></TestCaseParameter>
</template>
</q-splitter>
</q-tab-panel>
</q-tab-panels>
</div>
</template>
@ -78,16 +103,20 @@ import LibGrid from './LibGrid.vue';
import IndicatorGrid from './IndicatorGrid.vue';
import ValidatorGrid from './ValidatorGrid.vue';
import ProcessorGrid from './ProcessorGrid.vue';
import TestCase from './TestCase.vue';
import TestCaseParameter from './TestCaseParameter.vue';
const indicatorSplitterRef = ref(400); //
const testcaseSplitterRef = ref(300); //
const libTreeGridRef = ref(); //
const indicatorGridRef = ref(); //
const testcaseGridRef = ref(); //
const validatorGridRef = ref(); //
const processorGridRef = ref(); //
const testcaseGridRef = ref(); //
const testcaseParameterGridRef = ref(); //
const currentSelectedIndicatorOrTestcaseTabNameRef = ref('indicator');
//
const showStatus = reactive({
detail: false, //
@ -96,4 +125,5 @@ const showStatus = reactive({
});
const currentSelectedLibRef = ref({});
const currentSelectedIndicatorRef = ref({});
const currentSelectedTestCaseRef = ref({});
</script>

6
io.sc.engine.rule.frontend/src/views/lib/LibGrid.vue

@ -178,8 +178,7 @@
return arg.selected;
},
click: (arg) => {
let url = Environment.apiContextPath('/api/re/lib/export/' + arg.selected.id);
downloadIframe.src = url;
Downloader.get(Environment.apiContextPath('/api/re/lib/export/' + arg.selected.id));
},
},
]"
@ -249,12 +248,11 @@
></w-grid>
<ImportDialog ref="importDialogRef"></ImportDialog>
<ImportSampleDialog ref="importSampleDialogRef"></ImportSampleDialog>
<iframe ref="downloadIframe" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<script setup lang="ts">
import { useAttrs } from 'vue';
import { axios, Environment, Formater, EnumTools, DialogManager } from 'platform-core';
import { axios, Environment, Formater, EnumTools, DialogManager, Downloader } from 'platform-core';
import ImportDialog from './ImportDialog.vue';
import ImportSampleDialog from './ImportSampleDialog.vue';

4
io.sc.engine.rule.frontend/src/views/lib/ProcessorGrid.vue

@ -322,11 +322,11 @@ const props = defineProps({
const gridRef = ref();
const refresh = () => {
gridRef.value.refresh();
gridRef?.value?.refresh();
};
onMounted(() => {
gridRef.value.refresh();
gridRef?.value?.refresh();
});
defineExpose({

140
io.sc.engine.rule.frontend/src/views/lib/TestCase.vue

@ -0,0 +1,140 @@
<template>
<w-grid
ref="gridRef"
:title="$t('re.resources.designer.testCase.grid.title')"
dense-body
class="px-1"
hide-bottom
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="false"
:fetch-data-url="Environment.apiContextPath('/api/re/testCase/findByOwnerId?ownerId=' + lib.id)"
:data-url="Environment.apiContextPath('/api/re/testCase')"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
'add',
'clone',
{
extend: 'clone',
name: 'deepClone',
label: $t('deepClone'),
icon: 'bi-copy',
click: (arg) => {},
},
'edit',
'remove',
'separator',
{
name: 'execute',
label: $t('execute'),
icon: 'bi-caret-right',
},
{
name: 'executeAll',
label: $t('executeAll'),
icon: 'bi-caret-right-fill',
},
'view',
'separator',
'export',
]"
:columns="[
{ width: 50, name: 'order', label: $t('order'), hidden: true },
{ width: 100, name: 'id', label: $t('id'), hidden: true },
{
width: 80,
name: 'testResult',
label: $t('re.resources.designer.testCase.grid.entity.testResult'),
align: 'center',
sortable: false,
format: PassOrNotFormater,
},
{ width: 150, name: 'lastTestDate', label: $t('re.resources.designer.testCase.grid.entity.lastTestDate') },
{ width: 200, name: 'name', label: $t('name') },
{ width: '100%', name: 'description', label: $t('description') },
]"
:editor="{
dialog: {
width: '600px',
height: '250px',
},
form: {
colsNum: 1,
fields: [
{ name: 'order', label: $t('order'), type: 'text', hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'ownerType', label: $t('ownerType'), type: 'text', defaultValue: 'MODEL', hidden: true },
{ name: 'owner', label: $t('owner'), type: 'text', defaultValue: lib.resource, hidden: true },
{ name: 'ownerId', label: $t('ownerId'), type: 'text', defaultValue: lib.resource, hidden: true },
{ name: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'text' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'order', label: $t('order') },
{ name: 'id', label: $t('id') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
v-bind="attrs"
></w-grid>
</template>
<script setup lang="ts">
import { onMounted, ref, useAttrs } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, Tools } from 'platform-core';
import PassOrNotFormater from '@/utils/PassOrNotFormater';
const attrs = useAttrs();
const props = defineProps({
lib: { type: Object, default: undefined },
});
const gridRef = ref();
const refresh = () => {
gridRef?.value?.refresh();
};
onMounted(() => {
gridRef?.value?.refresh();
});
defineExpose({
refresh,
});
const Enums = await EnumTools.fetch([
'io.sc.platform.core.enums.RoundingMode',
'io.sc.engine.rule.core.enums.ParameterType',
'io.sc.engine.rule.core.enums.DeployStatus',
]);
let ValueTypeMap = {};
const ValueTypeList = [];
const response = await axios.get(Environment.apiContextPath('/api/re/dictionary/getAllDictionaryMap'));
if (response && response.data) {
ValueTypeMap = {};
ValueTypeList.splice(0, ValueTypeList.length);
for (const item of response.data) {
ValueTypeMap[item.key] = item.value;
ValueTypeList.push({ value: item.key, label: item.value });
}
}
</script>

192
io.sc.engine.rule.frontend/src/views/lib/TestCaseParameter.vue

@ -0,0 +1,192 @@
<template>
<w-grid
ref="gridRef"
:title="$t('re.resources.designer.testCaseParameter.grid.title')"
dense-body
class="px-1"
hide-bottom
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="false"
:tree-icon="
(row) => {
if (row.category === 'M') {
return { name: 'folder', color: 'amber' };
} else {
return { name: 'bi-p-circle' };
}
}
"
:fetch-data-url="Environment.apiContextPath('/api/re/testCaseParameter/findByTestCase?testCaseId=' + testCase.id)"
:data-url="Environment.apiContextPath('/api/re/testCaseParameter')"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
'expand',
'separator',
{
extend: 'edit',
},
'separator',
{
name: 'execute',
label: $t('execute'),
icon: 'bi-caret-right',
click: () => {
axios.post(Environment.apiContextPath('/api/re/testCase/executeTestCase/' + testCase.id)).then(() => {
gridRef?.refresh();
});
},
},
'separator',
'view',
'separator',
'export',
]"
:columns="[
{ width: 300, name: 'name', label: $t('name') },
{ width: 100, name: 'parameterType', label: $t('type'), format: Formater.enum(Enums.ParameterType) },
{
width: 100,
name: 'valueType',
label: $t('re.resources.designer.parameter.grid.entity.valueType'),
format: (value) => {
return ValueTypeMap[value];
},
},
{ width: 100, name: 'defaultValue', label: $t('defaultValue') },
{ width: 100, name: 'inputValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.inputValue') },
{ width: 100, name: 'expectValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.expectValue') },
{ width: 100, name: 'resultValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.resultValue') },
{ width: 100, name: 'skipCheck', label: $t('re.resources.designer.testCaseParameter.grid.entity.skipCheck') },
{ width: 100, name: 'testResult', label: $t('re.resources.designer.testCaseParameter.grid.entity.testResult'), format: PassOrNotFormater },
]"
:editor="{
dialog: {
width: '600px',
},
form: {
colsNum: 1,
fields: [
{ name: 'testCase', label: $t('testCase'), type: 'text', defaultValue: testCase.id, hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'source', label: $t('source'), type: 'text', hidden: true },
{ name: 'parameterType', label: $t('parameterType'), type: 'text', hidden: true },
{ name: 'scoreCardVarType', label: $t('scoreCardVarType'), type: 'text', hidden: true },
{ name: 'indicatorType', label: $t('indicatorType'), type: 'text', hidden: true },
{
name: 'inputValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.inputValue'),
type: 'code-mirror',
rows: 4,
showIf: (arg) => {
const parameterType = arg.form.getFieldValue('parameterType');
const scoreCardVarType = arg.form.getFieldValue('scoreCardVarType');
const indicatorType = arg.form.getFieldValue('indicatorType');
if (
(!Tools.isUndefinedOrNull(parameterType) && (parameterType === 'IN' || parameterType === 'IN_OPTION' || parameterType === 'INDICATOR')) ||
(!Tools.isUndefinedOrNull(scoreCardVarType) && scoreCardVarType !== 'RESULT') ||
(!Tools.isUndefinedOrNull(indicatorType) && indicatorType === 'INTERFACE')
) {
return true;
}
return false;
},
},
{
name: 'expectValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.expectValue'),
type: 'code-mirror',
rows: 4,
showIf: (arg) => {
const parameterType = arg.form.getFieldValue('parameterType');
const scoreCardVarType = arg.form.getFieldValue('scoreCardVarType');
const indicatorType = arg.form.getFieldValue('indicatorType');
if (
(!Tools.isUndefinedOrNull(parameterType) &&
(parameterType === 'INTERMEDIATE' || parameterType === 'OUT' || parameterType === 'RULE_RESULT' || parameterType === 'SINGLE_RULE_RESULT')) ||
!Tools.isUndefinedOrNull(scoreCardVarType) ||
(!Tools.isUndefinedOrNull(indicatorType) && indicatorType === 'INDICATOR')
) {
return true;
}
return false;
},
},
{
name: 'resultValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.resultValue'),
type: 'code-mirror',
rows: 4,
lang: 'json',
},
{ name: 'skipCheck', label: $t('re.resources.designer.testCaseParameter.grid.entity.skipCheck'), type: 'checkbox' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
@row-click="
(evt, row, index) => {
emit('rowClick', evt, row, index);
}
"
@before-request-data="
() => {
emit('beforeRequestData');
}
"
></w-grid>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, Tools } from 'platform-core';
import PassOrNotFormater from '@/utils/PassOrNotFormater';
const props = defineProps({
testCase: { type: Object, default: undefined },
});
const emit = defineEmits<{
(e: 'rowClick', evt: Event, row: any, index: number): void;
(e: 'beforeRequestData', requestParams: URLSearchParams | any, callback: any): void;
}>();
const gridRef = ref();
const refresh = () => {
gridRef?.value?.refresh();
};
onMounted(() => {
gridRef?.value?.refresh();
});
defineExpose({
refresh,
});
const Enums = await EnumTools.fetch(['io.sc.engine.rule.core.enums.ParameterType']);
let ValueTypeMap = {};
const response = await axios.get(Environment.apiContextPath('/api/re/dictionary/getAllDictionaryMap'));
if (response && response.data) {
ValueTypeMap = {};
for (const item of response.data) {
ValueTypeMap[item.key] = item.value;
}
}
</script>

4
io.sc.engine.rule.frontend/src/views/lib/ValidatorGrid.vue

@ -202,11 +202,11 @@ const ValueTypeAndValidatorTypeMapping = {
};
const refresh = () => {
gridRef.value.refresh();
gridRef?.value?.refresh();
};
onMounted(() => {
gridRef.value.refresh();
gridRef?.value?.refresh();
});
defineExpose({

7
io.sc.engine.rule.frontend/src/views/migration/Migration.vue

@ -62,8 +62,7 @@
:label="$t('re.migration.export.action')"
@click="
() => {
let url = Environment.apiContextPath('/api/re/migration/export');
downloadIframeRef.src = url;
Downloader.get(Environment.apiContextPath('/api/re/migration/export'));
}
"
></q-btn>
@ -133,15 +132,13 @@
</div>
<div class="col-1"></div>
</div>
<iframe ref="downloadIframeRef" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { axios, Environment, NotifyManager, DialogManager } from 'platform-core';
import { axios, Environment, NotifyManager, DialogManager, Downloader } from 'platform-core';
const fileRef = ref();
const fileValueRef = ref();
const serverFilePathRef = ref();
const downloadIframeRef = ref();
</script>

19
io.sc.engine.rule.frontend/src/views/resources/Resources.vue

@ -212,15 +212,22 @@
return arg.selected;
},
click: (arg) => {
//axios.get(Environment.apiContextPath('/api/re/resource/export/' + arg.selected.id));
let url = Environment.apiContextPath('/api/re/resource/export/' + arg.selected.id);
downloadIframe.src = url;
Downloader.get(Environment.apiContextPath('/api/re/resource/export/' + arg.selected.id));
},
},
]"
:columns="[
{ width: '100%', name: 'name', label: $t('name') },
{ width: 80, name: 'type', label: $t('type'), format: Formater.enum(Enums.ResourceType) },
{
width: 80,
name: 'type',
label: $t('type'),
format: (value, row) => {
if (value !== 'FOLDER') {
return Formater.enum(Enums.ResourceType)(value);
}
},
},
{ width: 100, name: 'code', label: $t('code') },
{ width: 60, name: 'version', label: $t('version') },
{ width: 60, name: 'status', label: $t('status'), format: Formater.enum(Enums.DeployStatus) },
@ -315,12 +322,11 @@
<DesignerDialog ref="designerDialogRef"></DesignerDialog>
<ImportDialog ref="importDialogRef" @after-imported="afterImported"></ImportDialog>
<ImportSampleDialog ref="importSampleDialogRef" @after-imported="afterImported"></ImportSampleDialog>
<iframe ref="downloadIframe" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { axios, Environment, DialogManager, Formater, EnumTools } from 'platform-core';
import { axios, Environment, DialogManager, Formater, EnumTools, Downloader } from 'platform-core';
import AttachmentDialog from './AttachmentDialog.vue';
import DesignerDialog from './designer/DesignerDialog.vue';
import ImportSampleDialog from './ImportSampleDialog.vue';
@ -332,7 +338,6 @@ const foreignValueRef = ref('');
const designerDialogRef = ref();
const importDialogRef = ref();
const importSampleDialogRef = ref();
const downloadIframe = ref();
const afterImported = () => {
treeGridRef.value.refresh();
};

2
io.sc.engine.rule.frontend/src/views/resources/designer/TestCaseParameter.vue

@ -1,7 +1,7 @@
<template>
<w-grid
ref="gridRef"
:title="$t('re.resources.designer.testCase.grid.title')"
:title="$t('re.resources.designer.testCaseParameter.grid.title')"
dense-body
class="px-1"
hide-bottom

3
io.sc.engine.rule.frontend/src/views/resources/designer/Testcase.vue

@ -1,7 +1,6 @@
<template>
<w-grid
ref="gridRef"
:height="200"
:title="$t('re.resources.designer.testCase.grid.title')"
dense-body
class="px-1"
@ -12,7 +11,7 @@
:tree="false"
:fetch-data-url="Environment.apiContextPath('/api/re/testCase/findByOwnerId?ownerId=' + model.resource)"
:data-url="Environment.apiContextPath('/api/re/testCase')"
:pageable="true"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',

283
io.sc.engine.rule.frontend/src/views/testcase/Testcase.vue

@ -1,4 +1,283 @@
<template>
<div>Testcase</div>
<q-splitter :model-value="splitterRef" unit="px" separator-style="width: 3px;" class="w-full" style="height: 100%">
<template #before>
<div class="pr-1" style="height: 100%">
<w-grid
ref="testcaseGridRef"
:title="$t('re.resources.designer.testCase.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="false"
:data-url="Environment.apiContextPath('/api/re/testCase')"
:pageable="true"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
'clone',
{
extend: 'clone',
name: 'deepClone',
label: $t('deepClone'),
icon: 'bi-copy',
click: (arg) => {},
},
'edit',
'remove',
'separator',
{
name: 'execute',
label: $t('execute'),
icon: 'bi-caret-right',
},
{
name: 'executeAll',
label: $t('executeAll'),
icon: 'bi-caret-right-fill',
},
'view',
'separator',
'export',
]"
:columns="[
{ width: 50, name: 'order', label: $t('order'), hidden: true },
{ width: 100, name: 'id', label: $t('id'), hidden: true },
{
width: 80,
name: 'testResult',
label: $t('re.resources.designer.testCase.grid.entity.testResult'),
align: 'center',
sortable: false,
format: PassOrNotFormater,
},
{ width: 150, name: 'lastTestDate', label: $t('re.resources.designer.testCase.grid.entity.lastTestDate') },
{ width: 200, name: 'name', label: $t('name') },
{ width: '100%', name: 'description', label: $t('description') },
]"
:editor="{
dialog: {
width: '600px',
height: '250px',
},
form: {
colsNum: 1,
fields: [
{ name: 'order', label: $t('order'), type: 'text', hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'text' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'order', label: $t('order') },
{ name: 'id', label: $t('id') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
@row-click="
(evt, row, index) => {
currentSelectedTestCaseRef = row;
testcaseParameterGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedTestCaseRef = {};
testcaseParameterGridRef?.refresh();
}
"
></w-grid>
</div>
</template>
<template #after>
<div class="pl-1" style="height: 100%">
<w-grid
ref="testcaseParameterGridRef"
:title="$t('re.resources.designer.testCaseParameter.grid.title')"
dense-body
hide-bottom
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="true"
:tree-icon="
(row) => {
if (row.category === 'M') {
return { name: 'folder', color: 'amber' };
} else {
return { name: 'bi-p-circle' };
}
}
"
:fetch-data-url="Environment.apiContextPath('/api/re/testCaseParameter/findByTestCase?testCaseId=' + currentSelectedTestCaseRef.id)"
:data-url="Environment.apiContextPath('/api/re/testCaseParameter')"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
'expand',
'separator',
{
extend: 'edit',
},
'separator',
{
name: 'execute',
label: $t('execute'),
icon: 'bi-caret-right',
click: () => {
axios.post(Environment.apiContextPath('/api/re/testCase/executeTestCase/' + currentSelectedTestCaseRef.id)).then(() => {
testcaseParameterGridRef?.refresh();
});
},
},
'separator',
'view',
'separator',
'export',
]"
:columns="[
{ width: 300, name: 'name', label: $t('name') },
{ width: 100, name: 'parameterType', label: $t('type'), format: Formater.enum(Enums.ParameterType) },
{
width: 100,
name: 'valueType',
label: $t('re.resources.designer.parameter.grid.entity.valueType'),
format: (value) => {
return ValueTypeMap[value];
},
},
{ width: 100, name: 'defaultValue', label: $t('defaultValue') },
{ width: 100, name: 'inputValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.inputValue') },
{ width: 100, name: 'expectValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.expectValue') },
{ width: 100, name: 'resultValue', label: $t('re.resources.designer.testCaseParameter.grid.entity.resultValue') },
{ width: 100, name: 'skipCheck', label: $t('re.resources.designer.testCaseParameter.grid.entity.skipCheck') },
{ width: 100, name: 'testResult', label: $t('re.resources.designer.testCaseParameter.grid.entity.testResult'), format: PassOrNotFormater },
]"
:editor="{
dialog: {
width: '600px',
},
form: {
colsNum: 1,
fields: [
{ name: 'testCase', label: $t('testCase'), type: 'text', defaultValue: currentSelectedTestCaseRef.id, hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'source', label: $t('source'), type: 'text', hidden: true },
{ name: 'parameterType', label: $t('parameterType'), type: 'text', hidden: true },
{ name: 'scoreCardVarType', label: $t('scoreCardVarType'), type: 'text', hidden: true },
{ name: 'indicatorType', label: $t('indicatorType'), type: 'text', hidden: true },
{
name: 'inputValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.inputValue'),
type: 'code-mirror',
rows: 4,
showIf: (arg) => {
const parameterType = arg.form.getFieldValue('parameterType');
const scoreCardVarType = arg.form.getFieldValue('scoreCardVarType');
const indicatorType = arg.form.getFieldValue('indicatorType');
if (
(!Tools.isUndefinedOrNull(parameterType) && (parameterType === 'IN' || parameterType === 'IN_OPTION' || parameterType === 'INDICATOR')) ||
(!Tools.isUndefinedOrNull(scoreCardVarType) && scoreCardVarType !== 'RESULT') ||
(!Tools.isUndefinedOrNull(indicatorType) && indicatorType === 'INTERFACE')
) {
return true;
}
return false;
},
},
{
name: 'expectValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.expectValue'),
type: 'code-mirror',
rows: 4,
showIf: (arg) => {
const parameterType = arg.form.getFieldValue('parameterType');
const scoreCardVarType = arg.form.getFieldValue('scoreCardVarType');
const indicatorType = arg.form.getFieldValue('indicatorType');
if (
(!Tools.isUndefinedOrNull(parameterType) &&
(parameterType === 'INTERMEDIATE' ||
parameterType === 'OUT' ||
parameterType === 'RULE_RESULT' ||
parameterType === 'SINGLE_RULE_RESULT')) ||
!Tools.isUndefinedOrNull(scoreCardVarType) ||
(!Tools.isUndefinedOrNull(indicatorType) && indicatorType === 'INDICATOR')
) {
return true;
}
return false;
},
},
{
name: 'resultValue',
label: $t('re.resources.designer.testCaseParameter.grid.entity.resultValue'),
type: 'code-mirror',
rows: 4,
lang: 'json',
},
{ name: 'skipCheck', label: $t('re.resources.designer.testCaseParameter.grid.entity.skipCheck'), type: 'checkbox' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
></w-grid>
</div>
</template>
</q-splitter>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, ref, useAttrs } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, Tools } from 'platform-core';
import PassOrNotFormater from '@/utils/PassOrNotFormater';
const splitterRef = ref(400); //
const testcaseGridRef = ref();
const testcaseParameterGridRef = ref();
const currentSelectedTestCaseRef = ref({});
const Enums = await EnumTools.fetch([
'io.sc.platform.core.enums.RoundingMode',
'io.sc.engine.rule.core.enums.ParameterType',
'io.sc.engine.rule.core.enums.DeployStatus',
]);
let ValueTypeMap = {};
const ValueTypeList = [];
const response = await axios.get(Environment.apiContextPath('/api/re/dictionary/getAllDictionaryMap'));
if (response && response.data) {
ValueTypeMap = {};
ValueTypeList.splice(0, ValueTypeList.length);
for (const item of response.data) {
ValueTypeMap[item.key] = item.value;
ValueTypeList.push({ value: item.key, label: item.value });
}
}
</script>

223
io.sc.engine.rule.frontend/src/views/workflow/Workflow.vue

@ -1,4 +1,223 @@
<template>
<div>workflow</div>
<q-splitter :model-value="splitterRef" unit="px" separator-style="width: 3px;" class="w-full" style="height: 100%">
<template #before>
<div class="pr-1" style="height: 100%">
<w-grid
ref="processTaskGridRef"
:title="$t('re.workflow.task.grid.title')"
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="false"
:fetch-data-url="Environment.apiContextPath('/api/re/resource/workflow/task/query')"
:pageable="true"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'refresh',
'separator',
{
name: 'viewResource',
label: $t('re.workflow.task.grid.toolbar.viewResource'),
icon: 'bi-boxes',
},
{
name: 'attachment',
label: $t('re.workflow.task.grid.toolbar.viewAttachment'),
icon: 'bi-briefcase-fill',
enableIf: (arg) => {
return arg.selected && arg.selected.attachments;
},
click: (arg) => {
if (arg.selected) {
foreignValueRef = arg.selected.id;
attachmentDialogRef.open();
}
},
},
'separator',
[
{
label: $t('operation'),
icon: 'bi-cursor',
},
{
name: 'claim',
label: $t('re.workflow.task.grid.toolbar.claim'),
icon: 'bi-clipboard-check',
enableIf: function (selecteds) {
return selecteds && selecteds.length > 0 && !selecteds[0].assignee;
},
click: (arg) => {
if (arg.selected) {
DialogManager.confirm($t('re.workflow.task.grid.toolbar.claim.tip'), () => {
axios.post(Environment.apiContextPath('/api/flowable/process/operation/claim/') + arg.selected.id).then(() => {
taskGridRef.refresh();
NotifyManager.success();
});
});
}
},
},
{
name: 'unclaim',
label: $t('re.workflow.task.grid.toolbar.unclaim'),
icon: 'bi-clipboard-x',
enableIf: function (arg) {
return arg.selected && arg.selected.assignee;
},
click: (arg) => {
if (arg.selected) {
DialogManager.confirm($t('re.workflow.task.grid.toolbar.unclaim.tip'), () => {
axios.post(Environment.apiContextPath('/api/flowable/process/operation/unClaim/') + arg.selected.id).then(() => {
taskGridRef.refresh();
NotifyManager.success();
});
});
}
},
},
{
name: 'complete',
label: $t('re.workflow.task.grid.toolbar.complete'),
icon: 'bi-caret-right',
enableIf: function (arg) {
return arg.selected;
},
click: (arg) => {
if (arg.selected) {
completeTaskDialogRef.open(arg.selected.id);
}
},
},
{
name: 'terminate',
label: $t('re.workflow.task.grid.toolbar.terminate'),
icon: 'bi-stop',
enableIf: function (arg) {
return arg.selected;
},
click: (arg) => {
if (arg.selected) {
DialogManager.confirm($t('re.workflow.task.grid.toolbar.terminate.tip'), () => {
axios.post(Environment.apiContextPath('/api/flowable/process/operation/terminateProcessInstance/') + arg.selected.id).then(() => {
taskGridRef.refresh();
NotifyManager.success();
});
});
}
},
},
],
'separator',
'view',
'separator',
'export',
]"
:columns="[
{ width: 50, name: 'resourceType', label: $t('type') },
{ width: 50, name: 'resourceCode', label: $t('code') },
{ width: 50, name: 'resourceName', label: $t('name') },
{ width: 50, name: 'resourceVersion', label: $t('version') },
{ width: 50, name: 'attachments', label: $t('attachment') },
{ width: 50, name: 'taskName', label: $t('re.workflow.task.grid.entity.taskName') },
{ width: 50, name: 'taskAssignee', label: $t('re.workflow.task.grid.entity.taskAssignee') },
{ width: 50, name: 'taskCreateTime', label: $t('re.workflow.task.grid.entity.taskCreateTime') },
]"
:editor="{
dialog: {
width: '600px',
height: '250px',
},
form: {
colsNum: 1,
fields: [
{ name: 'order', label: $t('order'), type: 'text', hidden: true },
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'name', label: $t('name'), type: 'text', required: true },
{ name: 'description', label: $t('description'), type: 'text' },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'order', label: $t('order') },
{ name: 'id', label: $t('id') },
{ name: 'name', label: $t('name') },
{ name: 'description', label: $t('description') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
@row-click="
(evt, row, index) => {
currentSelectedTaskRef = row;
historyProcessTaskGridRef?.refresh();
}
"
@before-request-data="
() => {
currentSelectedTaskRef = {};
historyProcessTaskGridRef?.refresh();
}
"
></w-grid>
</div>
</template>
<template #after>
<div class="pl-1" style="height: 100%">
<w-grid
ref="historyProcessTaskGridRef"
:title="$t('re.workflow.historyTask.grid.title')"
dense-body
hide-bottom
:config-button="false"
selection="multiple"
:checkbox-selection="false"
:tree="false"
:fetch-data-url="Environment.apiContextPath('/api/re/testCaseParameter/findByTestCase?testCaseId=' + currentSelectedTaskRef.id)"
:pageable="false"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['refresh', 'separator', 'view', 'separator', 'export']"
:columns="[
{ width: 100, name: 'taskName', label: $t('re.workflow.task.grid.entity.taskName') },
{ width: 100, name: 'taskAssignee', label: $t('re.workflow.task.grid.entity.taskAssignee') },
{ width: 120, name: 'taskEndTime', label: $t('re.workflow.task.grid.entity.taskEndTime') },
{ width: 300, name: 'taskTreatment', label: $t('re.workflow.task.grid.entity.taskTreatment') },
]"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
{ name: 'lastModifier', label: $t('lastModifier') },
{ name: 'lastModifyDate', label: $t('lastModifyDate'), format: Formater.none() },
{ name: 'corporationCode', label: $t('corporationCode') },
],
},
}"
></w-grid>
</div>
</template>
</q-splitter>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, ref, useAttrs } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, Tools } from 'platform-core';
import PassOrNotFormater from '@/utils/PassOrNotFormater';
const splitterRef = ref(800); //
const processTaskGridRef = ref();
const historyProcessTaskGridRef = ref();
const currentSelectedTaskRef = ref({});
</script>

3
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/resource/controller/ResourceWebController.java

@ -18,7 +18,9 @@ import io.sc.engine.rule.server.resource.entity.ResourceEntity;
import io.sc.engine.rule.server.resource.repository.ResourceRepository;
import io.sc.engine.rule.server.resource.service.ResourceService;
import io.sc.engine.rule.server.resource.vo.ResourceVo;
import io.sc.platform.core.util.FileUtil;
import io.sc.platform.core.util.ObjectMapper4Json;
import io.sc.platform.core.util.StringUtil;
import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.mvc.support.FileDownloader;
import org.slf4j.Logger;
@ -230,7 +232,6 @@ public class ResourceWebController extends RestCrudController<ResourceVo, Resour
* @throws Exception 违例
*/
@RequestMapping(value="export/{id}")
@ResponseBody
public void exportResource(@PathVariable(name="id",required=true)String id,HttpServletRequest request, HttpServletResponse response) throws Exception{
Resource po =service.exports(id);
if(po!=null) {

3
io.sc.platform.core.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.1.164",
"version": "8.1.169",
"description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件",
"main": "dist/platform-core.js",
@ -119,6 +119,7 @@
"file-saver": "2.0.5",
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"@maxgraph/core":"0.9.0",
"pinia": "2.1.7",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",

9
io.sc.platform.core.frontend/src/platform/components/workflow/WWorkflowAction.vue

@ -35,6 +35,8 @@ const props = defineProps({
defaultActionButtonsPlacement: { type: String, default: 'right' },
// goback
isGobackActionDropdown: { type: Boolean, default: false },
// submit
defaultSubmitButton: { type: Boolean, default: true },
});
/**
@ -43,6 +45,7 @@ const props = defineProps({
const emit = defineEmits<{
(
e: 'beforeSubmit', //
action: any, //
callback: any, //
): void;
(
@ -86,7 +89,9 @@ const buildButtons = (gobacks) => {
}
//
buttons.push({ title: t('submit') });
if (props.defaultSubmitButton) {
buttons.push({ title: t('submit'), transientVariables: { variableName: 'submit', variableValue: '' } });
}
// ()
if (props.defaultActionButtonsPlacement === 'right') {
@ -105,7 +110,7 @@ const buildButtons = (gobacks) => {
};
const buttonClick = (action) => {
emit('beforeSubmit', (value) => {
emit('beforeSubmit', action, (value) => {
if (value) {
DialogManager.confirm(t('lcdp.bpm.completeTask.action.tip', { action: action.title }), () => {
currentActionRef.value = action;

1
io.sc.platform.core.frontend/src/platform/i18n/messages.json

@ -10,6 +10,7 @@
"504": "Gateway Timeout(504) !",
"505": "HTTP Version Not Supported(505) !",
"NetworkError": "Network Error !",
"ERR_BAD_RESPONSE":"Server Response Error !",
"about": "About",
"cancel": "Cancel",
"changeRole": "Change Role",

1
io.sc.platform.core.frontend/src/platform/i18n/messages_tw_CN.json

@ -10,6 +10,7 @@
"504": "网关超时(504) !",
"505": "不支持的 HTTP 版本(505) !",
"NetworkError": "网络异常!",
"ERR_BAD_RESPONSE":"服務器響應錯誤!",
"about": "關於",
"cancel": "取消",
"changeRole": "切換角色",

1
io.sc.platform.core.frontend/src/platform/i18n/messages_zh_CN.json

@ -10,6 +10,7 @@
"504": "网关超时(504) !",
"505": "不支持的 HTTP 版本(505) !",
"NetworkError": "网络异常!",
"ERR_BAD_RESPONSE":"服务器响应错误!",
"about": "关于",
"cancel": "取消",
"changeRole": "切换角色",

4
io.sc.platform.core.frontend/src/platform/index.ts

@ -18,6 +18,7 @@ import '@quasar/extras/material-symbols-outlined/material-symbols-outlined.css';
//import '@quasar/extras/material-symbols-sharp/material-symbols-sharp.css';
import '@quasar/extras/eva-icons/eva-icons.css';
import '@quasar/extras/fontawesome-v6/fontawesome-v6.css';
import '@maxgraph/core/css/common.css';
//import './css/tailwind.css';
export default {
@ -62,7 +63,7 @@ export { PConst } from './PConst';
/**
*
*/
export { axios } from './plugin';
export { axios, blobAxios } from './plugin';
export { eventBus } from './plugin';
export { i18n } from './plugin';
export { usePlatformStore } from './plugin';
@ -88,6 +89,7 @@ export { TagViewManager } from './plugin';
*
*/
export { DictionaryTools } from './utils';
export { Downloader } from './utils';
export { EnumTools } from './utils';
export { DateTools } from './utils';
export { JavascriptLoader } from './utils';

141
io.sc.platform.core.frontend/src/platform/plugin/axios.ts

@ -4,84 +4,105 @@ import { i18n } from './i18n';
import { PConst } from '@/platform/PConst';
import { Environment } from '@/platform/plugin/environment';
import { NotifyManager } from './manager';
import { Tools } from '@/platform/utils';
const ignoredUrls: string[] = [PConst.API_I18N_MESSAGES_URL, PConst.API_APP_CONFIGURE_URL];
const gc = Environment.getConfigure();
const axios = Axios.create({
baseURL: gc.axios?.baseURL || '',
timeout: gc.axios?.timeout || 1000 * 60,
});
// 请求拦截器
axios.interceptors.request.use(
(config: any) => {
config.headers.locale = gc.setting.i18n.locale;
// 忽略无需认证的请求 URL
for (const url of ignoredUrls) {
if (config.url.includes(url)) {
return config;
}
}
// 对于需要认证的请求 URL 添加 basic 认证
const result = config;
if (gc.axios?.basicAuth?.enable) {
result.headers.Authorization = 'Basic ' + window.btoa(gc.axios.basicAuth.username + ':' + gc.axios.basicAuth.password);
const requestInterceptor = (config: any) => {
config.headers.locale = gc.setting.i18n.locale;
// 忽略无需认证的请求 URL
for (const url of ignoredUrls) {
if (config.url.includes(url)) {
return config;
}
return result;
},
(error: any) => {
return Promise.reject(error);
},
);
}
// 对于需要认证的请求 URL 添加 basic 认证
const result = config;
if (gc.axios?.basicAuth?.enable) {
result.headers.Authorization = 'Basic ' + window.btoa(gc.axios.basicAuth.username + ':' + gc.axios.basicAuth.password);
}
return result;
};
// 请求错误拦截器
const requestErrorInterceptor = (error: any) => {
return Promise.reject(error);
};
// 响应拦截器
axios.interceptors.response.use(
(response: any) => {
// 请求成功, 进入该方法说明 response 的状态码为 2xx
return response.data;
},
(error: any) => {
// 请求失败, 进入该方法说明 response 的状态码不为 2xx
if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') {
// 发生网络错误
const $t = i18n.global.t;
NotifyManager.error($t('NetworkError'));
const responseInterceptor = (response: any) => {
// 请求成功, 进入该方法说明 response 的状态码为 2xx
return response.data;
};
// 响应错误拦截器
const responseErrorInterceptor = (error: any) => {
// 请求失败, 进入该方法说明 response 的状态码不为 2xx
if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') {
// 发生网络错误
const $t = i18n.global.t;
NotifyManager.error($t('NetworkError'));
return Promise.reject({
code: 'NetworkError',
errorMessageI18nKey: 'NetworkError',
errorMessage: error.message,
exception: 'NetworkError',
stackTrace: error.stack,
data: null,
});
} else {
// 服务器端错误
const response = error?.response;
const status = response?.status;
const data = response?.data;
//下载错误
if (error.request.responseType === 'blob') {
NotifyManager.error(i18n.global.t(error?.code));
return Promise.reject(error);
}
//其他错误
if (status === 500) {
NotifyManager.error(i18n.global.t(data?.errorMessageI18nKey));
return Promise.reject(response.data);
} else {
NotifyManager.error(i18n.global.t(status));
return Promise.reject({
code: 'NetworkError',
errorMessageI18nKey: 'NetworkError',
code: status,
errorMessageI18nKey: status,
errorMessage: error.message,
exception: 'NetworkError',
exception: error.code,
stackTrace: error.stack,
data: null,
});
} else {
// 服务器端错误
const response = error?.response;
const status = response?.status;
const data = response?.data;
if (status === 500) {
NotifyManager.error(i18n.global.t(data?.errorMessageI18nKey));
return Promise.reject(response.data);
} else {
NotifyManager.error(i18n.global.t(status));
return Promise.reject({
code: status,
errorMessageI18nKey: status,
errorMessage: error.message,
exception: error.code,
stackTrace: error.stack,
data: null,
});
}
}
},
);
}
};
// 普通 axios
const axios = Axios.create({
baseURL: gc.axios?.baseURL || '',
timeout: gc.axios?.timeout || 1000 * 60,
});
axios.interceptors.request.use(requestInterceptor, requestErrorInterceptor);
axios.interceptors.response.use(responseInterceptor, responseErrorInterceptor);
// 下载二进制 axios
const blobAxios = Axios.create({
baseURL: gc.axios?.baseURL || '',
timeout: gc.axios?.timeout || 1000 * 60,
});
blobAxios.interceptors.request.use(requestInterceptor, requestErrorInterceptor);
blobAxios.interceptors.response.use((response: any) => {
return response;
}, responseErrorInterceptor);
export default {
install: (app: App) => {
app.config.globalProperties.$axios = axios;
app.config.globalProperties.$blobAxios = blobAxios;
},
};
export { axios };
export { axios, blobAxios };

2
io.sc.platform.core.frontend/src/platform/plugin/index.ts

@ -15,7 +15,7 @@ export default {
},
};
export { axios } from './axios';
export { axios, blobAxios } from './axios';
export { eventBus } from './quasar';
export { i18n } from './i18n';
export { usePlatformStore } from './pinia';

37
io.sc.platform.core.frontend/src/platform/utils/Downloader.ts

@ -0,0 +1,37 @@
import { blobAxios } from '@/platform';
class Downloader {
public static get(url: string, data: any) {
blobAxios.get(url, data, { responseType: 'blob' }).then((response) => {
Downloader.download(response);
});
}
public static post(url: string, data: any) {
blobAxios.post(url, data, { responseType: 'blob' }).then((response) => {
Downloader.download(response);
});
}
private static download(response) {
if (response) {
const { data, headers } = response;
let fileName = headers['content-disposition-url-encode'].match(/filename=(.*)/)[1];
fileName = decodeURIComponent(fileName || 'download');
// 如果下载的内容是 json 字符串, 返回的 data 是一个 js Object, 需要转换成 json 字符串
const _data = data instanceof Object ? JSON.stringify(data, null, ' ') : data;
const blob = new Blob([_data], { type: headers['content-type'] });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = decodeURI(fileName);
a.style.display = 'none';
document.body.appendChild(a);
a.click();
a.parentNode.removeChild(a);
window.URL.revokeObjectURL(url);
}
}
}
export { Downloader };

1
io.sc.platform.core.frontend/src/platform/utils/index.ts

@ -1,5 +1,6 @@
export { DateTools } from './DateTools';
export { DictionaryTools } from './DictionaryTools';
export { Downloader } from './Downloader';
export { EnumTools } from './EnumTools';
export { JavascriptLoader } from './JavascriptLoader';
export { QuasarTools } from './QuasarTools';

54
io.sc.platform.core.frontend/src/views/FormElements.vue

@ -1,39 +1,25 @@
<template>
<w-grid
ref="userGridRef"
:height="300"
:title="$t('system.user.grid.title')"
:config-button="true"
selection="multiple"
:checkbox-selection="true"
:data-url="Environment.apiContextPath('/api/system/user')"
:pagination="{
sortBy: 'loginName',
descending: false,
}"
:query-form-cols-num="3"
:query-form-fields="[
{ name: 'loginName', label: $t('loginName'), type: 'text' },
{ name: 'userName', label: $t('userName'), type: 'text' },
{ name: 'enable', label: $t('isEnable'), type: 'select' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator']"
:columns="[
{ width: 150, name: 'loginName', label: $t('loginName') },
{ width: '100%', name: 'userName', label: $t('userName') },
{
width: 150,
name: 'enable',
label: $t('status'),
format: Formater.checkTag(),
},
{ width: 100, name: 'lastModifier', label: $t('lastModifier') },
{ width: 110, name: 'lastModifyDate', label: $t('lastModifyDate') },
]"
></w-grid>
<div class="w-full border rounded-md" style="height: 100%">
<ToolBar></ToolBar>
<q-splitter :model-value="20" unit="%" separator-style="width:2px;" style="height: calc(100% - 50px)">
<template #before>
<SideBar></SideBar>
</template>
<template #after>
<q-splitter :model-value="65" unit="%" separator-style="width:2px;" style="height: 100%">
<template #before><Editor></Editor></template>
<template #after><Properties></Properties></template>
</q-splitter>
</template>
</q-splitter>
</div>
</template>
<script setup lang="ts">
import { Environment, Formater } from '@/platform';
import { ref, onMounted } from 'vue';
import { type CellStyle, Graph, InternalEvent } from '@maxgraph/core';
import ToolBar from './ToolBar.vue';
import SideBar from './SideBar.vue';
import Editor from './Editor.vue';
import Properties from './Properties.vue';
</script>

4
io.sc.platform.core.frontend/template-project/package.json

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.1.164",
"version": "8.1.169",
"description": "前端核心包,用于快速构建前端的脚手架",
"private": false,
"keywords": [],
@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.164",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

21
io.sc.platform.core.frontend/template-project/src/views/FormElements.vue

@ -18,7 +18,24 @@
{ name: 'enable', label: $t('isEnable'), type: 'select' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="['query', 'refresh', 'separator', 'add', 'clone', 'edit', 'remove', 'separator']"
:toolbar-actions="[
'query',
'refresh',
'separator',
'add',
'clone',
'edit',
'remove',
'separator',
{
name: 'download',
label: $t('download'),
click: () => {
//Downloader.get(Environment.apiContextPath('/api/re/resource/export/10e2a868-caaf-423d-a135-23f530f11696'));
Downloader.get(Environment.apiContextPath('/api/monitor/logger/downloadLogFile?fileName=log.log'));
},
},
]"
:columns="[
{ width: 150, name: 'loginName', label: $t('loginName') },
{ width: '100%', name: 'userName', label: $t('userName') },
@ -35,5 +52,5 @@
</template>
<script setup lang="ts">
import { Environment, Formater } from '@/platform';
import { Environment, Formater, Downloader } from '@/platform';
</script>

4
io.sc.platform.developer.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.developer.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

10
io.sc.platform.gradle/templates/pgp/setup/gradle.properties

@ -36,9 +36,9 @@ application_version=1.0.0
# platform
###########################################################
platform_group=io.sc
platform_version=8.1.30
platform_version=8.1.33
platform_plugin_version=8.1.13
platform_core_frontend_version=8.1.160
platform_core_frontend_version=8.1.169
###########################################################
# dependencies version
@ -62,13 +62,14 @@ jxls_jexcel_version=1.0.7
jxls_poi_version=1.0.15
jxls_version=2.4.6
mybatis_version=3.5.10
ooxml_schemas_version=4.1.2
opencsv_version=5.7.1
oshi_version=6.4.2
p6spy_version=3.9.1
pinyin4j_version=2.5.1
poi_ooxml_version=3.17
schemacrawler_version=16.19.11
poi_version=5.2.5
#schemacrawler_version=14.21.02
schemacrawler_version=16.19.11
spring_boot_version=2.7.18
spring_cloud_alibaba_version=2021.0.4.0
spring_cloud_context_version=3.1.4
@ -78,6 +79,7 @@ spring_statemachine_version=3.2.1
webjars_locator_weblogic_version=0.10
zip4j_version=2.11.5
###########################################################
# asciidoc deploy directory,the path must end with '/'
###########################################################

4
io.sc.platform.lcdp.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.lcdp.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

8
io.sc.platform.lcdp.frontend/src/views/Frontend.vue

@ -9,19 +9,15 @@
<div class="fit row wrap justify-center items-start content-start q-pt-md q-gutter-md">
<q-btn :loading="loading" outlined :label="$t('lcdp.frontend.export')" @click="exportFrontend" />
</div>
<div class="row q-pt-md">
<iframe ref="exportIframe" src="javascript:;" style="width: 100%; height: 400px"></iframe>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { axios, Environment } from 'platform-core';
import { axios, Environment, Downloader } from 'platform-core';
const frontendWebContextPath = ref('/');
const backendApiWebContextPath = ref('/');
const loading = ref(false);
const exportIframe = ref();
const exportFileInfo = reactive({ filePath: '', exportName: '' });
const exportFrontend = () => {
loading.value = true;
@ -36,7 +32,7 @@ const exportFrontend = () => {
let url = Environment.apiContextPath('/api/mvc/download?');
url += 'filePath=' + encodeURIComponent(exportFileInfo.filePath);
url += '&exportName=' + encodeURIComponent(exportFileInfo.exportName);
exportIframe.value.src = url;
Downloader.get(url);
})
.finally(() => {
loading.value = false;

4
io.sc.platform.mvc.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.mvc.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -78,7 +78,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

2
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/plugins/item/Parameter.java

@ -11,7 +11,7 @@ public class Parameter {
protected Integer order =0;
protected Integer priority =0;
protected String description;
protected Map<String, String> options =new LinkedHashMap<>();
protected Map<String, String> options;
//附加属性
private String configurationFileUrl; //菜单贡献项配置文件位置

9
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/support/FileDownloader.java

@ -4,6 +4,8 @@ import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Base64;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -24,7 +26,12 @@ public class FileDownloader {
public static void download(HttpServletRequest request,HttpServletResponse response,String name,InputStream inputStream) throws Exception{
response.setContentType(CONTENT_TYPE);
if(StringUtils.hasText(name)){
response.setHeader("Content-disposition", "attachment; filename=" + new String(name.getBytes("UTF-8"), "ISO8859-1"));
// 暴露 header 属性, 以便客户端 axios 能从 headers 中获取
response.setHeader("Access-Control-Expose-Headers","Content-Disposition,Content-Disposition-Url-Encode");
// 设置附件名称(通过浏览器直接下载时,可正常保存中文名称)
response.setHeader("Content-Disposition", "attachment; filename=" + new String(name.getBytes("UTF-8"), "ISO8859-1"));
// 设置附件名称(通过 axios 下载时,可正常保存中文名称)
response.setHeader("Content-Disposition-Url-Encode", "attachment; filename=" + URLEncoder.encode(name));
}
BufferedInputStream bis = null;
BufferedOutputStream bos = null;

8
io.sc.platform.poi/build.gradle

@ -0,0 +1,8 @@
dependencies {
api(
"org.apache.poi:ooxml-schemas:${ooxml_schemas_version}",
"org.apache.poi:poi:${poi_version}",
"org.apache.poi:poi-ooxml:${poi_version}",
"org.apache.poi:poi-scratchpad:${poi_version}",
)
}

0
io.sc.platform.poi/gradle.properties

4
io.sc.platform.security.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.security.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [
@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.2",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

3
io.sc.platform.security/src/main/resources/META-INF/platform/plugins/messages.json

@ -1,6 +1,7 @@
{
"includes":[
"io/sc/platform/security/i18n/initializer",
"io/sc/platform/security/i18n/messages"
"io/sc/platform/security/i18n/messages",
"io/sc/platform/security/i18n/parameter"
]
}

8
io.sc.platform.security/src/main/resources/META-INF/platform/plugins/parameters.json

@ -6,7 +6,11 @@
"id" : "parameter.login.encodePassword",
"parentId" : "parameter.system",
"code" : "parameter.login.encodePassword",
"defaultValue" : true,
"order" : 200
"defaultValue" : "true",
"order" : 200,
"options" : {
"true" : "parameter.login.encodePassword.options.true",
"false" : "parameter.login.encodePassword.options.false"
}
}
]

3
io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter.properties

@ -0,0 +1,3 @@
parameter.login.encodePassword=Encode Password in Login Page
parameter.login.encodePassword.options.true=True
parameter.login.encodePassword.options.false=False

3
io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter_tw_CN.properties

@ -0,0 +1,3 @@
parameter.login.encodePassword=\u767B\u9304\u9801\u9762\u5BC6\u78BC\u52A0\u5BC6
parameter.login.encodePassword.options.true=\u662F
parameter.login.encodePassword.options.false=\u5426

3
io.sc.platform.security/src/main/resources/io/sc/platform/security/i18n/parameter_zh_CN.properties

@ -0,0 +1,3 @@
parameter.login.encodePassword=\u767B\u5F55\u9875\u9762\u5BC6\u7801\u52A0\u5BC6
parameter.login.encodePassword.options.true=\u662F
parameter.login.encodePassword.options.false=\u5426

31
io.sc.platform.system.api/src/main/java/io/sc/platform/system/api/parameter/ParameterVo.java

@ -3,10 +3,17 @@ package io.sc.platform.system.api.parameter;
import io.sc.platform.orm.api.vo.BaseVo;
import io.sc.platform.orm.api.vo.CorporationAuditorVo;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class ParameterVo extends CorporationAuditorVo {
private String id;
private String code;
private String value;
private Integer order;
private String defaultValue;
private Map<String,String> options;
private String parent;
public String getId() {
@ -33,6 +40,30 @@ public class ParameterVo extends CorporationAuditorVo {
this.value = value;
}
public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public Map<String, String> getOptions() {
return options;
}
public void setOptions(Map<String, String> options) {
this.options = options;
}
public String getParent() {
return parent;
}

4
io.sc.platform.system.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.platform.system.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

4
io.sc.platform.system.frontend/src/i18n/messages.json

@ -1,8 +1,4 @@
{
"parameter.system":"System",
"parameter.system.homePage":"Home Page",
"parameter.login.encodePassword":"Login Password Encode",
"menu.system" : "System Manager",
"menu.system.license" : "License",
"menu.system.corporation" : "Corporation",

4
io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json

@ -1,8 +1,4 @@
{
"parameter.system":"系統",
"parameter.system.homePage":"首頁",
"parameter.login.encodePassword":"登錄頁面密碼加密",
"menu.system" : "系統管理",
"menu.system.license" : "許可證管理",
"menu.system.corporation" : "法人管理",

4
io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json

@ -1,8 +1,4 @@
{
"parameter.system":"系统",
"parameter.system.homePage":"首页",
"parameter.login.encodePassword":"登录页面密码加密",
"menu.system" : "系统管理",
"menu.system.license" : "许可证管理",
"menu.system.corporation" : "法人管理",

1
io.sc.platform.system.frontend/src/views/datasource/ConnectionPropertiesDialog.vue

@ -3,7 +3,6 @@
ref="dialogRef"
:title="$t('system.datasource.grid.toolbar.connectionProperties')"
width="900px"
height="600px"
:can-maximize="false"
:buttons="[
{

1
io.sc.platform.system.frontend/src/views/datasource/Datasource.vue

@ -53,7 +53,6 @@
:editor="{
dialog: {
width: '800px',
height: '500px',
},
form: {
colsNum: 1,

23
io.sc.platform.system.frontend/src/views/monitor/Log.vue

@ -1,13 +1,13 @@
<template>
<div>
<div style="height: 100%">
<q-tabs v-model="selectedTabRef" inline-label align="left" :breakpoint="0">
<q-tab name="view" icon="bi-receipt" :label="$t('system.monitor.log.tab.view')" />
<q-tab name="download" icon="bi-download" :label="$t('system.monitor.log.tab.download')" />
<q-tab name="level" icon="bi-sort-numeric-up" :label="$t('system.monitor.log.tab.level')" />
</q-tabs>
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive>
<q-tab-panel name="view">
<q-tab-panels v-model="selectedTabRef" animated swipeable keep-alive style="height: calc(100% - 48px)">
<q-tab-panel name="view" class="px-0 pb-0" style="height: 100%">
<div class="row q-pt-sm">
<div class="col-2">
<q-input v-model="logRows" :label="$t('system.monitor.log.viewer.logRows')" outlined dense />
@ -26,7 +26,7 @@
</div>
</div>
</q-tab-panel>
<q-tab-panel name="download">
<q-tab-panel name="download" class="px-0 pb-0" style="height: 100%">
<w-grid
ref="downloadGridRef"
:title="$t('system.monitor.log.download.grid.title')"
@ -46,10 +46,11 @@
name: 'download',
label: $t('download'),
icon: 'bi-download',
click: () => {
let url = Environment.apiContextPath('/api/monitor/logger/downloadLogFile?');
url += 'fileName=' + encodeURIComponent(downloadGridRef.getSelectedRows()[0].name);
downloadIframe.src = url;
enableIf: (arg) => {
return arg.selected;
},
click: (arg) => {
Downloader.get(Environment.apiContextPath('/api/monitor/logger/downloadLogFile?fileName=' + encodeURIComponent(arg.selected.name)));
},
},
]"
@ -69,7 +70,7 @@
>
</w-grid>
</q-tab-panel>
<q-tab-panel name="level">
<q-tab-panel name="level" class="px-0 pb-0" style="height: 100%">
<w-grid
ref="levelGridRef"
:title="$t('system.monitor.log.level.grid.title')"
@ -109,12 +110,11 @@
</w-grid>
</q-tab-panel>
</q-tab-panels>
<iframe ref="downloadIframe" src="javascript:;" style="width: 0px; height: 0px"></iframe>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Environment, axios, EnumTools, Options } from 'platform-core';
import { Environment, axios, EnumTools, Options, Downloader } from 'platform-core';
const LogLevelEnum = await EnumTools.fetch('io.sc.platform.core.enums.LogLevel');
@ -122,7 +122,6 @@ const selectedTabRef = ref('view');
const logRows = ref(20);
const autoRefresh = ref(false);
const logContent = ref('');
const downloadIframe = ref();
const downloadGridRef = ref();
const levelGridRef = ref();

88
io.sc.platform.system.frontend/src/views/parameter/Parameter.vue

@ -1,6 +1,6 @@
<template>
<w-grid
ref="parameterTreeGridRef"
ref="treeGridRef"
:title="$t('system.parameter.grid.title')"
:config-button="true"
selection="multiple"
@ -59,13 +59,34 @@
:editor="{
dialog: {
width: '600px',
height: '250px',
buttons: [
{
name: 'resetDefaultValue',
label: $t('resetDefaultValue'),
},
],
},
form: {
colsNum: 1,
fields: [
{ name: 'code', label: $t('code'), type: 'text' },
{ name: 'value', label: $t('value'), type: 'text' },
{
name: 'valueInput',
label: $t('value'),
type: 'text',
showIf: (arg) => {
return !isExistsOptions();
},
},
{
name: 'valueSelect',
label: $t('value'),
type: 'select',
showIf: (arg) => {
return isExistsOptions();
},
options: optionsRef,
},
],
},
}"
@ -76,6 +97,8 @@
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'value', label: $t('value') },
{ name: 'order', label: $t('order') },
{ name: 'parent', label: $t('parent') },
{ name: 'dataComeFrom', label: $t('dataComeFrom') },
{ name: 'creator', label: $t('creator') },
{ name: 'createDate', label: $t('createDate') },
@ -85,9 +108,66 @@
],
},
}"
@row-click="(evt, row, index) => {}"
@row-click="
(evt, row, index) => {
changeOptions();
}
"
@after-editor-open="
(row) => {
if (isExistsOptions()) {
treeGridRef.getEditorForm().setFieldValue('valueSelect', row.value);
} else {
treeGridRef.getEditorForm().setFieldValue('valueInput', row.value);
}
}
"
@before-editor-data-submit="
(data, callback) => {
if (isExistsOptions()) {
data.value = treeGridRef.getEditorForm().getFieldValue('valueSelect');
} else {
data.value = treeGridRef.getEditorForm().getFieldValue('valueInput');
}
callback(data);
}
"
></w-grid>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment, Tools, Formater } from 'platform-core';
const { t } = useI18n();
const treeGridRef = ref();
const optionsRef = ref([]);
const changeOptions = () => {
optionsRef.value.splice(0, optionsRef.value.length);
const rows = treeGridRef.value.getSelectedRows();
if (rows && rows.length > 0) {
const row = rows[0];
for (const key in row.options) {
optionsRef.value.push({ label: t(row.options[key]), value: key });
}
}
};
const getSelectedRow = () => {
const rows = treeGridRef.value.getSelectedRows();
if (rows && rows.length > 0) {
return rows[0];
}
return null;
};
const isExistsOptions = () => {
const rows = treeGridRef.value.getSelectedRows();
if (rows && rows.length > 0) {
const row = rows[0];
return row.options && Object.keys(row.options).length > 0;
}
return false;
};
</script>

1
io.sc.platform.system.frontend/src/views/shared/SelectMenuTreeGrid.vue

@ -2,6 +2,7 @@
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectMenu.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"

1
io.sc.platform.system.frontend/src/views/shared/SelectOrgTreeGrid.vue

@ -2,6 +2,7 @@
<w-grid
ref="treeGridRef"
:title="$t('system.shared.selectOrg.grid.title')"
hide-bottom
:config-button="false"
:tree="true"
selection="multiple"

2
io.sc.platform.system.frontend/src/views/shared/SelectRoleDialog.vue

@ -15,7 +15,7 @@
},
]"
>
<div class="px-2">
<div class="px-2" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectRole.dialog.grid.title')"

2
io.sc.platform.system.frontend/src/views/shared/SelectUserDialog.vue

@ -15,7 +15,7 @@
},
]"
>
<div class="px-2">
<div class="px-2" style="height: 100%">
<w-grid
ref="gridRef"
:title="$t('system.shared.selectUser.dialog.grid.title')"

3
io.sc.platform.system/src/main/java/io/sc/platform/system/ds/jpa/entity/DsEntity.java

@ -20,7 +20,7 @@ import static javax.persistence.InheritanceType.SINGLE_TABLE;
@JsonSubTypes.Type(value =JndiDsEntity.class, name = "JNDI"),
@JsonSubTypes.Type(value =JdbcDsEntity.class, name = "JDBC")
})
public abstract class DsEntity extends CorporationAuditorEntity<DsVo> {
public class DsEntity extends CorporationAuditorEntity<DsVo> {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2")
@ -43,6 +43,7 @@ public abstract class DsEntity extends CorporationAuditorEntity<DsVo> {
@Size(max=255)
private String description;
@Override
public void toVo(DsVo vo){
if(vo!=null){
super.toVo(vo);

2
io.sc.platform.system/src/main/java/io/sc/platform/system/i18n/jpa/entity/I18nEntity.java

@ -55,7 +55,7 @@ public class I18nEntity extends CorporationAuditorEntity<I18nVo> {
super.toVo(vo);
vo.setId(this.getId());
vo.setCode(this.getCode());
vo.setLang(this.getLang().toString());
vo.setLang(this.getLang()==null?null:this.getLang().toString());
vo.setMessage(this.getMessage());
return vo;
}

46
io.sc.platform.system/src/main/java/io/sc/platform/system/initializer/ParameterInitializer.java

@ -12,7 +12,6 @@ import java.util.UUID;
public class ParameterInitializer implements ApplicationInitializer {
private Boolean isInitialized =null;
private JdbcTemplate jdbcTemplate;
private ParameterService parameterService;
@Override
@ -22,7 +21,6 @@ public class ParameterInitializer implements ApplicationInitializer {
@Override
public void init(ApplicationContext applicationContext) {
this.jdbcTemplate =applicationContext.getBean(JdbcTemplate.class);
this.parameterService =applicationContext.getBean(ParameterService.class);
}
@ -41,44 +39,10 @@ public class ParameterInitializer implements ApplicationInitializer {
@Override
public void execute() throws ApplicationInitializerExecuteException {
String systemId =UUID.randomUUID().toString();
new InsertIntoSqlBuilder().table("SYS_PARAMETER")
.field("ID_", systemId)
.field("CODE_","parameter.system")
.field("VALUE_",null)
.field("PARENT_ID_",null)
.field("DATA_COME_FROM_","INPUT")
.field("CREATOR_","admin")
.field("CREATE_DATE_",new Date())
.field("LAST_MODIFIER_","admin")
.field("LAST_MODIFYDATE_",new Date())
.field("CORP_CODE_","_PRIMARY_")
.insert(jdbcTemplate);
new InsertIntoSqlBuilder().table("SYS_PARAMETER")
.field("ID_", UUID.randomUUID().toString())
.field("CODE_","parameter.system.homePage")
.field("VALUE_","/home")
.field("PARENT_ID_",systemId)
.field("DATA_COME_FROM_","INPUT")
.field("CREATOR_","admin")
.field("CREATE_DATE_",new Date())
.field("LAST_MODIFIER_","admin")
.field("LAST_MODIFYDATE_",new Date())
.field("CORP_CODE_","_PRIMARY_")
.insert(jdbcTemplate);
new InsertIntoSqlBuilder().table("SYS_PARAMETER")
.field("ID_", UUID.randomUUID().toString())
.field("CODE_","parameter.login.encodePassword")
.field("VALUE_","false")
.field("PARENT_ID_",systemId)
.field("DATA_COME_FROM_","INPUT")
.field("CREATOR_","admin")
.field("CREATE_DATE_",new Date())
.field("LAST_MODIFIER_","admin")
.field("LAST_MODIFYDATE_",new Date())
.field("CORP_CODE_","_PRIMARY_")
.insert(jdbcTemplate);
try {
parameterService.init();
} catch (Exception e) {
throw new ApplicationInitializerExecuteException(e);
}
}
}

3
io.sc.platform.system/src/main/java/io/sc/platform/system/menu/jpa/entity/MenuEntity.java

@ -35,7 +35,7 @@ import java.util.Objects;
@JsonSubTypes.Type(value = MenuUrlEntity.class, name = "URL"),
@JsonSubTypes.Type(value = MenuJavascriptEntity.class, name = "JAVASCRIPT")
})
public abstract class MenuEntity extends CorporationAuditorEntity<MenuVo> implements IdClearable {
public class MenuEntity extends CorporationAuditorEntity<MenuVo> implements IdClearable {
//ID,主键
@Id
@GeneratedValue(generator = "system-uuid")
@ -101,6 +101,7 @@ public abstract class MenuEntity extends CorporationAuditorEntity<MenuVo> implem
@JoinColumn(name="PARENT_ID_")
protected MenuGroupEntity parent;
@Override
public void toVo(MenuVo vo){
if(vo!=null){
super.toVo(vo);

4
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/LogViewerWebController.java

@ -132,8 +132,8 @@ public class LogViewerWebController {
* @param response HttpServletResponse 对象
* @throws Exception 违例
*/
@RequestMapping(value="downloadLogFile/{fileName:.+}",method=RequestMethod.GET)
public void downloadLogFile(@PathVariable("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) throws Exception{
@RequestMapping(value="downloadLogFile",method=RequestMethod.GET)
public void downloadLogFile(@RequestParam("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) throws Exception{
Resource resource =new DefaultResourceLoader().getResource("file://" + DirectoryManager.getInstance().getByName("dir.log") + "/" + fileName);
FileDownloader.download(request, response, fileName, resource);
}

35
io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/controller/ParameterWebController.java

@ -1,15 +1,48 @@
package io.sc.platform.system.parameter.controller;
import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.mvc.plugins.PluginManager;
import io.sc.platform.mvc.plugins.item.Parameter;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.system.api.parameter.ParameterVo;
import io.sc.platform.system.parameter.jpa.entity.ParameterEntity;
import io.sc.platform.system.parameter.jpa.repository.ParameterRepository;
import io.sc.platform.system.parameter.service.ParameterService;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("api/system/parameter")
public class ParameterWebController extends RestCrudController<ParameterVo, ParameterEntity,String, ParameterRepository, ParameterService> {
@Override
protected Page<ParameterVo> query(HttpServletRequest request, HttpServletResponse response, QueryParameter queryParameter) throws Exception {
Page<ParameterVo> page =super.query(request, response, queryParameter);
List<ParameterVo> vos =page.getContent();
if(vos!=null && !vos.isEmpty()){
List<Parameter> parameters = PluginManager.getInstance().getParameters();
if(parameters!=null && !parameters.isEmpty()){
Map<String,Parameter> parameterMap =new HashMap<>(parameters.size());
for(Parameter parameter : parameters){
parameterMap.put(parameter.getCode(),parameter);
}
for(ParameterVo vo : vos){
Parameter parameter =parameterMap.get(vo.getCode());
if(parameter!=null) {
vo.setDefaultValue(parameter.getDefaultValue());
if (parameter.getOptions() != null) {
vo.setOptions(parameter.getOptions());
}
}
}
}
}
return page;
}
}

101
io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/jpa/entity/ParameterEntity.java

@ -1,21 +1,26 @@
package io.sc.platform.system.parameter.jpa.entity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.sc.platform.orm.api.vo.BaseVo;
import io.sc.platform.mvc.plugins.item.Parameter;
import io.sc.platform.orm.DeepClone;
import io.sc.platform.orm.IdClearable;
import io.sc.platform.orm.entity.CorporationAuditorEntity;
import io.sc.platform.system.api.parameter.ParameterVo;
import io.sc.platform.system.parameter.jpa.support.ParameterEntityJsonSerializer;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* 法人实体类
* 系统参数实体类
*/
@Entity
@Table(name="SYS_PARAMETER")
public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> implements IdClearable {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid2")
@ -31,15 +36,34 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
@Size(max=255)
private String value;
//排序
@Column(name="ORDER_",nullable=false)
protected Integer order;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="PARENT_ID_")
private ParameterEntity parent;
//孩子集合
@OneToMany(mappedBy="parent",cascade= {CascadeType.PERSIST})
@OrderBy("order")
protected List<ParameterEntity> children =new ArrayList<ParameterEntity>();
public ParameterEntity(){}
public ParameterEntity(String id){
this.id =id;
}
public static ParameterEntity from(Parameter parameter){
ParameterEntity entity =new ParameterEntity();
entity.setId(parameter.getId());
entity.setCode(parameter.getCode());
entity.setValue(parameter.getDefaultValue());
entity.setOrder(parameter.getOrder());
entity.setParent(StringUtils.hasText(parameter.getParentId())?new ParameterEntity(parameter.getParentId()):null);
return entity;
}
@Override
public ParameterVo toVo() {
ParameterVo vo =new ParameterVo();
@ -47,6 +71,7 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
vo.setId(this.getId());
vo.setCode(this.getCode());
vo.setValue(this.getValue());
vo.setOrder(this.getOrder());
vo.setParent(this.getParent()==null?null:this.getParent().getId());
return vo;
}
@ -75,6 +100,14 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
this.value = value;
}
public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
public ParameterEntity getParent() {
return parent;
}
@ -82,4 +115,62 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> {
public void setParent(ParameterEntity parent) {
this.parent = parent;
}
public List<ParameterEntity> getChildren() {
return children;
}
public void setChildren(List<ParameterEntity> children) {
this.children = children;
}
/**
* 重新设置父
* @param parent 新父
*/
public void resetParent(ParameterEntity parent){
if(this.parent!=parent){
//首先移除之前的关系
if(this.parent!=null){
List<ParameterEntity> children =this.parent.getChildren();
if(children!=null && children.contains(this)){
children.remove(this);
}
}
//建立新的父子关系
if(parent!=null){
List<ParameterEntity> children =parent.getChildren();
if(children!=null && !children.contains(this)){
children.add(this);
}
}
this.parent =parent;
}
}
@Override
public void clearId() {
this.setId(null);
//清除所有 children 的 Id 值
List<ParameterEntity> children =this.getChildren();
if(children!=null && children.size()>0) {
for(ParameterEntity child : children) {
child.clearId();
}
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
ParameterEntity entity = (ParameterEntity) o;
return Objects.equals(code, entity.code);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), code);
}
}

1
io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/service/ParameterService.java

@ -6,4 +6,5 @@ import io.sc.platform.system.parameter.jpa.entity.ParameterEntity;
import io.sc.platform.system.parameter.jpa.repository.ParameterRepository;
public interface ParameterService extends DaoService<ParameterEntity, String, ParameterRepository>, SystemParameterService {
public void init() throws Exception;
}

59
io.sc.platform.system/src/main/java/io/sc/platform/system/parameter/service/impl/ParameterServiceImpl.java

@ -1,19 +1,50 @@
package io.sc.platform.system.parameter.service.impl;
import io.sc.platform.core.util.TreeBuilder;
import io.sc.platform.mvc.plugins.PluginManager;
import io.sc.platform.mvc.plugins.item.Parameter;
import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.system.menu.jpa.entity.MenuEntity;
import io.sc.platform.system.menu.jpa.entity.MenuGroupEntity;
import io.sc.platform.system.menu.service.support.MenuEntityTreeBuilder;
import io.sc.platform.system.parameter.jpa.entity.ParameterEntity;
import io.sc.platform.system.parameter.jpa.repository.ParameterRepository;
import io.sc.platform.system.parameter.service.ParameterService;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.transaction.Transactional;
import java.util.*;
@Service
public class ParameterServiceImpl extends DaoServiceImpl<ParameterEntity, String, ParameterRepository> implements ParameterService {
@Override
@Transactional
public void init() throws Exception {
List<Parameter> parameters =PluginManager.getInstance().getParameters();
if(parameters!=null && !parameters.isEmpty()) {
List<ParameterEntity> entities =new ArrayList<>();
for(Parameter parameter : parameters){
entities.add(ParameterEntity.from(parameter));
}
TreeBuilder<ParameterEntity,String> treeBuilder =new ParameterEntityTreeBuilder();
entities =treeBuilder.buildAndGetRoots(entities);
if(entities!=null && !entities.isEmpty()){
for(ParameterEntity entity : entities){
entity.clearId();
repository.save(entity);
}
}
}
}
@Override
public String[] getDefaultSortBy() {
return new String[]{"order"};
}
@Override
public boolean containsParameter(String code) {
if(StringUtils.hasText(code)) {
@ -72,4 +103,24 @@ public class ParameterServiceImpl extends DaoServiceImpl<ParameterEntity, String
}
return Collections.emptyMap();
}
static class ParameterEntityTreeBuilder extends TreeBuilder<ParameterEntity,String> {
@Override
public String getId(ParameterEntity entity) {
return entity.getId();
}
@Override
public String getParentId(ParameterEntity entity) {
if(entity.getParent()!=null) {
return entity.getParent().getId();
}
return null;
}
@Override
public void resetParent(ParameterEntity entity, ParameterEntity parent) {
entity.resetParent(parent);
}
}
}

7
io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java

@ -440,20 +440,21 @@ public class UserServiceImpl extends DaoServiceImpl<UserEntity, String, UserRepo
}
private List<FrontEndRoute> getFrontEndRoutes(List<MenuVo> menus){
List<FrontEndRoute> result = new ArrayList<>();
Map<String,FrontEndRoute> frontEndRouteMap =new HashMap<>();
if(menus!=null && !menus.isEmpty()) {
List<FrontEndRoute> result = new ArrayList<>();
for(MenuVo menu : menus){
if (menu instanceof MenuRouteVo) {
MenuRouteVo routeMenu = (MenuRouteVo) menu;
FrontEndRoute route = PluginManager.getInstance().getFrontEndRouteByName(routeMenu.getRouteName());
if(route!=null) {
result.add(route);
frontEndRouteMap.put(route.getName(),route);
}
}
}
return result;
}
return Collections.emptyList();
return result;
}
@Override

3
io.sc.platform.system/src/main/resources/META-INF/platform/plugins/messages.json

@ -1,5 +1,6 @@
{
"includes":[
"io/sc/platform/system/i18n/initializer"
"io/sc/platform/system/i18n/initializer",
"io/sc/platform/system/i18n/parameter"
]
}

3
io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter.properties

@ -0,0 +1,3 @@
parameter.system=System
parameter.system.homePage=Home Page
parameter.login.encodePassword=\u767B\u9304\u9801\u9762\u5BC6\u78BC\u52A0\u5BC6

3
io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter_tw_CN.properties

@ -0,0 +1,3 @@
parameter.system=\u7CFB\u7D71
parameter.system.homePage=\u9996\u9801
parameter.login.encodePassword=\u767B\u9304\u9801\u9762\u5BC6\u78BC\u52A0\u5BC6

3
io.sc.platform.system/src/main/resources/io/sc/platform/system/i18n/parameter_zh_CN.properties

@ -0,0 +1,3 @@
parameter.system=\u7CFB\u7EDF
parameter.system.homePage=\u9996\u9875
parameter.login.encodePassword=\u767B\u9304\u9801\u9762\u5BC6\u78BC\u52A0\u5BC6

5
io.sc.platform.system/src/main/resources/liquibase/io.sc.platform.system_8.0.0_20220606__System Database Schema DDL.xml

@ -209,12 +209,13 @@
<!-- 系统参数表 -->
<createTable tableName="SYS_PARAMETER" remarks="系统参数表">
<column name="ID_" type="NVARCHAR(36)" remarks="ID">
<column name="ID_" type="NVARCHAR(255)" remarks="ID">
<constraints primaryKey="true"/>
</column>
<column name="CODE_" type="NVARCHAR(255)" remarks="代码"></column>
<column name="VALUE_" type="NVARCHAR(1024)" remarks="值"></column>
<column name="PARENT_ID_" type="NVARCHAR(36)" remarks="父ID"></column>
<column name="ORDER_" type="INTEGER" remarks="顺序"></column>
<column name="PARENT_ID_" type="NVARCHAR(255)" remarks="父ID"></column>
<column name="JPA_VERSION_" type="INTEGER" remarks="JPA乐观锁版本"/>
<column name="DATA_COME_FROM_" type="NVARCHAR(10)" remarks="数据来源(INPUT:手工录入,IMPORT:系统自动导入)"/>
<column name="CREATOR_" type="NVARCHAR(255)" remarks="创建人"/>

4
io.sc.standard.frontend/package.json

@ -1,6 +1,6 @@
{
"name": "io.sc.standard.frontend",
"version": "8.1.30",
"version": "8.1.33",
"description": "",
"private": false,
"keywords": [],
@ -91,7 +91,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.160",
"platform-core": "8.1.169",
"quasar": "2.14.5",
"tailwindcss": "3.4.0",
"vue": "3.4.3",

13
settings.gradle

@ -12,8 +12,8 @@ include ':io.sc.engine.rule.client'
include ':io.sc.engine.rule.client.spring'
include ':io.sc.engine.rule.core'
include ':io.sc.engine.rule.frontend'
include ':io.sc.engine.rule.server'
include ':io.sc.engine.rule.sample'
include ':io.sc.engine.rule.server'
include ':io.sc.platform.app'
include ':io.sc.platform.app-nacos'
include ':io.sc.platform.attachment'
@ -24,8 +24,8 @@ include ':io.sc.platform.core.frontend'
include ':io.sc.platform.csv'
include ':io.sc.platform.data'
include ':io.sc.platform.developer'
include ':io.sc.platform.developer.frontend'
include ':io.sc.platform.developer.doc'
include ':io.sc.platform.developer.frontend'
include ':io.sc.platform.flowable'
include ':io.sc.platform.gradle'
include ':io.sc.platform.groovy'
@ -41,10 +41,6 @@ include ':io.sc.platform.jdbc.driver.sqlite'
include ':io.sc.platform.jdbc.driver.tidb'
include ':io.sc.platform.jdbc.liquibase'
include ':io.sc.platform.jdbc.schemacrawler'
include ':io.sc.platform.scheduler.core'
include ':io.sc.platform.scheduler.executor'
include ':io.sc.platform.scheduler.manager'
include ':io.sc.platform.scheduler.manager.frontend'
include ':io.sc.platform.lcdp'
include ':io.sc.platform.lcdp.frontend'
include ':io.sc.platform.monitor'
@ -53,6 +49,11 @@ include ':io.sc.platform.mvc.frontend'
include ':io.sc.platform.orm'
include ':io.sc.platform.orm.api'
include ':io.sc.platform.orm.mybatis'
include ':io.sc.platform.poi'
include ':io.sc.platform.scheduler.core'
include ':io.sc.platform.scheduler.executor'
include ':io.sc.platform.scheduler.manager'
include ':io.sc.platform.scheduler.manager.frontend'
include ':io.sc.platform.security'
include ':io.sc.platform.security.frontend'
include ':io.sc.platform.security.loginform'

Loading…
Cancel
Save