Browse Source

update

main
wangshaoping 8 months ago
parent
commit
a120337cff
  1. 2
      io.sc.engine.rule.frontend/package.json
  2. 1
      io.sc.engine.rule.frontend/src/i18n/messages.json
  3. 1
      io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json
  4. 1
      io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
  5. 20
      io.sc.engine.rule.frontend/src/utils/PlaceHolder.ts
  6. 96
      io.sc.engine.rule.frontend/src/views/resources/designer/GroovyFunctions.ts
  7. 361
      io.sc.engine.rule.frontend/src/views/resources/designer/Processor.vue
  8. 2
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/service/impl/ParameterServiceImpl.java
  9. 2
      io.sc.platform.core.frontend/package.json
  10. 42
      io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue
  11. 26
      io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts
  12. 7
      io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue
  13. 4
      io.sc.platform.core.frontend/template-project/package.json
  14. 7
      io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/code-mirror.vue
  15. 108
      io.sc.platform.core/src/main/resources/io/sc/platform/core/config/logback-spring.xml

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
"platform-core": "8.1.237",
"platform-core": "8.1.244",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",

1
io.sc.engine.rule.frontend/src/i18n/messages.json

@ -87,6 +87,7 @@
"re.resources.designer.processor.grid.entity.numberRange": "Number Range",
"re.resources.designer.processor.grid.entity.conditionRangeVar": "Condition Range",
"re.resources.designer.processor.grid.entity.conditionRange": "Condition Range",
"re.resources.designer.processor.grid.entity.pmml": "PMML",
"re.resources.designer.processor.grid.entity.decisionTable2C": "Simple Decision Table",
"re.resources.designer.processor.grid.entity.decisionTable": "Decision Table",
"re.resources.designer.processor.grid.entity.groovyScript": "Groovy Script",

1
io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json

@ -87,6 +87,7 @@
"re.resources.designer.processor.grid.entity.numberRange": "數值分段",
"re.resources.designer.processor.grid.entity.conditionRangeVar": "條件分段",
"re.resources.designer.processor.grid.entity.conditionRange": "條件分段",
"re.resources.designer.processor.grid.entity.pmml": "PMML",
"re.resources.designer.processor.grid.entity.decisionTable2C": "簡單決策表",
"re.resources.designer.processor.grid.entity.decisionTable": "決策表",
"re.resources.designer.processor.grid.entity.groovyScript": "腳本代碼",

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

@ -87,6 +87,7 @@
"re.resources.designer.processor.grid.entity.numberRange": "数值分段",
"re.resources.designer.processor.grid.entity.conditionRangeVar": "条件分段",
"re.resources.designer.processor.grid.entity.conditionRange": "条件分段",
"re.resources.designer.processor.grid.entity.pmml": "PMML",
"re.resources.designer.processor.grid.entity.decisionTable2C": "简单决策表",
"re.resources.designer.processor.grid.entity.decisionTable": "决策表",
"re.resources.designer.processor.grid.entity.groovyScript": "脚本代码",

20
io.sc.engine.rule.frontend/src/utils/PlaceHolder.ts

@ -0,0 +1,20 @@
import { Tools } from 'platform-core';
class PlaceHolder {
static #prefix: string = '<span class="p-0.5"><span class="p-0.5 border border-gray-800 rounded-md">';
static #suffix: string = '</span></span>';
public static replace(str, prefix, suffix) {
if (str) {
if (Tools.isUndefinedOrNull(prefix)) {
prefix = PlaceHolder.#prefix;
}
if (Tools.isUndefinedOrNull(suffix)) {
suffix = PlaceHolder.#suffix;
}
return str.replace(/\$\{(.+?)\}/g, prefix + '$1' + suffix);
}
return str;
}
}
export { PlaceHolder };

96
io.sc.engine.rule.frontend/src/views/resources/designer/GroovyFunctions.ts

@ -1,42 +1,66 @@
const GroovyFunctions = [
{ label: 'PI', type: 'constant', apply: 'PI', detail: '常量 π' },
{ label: 'E', type: 'constant', apply: 'E', detail: '常量 e' },
{ label: 'IEEEremainder(v1,v2)', type: 'function', apply: 'IEEEremainder(v1,v2)', detail: '根据 IEEE 754 标准返回 v1 除以 v2 的余数' },
{ label: 'abs(v)', type: 'function', apply: 'abs(v)', detail: '绝对值' },
{ label: 'acos(v)', type: 'function', apply: 'acos(v)', detail: '反余弦' },
{ label: 'asin(v)', type: 'function', apply: 'asin(v)', detail: '反正弦' },
{ label: 'atan(v)', type: 'function', apply: 'atan(v)', detail: '' },
{ label: 'atan2(v)', type: 'function', apply: 'atan2(v)', detail: '' },
{ label: 'cbrt(v)', type: 'function', apply: 'cbrt(v)', detail: '' },
{ label: 'ceil(v)', type: 'function', apply: 'ceil(v)', detail: '' },
{ label: 'cos(v)', type: 'function', apply: 'cos(v)', detail: '' },
{ label: 'cosh(v)', type: 'function', apply: 'cosh(v)', detail: '' },
{ label: 'exp(v)', type: 'function', apply: 'exp(v)', detail: '' },
{ label: 'expm1(v)', type: 'function', apply: 'expm1(v)', detail: '' },
{ label: 'floor(v)', type: 'function', apply: 'floor(v)', detail: '' },
{ label: 'inverseNormalDistributioin(x)', type: 'function', apply: 'inverseNormalDistributioin(x)', detail: '' },
{ label: 'join(split,s1,s2,s3...,sn)', type: 'function', apply: 'join(split,s1,s2,s3...,sn)', detail: '' },
{ label: 'ln(v)', type: 'function', apply: 'ln(v)', detail: '' },
{ label: 'max(v1,v2,...)', type: 'function', apply: 'max(v1,v2,...)', detail: '' },
{ label: 'min(v1,v2,...)', type: 'function', apply: 'min(v1,v2,...)', detail: '' },
{ label: 'normalDistributioin(x)', type: 'function', apply: 'normalDistributioin(x)', detail: '' },
{ label: 'pow(x,y)', type: 'function', apply: 'pow(x,y)', detail: '' },
{ label: 'random()', type: 'function', apply: 'random()', detail: '' },
{ label: 'rint(v)', type: 'function', apply: 'rint(v)', detail: '' },
{ label: 'round(v)', type: 'function', apply: 'round(v)', detail: '' },
{ label: 'sin(v)', type: 'function', apply: 'sin(v)', detail: '' },
{ label: 'sinh(v)', type: 'function', apply: 'sinh(v)', detail: '' },
{ label: 'sqrt(v)', type: 'function', apply: 'sqrt(v)', detail: '' },
{ label: 'sum(v1,v2,...)', type: 'function', apply: 'sum(v1,v2,...)', detail: '' },
{ label: 'tan(v)', type: 'function', apply: 'tan(v)', detail: '' },
{ label: 'tanh(v)', type: 'function', apply: 'tanh(v)', detail: '' },
{ label: 'toDegrees(v)', type: 'function', apply: 'toDegrees(v)', detail: '' },
{ label: 'toRadians(v)', type: 'function', apply: 'toRadians(v)', detail: '' },
{ boost: -50, label: '==', type: 'keyword', apply: '==', detail: '等于', info: '等于' },
{ boost: -50, label: '>', type: 'keyword', apply: '>', detail: '大于', info: '大于' },
{ boost: -50, label: '>=', type: 'keyword', apply: '>=', detail: '大于等于', info: '大于等于' },
{ boost: -50, label: '<', type: 'keyword', apply: '<', detail: '小于', info: '小于' },
{ boost: -50, label: '<=', type: 'keyword', apply: '<=', detail: '小于等于', info: '小于等于' },
{ boost: -50, label: '&&', type: 'keyword', apply: '&&', detail: '并且', info: '并且' },
{ boost: -50, label: '||', type: 'keyword', apply: '||', detail: '或者', info: '或者' },
{ boost: -50, label: '!', type: 'keyword', apply: '!', detail: '非', info: '非' },
{ boost: -60, label: 'PI', type: 'constant', apply: 'PI', detail: '常量 π', info: '常量 π' },
{ boost: -60, label: 'E', type: 'constant', apply: 'E', detail: '常量 e', info: '常量 e' },
{
label: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
boost: -70,
label: 'IEEEremainder(v1,v2)',
type: 'function',
apply: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
detail: '',
apply: 'IEEEremainder(v1,v2)',
detail: '余数',
info: '根据 IEEE 754 标准返回 v1 除以 v2 的余数',
},
{ boost: -70, label: 'abs(v)', type: 'function', apply: 'abs(v)', detail: '绝对值', info: '绝对值' },
{ boost: -70, label: 'acos(v)', type: 'function', apply: 'acos(v)', detail: '反余弦', info: '反余弦' },
{ boost: -70, label: 'asin(v)', type: 'function', apply: 'asin(v)', detail: '反正弦', info: '大于' },
{ boost: -70, label: 'atan(v)', type: 'function', apply: 'atan(v)', detail: '反正切', info: '反正切' },
{ boost: -70, label: 'atan2(v)', type: 'function', apply: 'atan2(v)', detail: '', info: '大于' },
{ boost: -70, label: 'cbrt(v)', type: 'function', apply: 'cbrt(v)', detail: '立方根', info: '立方根' },
{ boost: -70, label: 'ceil(v)', type: 'function', apply: 'ceil(v)', detail: '向上取整', info: '返回大于或等于 v 的最接近的整数' },
{ boost: -70, label: 'cos(v)', type: 'function', apply: 'cos(v)', detail: '余弦', info: '余弦' },
{ boost: -70, label: 'cosh(v)', type: 'function', apply: 'cosh(v)', detail: '双曲余弦', info: '双曲余弦' },
{ boost: -70, label: 'exp(v)', type: 'function', apply: 'exp(v)', detail: 'e 的 v 次方', info: 'e 的 v 次方' },
{ boost: -70, label: 'expm1(v)', type: 'function', apply: 'expm1(v)', detail: '', info: '大于' },
{ boost: -70, label: 'floor(v)', type: 'function', apply: 'floor(v)', detail: '向下取整', info: '返回小于或等于 v 的最接近的整数' },
{ boost: -70, label: 'inverseNormalDistributioin(x)', type: 'function', apply: 'inverseNormalDistributioin(x)', detail: '反正态分布', info: '反正态分布' },
{
boost: -70,
label: 'join(split,V1,V2,V3...,Vn)',
type: 'function',
apply: 'join(split,V1,V2,V3...,Vn)',
detail: '字符串连接',
info: '采用 split 分隔符连接 V1, V2, V3..., Vn',
},
{ boost: -70, label: 'ln(v)', type: 'function', apply: 'ln(v)', detail: '自然对数', info: '自然对数' },
{ boost: -70, label: 'max(V1,V2,V3...,Vn)', type: 'function', apply: 'max(V1,V2,V3...,Vn)', detail: '最大值', info: '返回 V1, V2, V3..., Vn 中最大的那个值' },
{ boost: -70, label: 'min(v1,v2,...)', type: 'function', apply: 'min(v1,v2,...)', detail: '最小值', info: '返回 V1, V2, V3..., Vn 中最小的那个值' },
{ boost: -70, label: 'normalDistributioin(x)', type: 'function', apply: 'normalDistributioin(x)', detail: '正态分布', info: '正态分布' },
{ boost: -70, label: 'pow(x,y)', type: 'function', apply: 'pow(x,y)', detail: '指数', info: '返回 x 的 y 次方' },
{ boost: -70, label: 'random()', type: 'function', apply: 'random()', detail: '随机数', info: '返回 0 ~ 1 之间的一个随机数' },
{ boost: -70, label: 'rint(v)', type: 'function', apply: 'rint(v)', detail: '最近整数', info: '返回和 v 最接近的整数' },
{ boost: -70, label: 'round(v)', type: 'function', apply: 'round(v)', detail: '四舍五入', info: '四舍五入' },
{ boost: -70, label: 'sin(v)', type: 'function', apply: 'sin(v)', detail: '正弦', info: '正弦' },
{ boost: -70, label: 'sinh(v)', type: 'function', apply: 'sinh(v)', detail: '双曲正弦', info: '双曲正弦' },
{ boost: -70, label: 'sqrt(v)', type: 'function', apply: 'sqrt(v)', detail: '平方根', info: '平方根' },
{ boost: -70, label: 'sum(V1,V2,V3...,Vn)', type: 'function', apply: 'sum(V1,V2,V3...,Vn)', detail: '求和', info: '返回 V1, V2, V3..., Vn 的和' },
{ boost: -70, label: 'tan(v)', type: 'function', apply: 'tan(v)', detail: '正切', info: '正切' },
{ boost: -70, label: 'tanh(v)', type: 'function', apply: 'tanh(v)', detail: '双曲正切', info: '双曲正切' },
{ boost: -70, label: 'toDegrees(v)', type: 'function', apply: 'toDegrees(v)', detail: '幅度转角度', info: '返回 v 的角度值' },
{ boost: -70, label: 'toRadians(v)', type: 'function', apply: 'toRadians(v)', detail: '角度转幅度', info: '返回 v 的幅度值' },
{
boost: -70,
label: 'transformSequencing(v,si,sm,ti,tm)',
type: 'function',
apply: 'transformSequencing(v,si,sm,ti,tm)',
detail: '缩放',
info: '根据 v 所在 si 和 sm 的位置, 缩放到 ti 和 tm 对应的位置',
},
];

361
io.sc.engine.rule.frontend/src/views/resources/designer/Processor.vue

@ -205,6 +205,33 @@
'edit',
'remove',
'separator',
{
name: 'enable',
label: (arg) => {
if (arg.selected?.enable) {
return $t('disable');
}
return $t('enable');
},
icon: (arg) => {
if (arg.selected?.enable) {
return 'x';
}
return 'check';
},
enableIf: (arg) => {
return arg.selected;
},
click: (arg) => {
const data = arg.selected;
data.enable = !data.enable;
console.log(data);
axios.put(Environment.apiContextPath('/api/re/model/parameter/' + data.id), data).then((response) => {
gridRef.replaceRow(response.data);
});
},
},
'separator',
'view',
'separator',
'export',
@ -223,32 +250,51 @@
if ('OPTION_VALUE' === type) {
return row.optionCode;
} else if ('ARITHMETIC' === type) {
return row.arithmetic;
return PlaceHolder.replace(row.arithmetic);
} else if ('TERNARY' === type) {
return row.ternaryCondition + ' <b><span>?</span></b> ' + row.ternaryTrue + ' <b><span>:</span></b> ' + row.ternaryFalse;
} else if ('WHEN_THEN' === type) {
var str = '';
let str = '';
if (row.isWhenThenShorted) {
str += '<span>' + $t('re.resources.designer.processor.grid.entity.isWhenThenShorted') + ', </span>';
}
if (row.when) {
str += '<span>When</span> ' + row.when + ' ';
str += '<span>When</span> ' + PlaceHolder.replace(row.when) + ' ';
}
if (row.then) {
str += '<span>Then</span> ' + row.then;
str += '<span>Then</span> ' + PlaceHolder.replace(row.then);
}
return str;
} else if ('NUMBER_RANGE' === type) {
var objs = Tools.json2Object(row.numberRange);
const objs = Tools.json2Object(row.numberRange);
if (objs) {
var str = '<div>' + row.numberRangeVar + ':</div>';
str += `<div class='border'>`;
let str = `<div class='border border-b-0'>`;
str += `<table width='100%'>`;
for (var i = 0; i < objs.length; i++) {
var obj = objs[i];
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
str += '<tr>';
if (i == 0) {
str += ' <td rowspan=' + objs.length + '>' + PlaceHolder.replace(row.numberRangeVar) + '</td>';
}
str += ' <td>' + Tools.generateIntervalRange(obj.minIncluded, obj.min, obj.max, obj.maxIncluded) + '</td>';
str += ' <td><span>' + ('' + obj.value) + '</span></td>';
str += ' <td>' + ('' + PlaceHolder.replace('' + obj.value)) + '</td>';
str += '</tr>';
}
str += '</table>';
str += '</div>';
return str;
}
return '';
} else if ('CONDITION_RANGE' === type) {
const objs = Tools.json2Object(row.conditionRange);
if (objs) {
let str = `<div class='border border-b-0'>`;
str += `<table width='100%'>`;
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
str += '<tr>';
str += ' <td>' + PlaceHolder.replace(obj.condition) + '</td>';
str += ' <td><span>' + ('' + PlaceHolder.replace(obj.value)) + '</span></td>';
str += '</tr>';
}
str += '</table>';
@ -256,13 +302,21 @@
return str;
}
return '';
} else if ('PMML' === type) {
return {
componentType: 'w-code-mirror',
bindModelValue: true,
attrs: {
rows: 3,
},
};
}
},
},
]"
:editor="{
dialog: {
width: '600px',
width: '800px',
},
form: {
colsNum: 1,
@ -271,8 +325,8 @@
{ name: 'id', label: $t('id'), type: 'text', hidden: true },
{ name: 'order', label: $t('order'), type: 'number', hidden: true },
{ name: 'type', label: $t('type'), type: 'text', hidden: true },
{ name: 'description', label: $t('description'), type: 'text' },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true },
{ name: 'description', label: $t('description'), type: 'text', hidden: true },
{ name: 'enable', label: $t('enable'), type: 'checkbox', defaultValue: true, hidden: true },
{
name: 'optionCode',
label: $t('re.resources.designer.processor.grid.entity.optionCode'),
@ -288,6 +342,8 @@
type: 'code-mirror',
lang: 'java',
rows: 5,
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -300,7 +356,8 @@
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -313,7 +370,8 @@
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -326,7 +384,8 @@
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -339,7 +398,8 @@
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -352,7 +412,8 @@
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
@ -370,45 +431,232 @@
{
name: 'numberRangeVar',
label: $t('re.resources.designer.processor.grid.entity.numberRangeVar'),
showIf: (arg) => {
return 'NUMBER_RANGE' === arg.form.getFieldValue('type');
},
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {
return 'NUMBER_RANGE' === arg.form.getFieldValue('type');
},
},
{
name: 'numberRange',
label: $t('re.resources.designer.processor.grid.entity.numberRange'),
showIf: (arg) => {
return 'NUMBER_RANGE' === arg.form.getFieldValue('type');
},
type: 'w-grid',
height: 300,
denseBody: true,
draggable: true,
pageable: false,
configButton: false,
toolbarConfigure: { noIcon: false },
toolbarActions: ['add', 'clone', 'remove'],
toolbarActions: [
'add',
'clone',
'edit',
{
extend: 'remove',
click: (arg) => {
const grid = gridRef.getEditorForm().getFieldComponent('numberRange');
grid.removeRows(arg.selecteds);
},
},
'separator',
{
name: 'example',
label: $t('example'),
icon: 'bi-balloon',
click: (arg) => {
const grid = gridRef.getEditorForm().getFieldComponent('numberRange');
const sampleData = [
{ uuid: Tools.uuid(), minIncluded: false, min: null, max: 0, maxIncluded: false, value: 1 },
{ uuid: Tools.uuid(), minIncluded: true, min: 0, max: 1, maxIncluded: false, value: 2 },
{ uuid: Tools.uuid(), minIncluded: true, min: 1, max: 2, maxIncluded: false, value: 3 },
{ uuid: Tools.uuid(), minIncluded: true, min: 2, max: 3, maxIncluded: false, value: 4 },
{ uuid: Tools.uuid(), minIncluded: true, min: 3, max: null, maxIncluded: false, value: 5 },
{ uuid: Tools.uuid(), minIncluded: false, min: null, max: null, maxIncluded: false, value: 0 },
];
grid.setLocalData(sampleData);
},
},
],
primaryKey: 'uuid',
columns: [
{ width: 200, name: 'uuid', label: 'uuid', hidden: true },
{ width: 60, name: 'minIncluded', label: $t('include') },
{ width: 100, name: 'min', label: $t('minValue'), align: 'center' },
{ width: 100, name: 'max', label: $t('maxValue'), align: 'center' },
{ width: 60, name: 'maxIncluded', label: $t('include'), type: 'boolean' },
{ width: '100%', name: 'value', label: $t('value') },
{
width: 60,
name: 'minIncluded',
label: $t('include'),
align: 'center',
sortable: false,
format: (value) => {
if (value) {
return '[';
} else {
return '(';
}
},
},
{ width: 100, name: 'min', label: $t('minValue'), align: 'right', sortable: false },
{ width: 100, name: 'max', label: $t('maxValue'), align: 'right', sortable: false },
{
width: 60,
name: 'maxIncluded',
label: $t('include'),
align: 'center',
sortable: false,
format: (value) => {
if (value) {
return '[';
} else {
return ')';
}
},
},
{ width: '100%', name: 'value', label: $t('value'), sortable: false },
],
showIf: (arg) => {
return 'NUMBER_RANGE' === arg.form.getFieldValue('type');
editor: {
dialog: {
width: '600px',
},
form: {
colsNum: 4,
fields: [
{ name: 'uuid', label: 'uuid', hidden: true, colSpan: 4 },
{ name: 'min', label: $t('minValue'), type: 'text', colSpan: 3 },
{ name: 'minIncluded', label: $t('include'), type: 'checkbox' },
{ name: 'max', label: $t('maxValue'), type: 'text', colSpan: 3 },
{ name: 'maxIncluded', label: $t('include'), type: 'checkbox' },
{ name: 'value', label: $t('value'), type: 'number', colSpan: 3 },
],
},
},
onBeforeEditorDataSubmit: (data, callback) => {
const grid = gridRef.getEditorForm().getFieldComponent('numberRange');
const form = grid.getEditorForm();
if ('add' == form.getStatus() || 'clone' == form.getStatus()) {
data.uuid = Tools.uuid();
grid.addRow(data);
callback(false);
} else if ('edit' == form.getStatus()) {
grid.replaceRow(data);
callback(false);
}
},
},
{
name: 'conditionRange',
label: $t('re.resources.designer.processor.grid.entity.conditionRange'),
type: 'code-mirror',
rows: 1,
showIf: (arg) => {
return 'CONDITION_RANGE' === arg.form.getFieldValue('type');
},
type: 'w-grid',
height: 300,
denseBody: true,
draggable: true,
pageable: false,
configButton: false,
toolbarConfigure: { noIcon: false },
toolbarActions: [
'add',
'clone',
'edit',
{
extend: 'remove',
click: (arg) => {
const grid = gridRef.getEditorForm().getFieldComponent('conditionRange');
grid.removeRows(arg.selecteds);
},
},
'separator',
{
name: 'example',
label: $t('example'),
icon: 'bi-balloon',
click: (arg) => {
const grid = gridRef.getEditorForm().getFieldComponent('conditionRange');
const sampleData = [
{ uuid: Tools.uuid(), condition: '${变量名}<=0', value: '0' },
{ uuid: Tools.uuid(), condition: '${变量名}>0 && ${变量名}<=50', value: '50' },
{ uuid: Tools.uuid(), condition: '${变量名}>50 && ${变量名}<=80', value: '80' },
{ uuid: Tools.uuid(), condition: '${变量名}>80 && ${变量名}<=100', value: '100' },
{ uuid: Tools.uuid(), condition: '${变量名}>100', value: '60' },
];
grid.setLocalData(sampleData);
},
},
],
primaryKey: 'uuid',
columns: [
{ name: 'uuid', label: 'uuid', hidden: true },
{
name: 'condition',
label: $t('condition'),
align: 'left',
sortable: false,
format: (value) => {
return PlaceHolder.replace(value);
},
},
{
name: 'value',
label: $t('value'),
sortable: false,
format: (value) => {
return PlaceHolder.replace(value);
},
},
],
editor: {
dialog: {
width: '600px',
},
form: {
colsNum: 1,
fields: [
{ name: 'uuid', label: 'uuid', hidden: true },
{
name: 'condition',
label: $t('condition'),
type: 'code-mirror',
lang: 'java',
rows: 1,
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
},
{
name: 'value',
label: $t('value'),
type: 'code-mirror',
lang: 'java',
rows: 1,
placeholder: true,
autoCompletion: true,
autoCompletionOptions: autoCompletionOptionsRef,
extAutoCompletionOptions: GroovyFunctions,
},
],
},
},
onBeforeEditorDataSubmit: (data, callback) => {
const grid = gridRef.getEditorForm().getFieldComponent('conditionRange');
const form = grid.getEditorForm();
if ('add' == form.getStatus() || 'clone' == form.getStatus()) {
data.uuid = Tools.uuid();
grid.addRow(data);
callback(false);
} else if ('edit' == form.getStatus()) {
grid.replaceRow(data);
callback(false);
}
},
},
{
name: 'decisionTable2C',
@ -450,7 +698,9 @@
name: 'pmml',
label: $t('re.resources.designer.processor.grid.entity.pmml'),
type: 'code-mirror',
rows: 1,
rows: 10,
lineNumber: true,
lang: 'xml',
showIf: (arg) => {
return 'PMML' === arg.form.getFieldValue('type');
},
@ -544,6 +794,39 @@
],
},
}"
@before-editor-data-submit="
(data, callback) => {
const form = gridRef.getEditorForm();
if ('NUMBER_RANGE' === data.type) {
const grid = form.getFieldComponent('numberRange');
const localData = grid.getLocalData();
const ranges = [];
for (const item of localData) {
ranges.push({
uuid: item.uuid,
minIncluded: item.minIncluded,
min: item.min,
max: item.max,
maxIncluded: item.maxIncluded,
value: item.value,
});
}
data.numberRange = Tools.object2Json(ranges);
} else if ('CONDITION_RANGE' === data.type) {
const grid = form.getFieldComponent('conditionRange');
const localData = grid.getLocalData();
const ranges = [];
for (const item of localData) {
ranges.push({
uuid: item.uuid,
condition: item.condition,
value: item.value,
});
}
data.conditionRange = Tools.object2Json(ranges);
}
}
"
@after-editor-open="
(row) => {
axios.get(Environment.apiContextPath('/api/re/model/parameter/listParemterHintsByParameterId/' + parameter.id)).then((response) => {
@ -572,9 +855,13 @@
optionOptionsRef = parameters;
});
if ('NUMBER_RANGE' === row.type) {
const fields = gridRef.getEditorForm().getFields();
console.log(fields);
numberRangeGridRef.setLocalData(Tools.json2Object(row.numberRange));
const grid = gridRef.getEditorForm().getFieldComponent('numberRange');
const rows = Tools.json2Object(row.numberRange);
grid.setLocalData(rows);
} else if ('CONDITION_RANGE' === row.type) {
const grid = gridRef.getEditorForm().getFieldComponent('conditionRange');
const rows = Tools.json2Object(row.conditionRange);
grid.setLocalData(rows);
}
}
"
@ -583,6 +870,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { axios, Environment, Formater, Tools, EnumTools, Options } from 'platform-core';
import { PlaceHolder } from '@/utils/PlaceHolder';
import GroovyFunctions from './GroovyFunctions';
const props = defineProps({
@ -599,7 +887,6 @@ const emit = defineEmits<{
const gridRef = ref();
const autoCompletionOptionsRef = ref([]);
const optionOptionsRef = ref([]);
const numberRangeGridRef = ref();
const refresh = () => {
gridRef.value.refresh();

2
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/model/service/impl/ParameterServiceImpl.java

@ -60,7 +60,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.util.*;
@Service("reParameterService")
@Service("io.sc.engine.rule.server.model.service.impl.ParameterServiceImpl")
public class ParameterServiceImpl extends DaoServiceImpl<ParameterEntity, String, ParameterRepository> implements ParameterService{
@Autowired private ApplicationContext applicationContext;
@Autowired private ModelService modelService;

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

@ -1,6 +1,6 @@
{
"name": "platform-core",
"version": "8.1.240",
"version": "8.1.244",
"description": "前端核心包,用于快速构建前端的脚手架",
"//main": "库的主文件",
"main": "dist/platform-core.js",

42
io.sc.platform.core.frontend/src/platform/components/form/elements/WCodeMirror.vue

@ -20,7 +20,7 @@
>
<template #label> <span v-if="requiredIfComputed" style="color: red">*</span> {{ attrs.label }}</template>
<template #control>
<div ref="codemirrorRef" style="width: 100%" @focus.stop.prevent="() => {}" @click.stop.prevent="() => {}"></div>
<div ref="codemirrorRef" style="padding-top: 8px; padding-bottom: 4px; width: 100%" @focus.stop.prevent="() => {}" @click.stop.prevent="() => {}"></div>
</template>
<template v-if="!Tools.isEmpty(codeMirrorValue) && attrs.button" #append>
<q-btn
@ -70,7 +70,15 @@ const props = defineProps({
type: Function,
default: () => {},
},
modelValue: { type: String, default: '' },
modelValue: { type: [Number, String], default: '' },
lang: { type: String, default: 'json' },
width: { type: [Number, String], default: '100%' },
height: { type: [Number, String], default: undefined },
rows: { type: Number, default: 4 },
tabSize: { type: Number, default: 4 },
lineNumber: { type: Boolean, default: false },
autoCompletion: { type: Boolean, default: false },
placeholder: { type: Boolean, default: false },
autoCompletionOptions: {
type: Array,
default: () => {
@ -83,11 +91,6 @@ const props = defineProps({
return [];
},
},
lang: { type: String, default: 'json' },
width: { type: [Number, String], default: '100%' },
height: { type: [Number, String], default: undefined },
rows: { type: Number, default: 4 },
tabSize: { type: Number, default: 4 },
showIf: {
type: Function,
default: () => {
@ -250,7 +253,7 @@ const autoCompletionFunction = (context: autocomplete.CompletionContext) => {
};
};
const autoCompletion = (lang: string) => {
const createAutoCompletion = (lang: string) => {
lang = lang || 'json';
switch (lang.toLowerCase()) {
case 'html':
@ -279,6 +282,19 @@ const stackLabelRef = ref(!Tools.isUndefinedOrNull(codeMirrorValue.value));
let editorView;
let isFocus = false;
if (props.lineNumber) {
//
basicSetup.push(view.lineNumbers());
}
if (props.autoCompletion) {
//
basicSetup.push(createAutoCompletion(props.lang));
}
if (props.placeholder) {
//
basicSetup.push(PlaceholderPlugin);
}
onMounted(() => {
if (codemirrorRef.value) {
let language = new Compartment();
@ -293,13 +309,12 @@ onMounted(() => {
'&': {
outline: 'none !important',
width: Tools.px(props.width),
height: props.height ? Tools.px(props.height) : props.rows * 22 + 'px',
height: props.height ? Tools.px(props.height) : props.rows * 20 + 8 + 'px',
},
'.cm-content': {
'line-height': '20px',
},
}),
// java
autoCompletion(props.lang),
//
PlaceholderPlugin,
// , , blur
EditorView.updateListener.of(function (e) {
// emits('update:modelValue', e.state.doc.toString());
@ -378,4 +393,3 @@ defineExpose({
configure,
});
</script>
./w-code-mirror/GroovyFunctions

26
io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts

@ -11,15 +11,16 @@ class PlaceholderWidget extends WidgetType {
}
toDOM() {
const container = document.createElement('span');
container.className = 'px-0.5';
const elt = document.createElement('span');
elt.setAttribute('placeholder', true);
elt.style.cssText = `
border: 1px solid gray;
border-radius: 4px;
padding: 2px 2px;
`;
elt.className = 'p-0.5 border border-gray-800 rounded-md';
elt.textContent = this.name;
return elt;
container.appendChild(elt);
return container;
}
ignoreEvent() {
@ -55,22 +56,13 @@ const placeholderPlugin = ViewPlugin.fromClass(
mouseover: (e, view) => {
const target = e.target as HTMLElement;
if (target.tagName.toLowerCase() === 'span' && target.getAttribute('placeholder')) {
target.style.cssText = `
border: 1px solid gray;
border-radius: 4px;
padding: 2px 2px;
background: orange;
`;
target.className = 'p-0.5 border border-orange-400 rounded-md';
}
},
mouseout: (e, view) => {
const target = e.target as HTMLElement;
if (target.tagName.toLowerCase() === 'span' && target.getAttribute('placeholder')) {
target.style.cssText = `
border: 1px solid gray;
border-radius: 4px;
padding: 2px 2px;
`;
target.className = 'p-0.5 border border-gray-800 rounded-md';
}
},
contextmenu: (e, view) => {

7
io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue

@ -228,7 +228,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,
@ -261,8 +260,10 @@
label: $t('re.resources.designer.processor.grid.entity.ternaryCondition'),
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
rows: 50,
lineNumber: true,
placeholder: true,
autoCompletion: true,
autoCompletionOptions: GroovyFunctions,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {

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

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

7
io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/code-mirror.vue

@ -228,7 +228,6 @@
:editor="{
dialog: {
width: '600px',
height: '400px',
},
form: {
colsNum: 1,
@ -261,8 +260,10 @@
label: $t('re.resources.designer.processor.grid.entity.ternaryCondition'),
type: 'code-mirror',
lang: 'java',
rows: 1,
height: '32px',
rows: 50,
lineNumber: true,
placeholder: true,
autoCompletion: true,
autoCompletionOptions: GroovyFunctions,
extAutoCompletionOptions: GroovyFunctions,
showIf: (arg) => {

108
io.sc.platform.core/src/main/resources/io/sc/platform/core/config/logback-spring.xml

@ -16,51 +16,99 @@
<!-- 在控制台中输出日志 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 在磁盘文件中输出日志 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 所有日志文件 -->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<file>${homedir}/logs/log.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/log.%d.log</fileNamePattern>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/log.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>NEUTRAL</onMismatch>
</filter>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
<logger name="org.wsp.engine.model.core.code" level="info" additivity="false"/>
<logger name="org.wsp.engine.rule.core.code" level="debug" additivity="false">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</logger>
<!-- 信息日志文件 -->
<appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<file>${homedir}/logs/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/debug.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="org.springframework.security" level="info" additivity="false">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</logger>
<!-- 信息日志文件 -->
<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<file>${homedir}/logs/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/info.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 警告日志文件 -->
<appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<file>${homedir}/logs/warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/warn.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 可对不同的日志写入不同的文件示例 -->
<!--
<appender name="RULE_ENGINE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 错误日志文件 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder><pattern>${pattern}</pattern></encoder>
<file>${homedir}/logs/rule-engine.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/rule-engine.%d.log</fileNamePattern>
<file>${homedir}/logs/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${homedir}/logs/error.%d.%i.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<logger name="org.wsp.engine.rule.core.code" level="debug" additivity="false">
<root level="debug">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<appender-ref ref="RULE_ENGINE_FILE" />
</logger>
-->
<appender-ref ref="FILE_ALL" />
<appender-ref ref="FILE_DEBUG" />
<appender-ref ref="FILE_INFO" />
<appender-ref ref="FILE_WARN" />
<appender-ref ref="FILE_ERROR" />
</root>
</configuration>
Loading…
Cancel
Save