diff --git a/app.platform/build.gradle b/app.platform/build.gradle
index 7314c171..a9ecd9b0 100644
--- a/app.platform/build.gradle
+++ b/app.platform/build.gradle
@@ -20,21 +20,21 @@ dependencies {
project(":io.sc.platform.scheduler.manager"),
project(":io.sc.platform.scheduler.executor"),
-// project(":io.sc.engine.mv"),
-// project(":io.sc.engine.mv.frontend"),
-// project(":io.sc.engine.mv.sample"),
-//
-// project(":io.sc.engine.rule.client"),
-// project(":io.sc.engine.rule.client.spring"),
-// project(":io.sc.engine.rule.core"),
-// project(":io.sc.engine.rule.server"),
-// project(":io.sc.engine.rule.sample"),
-//
+ project(":io.sc.engine.mv"),
+ project(":io.sc.engine.mv.frontend"),
+ project(":io.sc.engine.mv.sample"),
+
+ project(":io.sc.engine.rule.client"),
+ project(":io.sc.engine.rule.client.spring"),
+ project(":io.sc.engine.rule.core"),
+ project(":io.sc.engine.rule.server"),
+ project(":io.sc.engine.rule.sample"),
+
project(":io.sc.engine.st"),
project(":io.sc.engine.st.frontend"),
- project(":erm"),
- project(":erm.frontend"),
+// project(":erm"),
+// project(":erm.frontend"),
project(":io.sc.standard"),
)
diff --git a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/util/ExpressionReplacer.java b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/util/ExpressionReplacer.java
index ad4b953f..de4ec73d 100644
--- a/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/util/ExpressionReplacer.java
+++ b/io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/util/ExpressionReplacer.java
@@ -36,9 +36,11 @@ public class ExpressionReplacer {
public static String placeholder(String varName,String fieldName) {
if(varName!=null) {
if(fieldName!=null) {
- return "${" + varName + "." + fieldName + "}";
+ //return "${" + varName + "." + fieldName + "}";
+ return varName + "." + fieldName;
}else {
- return "${" + varName + "}";
+ //return "${" + varName + "}";
+ return varName;
}
}
return null;
diff --git a/io.sc.engine.rule.frontend/package.json b/io.sc.engine.rule.frontend/package.json
index e39133fb..9e3f7f57 100644
--- a/io.sc.engine.rule.frontend/package.json
+++ b/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.231",
+ "platform-core": "8.1.237",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",
diff --git a/io.sc.engine.rule.frontend/src/i18n/messages.json b/io.sc.engine.rule.frontend/src/i18n/messages.json
index 401c38be..daeb2de2 100644
--- a/io.sc.engine.rule.frontend/src/i18n/messages.json
+++ b/io.sc.engine.rule.frontend/src/i18n/messages.json
@@ -83,7 +83,7 @@
"re.resources.designer.processor.grid.entity.when": "When Expression",
"re.resources.designer.processor.grid.entity.then": "Then Expression",
"re.resources.designer.processor.grid.entity.isWhenThenShorted": "Shorted",
- "re.resources.designer.processor.grid.entity.numberRangeVar": "Number Range",
+ "re.resources.designer.processor.grid.entity.numberRangeVar": "Number Range Expression",
"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",
diff --git a/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json b/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json
index 51a539ce..c8b75502 100644
--- a/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json
+++ b/io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json
@@ -83,7 +83,7 @@
"re.resources.designer.processor.grid.entity.when": "When 表達式",
"re.resources.designer.processor.grid.entity.then": "Then 表達式",
"re.resources.designer.processor.grid.entity.isWhenThenShorted": "短路操作",
- "re.resources.designer.processor.grid.entity.numberRangeVar": "數值分段",
+ "re.resources.designer.processor.grid.entity.numberRangeVar": "數值分段表達式",
"re.resources.designer.processor.grid.entity.numberRange": "數值分段",
"re.resources.designer.processor.grid.entity.conditionRangeVar": "條件分段",
"re.resources.designer.processor.grid.entity.conditionRange": "條件分段",
diff --git a/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json b/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
index f2ff25ae..2abba359 100644
--- a/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
+++ b/io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
@@ -83,7 +83,7 @@
"re.resources.designer.processor.grid.entity.when": "When 表达式",
"re.resources.designer.processor.grid.entity.then": "Then 表达式",
"re.resources.designer.processor.grid.entity.isWhenThenShorted": "短路操作",
- "re.resources.designer.processor.grid.entity.numberRangeVar": "数值分段",
+ "re.resources.designer.processor.grid.entity.numberRangeVar": "数值分段表达式",
"re.resources.designer.processor.grid.entity.numberRange": "数值分段",
"re.resources.designer.processor.grid.entity.conditionRangeVar": "条件分段",
"re.resources.designer.processor.grid.entity.conditionRange": "条件分段",
diff --git a/io.sc.engine.rule.frontend/src/views/resources/ImportSampleDialog.vue b/io.sc.engine.rule.frontend/src/views/resources/ImportSampleDialog.vue
index d711456c..734fb6a0 100644
--- a/io.sc.engine.rule.frontend/src/views/resources/ImportSampleDialog.vue
+++ b/io.sc.engine.rule.frontend/src/views/resources/ImportSampleDialog.vue
@@ -25,13 +25,13 @@
click: (arg) => {
if (arg.tickeds && arg.tickeds.length > 0) {
const ids = Tools.extractProperties(arg.tickeds, 'id');
- console.log(ids);
- DialogManager.confirm($t('re.resources.importSample.grid.toolbar.import.tip'), () => {
- axios.post(Environment.apiContextPath('/api/re/resource/createExample'), ids).then(() => {
- close();
- emit('afterImported');
- });
+ axios.post(Environment.apiContextPath('/api/re/resource/createExample'), ids, { loading: true }).then(() => {
+ close();
+ emit('afterImported');
});
+ // DialogManager.confirm($t('re.resources.importSample.grid.toolbar.import.tip'), () => {
+
+ // });
}
},
},
@@ -64,12 +64,14 @@
+./w-code-mirror/GroovyFunctions
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/WListGrid.vue b/io.sc.platform.core.frontend/src/platform/components/form/elements/WListGrid.vue
new file mode 100644
index 00000000..1b6a3fa8
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/elements/WListGrid.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
diff --git a/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts
new file mode 100644
index 00000000..efc9a3f3
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/platform/components/form/elements/w-code-mirror/PlaceholderPlugin.ts
@@ -0,0 +1,84 @@
+import { EditorView, ViewPlugin, ViewUpdate, MatchDecorator, Decoration, DecorationSet, WidgetType } from '@codemirror/view';
+
+class PlaceholderWidget extends WidgetType {
+ constructor(name) {
+ super();
+ this.name = name;
+ }
+
+ eq(other) {
+ return this.name == other.name;
+ }
+
+ toDOM() {
+ const elt = document.createElement('span');
+ elt.setAttribute('placeholder', true);
+ elt.style.cssText = `
+ border: 1px solid gray;
+ border-radius: 4px;
+ padding: 2px 2px;
+ `;
+ elt.textContent = this.name;
+ return elt;
+ }
+
+ ignoreEvent() {
+ return false;
+ }
+}
+
+const placeholderMatcher = new MatchDecorator({
+ regexp: /\$\{(.+?)\}/g,
+ decoration: (match) =>
+ Decoration.replace({
+ widget: new PlaceholderWidget(match[1]),
+ }),
+});
+
+const placeholderPlugin = ViewPlugin.fromClass(
+ class {
+ placeholders: DecorationSet;
+ constructor(view: EditorView) {
+ this.placeholders = placeholderMatcher.createDeco(view);
+ }
+ update(update: ViewUpdate) {
+ this.placeholders = placeholderMatcher.updateDeco(update, this.placeholders);
+ }
+ },
+ {
+ decorations: (instance) => instance.placeholders,
+ provide: (plugin) =>
+ EditorView.atomicRanges.of((view) => {
+ return view.plugin(plugin)?.placeholders || Decoration.none;
+ }),
+ eventHandlers: {
+ 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;
+ `;
+ }
+ },
+ 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;
+ `;
+ }
+ },
+ contextmenu: (e, view) => {
+ e.preventDefault();
+ console.log(view);
+ },
+ },
+ },
+);
+
+export default placeholderPlugin;
diff --git a/io.sc.platform.core.frontend/src/platform/plugin/axios.ts b/io.sc.platform.core.frontend/src/platform/plugin/axios.ts
index d8ffab41..eff20714 100644
--- a/io.sc.platform.core.frontend/src/platform/plugin/axios.ts
+++ b/io.sc.platform.core.frontend/src/platform/plugin/axios.ts
@@ -4,6 +4,7 @@ import { i18n } from './i18n';
import { PConst } from '@/platform/PConst';
import { Environment } from '@/platform/plugin/environment';
import { NotifyManager } from './manager';
+import { QuasarTools } from '@/platform/utils';
const ignoredUrls: string[] = [PConst.API_I18N_MESSAGES_URL, PConst.API_APP_CONFIGURE_URL];
const gc = Environment.getConfigure();
@@ -22,6 +23,14 @@ const requestInterceptor = (config: any) => {
if (gc.axios?.basicAuth?.enable) {
result.headers.Authorization = 'Basic ' + window.btoa(gc.axios.basicAuth.username + ':' + gc.axios.basicAuth.password);
}
+ // 如果请求时传入 { loading: true } 属性, 则自动显示 "正在处理..., 请等待" 模态对话框
+ if (config?.loading) {
+ QuasarTools.getQuasar()?.loading?.show({
+ message: i18n.global.t('loading'),
+ boxClass: 'bg-grey-2 text-grey-9',
+ spinnerColor: 'primary',
+ });
+ }
return result;
};
@@ -33,11 +42,13 @@ const requestErrorInterceptor = (error: any) => {
// 响应拦截器
const responseInterceptor = (response: any) => {
// 请求成功, 进入该方法说明 response 的状态码为 2xx
+ QuasarTools.getQuasar()?.loading?.hide();
return response.data;
};
// 响应错误拦截器
const responseErrorInterceptor = (error: any) => {
+ QuasarTools.getQuasar()?.loading?.hide();
// 请求失败, 进入该方法说明 response 的状态码不为 2xx
if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') {
// 发生网络错误
@@ -94,6 +105,7 @@ const noErrorAxios = Axios.create({
});
noErrorAxios.interceptors.request.use(requestInterceptor, requestErrorInterceptor);
noErrorAxios.interceptors.response.use(responseInterceptor, (error: any) => {
+ QuasarTools.getQuasar()?.loading?.hide();
// 请求失败, 进入该方法说明 response 的状态码不为 2xx
if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') {
// 发生网络错误
diff --git a/io.sc.platform.core.frontend/src/platform/utils/QuasarTools.ts b/io.sc.platform.core.frontend/src/platform/utils/QuasarTools.ts
index 76eff2fb..d6b70b28 100644
--- a/io.sc.platform.core.frontend/src/platform/utils/QuasarTools.ts
+++ b/io.sc.platform.core.frontend/src/platform/utils/QuasarTools.ts
@@ -5,6 +5,24 @@ import { Environment } from '@/platform/plugin/environment';
* Quasar 工具类
*/
class QuasarTools {
+ static #quasar: any = null;
+
+ /**
+ * 获取 quasar 示例
+ * @returns quasar 示例
+ */
+ public static getQuasar() {
+ return QuasarTools.#quasar;
+ }
+
+ /**
+ * 设置 quasar 示例
+ * @param quasar quasar 示例
+ */
+ public static setQuasar(quasar: any) {
+ QuasarTools.#quasar = quasar;
+ }
+
/**
* 改变 quasar 的 CSS 中的变量值
* @param key 变量名
diff --git a/io.sc.platform.core.frontend/src/routes/routes.json b/io.sc.platform.core.frontend/src/routes/routes.json
index 9a499a7d..c0f6d157 100644
--- a/io.sc.platform.core.frontend/src/routes/routes.json
+++ b/io.sc.platform.core.frontend/src/routes/routes.json
@@ -52,6 +52,32 @@
}
},
+ {
+ "name": "route.testcase.codemirror",
+ "path": "testcase/codemirror",
+ "parent": "/",
+ "priority": 0,
+ "component": "component.testcase.codemirror",
+ "componentPath": "@/views/testcase/code-mirror/code-mirror.vue",
+ "redirect": null,
+ "meta": {
+ "permissions": ["/testcase/loading/**/*"]
+ }
+ },
+
+ {
+ "name": "route.testcase.loading",
+ "path": "testcase/loading",
+ "parent": "/",
+ "priority": 0,
+ "component": "component.testcase.loading",
+ "componentPath": "@/views/testcase/loading/loading.vue",
+ "redirect": null,
+ "meta": {
+ "permissions": ["/testcase/loading/**/*"]
+ }
+ },
+
{
"name": "route.testcase.excel",
"path": "testcase/excel",
diff --git a/io.sc.platform.core.frontend/src/views/testcase/code-mirror/GroovyFunctions.ts b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/GroovyFunctions.ts
new file mode 100644
index 00000000..672e902a
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/GroovyFunctions.ts
@@ -0,0 +1,43 @@
+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: '' },
+ {
+ label: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
+ type: 'function',
+ apply: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
+ detail: '',
+ },
+];
+
+export default GroovyFunctions;
diff --git a/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue
new file mode 100644
index 00000000..135cfe7d
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/views/testcase/code-mirror/code-mirror.vue
@@ -0,0 +1,525 @@
+
+
+
+
diff --git a/io.sc.platform.core.frontend/src/views/testcase/loading/loading.vue b/io.sc.platform.core.frontend/src/views/testcase/loading/loading.vue
new file mode 100644
index 00000000..65db1949
--- /dev/null
+++ b/io.sc.platform.core.frontend/src/views/testcase/loading/loading.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/io.sc.platform.core.frontend/template-project/package.json b/io.sc.platform.core.frontend/template-project/package.json
index 2d18dea0..18aaba2d 100644
--- a/io.sc.platform.core.frontend/template-project/package.json
+++ b/io.sc.platform.core.frontend/template-project/package.json
@@ -1,6 +1,6 @@
{
"name": "platform-core",
- "version": "8.1.231",
+ "version": "8.1.237",
"description": "前端核心包,用于快速构建前端的脚手架",
"private": false,
"keywords": [],
@@ -104,7 +104,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
- "platform-core": "8.1.231",
+ "platform-core": "8.1.237",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",
diff --git a/io.sc.platform.core.frontend/template-project/src/components/index.ts b/io.sc.platform.core.frontend/template-project/src/components/index.ts
index 8dfeb7fd..39705852 100644
--- a/io.sc.platform.core.frontend/template-project/src/components/index.ts
+++ b/io.sc.platform.core.frontend/template-project/src/components/index.ts
@@ -6,6 +6,8 @@ import component_testcase_openNoMenuRoute from '@/views/testcase/route/OpenNoMen
import component_testcase_noMenuRoute from '@/views/testcase/route/NoMenuRoute.vue';
import component_testcase_mathEditor from '@/views/testcase/math/MathEditor.vue';
import component_testcase_form from '@/views/testcase/form/form.vue';
+import component_testcase_codemirror from '@/views/testcase/code-mirror/code-mirror.vue';
+import component_testcase_loading from '@/views/testcase/loading/loading.vue';
import component_testcase_excel from '@/views/testcase/excel/Excel.vue';
import component_testcase_word from '@/views/testcase/word/Word.vue';
import component_testcase_likmDialog from '@/views/likm/Dialog.vue';
@@ -23,6 +25,8 @@ const localComponents = {
'component.testcase.noMenuRoute': component_testcase_noMenuRoute,
'component.testcase.mathEditor': component_testcase_mathEditor,
'component.testcase.form': component_testcase_form,
+ 'component.testcase.codemirror': component_testcase_codemirror,
+ 'component.testcase.loading': component_testcase_loading,
'component.testcase.excel': component_testcase_excel,
'component.testcase.word': component_testcase_word,
'component.testcase.likmDialog': component_testcase_likmDialog,
diff --git a/io.sc.platform.core.frontend/template-project/src/i18n/messages.json b/io.sc.platform.core.frontend/template-project/src/i18n/messages.json
index aa4092d5..a5945b76 100644
--- a/io.sc.platform.core.frontend/template-project/src/i18n/messages.json
+++ b/io.sc.platform.core.frontend/template-project/src/i18n/messages.json
@@ -3,6 +3,8 @@
"menu.testcase.openNoMenuRoute": "Open No Menu Route",
"menu.testcase.mathEditor": "Math Formual Editor",
"menu.testcase.form":"Form Element",
+ "menu.testcase.codemirror":"Code Mirror",
+ "menu.testcase.loading":"Loading",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
diff --git a/io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json b/io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json
index 67d73c56..73b0171f 100644
--- a/io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json
+++ b/io.sc.platform.core.frontend/template-project/src/i18n/messages_tw_CN.json
@@ -3,6 +3,8 @@
"menu.testcase.openNoMenuRoute": "打開無關聯菜單的路由",
"menu.testcase.mathEditor": "數學公式編輯器",
"menu.testcase.form":"表單元素",
+ "menu.testcase.codemirror":"代碼編輯器",
+ "menu.testcase.loading":"正在加載",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
diff --git a/io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json b/io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json
index 27fc8c52..6b203fb1 100644
--- a/io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json
+++ b/io.sc.platform.core.frontend/template-project/src/i18n/messages_zh_CN.json
@@ -3,6 +3,8 @@
"menu.testcase.openNoMenuRoute": "打开无关联菜单的路由示例",
"menu.testcase.mathEditor": "数学公式编辑器",
"menu.testcase.form":"表单元素",
+ "menu.testcase.codemirror":"代码编辑器",
+ "menu.testcase.loading":"正在加載",
"menu.testcase.excel": "Excel",
"menu.testcase.word": "Word",
diff --git a/io.sc.platform.core.frontend/template-project/src/menus/menus.json b/io.sc.platform.core.frontend/template-project/src/menus/menus.json
index ed7f8b9c..5dee34b0 100644
--- a/io.sc.platform.core.frontend/template-project/src/menus/menus.json
+++ b/io.sc.platform.core.frontend/template-project/src/menus/menus.json
@@ -45,6 +45,24 @@
"icon": "bi-palette",
"routeName": "route.testcase.form"
},
+ {
+ "type": "ROUTE",
+ "order": 350,
+ "parentId": "menu.testcase",
+ "id": "menu.testcase.codemirror",
+ "titleI18nKey": "menu.testcase.codemirror",
+ "icon": "bi-palette",
+ "routeName": "route.testcase.codemirror"
+ },
+ {
+ "type": "ROUTE",
+ "order": 350,
+ "parentId": "menu.testcase",
+ "id": "menu.testcase.loading",
+ "titleI18nKey": "menu.testcase.loading",
+ "icon": "bi-palette",
+ "routeName": "route.testcase.loading"
+ },
{
"type": "ROUTE",
"order": 400,
diff --git a/io.sc.platform.core.frontend/template-project/src/routes/routes.json b/io.sc.platform.core.frontend/template-project/src/routes/routes.json
index 9a499a7d..c0f6d157 100644
--- a/io.sc.platform.core.frontend/template-project/src/routes/routes.json
+++ b/io.sc.platform.core.frontend/template-project/src/routes/routes.json
@@ -52,6 +52,32 @@
}
},
+ {
+ "name": "route.testcase.codemirror",
+ "path": "testcase/codemirror",
+ "parent": "/",
+ "priority": 0,
+ "component": "component.testcase.codemirror",
+ "componentPath": "@/views/testcase/code-mirror/code-mirror.vue",
+ "redirect": null,
+ "meta": {
+ "permissions": ["/testcase/loading/**/*"]
+ }
+ },
+
+ {
+ "name": "route.testcase.loading",
+ "path": "testcase/loading",
+ "parent": "/",
+ "priority": 0,
+ "component": "component.testcase.loading",
+ "componentPath": "@/views/testcase/loading/loading.vue",
+ "redirect": null,
+ "meta": {
+ "permissions": ["/testcase/loading/**/*"]
+ }
+ },
+
{
"name": "route.testcase.excel",
"path": "testcase/excel",
diff --git a/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/GroovyFunctions.ts b/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/GroovyFunctions.ts
new file mode 100644
index 00000000..672e902a
--- /dev/null
+++ b/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/GroovyFunctions.ts
@@ -0,0 +1,43 @@
+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: '' },
+ {
+ label: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
+ type: 'function',
+ apply: 'transformSequencing(value,sourceMin,sourceMax,targetMin,targetMax)',
+ detail: '',
+ },
+];
+
+export default GroovyFunctions;
diff --git a/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/code-mirror.vue b/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/code-mirror.vue
new file mode 100644
index 00000000..135cfe7d
--- /dev/null
+++ b/io.sc.platform.core.frontend/template-project/src/views/testcase/code-mirror/code-mirror.vue
@@ -0,0 +1,525 @@
+
+
+
+
diff --git a/io.sc.platform.core.frontend/template-project/src/views/testcase/loading/loading.vue b/io.sc.platform.core.frontend/template-project/src/views/testcase/loading/loading.vue
new file mode 100644
index 00000000..65db1949
--- /dev/null
+++ b/io.sc.platform.core.frontend/template-project/src/views/testcase/loading/loading.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties
index 595244d6..3217bda5 100644
--- a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties
+++ b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words.properties
@@ -227,4 +227,5 @@ paste=Paste
cut =Cut
online=Online
offline=Offline
-finish=Finish
\ No newline at end of file
+finish=Finish
+loading=Processing, please wait ......
\ No newline at end of file
diff --git a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties
index 7cfc4571..7a7cbba8 100644
--- a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties
+++ b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_tw_CN.properties
@@ -227,4 +227,5 @@ paste=\u7C98\u8CBC
cut =\u526A\u5207
online=\u5728\u7DDA
offline=\u96E2\u7DDA
-finish=\u5B8C\u6210
\ No newline at end of file
+finish=\u5B8C\u6210
+loading=\u6B63\u5728\u8655\u7406, \u8ACB\u7B49\u5F85......
\ No newline at end of file
diff --git a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties
index 860934cb..f710bf61 100644
--- a/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties
+++ b/io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/words_zh_CN.properties
@@ -227,4 +227,5 @@ paste=\u7C98\u8D34
cut =\u526A\u5207
online=\u5728\u7EBF
offline=\u79BB\u7EBF
-finish=\u5B8C\u6210
\ No newline at end of file
+finish=\u5B8C\u6210
+loading=\u6B63\u5728\u5904\u7406, \u8BF7\u7B49\u5F85......
\ No newline at end of file
diff --git a/io.sc.platform.developer.frontend/package.json b/io.sc.platform.developer.frontend/package.json
index a59b9cd9..58d6c68d 100644
--- a/io.sc.platform.developer.frontend/package.json
+++ b/io.sc.platform.developer.frontend/package.json
@@ -92,7 +92,7 @@
"luckyexcel": "1.0.1",
"mockjs": "1.1.0",
"pinia": "2.1.7",
- "platform-core": "8.1.231",
+ "platform-core": "8.1.232",
"quasar": "2.15.3",
"tailwindcss": "3.4.3",
"vue": "3.4.24",
diff --git a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/support/JpaEntityPersistentEvent.java b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/support/JpaEntityPersistentEvent.java
index 3fefb7ae..54e74120 100644
--- a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/support/JpaEntityPersistentEvent.java
+++ b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/entity/support/JpaEntityPersistentEvent.java
@@ -6,8 +6,6 @@ import org.springframework.context.ApplicationEvent;
* Jpa
*/
public class JpaEntityPersistentEvent extends ApplicationEvent{
- private static final long serialVersionUID = -73175079790751083L;
-
private Class> entityClass; //实体类
private JpaEntityPersistentEventType type; //类型:增删改
private Object oldEntity; //原实体对象
diff --git a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/DaoRepository.java b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/DaoRepository.java
index 57192a8a..7825d2e3 100644
--- a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/DaoRepository.java
+++ b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/DaoRepository.java
@@ -9,6 +9,7 @@ import org.springframework.data.repository.NoRepositoryBean;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.ManagedType;
import java.io.Serializable;
+import java.util.List;
@NoRepositoryBean
public interface DaoRepository extends JpaRepository,JpaSpecificationExecutor{
@@ -24,4 +25,10 @@ public interface DaoRepository extends JpaRepository<
public String getIdName();
public ID getId(E entity);
public void setId(E entity,ID id);
+
+ public S save(S entity,boolean isSendEvent);
+ public List saveAll(Iterable entities, boolean isSendEvent);
+ public void delete(E entity,boolean isSendEvent);
+ public void deleteInBatch(Iterable entities,boolean isSendEvent);
+ public void deleteAllInBatch(boolean isSendEvent);
}
diff --git a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/impl/DaoRepositoryImpl.java b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/impl/DaoRepositoryImpl.java
index cee6bd13..631216e0 100644
--- a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/impl/DaoRepositoryImpl.java
+++ b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/repository/impl/DaoRepositoryImpl.java
@@ -1,21 +1,33 @@
package io.sc.platform.orm.repository.impl;
+import io.sc.platform.core.Environment;
+import io.sc.platform.orm.entity.support.JpaEntityPersistentEvent;
+import io.sc.platform.orm.entity.support.JpaEntityPersistentEventType;
import io.sc.platform.orm.repository.DaoRepository;
import io.sc.platform.orm.service.support.ManagedTypeAttributes;
+import org.springframework.context.ApplicationContext;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.SingularAttribute;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.springframework.data.jpa.repository.query.QueryUtils.DELETE_ALL_QUERY_STRING;
+import static org.springframework.data.jpa.repository.query.QueryUtils.applyAndBind;
+import static org.springframework.data.jpa.repository.query.QueryUtils.getQueryString;
public class DaoRepositoryImpl extends SimpleJpaRepository implements DaoRepository {
private JpaEntityInformation jpaEntityInformation;
private EntityManager entityManager;
-
+
public DaoRepositoryImpl(Class domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
}
@@ -82,4 +94,136 @@ public class DaoRepositoryImpl extends SimpleJpaRepos
wrapper.setPropertyValue(idName, id);
}
}
+
+ @Override
+ @Transactional
+ public S save(S entity) {
+ Assert.notNull(entity, "Entity must not be null.");
+ if (jpaEntityInformation.isNew(entity)) {
+ entityManager.persist(entity);
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.AFTER_ADD,null, entity));
+ return entity;
+ } else if("".equals(getId(entity))){//当单一主键为空字符串时,也认为需要新增
+ setId(entity,null);
+ entityManager.persist(entity);
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.AFTER_ADD,null, entity));
+ return entity;
+ }else {
+ E oldEntity = this.getReferenceById(getId(entity));
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(), JpaEntityPersistentEventType.BEFORE_UPDATE, oldEntity, entity));
+ S result = entityManager.merge(entity);
+ return result;
+ }
+ }
+
+ @Override
+ @Transactional
+ public S save(S entity, boolean isSendEvent) {
+ if (jpaEntityInformation.isNew(entity)) {
+ entityManager.persist(entity);
+ if(isSendEvent) {applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.AFTER_ADD,null, entity));}
+ return entity;
+ } else if("".equals(getId(entity))){//当单一主键为空字符串时,也认为需要新增
+ setId(entity,null);
+ entityManager.persist(entity);
+ if(isSendEvent) {applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.AFTER_ADD,null, entity));}
+ return entity;
+ }else {
+ E oldEntity =this.getReferenceById(getId(entity));
+ if(isSendEvent) {applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.BEFORE_UPDATE,oldEntity, entity));}
+ S result =entityManager.merge(entity);
+ return result;
+ }
+ }
+
+ @Override
+ @Transactional
+ public List saveAll(Iterable entities, boolean isSendEvent) {
+ Assert.notNull(entities, "The given Iterable of entities not be null!");
+ List result = new ArrayList();
+ if(isSendEvent) {
+ for (S entity : entities) {
+ result.add(save(entity));
+ }
+ }else {
+ for (S entity : entities) {
+ result.add(save(entity,false));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ @Transactional
+ public void delete(E entity) {
+ Assert.notNull(entity, "The entity must not be null!");
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.BEFORE_DELETE,entity, null));
+ entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
+ }
+
+ @Override
+ @Transactional
+ public void delete(E entity,boolean isSendEvent) {
+ Assert.notNull(entity, "The entity must not be null!");
+ if(isSendEvent) {
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.BEFORE_DELETE,entity, null));
+ }
+ entityManager.remove(entityManager.contains(entity) ? entity : entityManager.merge(entity));
+ }
+
+ @Override
+ @Transactional
+ public void deleteInBatch(Iterable entities) {
+ Assert.notNull(entities, "The given Iterable of entities not be null!");
+
+ if (!entities.iterator().hasNext()) {
+ return;
+ }
+ E entity =entities.iterator().next();
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.BEFORE_DELETE,entities, null));
+ applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, jpaEntityInformation.getEntityName()), entities, entityManager)
+ .executeUpdate();
+ }
+
+ @Override
+ @Transactional
+ public void deleteInBatch(Iterable entities,boolean isSendEvent) {
+ Assert.notNull(entities, "The given Iterable of entities not be null!");
+
+ if (!entities.iterator().hasNext()) {
+ return;
+ }
+ E entity =entities.iterator().next();
+ if(isSendEvent) {
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(entity.getClass(),JpaEntityPersistentEventType.BEFORE_DELETE,entities, null));
+ }
+ applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, jpaEntityInformation.getEntityName()), entities, entityManager)
+ .executeUpdate();
+ }
+
+ @Override
+ @Transactional
+ public void deleteAllInBatch() {
+ String entityName =jpaEntityInformation.getEntityName();
+ Assert.hasText(entityName, "Entity name must not be null or empty!");
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(jpaEntityInformation.getJavaType(),JpaEntityPersistentEventType.BEFORE_DELETE_ALL,null, null));
+ String sql =String.format("delete from %s x", entityName);
+ entityManager.createQuery(sql).executeUpdate();
+ }
+
+ @Override
+ @Transactional
+ public void deleteAllInBatch(boolean isSendEvent) {
+ String entityName =jpaEntityInformation.getEntityName();
+ Assert.hasText(entityName, "Entity name must not be null or empty!");
+ if(isSendEvent) {
+ applicationContext().publishEvent(new JpaEntityPersistentEvent(jpaEntityInformation.getJavaType(),JpaEntityPersistentEventType.BEFORE_DELETE_ALL,null, null));
+ }
+ String sql =String.format("delete from %s x", entityName);
+ entityManager.createQuery(sql).executeUpdate();
+ }
+
+ private ApplicationContext applicationContext(){
+ return Environment.getInstance().getApplicationContext();
+ }
}
diff --git a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/impl/DaoServiceImpl.java b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/impl/DaoServiceImpl.java
index 685d80aa..9f04d903 100644
--- a/io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/impl/DaoServiceImpl.java
+++ b/io.sc.platform.orm/src/main/java/io/sc/platform/orm/service/impl/DaoServiceImpl.java
@@ -2,6 +2,8 @@ package io.sc.platform.orm.service.impl;
import io.sc.platform.core.Environment;
import io.sc.platform.orm.entity.CorporationAuditorEntity;
+import io.sc.platform.orm.entity.support.JpaEntityPersistentEvent;
+import io.sc.platform.orm.entity.support.JpaEntityPersistentEventType;
import io.sc.platform.orm.repository.DaoRepository;
import io.sc.platform.orm.service.DaoService;
import io.sc.platform.orm.service.support.*;
@@ -254,10 +256,14 @@ public abstract class DaoServiceImpl