Browse Source

基础框架发布: 8.2.41

1. 规则引擎将枚举变量替换为枚举值返回给客户端。

前端核心发布: 8.2.134
  1. 修改错误处理机制
main
wangshaoping 1 month ago
parent
commit
b3ce91b630
  1. 12
      io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue
  2. 3
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/common/service/impl/ParameterAndValueTypeServiceImpl.java
  3. 9
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/common/service/support/Property.java
  4. 4
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/dictionary/service/EnumItemService.java
  5. 33
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/dictionary/service/impl/EnumItemServiceImpl.java
  6. 41
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/ParameterEntity.java
  7. 20
      io.sc.platform.core.frontend/src/platform/plugin/manager/ServerExceptionHandler.ts
  8. 275
      io.sc.platform.core.frontend/src/views/testcase/form/form.vue
  9. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception.properties
  10. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_tw_CN.properties
  11. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_zh_CN.properties

12
io.sc.engine.rule.frontend/src/views/resources/designer/Parameter.vue

@ -281,7 +281,11 @@
name: 'componentType',
label: $t('re.addition.grid.entity.componentType'),
format: (value: any, row: any) => {
if (value) {
return $t('io.sc.engine.rule.core.enums.QualitativeAdditionComponentType.' + value);
} else {
return null;
}
},
},
{
@ -293,7 +297,13 @@
width: 70,
name: 'required',
label: $t('required'),
format: Formater.yesNo(),
format: (value: any, row: any) => {
if (row.componentType) {
return Formater.yesNo()(value);
} else {
return null;
}
},
},
{
width: 120,

3
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/common/service/impl/ParameterAndValueTypeServiceImpl.java

@ -377,10 +377,13 @@ public class ParameterAndValueTypeServiceImpl implements ParameterAndValueTypeSe
property.setType("ENUM");
if(EnumDictionaryItemValueType.STRING.equals(item.getValueType())){
property.setValueType("java.lang.String");
property.setValue(item.getValue());
}else if(EnumDictionaryItemValueType.INTEGER.equals(item.getValueType())){
property.setValueType("java.lang.Long");
property.setValue(item.getValue());
}else if(EnumDictionaryItemValueType.DECIMAL.equals(item.getValueType())){
property.setValueType("java.math.BigDecimal");
property.setValue(item.getValue());
}
// 添加枚举类型的枚举项的数据类型
buildValueType(parameterAndValueType,property.getValueType(),property.getValueTypeVersion(),locale);

9
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/common/service/support/Property.java

@ -7,6 +7,7 @@ public class Property {
private String valueType;
private Integer valueTypeVersion;
private Boolean valueTypeIsList =false;
private String value;
public String getCode() {
return code;
@ -55,4 +56,12 @@ public class Property {
public void setValueTypeIsList(Boolean valueTypeIsList) {
this.valueTypeIsList = valueTypeIsList;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

4
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/dictionary/service/EnumItemService.java

@ -4,6 +4,8 @@ import io.sc.engine.rule.server.dictionary.entity.EnumItemEntity;
import io.sc.engine.rule.server.dictionary.repository.EnumItemRepository;
import io.sc.platform.orm.service.DaoService;
public interface EnumItemService extends DaoService<EnumItemEntity, String, EnumItemRepository>{
import java.util.Map;
public interface EnumItemService extends DaoService<EnumItemEntity, String, EnumItemRepository>{
public Map<String,String> getAllEnumItemValues();
}

33
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/dictionary/service/impl/EnumItemServiceImpl.java

@ -7,12 +7,15 @@ import io.sc.engine.rule.server.dictionary.repository.EnumDictionaryRepository;
import io.sc.engine.rule.server.dictionary.repository.EnumItemRepository;
import io.sc.engine.rule.server.dictionary.service.EnumItemService;
import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.util.CollectionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service("io.sc.engine.rule.server.dictionary.service.impl.EnumItemServiceImpl")
@ -91,4 +94,34 @@ public class EnumItemServiceImpl extends DaoServiceImpl<EnumItemEntity, String,
}
return super.update(primaryKey, entity);
}
@Override
public Map<String, String> getAllEnumItemValues() {
Map<String, String> result =new HashMap<>();
List<EnumDictionaryEntity> enumDictionaryEntities =enumDictionaryRepository.findAll();
if(CollectionUtil.hasElements(enumDictionaryEntities)){
for(EnumDictionaryEntity entity : enumDictionaryEntities){
List<EnumItemEntity> items =entity.getItems();
if(CollectionUtil.hasElements(items)){
for(EnumItemEntity item : items){
String key ="#{" + entity.getCode() + (entity.getVersion()==null?"":"_V"+ entity.getVersion())+ "}.#{" + item.getCode() + "}";
String value ="";
switch (item.getValueType()){
case INTEGER:
case DECIMAL:
value =item.getValue();
break;
case STRING:
value ="\"" + item.getValue() + "\"";
break;
}
if(StringUtils.hasText(key) && StringUtils.hasText(value)) {
result.put(key, value);
}
}
}
}
}
return result;
}
}

41
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/entity/ParameterEntity.java

@ -10,16 +10,19 @@ import io.sc.engine.rule.core.enums.ReplaceMode;
import io.sc.engine.rule.server.common.CodeAndNameReplacer;
import io.sc.engine.rule.server.common.service.support.ParameterAndValueType;
import io.sc.engine.rule.server.common.service.support.ParameterCodeReplacer;
import io.sc.engine.rule.server.dictionary.service.EnumItemService;
import io.sc.engine.rule.server.model.entity.parameter.*;
import io.sc.engine.rule.server.model.vo.ParameterVo;
import io.sc.engine.rule.server.resource.entity.ResourceEntity;
import io.sc.engine.rule.server.testcase.annotation.TestCaseParameterAble;
import io.sc.engine.rule.server.testcase.wrapper.TestCaseParameterWrapper;
import io.sc.platform.core.Environment;
import io.sc.platform.orm.DeepClone;
import io.sc.platform.orm.IdClearable;
import io.sc.platform.orm.converter.MapStringConverter;
import io.sc.platform.orm.converter.NumericBooleanConverter;
import io.sc.platform.orm.entity.CorporationAuditorEntity;
import io.sc.platform.util.CollectionUtil;
import io.sc.platform.util.ObjectMapperUtil;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.beans.BeanUtils;
@ -410,12 +413,32 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> imple
return json;
}
try {
// 获取枚举项服务
EnumItemService service =Environment.getInstance().getApplicationContext().getBean(EnumItemService.class);
List<Property> properties = ObjectMapperUtil.json().readValue(json, new TypeReference<List<Property>>() {
});
for (Property property : properties) {
property.setValue(parameterAndValueType.replace(property.getValue(), mode));
property.setCalValue(parameterAndValueType.replace(property.getValue(), mode));
property.setPrompt(parameterAndValueType.replace(property.getPrompt(), mode));
property.setCalPrompt(parameterAndValueType.replace(property.getPrompt(), mode));
property.normalize();
// 将枚举值变量替换成枚举值常量,便于客户端使用
if(service!=null){
Map<String,String> items =service.getAllEnumItemValues();
if(items!=null && !items.isEmpty()){
for(String key : items.keySet()){
if(property.getCalValue()!=null) {
property.setCalValue(property.getCalValue().replace(key, items.get(key)));
}
if(property.getCalPrompt()!=null) {
property.setCalPrompt(property.getCalPrompt().replace(key, items.get(key)));
}
}
}
}
}
return ObjectMapperUtil.json().writeValueAsString(properties);
} catch (Exception e) {
@ -426,6 +449,7 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> imple
static class Property {
String name;
String value;
String calValue;
QualitativeAdditionComponentType componentType;
Boolean required;
String label;
@ -438,6 +462,7 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> imple
String attachmentExtendNames;
Integer attachmentMaxCount;
String prompt;
String calPrompt;
public void normalize(){
if(componentType==null) {
@ -501,6 +526,14 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> imple
this.value = value;
}
public String getCalValue() {
return calValue;
}
public void setCalValue(String calValue) {
this.calValue = calValue;
}
public QualitativeAdditionComponentType getComponentType() {
return componentType;
}
@ -596,6 +629,14 @@ public class ParameterEntity extends CorporationAuditorEntity<ParameterVo> imple
public void setPrompt(String prompt) {
this.prompt = prompt;
}
public String getCalPrompt() {
return calPrompt;
}
public void setCalPrompt(String calPrompt) {
this.calPrompt = calPrompt;
}
}
}

20
io.sc.platform.core.frontend/src/platform/plugin/manager/ServerExceptionHandler.ts

@ -24,6 +24,21 @@ class ServerExceptionHandler {
}
public static handle(error: ResponseErrorType) {
const exception = error?.exception;
if (exception) {
//普通错误
if ('java.lang.RuntimeException' === exception) {
// RuntimeException
if (error.errorMessage) {
//服务端指定了错误消息, 则直接使用该消息,如: throw new RuntimeException("error!");
NotifyManager.error(i18n.global.t(error.errorMessage));
} else {
//服务端未指定错误消息, 则直接显示:"服务器发生错误,请联系管理员", 如: throw new RuntimeException();
NotifyManager.error(i18n.global.t('java.lang.Exception'));
}
} else {
// 非 RuntimeException
const message = i18n.global.t(error?.errorMessageI18nKey);
if (error?.errorMessageI18nKey === message) {
NotifyManager.error(i18n.global.t('java.lang.Exception'));
@ -31,6 +46,11 @@ class ServerExceptionHandler {
NotifyManager.error(message);
}
}
} else {
//下载错误
NotifyManager.error(i18n.global.t('java.lang.Exception'));
}
}
public static getError(error: any): ResponseErrorType {
if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') {

275
io.sc.platform.core.frontend/src/views/testcase/form/form.vue

@ -1,199 +1,112 @@
<template>
<div>
<w-form
v-model="valueReactive"
:cols-num="12"
:fields="[
<w-grid
ref="i18nGridRef"
:title="$t('system.i18n.grid.title')"
:config-button="true"
db-click-operation="edit"
selection="multiple"
:checkbox-selection="true"
:data-url="Environment.apiContextPath('/api/system/i18n')"
:query-form-fields="[
{ name: 'code', label: $t('code'), type: 'w-text' },
{ name: 'message', label: $t('i18nMessage'), type: 'w-text' },
{ name: 'lang', label: $t('language'), type: 'w-select', options: Options.enum(LanguageEnum), queryOperator: 'equals' },
]"
:toolbar-configure="{ noIcon: false }"
:toolbar-actions="[
'query',
'refresh',
'separator',
'add',
'clone',
'edit',
'remove',
{
colSpan: 2,
name: 'datasource',
label: $t('developer.backend.export.liquibase.datasource'),
type: 'w-select',
options: datasourceOptionsRef,
onUpdateValue: (args) => {
datasourceChanged(args.value);
name: 'deleteAll',
label: $t('deleteAll'),
icon: 'bi-trash3',
click: () => {
DialogManager.confirm($t('system.i18n.grid.toolbar.removeAll.tip'), () => {
axios.post(Environment.apiContextPath('/api/system/i18n/removeMessages'), {}, { loading: true }).then(() => {
NotifyManager.info($t('operationSuccess'));
i18nGridRef.refresh();
});
});
},
},
'separator',
{
colSpan: 2,
name: 'catalog',
label: $t('developer.backend.export.liquibase.catalog'),
type: 'w-select',
options: catalogOptionsRef,
onUpdateValue: (args) => {
catalogChanged(valueReactive.datasource, args.value);
name: 'importAll',
label: $t('import'),
icon: 'bi-arrow-right-circle',
click: () => {
DialogManager.confirm($t('system.i18n.grid.toolbar.importAll.tip'), () => {
axios.post(Environment.apiContextPath('/api/system/i18n/importMessages'), {}, { loading: true }).then(() => {
NotifyManager.info($t('operationSuccess'));
i18nGridRef.refresh();
});
});
},
},
'separator',
{
colSpan: 2,
name: 'schema',
label: $t('developer.backend.export.liquibase.schema'),
type: 'w-select',
options: schemaOptionsRef,
onUpdateValue: (args) => {
schemaChanged(valueReactive.datasource, valueReactive.catalog, args.value);
name: 'reload',
label: $t('reload'),
icon: 'bi-arrow-repeat',
click: (args) => {
axios.post(Environment.apiContextPath('/api/system/i18n/reload')).then(() => {
NotifyManager.info($t('operationSuccess'));
});
},
},
{
colSpan: 6,
name: 'tables',
label: $t('developer.backend.export.liquibase.tables'),
type: 'w-grid-select',
multiple: true,
displayValue: 'name',
grid: {
denseBody: true,
hideBottom: true,
configButton: true,
checkboxSelection: true,
primaryKey: 'name',
dataUrl: Environment.apiContextPath(
'/api/jdbc/metadata/getTables?datasource=' +
(valueReactive.datasource || '') +
'&catalog=' +
(valueReactive.catalog || '') +
'&schema=' +
(valueReactive.schema || ''),
),
pageable: false,
sortBy: ['type', 'namec', '-lastModifyDate'],
sortNo: true,
toolbarConfigure: { noIcon: false },
toolbarActions: ['refresh'],
columns: [
{ name: 'name', label: $t('name') },
{ name: 'remarks', label: $t('remarks') },
'separator',
'view',
'separator',
'export',
]"
:columns="[
{ width: 500, name: 'code', label: $t('code') },
{ width: 100, name: 'lang', label: $t('language'), format: Formater.enum(LanguageEnum) },
{ width: '100%', name: 'message', label: $t('i18nMessage') },
]"
:editor="{
dialog: {
width: '600px',
},
form: {
colsNum: 1,
fields: [
{ name: 'code', label: $t('code'), type: 'w-text', requiredIf: true },
{ name: 'lang', label: $t('language'), type: 'w-select', requiredIf: true, options: Options.enum(LanguageEnum) },
{ name: 'message', label: $t('i18nMessage'), type: 'w-text', requiredIf: true },
],
},
}"
:viewer="{
panel: {
columnNum: 1,
fields: [
{ name: 'id', label: $t('id') },
{ name: 'code', label: $t('code') },
{ name: 'lang', label: $t('language'), format: Formater.none() },
{ name: 'message', label: $t('i18nMessage') },
{ 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') },
],
},
{ colSpan: 12, name: 'sql', label: $t('SQL'), type: 'w-code-mirror', toolbar: false, lang: 'sql' },
]"
>
</w-form>
<div class="row justify-center q-gutter-md py-2">
<w-progress-btn
ref="progressBtnRef"
icon="bi-database-down"
:label="$t('export')"
data-url="/api/jdbc/data/traceExporterExecuteProgress"
@click="exportData"
@success="
(progressInfo) => {
Downloader.get(Environment.apiContextPath('/api/mvc/download?filePath=' + encodeURIComponent(progressInfo.result)));
}
"
></w-progress-btn>
</div>
</div>
}"
@row-click="(evt, row, index) => {}"
></w-grid>
</template>
<script setup lang="ts">
import 'tailwindcss/utilities.css';
import { ref, reactive, onMounted, onUpdated } from 'vue';
import { t, axios, Environment, DialogManager, Downloader } from '@/platform';
const progressBtnRef = ref();
const datasourceOptionsRef = ref([]);
const catalogOptionsRef = ref([]);
const schemaOptionsRef = ref([]);
const tablesOptionsRef = ref([]);
import { ref } from 'vue';
import { axios, Environment, EnumTools, Formater, Options, DialogManager, NotifyManager } from '@/platform';
const valueReactive = reactive({
datasource: undefined,
catalog: undefined,
schema: undefined,
tables: [],
sql: undefined,
});
const loadDatasource = () => {
axios.get(Environment.apiContextPath('/api/system/datasource?pageable=false&sortBy=name')).then((response) => {
const data = response?.data.content;
const datasourceOptions = [{ label: t('default'), value: '' }];
if (data && data.length > 0) {
for (let item of data) {
datasourceOptions.push({ label: item.name, value: item.name });
}
}
datasourceOptionsRef.value = datasourceOptions;
});
};
const datasourceChanged = (datasource: string) => {
datasource = datasource || '';
axios.get(Environment.apiContextPath('/api/jdbc/metadata/getCatalogs?datasource=' + datasource)).then((response) => {
const data = response?.data;
const catalogOptions = [];
if (data && data.length > 0) {
for (let item of data) {
catalogOptions.push({ label: item.name, value: item.name });
}
}
catalogOptionsRef.value = catalogOptions;
schemaOptionsRef.value = [];
tablesOptionsRef.value = [];
});
};
const catalogChanged = (datasource: string, catalog: string) => {
datasource = datasource || '';
axios.get(Environment.apiContextPath('/api/jdbc/metadata/getSchemas?datasource=' + datasource + '&catalog=' + catalog)).then((response) => {
const data = response?.data;
const schemaOptions = [];
if (data && data.length > 0) {
for (let item of data) {
schemaOptions.push({ label: item.name, value: item.name });
}
}
schemaOptionsRef.value = schemaOptions;
tablesOptionsRef.value = [];
if (schemaOptions.length === 0) {
schemaChanged(datasource, catalog, '');
} else if (schemaOptions.length === 1) {
schemaChanged(datasource, catalog, schemaOptions[0]);
}
});
};
const schemaChanged = (datasource: string, catalog: string, schema: string) => {
datasource = datasource || '';
catalog = catalog || '';
schema = schema || '';
axios
.get(Environment.apiContextPath('/api/jdbc/metadata/getTables?datasource=' + datasource + '&catalog=' + catalog + '&schema=' + schema))
.then((response) => {
const data = response?.data;
const tablesOptions = [];
if (data && data.length > 0) {
for (let item of data) {
tablesOptions.push({ label: item.name + ' - ' + item.remarks, value: item.name });
}
}
tablesOptionsRef.value = tablesOptions;
});
};
const exportData = (e) => {
DialogManager.confirm(t('developer.backend.export.liquibase.export.tip'), () => {
const data = valueReactive;
const config = {
datasource: data.datasource,
schema: data.schema,
tables: [],
};
const length = data.tables.length;
const sql = length === 1 ? data.sql : '';
for (let i = 0; i < length; i++) {
config.tables[i] = { name: data.tables[i], sql: sql ? sql : 'select * from ' + data.tables[i] };
}
axios.post(Environment.apiContextPath('/api/jdbc/data/exportData'), config).then((response) => {
progressBtnRef.value.start();
});
});
};
onMounted(() => {
loadDatasource();
datasourceChanged('');
});
const i18nGridRef = ref();
const LanguageEnum = await EnumTools.fetch('io.sc.platform.core.enums.Language');
</script>

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception.properties

@ -1,4 +1,4 @@
java.lang.Exception=Server Error\uFF01 Please try again.
java.lang.Exception=Server Error\uFF01 Please Contact the Administrator.
io.sc.platform.core.response.ValidateException=Request Parameter Validate Error
io.sc.platform.core.exception.PasswordStrengthException=Password must contain uppercase, lowercase, numbers, special characters, and must be greater than or equal to {0} in length.
io.sc.platform.core.exception.LicenseInvalidatedException=License Invalidated!

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_tw_CN.properties

@ -1,4 +1,4 @@
java.lang.Exception=\u670D\u52D9\u5668\u932F\u8AA4\uFF01\u8ACB\u91CD\u65B0\u5617\u8A66\u4E00\u6B21.
java.lang.Exception=\u670D\u52D9\u5668\u53D1\u751F\u932F\u8AA4\uFF01\u8ACB\u806F\u7E6B\u7CFB\u7D71\u7BA1\u7406\u54E1.
io.sc.platform.core.response.ValidateException=\u8ACB\u6C42\u53C3\u6578\u9A57\u8B49\u932F\u8AA4
io.sc.platform.core.exception.PasswordStrengthException=\u5BC6\u78BC\u5FC5\u9808\u5305\u542B:\u5927\u5BEB\u5B57\u6BCD\u3001\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u3001\u7279\u6B8A\u5B57\u7B26, \u4E14\u9577\u5EA6\u5FC5\u9808\u5927\u65BC\u7B49\u65BC {0} \u4E2A\u3002
io.sc.platform.core.exception.LicenseInvalidatedException=\u8A31\u53EF\u8B49\u5931\u6548!

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_zh_CN.properties

@ -1,4 +1,4 @@
java.lang.Exception=\u670D\u52A1\u5668\u9519\u8BEF\uFF01\u8BF7\u91CD\u65B0\u5C1D\u8BD5\u4E00\u6B21.
java.lang.Exception=\u670D\u52A1\u5668\u9519\u8BEF\uFF01\u8BF7\u8054\u7CFB\u7CFB\u7EDF\u7BA1\u7406\u5458.
io.sc.platform.core.response.ValidateException=\u8BF7\u6C42\u53C2\u6570\u9A8C\u8BC1\u9519\u8BEF
io.sc.platform.core.exception.PasswordStrengthException=\u5BC6\u7801\u5FC5\u987B\u5305\u542B:\u5927\u5199\u5B57\u6BCD\u3001\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u7279\u6B8A\u5B57\u7B26, \u4E14\u957F\u5EA6\u5FC5\u987B\u5927\u4E8E\u7B49\u4E8E {0} \u4E2A\u3002
io.sc.platform.core.exception.LicenseInvalidatedException=\u8BB8\u53EF\u8BC1\u5931\u6548!
Loading…
Cancel
Save