Browse Source

update

main
wangshaoping 7 months ago
parent
commit
c9c54344cc
  1. 2
      app.platform/build-common.gradle
  2. 2
      erm.frontend/package.json
  3. 2
      gradle.properties
  4. 2
      io.sc.engine.mv.frontend/package.json
  5. 1
      io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java
  6. 238
      io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/support/processor/MathFormula.java
  7. 4
      io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java
  8. 1
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/groovy.ftl
  9. 2
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib/lib.ftl
  10. 2
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib_groovy.ftl
  11. 2
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/model.ftl
  12. 4
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/MATH_FORMULA.ftl
  13. 2
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties
  14. 2
      io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties
  15. 2
      io.sc.engine.rule.frontend/package.json
  16. 2
      io.sc.engine.rule.frontend/src/components/index.ts
  17. 1
      io.sc.engine.rule.frontend/src/i18n/messages.json
  18. 1
      io.sc.engine.rule.frontend/src/i18n/messages_tw_CN.json
  19. 1
      io.sc.engine.rule.frontend/src/i18n/messages_zh_CN.json
  20. 6
      io.sc.engine.rule.frontend/src/menus/menus.json
  21. 15
      io.sc.engine.rule.frontend/src/routes/routes.json
  22. 4
      io.sc.engine.rule.frontend/src/views/functions/Functions.vue
  23. 4
      io.sc.engine.rule.frontend/src/views/lib/ProcessorGrid.vue
  24. 9
      io.sc.engine.rule.frontend/src/views/resources/designer/Processor.vue
  25. 1
      io.sc.engine.rule.server/build.gradle
  26. 17
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/testcase/service/impl/TestCaseServiceImpl.java
  27. 13
      io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/testcase/support/CellStyleBuilder.java
  28. 2227
      io.sc.engine.rule.server/src/main/resources/io/sc/engine/rule/server/sample/引擎示例.json
  29. 2
      io.sc.engine.st.frontend/package.json
  30. 1
      io.sc.platform.core.frontend/src/platform/components/form/WForm.vue
  31. 92
      io.sc.platform.core.frontend/src/platform/components/math/context-menu/ContextMenu.vue
  32. 3
      io.sc.platform.core.frontend/src/platform/components/math/dialog/NumberEditorDialog.vue
  33. 2
      io.sc.platform.core.frontend/src/platform/components/math/dialog/VariableEditorDialog.vue
  34. 24
      io.sc.platform.core.frontend/src/platform/components/math/dialog/XmlDialog.vue
  35. 4
      io.sc.platform.core.frontend/src/platform/components/math/toolbar/Toolbar.vue
  36. 2
      io.sc.platform.core.frontend/src/platform/components/math/toolbar/actions/Xml.vue
  37. 2
      io.sc.platform.core.frontend/src/platform/components/math/toolbar/base/Addition.vue
  38. 6
      io.sc.platform.core.frontend/src/platform/components/math/toolbar/base/NumberConst.vue
  39. 7
      io.sc.platform.core.frontend/src/platform/i18n/messages.json
  40. 7
      io.sc.platform.core.frontend/src/platform/i18n/messages_tw_CN.json
  41. 7
      io.sc.platform.core.frontend/src/platform/i18n/messages_zh_CN.json
  42. 4
      io.sc.platform.core.frontend/template-project/package.json
  43. 170
      io.sc.platform.core.frontend/template-project/src/views/testcase/math/AutoCompletionManager.ts
  44. 15
      io.sc.platform.core.frontend/template-project/src/views/testcase/math/MathEditor.vue
  45. 2
      io.sc.platform.developer.frontend/package.json
  46. 2
      io.sc.platform.gradle/templates/pgp/setup/gradle.properties
  47. 2
      io.sc.platform.lcdp.frontend/package.json
  48. 1
      io.sc.platform.monitor/src/main/java/io/sc/platform/monitor/service/impl/SystemMonitorImpl.java
  49. 18
      io.sc.platform.monitor/src/main/java/io/sc/platform/monitor/service/support/ServerInfo.java
  50. 2
      io.sc.platform.mvc.frontend/package.json
  51. 2
      io.sc.platform.security.frontend/package.json
  52. 2
      io.sc.platform.system.frontend/package.json
  53. 24
      io.sc.platform.system.frontend/src/i18n/messages.json
  54. 24
      io.sc.platform.system.frontend/src/i18n/messages_tw_CN.json
  55. 2
      io.sc.platform.system.frontend/src/i18n/messages_zh_CN.json
  56. 50
      io.sc.platform.system.frontend/src/views/monitor/ServerInfo.vue
  57. 5
      io.sc.platform.system/src/main/java/io/sc/platform/system/auditlog/service/AuditLogService.java
  58. 28
      io.sc.platform.system/src/main/java/io/sc/platform/system/auditlog/service/impl/AuditLogServiceImpl.java
  59. 7
      io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/MetricsWebController.java
  60. 2
      io.sc.standard.frontend/package.json

2
app.platform/build-common.gradle

@ -6,7 +6,7 @@
* 2. gradle bootwar -Dtarget=undertow # undertow, target=undertow * 2. gradle bootwar -Dtarget=undertow # undertow, target=undertow
* 3. gradle bootwar -Dtarget=jetty # jetty, target=jetty * 3. gradle bootwar -Dtarget=jetty # jetty, target=jetty
*/ */
def target =System.getProperty("target") ?: "undertow"; def target =System.getProperty("target") ?: "tomcat";
System.setProperty('target',target); System.setProperty('target',target);
// targetRuntime build.gradle // targetRuntime build.gradle

2
erm.frontend/package.json

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

2
gradle.properties

@ -38,7 +38,7 @@ application_version=1.0.0
platform_group=io.sc platform_group=io.sc
platform_version=8.1.44 platform_version=8.1.44
platform_plugin_version=8.1.44 platform_plugin_version=8.1.44
platform_core_frontend_version=8.1.275 platform_core_frontend_version=8.1.279
########################################################### ###########################################################
# dependencies version # dependencies version

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

1
io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/GroovySourceCodeGenerator.java

@ -87,6 +87,7 @@ public class GroovySourceCodeGenerator implements CodeGenerator{
root.put("ValueType", getStaticMethod("io.sc.engine.rule.core.enums.ValueType")); root.put("ValueType", getStaticMethod("io.sc.engine.rule.core.enums.ValueType"));
root.put("ObjectProperty", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.ObjectProperty")); root.put("ObjectProperty", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.ObjectProperty"));
root.put("MathFormula", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.MathFormula"));
root.put("ConditionRange", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.ConditionRange")); root.put("ConditionRange", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.ConditionRange"));
root.put("NumberRange", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.NumberRange")); root.put("NumberRange", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.NumberRange"));
root.put("DecisionTable2C", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.DecisionTable2C")); root.put("DecisionTable2C", getStaticMethod("io.sc.engine.rule.core.code.impl.support.processor.DecisionTable2C"));

238
io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/code/impl/support/processor/MathFormula.java

@ -6,6 +6,8 @@ import io.sc.engine.rule.core.po.lib.Indicator;
import io.sc.engine.rule.core.po.lib.processor.MathFormulaIndicatorProcessor; import io.sc.engine.rule.core.po.lib.processor.MathFormulaIndicatorProcessor;
import io.sc.engine.rule.core.po.model.Parameter; import io.sc.engine.rule.core.po.model.Parameter;
import io.sc.engine.rule.core.po.model.processor.MathFormulaParameterProcessor; import io.sc.engine.rule.core.po.model.processor.MathFormulaParameterProcessor;
import io.sc.engine.rule.core.util.CodeReplacer;
import io.sc.engine.rule.core.util.ExpressionReplacer;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
@ -15,7 +17,6 @@ import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.Characters; import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement; import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent; import javax.xml.stream.events.XMLEvent;
import java.io.Reader; import java.io.Reader;
@ -24,64 +25,134 @@ import java.util.ArrayDeque;
@JsonIgnoreProperties(ignoreUnknown=true) @JsonIgnoreProperties(ignoreUnknown=true)
public class MathFormula { public class MathFormula {
public static MathType parse(String xml) throws Exception { public static String generateGroovyCode(Indicator indicator, MathFormulaIndicatorProcessor processor) throws Exception {
if(!StringUtils.hasText(xml)){ if (indicator == null || processor == null) {
return null; return null;
} }
Reader reader = new StringReader(xml); String mathXml =processor.getMathFormula();
XMLInputFactory factory = XMLInputFactory.newInstance(); // Or newFactory() if(!StringUtils.hasText(mathXml)){
XMLStreamReader xmlReader = factory.createXMLStreamReader(reader); return null;
}
JAXBContext decodeJAXBContext =JAXBContext.newInstance(MathType.class); mathXml =mathXml.trim();
Unmarshaller unmarshaller =decodeJAXBContext.createUnmarshaller(); if(!mathXml.startsWith("<math>") && !mathXml.endsWith("</math>")){
JAXBElement<MathType> obj =unmarshaller.unmarshal(xmlReader,MathType.class); mathXml ="<math>" + mathXml + "</math>";
return obj.getValue(); }
return ExpressionReplacer.groovy(buildGroovyCode(mathXml),null);
} }
public static String generateGroovyCode(Indicator indicator, MathFormulaIndicatorProcessor processor) throws Exception { public static String generateGroovyCode(Parameter parameter, MathFormulaParameterProcessor processor) throws Exception{
if (indicator == null || processor == null) { if (parameter == null || processor == null) {
return null; return null;
} }
String xml =processor.getMathFormula(); String mathXml =processor.getMathFormula();
if(!StringUtils.hasText(xml)){ if(!StringUtils.hasText(mathXml)){
return null; return null;
} }
Reader reader = new StringReader(xml); mathXml =mathXml.trim();
if(!mathXml.startsWith("<math>") && !mathXml.endsWith("</math>")){
mathXml ="<math>" + mathXml + "</math>";
}
return ExpressionReplacer.groovy(buildGroovyCode(mathXml),null);
}
private static String buildGroovyCode(String mathXml) throws Exception{
Reader reader = new StringReader(mathXml);
XMLInputFactory xmlInputFactory =XMLInputFactory.newFactory(); XMLInputFactory xmlInputFactory =XMLInputFactory.newFactory();
XMLEventReader xmlEventReader =xmlInputFactory.createXMLEventReader(reader); XMLEventReader xmlEventReader =xmlInputFactory.createXMLEventReader(reader);
StringBuilder sb =new StringBuilder(); StringBuilder sb =new StringBuilder();
ArrayDeque<String> tagNameDeque =new ArrayDeque<>();
while(xmlEventReader.hasNext()){ while(xmlEventReader.hasNext()){
XMLEvent xmlEvent = xmlEventReader.nextEvent(); XMLEvent xmlEvent = xmlEventReader.nextEvent();
if (xmlEvent.isStartElement()){ if (xmlEvent.isStartElement()){
StartElement startElement = xmlEvent.asStartElement(); StartElement startElement = xmlEvent.asStartElement();
if("mi".equalsIgnoreCase(startElement.getName().getLocalPart())){ String tagName =startElement.getName().getLocalPart();
tagNameDeque.push(tagName);
if("mspace".equalsIgnoreCase(tagName)){
}else if("mrow".equalsIgnoreCase(tagName)){
sb.append("(");
}else if("msqrt".equalsIgnoreCase(tagName)){
sb.append("sqrt(");
}else if("mroot".equalsIgnoreCase(tagName)){
sb.append("root(");
}else if("msup".equalsIgnoreCase(tagName)){
sb.append("pow(");
}else if("mfrac".equalsIgnoreCase(tagName)){
sb.append("div(");
} }
} else if(xmlEvent.isCharacters()){ } else if(xmlEvent.isCharacters()){
Characters characters = xmlEvent.asCharacters(); Characters characters = xmlEvent.asCharacters();
sb.append(characters.getData()); String text =characters.getData().trim();
} else if(xmlEvent.isEndElement()){ String tagName =tagNameDeque.peek();
EndElement endElement =xmlEvent.asEndElement(); if("mi".equalsIgnoreCase(tagName)){
if("mi".equalsIgnoreCase(endElement.getName().getLocalPart())) { if("(".equalsIgnoreCase(text) || ")".equalsIgnoreCase(text)){
sb.append(text);
}else{
sb.append("${").append(text);
}
}else if("mo".equalsIgnoreCase(tagName)){
if("×".equalsIgnoreCase(text)){
sb.append("*");
}else if("≥".equalsIgnoreCase(text)){
sb.append(">=");
}else if("≤".equalsIgnoreCase(text)){
sb.append("<=");
}else if("=".equalsIgnoreCase(text)){
sb.append("==");
}else{
sb.append(text);
}
}else if("mn".equalsIgnoreCase(tagName)){
if("e".equalsIgnoreCase(text)){
sb.append("E");
}else if("π".equalsIgnoreCase(text)){
sb.append("PI");
}else{
sb.append(text);
}
}else{
sb.append(text);
}
} else if(xmlEvent.isEndElement()) {
String tagName = tagNameDeque.poll();
String previousTagName =tagNameDeque.peek();
if("mspace".equalsIgnoreCase(tagName)){
}else if("mi".equalsIgnoreCase(tagName)){
String lastText =sb.substring(sb.length()-1);
if("(".equalsIgnoreCase(lastText) || ")".equalsIgnoreCase(lastText)){
}else{
sb.append("}");
}
}else if("mrow".equalsIgnoreCase(tagName)){
sb.append(")");
if(
"msqrt".equalsIgnoreCase(previousTagName) ||
"mroot".equalsIgnoreCase(previousTagName) ||
"msup".equalsIgnoreCase(previousTagName) ||
"mfrac".equalsIgnoreCase(previousTagName)
){
sb.append(",");
}
}else if("msqrt".equalsIgnoreCase(tagName)){
sb.setLength(sb.length()-1);
sb.append(")");
}else if("mroot".equalsIgnoreCase(tagName)){
sb.setLength(sb.length()-1);
sb.append(")");
}else if("msup".equalsIgnoreCase(tagName)){
sb.setLength(sb.length()-1);
sb.append(")");
}else if("mfrac".equalsIgnoreCase(tagName)){
sb.setLength(sb.length()-1);
sb.append(")");
} }
} }
} }
return sb.toString(); return sb.toString();
} }
public static String generateGroovyCode(Parameter parameter, MathFormulaParameterProcessor processor) throws Exception{
if (parameter == null || processor == null) {
return null;
}
MathType math =parse(processor.getMathFormula());
if(math==null){
return null;
}
return null;
}
public static void main(String[] args)throws Exception { public static void main(String[] args)throws Exception {
String xml ="<math>\n" + String xml ="<math>\n" +
" <mspace/>\n" + " <mspace/>\n" +
@ -145,104 +216,7 @@ public class MathFormula {
" <mn>50</mn>\n" + " <mn>50</mn>\n" +
" <mspace/>\n" + " <mspace/>\n" +
"</math>"; "</math>";
Reader reader = new StringReader(xml);
XMLInputFactory xmlInputFactory =XMLInputFactory.newFactory(); System.out.println(MathFormula.buildGroovyCode(xml));
XMLEventReader xmlEventReader =xmlInputFactory.createXMLEventReader(reader);
StringBuilder sb =new StringBuilder();
ArrayDeque<String> deque =new ArrayDeque<>();
ArrayDeque<Boolean> twoPartDeque =new ArrayDeque<>();
while(xmlEventReader.hasNext()){
XMLEvent xmlEvent = xmlEventReader.nextEvent();
if (xmlEvent.isStartElement()){
StartElement startElement = xmlEvent.asStartElement();
deque.push(startElement.getName().getLocalPart());
String tagName =deque.peek();
switch (tagName){
case "mspace":
break;
case "mrow":
sb.append("(");
break;
case "mfrac":
twoPartDeque.push(true);
break;
case "msqrt":
sb.append("sqrt(");
break;
case "mroot":
twoPartDeque.push(true);
sb.append("root(");
break;
case "msup":
twoPartDeque.push(true);
sb.append("pow(");
break;
}
} else if(xmlEvent.isCharacters()){
String tagName =deque.peek();
Characters characters = xmlEvent.asCharacters();
String text =characters.getData().trim();
switch (tagName){
case "mi":
sb.append("${").append(text);
break;
case "mo":
switch (text){
case "×":
sb.append("*");
break;
case "≥":
sb.append(">=");
break;
case "≤":
sb.append("<=");
break;
case "=":
sb.append("==");
break;
default:
sb.append(text);
}
break;
case "mn":
sb.append(text);
break;
}
} else if(xmlEvent.isEndElement()) {
EndElement endElement = xmlEvent.asEndElement();
String tagName = deque.peek();
deque.pop();
switch (tagName) {
case "mi":
sb.append("}");
break;
case "mspace":
break;
case "mrow":
sb.append(")");
if (twoPartDeque.peek()!=null && twoPartDeque.peek() && deque.peek()!=null) {
switch (deque.peek()){
case "mfrac":
sb.append("/");
break;
case "mroot":
case "msup":
sb.append(",");
break;
}
twoPartDeque.pop();
}
break;
case "mfrac":
break;
case "msqrt":
case "mroot":
case "msup":
sb.append(")");
break;
}
}
}
System.out.println(sb.toString());
} }
} }

4
io.sc.engine.rule.core/src/main/java/io/sc/engine/rule/core/function/ArithmeticFunction.java

@ -144,4 +144,8 @@ public class ArithmeticFunction {
public static Double root(Double x,Double y){ public static Double root(Double x,Double y){
return Math.pow(x,1/y); return Math.pow(x,1/y);
} }
public static Double div(Double x, Double y){
return x/y;
}
} }

1
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/groovy.ftl

@ -73,6 +73,7 @@ import static io.sc.engine.rule.core.function.ArithmeticFunction.log;
import static io.sc.engine.rule.core.function.ArithmeticFunction.ln; import static io.sc.engine.rule.core.function.ArithmeticFunction.ln;
import static io.sc.engine.rule.core.function.ArithmeticFunction.lg; import static io.sc.engine.rule.core.function.ArithmeticFunction.lg;
import static io.sc.engine.rule.core.function.ArithmeticFunction.root; import static io.sc.engine.rule.core.function.ArithmeticFunction.root;
import static io.sc.engine.rule.core.function.ArithmeticFunction.div;
import static io.sc.engine.rule.core.function.ArithmeticFunction.transformSequencing; import static io.sc.engine.rule.core.function.ArithmeticFunction.transformSequencing;
import static io.sc.engine.rule.core.function.DateFunction.now; import static io.sc.engine.rule.core.function.DateFunction.now;

2
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib/lib.ftl

@ -80,6 +80,8 @@ class ${CodeReplacer.className(lib.code,lib.version)}{
<#include "/processor/OBJECT_PROPERTIES.ftl"/> <#include "/processor/OBJECT_PROPERTIES.ftl"/>
<#elseif "OPTION_VALUE"==(processor.type)!> <#elseif "OPTION_VALUE"==(processor.type)!>
<#include "/processor/OPTION_VALUE.ftl"/> <#include "/processor/OPTION_VALUE.ftl"/>
<#elseif "MATH_FORMULA"==(processor.type)!>
<#include "/processor/MATH_FORMULA.ftl"/>
<#elseif "ARITHMETIC"==(processor.type)!> <#elseif "ARITHMETIC"==(processor.type)!>
<#include "/processor/ARITHMETIC.ftl"/> <#include "/processor/ARITHMETIC.ftl"/>
<#elseif "TERNARY"==(processor.type)!> <#elseif "TERNARY"==(processor.type)!>

2
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/lib_groovy.ftl

@ -72,6 +72,8 @@ class ${CodeReplacer.className(lib.code,lib.version)}{
<#include "/processor/OBJECT_PROPERTIES.ftl"/> <#include "/processor/OBJECT_PROPERTIES.ftl"/>
<#elseif "OPTION_VALUE"==(processor.type)!> <#elseif "OPTION_VALUE"==(processor.type)!>
<#include "/processor/OPTION_VALUE.ftl"/> <#include "/processor/OPTION_VALUE.ftl"/>
<#elseif "MATH_FORMULA"==(processor.type)!>
<#include "/processor/MATH_FORMULA.ftl"/>
<#elseif "ARITHMETIC"==(processor.type)!> <#elseif "ARITHMETIC"==(processor.type)!>
<#include "/processor/ARITHMETIC.ftl"/> <#include "/processor/ARITHMETIC.ftl"/>
<#elseif "TERNARY"==(processor.type)!> <#elseif "TERNARY"==(processor.type)!>

2
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/model/model.ftl

@ -169,6 +169,8 @@ class ${CodeReplacer.className(resource.code,resource.version)} {
<#include "/processor/OBJECT_PROPERTIES.ftl"/> <#include "/processor/OBJECT_PROPERTIES.ftl"/>
<#elseif "OPTION_VALUE"==(processor.type)!> <#elseif "OPTION_VALUE"==(processor.type)!>
<#include "/processor/OPTION_VALUE.ftl"/> <#include "/processor/OPTION_VALUE.ftl"/>
<#elseif "MATH_FORMULA"==(processor.type)!>
<#include "/processor/MATH_FORMULA.ftl"/>
<#elseif "ARITHMETIC"==(processor.type)!> <#elseif "ARITHMETIC"==(processor.type)!>
<#include "/processor/ARITHMETIC.ftl"/> <#include "/processor/ARITHMETIC.ftl"/>
<#elseif "TERNARY"==(processor.type)!> <#elseif "TERNARY"==(processor.type)!>

4
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/code/template/groovy/processor/MATH_FORMULA.ftl

@ -0,0 +1,4 @@
//数学公式
${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)} =${MathFormula.generateGroovyCode(parameter,processor)};
if(log.isDebugEnabled()){log.debug(" 数学公式运算结果 : {}",${ExpressionReplacer.ARGUMENT_NAME}.${CodeReplacer.fieldName(parameter.code)});}

2
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_tw_CN.properties

@ -47,7 +47,7 @@ io.sc.engine.rule.core.enums.ParameterType.CONSTANT=\u5E38\u91CF
# \u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E # \u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E
#================================================ #================================================
io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A
io.sc.engine.rule.core.enums.ProcessorType.OBJECT_PROPERTIES=\u5C0D\u8C61\u5C6C\u6027 io.sc.engine.rule.core.enums.ProcessorType.OBJECT_PROPERTIES=\u5C0D\u8C61\u5C6C\u6027\u8CE6\u503C
io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9078\u9805\u503C io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9078\u9805\u503C
io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6578\u5B78\u516C\u5F0F io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6578\u5B78\u516C\u5F0F
io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6578\u904B\u7B97 io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6578\u904B\u7B97

2
io.sc.engine.rule.core/src/main/resources/io/sc/engine/rule/core/i18n/enums_zh_CN.properties

@ -47,7 +47,7 @@ io.sc.engine.rule.core.enums.ParameterType.CONSTANT=\u5E38\u91CF
# \u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E # \u5904\u7406\u5668\u7C7B\u578B\u679A\u4E3E
#================================================ #================================================
io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A io.sc.engine.rule.core.enums.ProcessorType.EMPTY=\u7A7A
io.sc.engine.rule.core.enums.ProcessorType.OBJECT_PROPERTIES=\u5BF9\u8C61\u5C5E\u6027 io.sc.engine.rule.core.enums.ProcessorType.OBJECT_PROPERTIES=\u5BF9\u8C61\u5C5E\u6027\u8D4B\u503C
io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9009\u9879\u503C io.sc.engine.rule.core.enums.ProcessorType.OPTION_VALUE=\u9009\u9879\u503C
io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6570\u5B66\u516C\u5F0F io.sc.engine.rule.core.enums.ProcessorType.MATH_FORMULA=\u6570\u5B66\u516C\u5F0F
io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6570\u8FD0\u7B97 io.sc.engine.rule.core.enums.ProcessorType.ARITHMETIC=\u7B97\u6570\u8FD0\u7B97

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

2
io.sc.engine.rule.frontend/src/components/index.ts

@ -8,6 +8,7 @@ import component_engine_rule_authorization from '@/views/authorization/Authoriza
import component_engine_rule_workflow from '@/views/workflow/Workflow.vue'; import component_engine_rule_workflow from '@/views/workflow/Workflow.vue';
import component_engine_rule_dictionary from '@/views/dictionary/Dictionary.vue'; import component_engine_rule_dictionary from '@/views/dictionary/Dictionary.vue';
import component_engine_rule_lib from '@/views/lib/Lib.vue'; import component_engine_rule_lib from '@/views/lib/Lib.vue';
import component_engine_rule_functions from '@/views/functions/Functions.vue';
import component_engine_rule_testcase from '@/views/testcase/Testcase.vue'; import component_engine_rule_testcase from '@/views/testcase/Testcase.vue';
import component_engine_rule_migration from '@/views/migration/Migration.vue'; import component_engine_rule_migration from '@/views/migration/Migration.vue';
@ -18,6 +19,7 @@ const localComponents = {
'component.engine.rule.workflow': component_engine_rule_workflow, 'component.engine.rule.workflow': component_engine_rule_workflow,
'component.engine.rule.dictionary': component_engine_rule_dictionary, 'component.engine.rule.dictionary': component_engine_rule_dictionary,
'component.engine.rule.lib': component_engine_rule_lib, 'component.engine.rule.lib': component_engine_rule_lib,
'component.engine.rule.functions': component_engine_rule_functions,
'component.engine.rule.testcase': component_engine_rule_testcase, 'component.engine.rule.testcase': component_engine_rule_testcase,
'component.engine.rule.migration': component_engine_rule_migration, 'component.engine.rule.migration': component_engine_rule_migration,
}; };

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

@ -5,6 +5,7 @@
"menu.engine.rule.workflow": "Workflow", "menu.engine.rule.workflow": "Workflow",
"menu.engine.rule.dictionary": "Meta Data Manager", "menu.engine.rule.dictionary": "Meta Data Manager",
"menu.engine.rule.lib": "Feature Library Manager", "menu.engine.rule.lib": "Feature Library Manager",
"menu.engine.rule.functions": "Function Library",
"menu.engine.rule.testcase": "Test Case Manager", "menu.engine.rule.testcase": "Test Case Manager",
"menu.engine.rule.migration": "Data Back and Migration", "menu.engine.rule.migration": "Data Back and Migration",

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

@ -5,6 +5,7 @@
"menu.engine.rule.workflow": "流程審批", "menu.engine.rule.workflow": "流程審批",
"menu.engine.rule.dictionary": "元數據管理", "menu.engine.rule.dictionary": "元數據管理",
"menu.engine.rule.lib": "特征庫管理", "menu.engine.rule.lib": "特征庫管理",
"menu.engine.rule.functions": "函數庫",
"menu.engine.rule.testcase": "試算用例", "menu.engine.rule.testcase": "試算用例",
"menu.engine.rule.migration": "數據備份和遷移", "menu.engine.rule.migration": "數據備份和遷移",

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

@ -5,6 +5,7 @@
"menu.engine.rule.workflow": "流程审批", "menu.engine.rule.workflow": "流程审批",
"menu.engine.rule.dictionary": "元数据管理", "menu.engine.rule.dictionary": "元数据管理",
"menu.engine.rule.lib": "特征库管理", "menu.engine.rule.lib": "特征库管理",
"menu.engine.rule.functions": "函数库",
"menu.engine.rule.testcase": "试算用例管理", "menu.engine.rule.testcase": "试算用例管理",
"menu.engine.rule.migration": "数据备份和迁移", "menu.engine.rule.migration": "数据备份和迁移",

6
io.sc.engine.rule.frontend/src/menus/menus.json

@ -29,9 +29,11 @@
{"type":"ROUTE", "order":400, "parentId":"menu.engine.rule", "id":"menu.engine.rule.dictionary", "titleI18nKey":"menu.engine.rule.dictionary", "icon":"bi-list-ol", "routeName":"route.engine.rule.dictionary"}, {"type":"ROUTE", "order":400, "parentId":"menu.engine.rule", "id":"menu.engine.rule.dictionary", "titleI18nKey":"menu.engine.rule.dictionary", "icon":"bi-list-ol", "routeName":"route.engine.rule.dictionary"},
/*/*/ /*/*/
{"type":"ROUTE", "order":500, "parentId":"menu.engine.rule", "id":"menu.engine.rule.lib", "titleI18nKey":"menu.engine.rule.lib", "icon":"bi-folder2", "routeName":"route.engine.rule.lib"}, {"type":"ROUTE", "order":500, "parentId":"menu.engine.rule", "id":"menu.engine.rule.lib", "titleI18nKey":"menu.engine.rule.lib", "icon":"bi-folder2", "routeName":"route.engine.rule.lib"},
/*/*/
{"type":"ROUTE", "order":600, "parentId":"menu.engine.rule", "id":"menu.engine.rule.functions", "titleI18nKey":"menu.engine.rule.functions", "icon":"bi-folder2", "routeName":"route.engine.rule.functions"},
/*/*/ /*/*/
{"type":"ROUTE", "order":600, "parentId":"menu.engine.rule", "id":"menu.engine.rule.testcase", "titleI18nKey":"menu.engine.rule.testcase", "icon":"bi-suitcase-lg", "routeName":"route.engine.rule.testcase"}, {"type":"ROUTE", "order":700, "parentId":"menu.engine.rule", "id":"menu.engine.rule.testcase", "titleI18nKey":"menu.engine.rule.testcase", "icon":"bi-suitcase-lg", "routeName":"route.engine.rule.testcase"},
/*/*/ /*/*/
{"type":"ROUTE", "order":700, "parentId":"menu.engine.rule", "id":"menu.engine.rule.migration", "titleI18nKey":"menu.engine.rule.migration", "icon":"bi-share", "routeName":"route.engine.rule.migration"} {"type":"ROUTE", "order":800, "parentId":"menu.engine.rule", "id":"menu.engine.rule.migration", "titleI18nKey":"menu.engine.rule.migration", "icon":"bi-share", "routeName":"route.engine.rule.migration"}
] ]

15
io.sc.engine.rule.frontend/src/routes/routes.json

@ -90,6 +90,21 @@
] ]
} }
}, },
{
"name": "route.engine.rule.functions",
"path": "re/functions",
"parent": "/",
"priority": 0,
"module": "io.sc.engine.rule.frontend",
"component": "component.engine.rule.functions",
"componentPath": "@/views/functions/Functions.vue",
"redirect": null,
"meta": {
"permissions": [
"/re/functions/**/*"
]
}
},
{ {
"name": "route.engine.rule.testcase", "name": "route.engine.rule.testcase",
"path": "re/testcase", "path": "re/testcase",

4
io.sc.engine.rule.frontend/src/views/functions/Functions.vue

@ -0,0 +1,4 @@
<template>
<div>functions</div>
</template>
<script setup lang="ts"></script>

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

@ -453,7 +453,8 @@
colSpan: 5, colSpan: 5,
name: 'mathFormula', name: 'mathFormula',
label: $t('re.resources.designer.processor.grid.entity.mathFormula'), label: $t('re.resources.designer.processor.grid.entity.mathFormula'),
type: 'expression', type: 'math',
autoCompletion: autoCompletion,
showIf: (arg) => { showIf: (arg) => {
return 'MATH_FORMULA' === arg.form.getFieldValue('type'); return 'MATH_FORMULA' === arg.form.getFieldValue('type');
}, },
@ -580,6 +581,7 @@
return 'NUMBER_RANGE' === arg.form.getFieldValue('type'); return 'NUMBER_RANGE' === arg.form.getFieldValue('type');
}, },
type: 'w-grid', type: 'w-grid',
dbClickOperation: 'edit',
height: 300, height: 300,
denseBody: true, denseBody: true,
draggable: true, draggable: true,

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

@ -333,7 +333,7 @@
return row.optionCode; return row.optionCode;
} else if ('MATH_FORMULA' === type) { } else if ('MATH_FORMULA' === type) {
return { return {
componentType: 'w-expression', componentType: 'w-math',
attrs: { attrs: {
modelValue: row.mathFormula, modelValue: row.mathFormula,
readOnly: true, readOnly: true,
@ -595,7 +595,8 @@
colSpan: 5, colSpan: 5,
name: 'mathFormula', name: 'mathFormula',
label: $t('re.resources.designer.processor.grid.entity.mathFormula'), label: $t('re.resources.designer.processor.grid.entity.mathFormula'),
type: 'expression', type: 'math',
autoCompletion: autoCompletion,
showIf: (arg) => { showIf: (arg) => {
return 'MATH_FORMULA' === arg.form.getFieldValue('type'); return 'MATH_FORMULA' === arg.form.getFieldValue('type');
}, },
@ -803,9 +804,9 @@
colsNum: 4, colsNum: 4,
fields: [ fields: [
{ name: 'uuid', label: 'uuid', hidden: true, colSpan: 4 }, { name: 'uuid', label: 'uuid', hidden: true, colSpan: 4 },
{ name: 'min', label: $t('minValue'), type: 'number', colSpan: 3 }, { name: 'min', label: $t('minValue'), type: 'text', colSpan: 3 },
{ name: 'minIncluded', label: $t('include'), type: 'checkbox' }, { name: 'minIncluded', label: $t('include'), type: 'checkbox' },
{ name: 'max', label: $t('maxValue'), type: 'number', colSpan: 3 }, { name: 'max', label: $t('maxValue'), type: 'text', colSpan: 3 },
{ name: 'maxIncluded', label: $t('include'), type: 'checkbox' }, { name: 'maxIncluded', label: $t('include'), type: 'checkbox' },
{ name: 'value', label: $t('value'), type: 'number', colSpan: 3 }, { name: 'value', label: $t('value'), type: 'number', colSpan: 3 },
], ],

1
io.sc.engine.rule.server/build.gradle

@ -16,6 +16,7 @@ dependencies {
"org.webjars:org.webjars.codemirror:5.37.0", "org.webjars:org.webjars.codemirror:5.37.0",
"org.webjars:org.webjars.mxgraph:3.9.12", "org.webjars:org.webjars.mxgraph:3.9.12",
"org.webjars:org.webjars.jquery:1.12.4", "org.webjars:org.webjars.jquery:1.12.4",
"org.webjars:org.webjars.mathfonts:1.0.0",
) )
} }

17
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/testcase/service/impl/TestCaseServiceImpl.java

@ -1,12 +1,9 @@
package io.sc.engine.rule.server.testcase.service.impl; package io.sc.engine.rule.server.testcase.service.impl;
import io.sc.engine.rule.client.Executor; import io.sc.engine.rule.client.Executor;
import io.sc.engine.rule.client.runtime.EngineRuntime;
import io.sc.engine.rule.client.runtime.impl.groovy.GroovyScriptEngineService; import io.sc.engine.rule.client.runtime.impl.groovy.GroovyScriptEngineService;
import io.sc.engine.rule.client.runtime.impl.groovy.GroovyScriptEngineServiceImpl; import io.sc.engine.rule.client.runtime.impl.groovy.GroovyScriptEngineServiceImpl;
import io.sc.engine.rule.client.runtime.impl.groovy.GroovyScriptExecutor;
import io.sc.engine.rule.client.spring.service.ExecutorFactoryService; import io.sc.engine.rule.client.spring.service.ExecutorFactoryService;
import io.sc.engine.rule.core.code.CodeGenerator;
import io.sc.engine.rule.core.code.SourceCode; import io.sc.engine.rule.core.code.SourceCode;
import io.sc.engine.rule.core.code.impl.GroovySourceCodeGenerator; import io.sc.engine.rule.core.code.impl.GroovySourceCodeGenerator;
import io.sc.engine.rule.core.code.impl.support.ParameterResult; import io.sc.engine.rule.core.code.impl.support.ParameterResult;
@ -48,11 +45,13 @@ import io.sc.engine.rule.server.testcase.support.CellStyleBuilder;
import io.sc.engine.rule.server.testcase.wrapper.Option; import io.sc.engine.rule.server.testcase.wrapper.Option;
import io.sc.engine.rule.server.testcase.wrapper.TestCaseParameterWrapper; import io.sc.engine.rule.server.testcase.wrapper.TestCaseParameterWrapper;
import io.sc.engine.rule.server.testcase.wrapper.TestCaseWrapper; import io.sc.engine.rule.server.testcase.wrapper.TestCaseWrapper;
import io.sc.platform.core.Environment;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.CriteriaBuilder; import io.sc.platform.orm.service.support.CriteriaBuilder;
import io.sc.platform.orm.service.support.QueryParameter; import io.sc.platform.orm.service.support.QueryParameter;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*; import org.apache.poi.xssf.usermodel.*;
@ -315,6 +314,7 @@ public class TestCaseServiceImpl extends DaoServiceImpl<TestCaseEntity, String,
wrappers.addAll(outputs); wrappers.addAll(outputs);
XSSFWorkbook workbook = new XSSFWorkbook(); XSSFWorkbook workbook = new XSSFWorkbook();
XSSFDataFormat dataFormat = workbook.createDataFormat();
XSSFSheet sheet = workbook.createSheet(); XSSFSheet sheet = workbook.createSheet();
CellStyleBuilder styleBuilder =new CellStyleBuilder(workbook); CellStyleBuilder styleBuilder =new CellStyleBuilder(workbook);
@ -460,7 +460,7 @@ public class TestCaseServiceImpl extends DaoServiceImpl<TestCaseEntity, String,
XSSFDataValidationHelper helper = new XSSFDataValidationHelper(sheet); XSSFDataValidationHelper helper = new XSSFDataValidationHelper(sheet);
XSSFDataValidationConstraint constraint = (XSSFDataValidationConstraint)helper.createExplicitListConstraint(optionStrings.toArray(new String[]{})); XSSFDataValidationConstraint constraint = (XSSFDataValidationConstraint)helper.createExplicitListConstraint(optionStrings.toArray(new String[]{}));
//参数顺序:开始行、结束行、开始列、结束列 //参数顺序:开始行、结束行、开始列、结束列
CellRangeAddressList addressList = new CellRangeAddressList(rowIndex+1,200,colIndex-1,colIndex-1); CellRangeAddressList addressList = new CellRangeAddressList(rowIndex+1,1000,colIndex-1,colIndex-1);
XSSFDataValidation validation = (XSSFDataValidation)helper.createValidation(constraint, addressList); XSSFDataValidation validation = (XSSFDataValidation)helper.createValidation(constraint, addressList);
validation.setSuppressDropDownArrow(true); validation.setSuppressDropDownArrow(true);
validation.setShowErrorBox(true); validation.setShowErrorBox(true);
@ -470,6 +470,11 @@ public class TestCaseServiceImpl extends DaoServiceImpl<TestCaseEntity, String,
try{ try{
String typeName =messageSource.getMessage(wrapper.getValueType(), null, locale); String typeName =messageSource.getMessage(wrapper.getValueType(), null, locale);
cell.setCellValue(typeName); cell.setCellValue(typeName);
if("java.lang.String".equalsIgnoreCase(wrapper.getValueType())){
XSSFCellStyle textStyle =workbook.createCellStyle();
textStyle.setDataFormat(dataFormat.getFormat("TEXT"));
sheet.setDefaultColumnStyle(colIndex-1,textStyle);
}
}catch (Exception e) { }catch (Exception e) {
cell.setCellValue(wrapper.getValueType()); cell.setCellValue(wrapper.getValueType());
} }

13
io.sc.engine.rule.server/src/main/java/io/sc/engine/rule/server/testcase/support/CellStyleBuilder.java

@ -2,6 +2,7 @@ package io.sc.engine.rule.server.testcase.support;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFDataFormat;
import org.apache.poi.xssf.usermodel.XSSFFont; import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -14,6 +15,7 @@ public class CellStyleBuilder {
private IndexedColors color; private IndexedColors color;
private boolean border =false; private boolean border =false;
private boolean wrap =true; private boolean wrap =true;
private String dataFormat;
public CellStyleBuilder(XSSFWorkbook workbook){ public CellStyleBuilder(XSSFWorkbook workbook){
this.workbook =workbook; this.workbook =workbook;
@ -60,6 +62,12 @@ public class CellStyleBuilder {
// wrap // wrap
style.setWrapText(wrap); style.setWrapText(wrap);
// data format
if(dataFormat!=null) {
XSSFDataFormat format = workbook.createDataFormat();
style.setDataFormat(format.getFormat(dataFormat));
}
return style; return style;
} }
@ -108,4 +116,9 @@ public class CellStyleBuilder {
this.wrap =false; this.wrap =false;
return this; return this;
} }
public CellStyleBuilder dataFormat(String dataFormat){
this.dataFormat =dataFormat;
return this;
}
} }

2227
io.sc.engine.rule.server/src/main/resources/io/sc/engine/rule/server/sample/引擎示例.json

File diff suppressed because one or more lines are too long

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

1
io.sc.platform.core.frontend/src/platform/components/form/WForm.vue

@ -106,6 +106,7 @@ const fiedType = {
optionGroup: 'w-option-group', optionGroup: 'w-option-group',
file: 'w-file', file: 'w-file',
expression: 'w-expression', expression: 'w-expression',
math: 'w-math',
}; };
const defaultValueHandler = (field) => { const defaultValueHandler = (field) => {

92
io.sc.platform.core.frontend/src/platform/components/math/context-menu/ContextMenu.vue

@ -1,6 +1,33 @@
<template> <template>
<q-menu ref="contextMenuRef" context-menu> <q-menu ref="contextMenuRef" context-menu>
<q-list dense style="min-width: 100px"> <q-list dense style="min-width: 100px">
<q-item v-if="targetElementTagName === 'mi'" v-close-popup clickable @click="miTomn">
<q-item-section>{{ $t('math.contextMenu.miTomn') }}</q-item-section>
</q-item>
<q-item v-if="targetElementTagName === 'mn'" v-close-popup clickable @click="mnTomi">
<q-item-section>{{ $t('math.contextMenu.mnTomi') }}</q-item-section>
</q-item>
<q-separator v-if="targetElementTagName === 'mn'" inset spaced />
<q-item v-if="targetElementTagName === 'mn'" v-close-popup clickable @click="mnTo0">
<q-item-section>{{ $t('math.contextMenu.mnTo0') }}</q-item-section>
</q-item>
<q-item v-if="targetElementTagName === 'mn'" v-close-popup clickable @click="mnTo1">
<q-item-section>{{ $t('math.contextMenu.mnTo1') }}</q-item-section>
</q-item>
<q-separator v-if="targetElementTagName === 'mi' || targetElementTagName === 'mn'" inset spaced />
<q-item v-close-popup clickable @click="copy">
<q-item-section>{{ $t('copy') }}</q-item-section>
</q-item>
<q-item v-close-popup clickable @click="paste">
<q-item-section>{{ $t('paste') }}</q-item-section>
</q-item>
<q-item v-close-popup clickable @click="cut">
<q-item-section>{{ $t('cut') }}</q-item-section>
</q-item>
<q-item v-close-popup clickable @click="remove"> <q-item v-close-popup clickable @click="remove">
<q-item-section>{{ $t('delete') }}</q-item-section> <q-item-section>{{ $t('delete') }}</q-item-section>
</q-item> </q-item>
@ -9,32 +36,85 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { copyToClipboard } from 'quasar';
const emit = defineEmits(['changed']); const emit = defineEmits(['changed']);
const contextMenuRef = ref(); const contextMenuRef = ref();
let targetElement = null; const targetElementRef = ref();
const targetElementTagName = ref();
const show = (element) => { const show = (element) => {
targetElement = element; targetElementRef.value = element;
targetElementTagName.value = element.tagName;
contextMenuRef.value.show(); contextMenuRef.value.show();
}; };
const remove = (element) => { const remove = (element) => {
if (targetElement) { if (targetElementRef.value) {
const previous = targetElement.previousElementSibling; const previous = targetElementRef.value.previousElementSibling;
if (previous?.tagName === 'mspace') { if (previous?.tagName === 'mspace') {
previous.outerHTML = ''; previous.outerHTML = '';
} }
const next = targetElement.nextElementSibling; const next = targetElementRef.value.nextElementSibling;
if (next?.tagName === 'mspace') { if (next?.tagName === 'mspace') {
next.outerHTML = ''; next.outerHTML = '';
} }
targetElement.outerHTML = '<mspace></mspace>'; targetElementRef.value.outerHTML = '<mspace></mspace>';
emit('changed'); emit('changed');
} }
}; };
const miTomn = () => {
if (targetElementRef.value) {
targetElementRef.value.outerHTML = '<mn>n</mn>';
emit('changed');
}
};
const mnTomi = () => {
if (targetElementRef.value) {
targetElementRef.value.outerHTML = '<mi>x</mi>';
emit('changed');
}
};
const mnTo0 = () => {
if (targetElementRef.value) {
targetElementRef.value.outerHTML = '<mn>0</mn>';
emit('changed');
}
};
const mnTo1 = () => {
if (targetElementRef.value) {
targetElementRef.value.outerHTML = '<mn>1</mn>';
emit('changed');
}
};
const copy = () => {
copyToClipboard(targetElementRef.value.outerHTML);
};
const paste = () => {
window.navigator.clipboard.readText().then((text) => {
console.log(text);
targetElementRef.value.outerHTML = text;
emit('changed');
});
};
const cut = () => {
copyToClipboard(targetElementRef.value.outerHTML);
if (targetElementRef.value.tagName === 'mrow') {
targetElementRef.value.innerHTML = '<mspace/>';
} else {
remove(targetElementRef.value);
}
emit('changed');
};
defineExpose({ defineExpose({
show, show,
remove, remove,

3
io.sc.platform.core.frontend/src/platform/components/math/dialog/NumberEditorDialog.vue

@ -9,7 +9,8 @@
label: $t('confirm'), label: $t('confirm'),
noCaps: true, noCaps: true,
click: () => { click: () => {
targetElementRef.innerHTML = modelValueRef; let string = modelValueRef;
targetElementRef.innerHTML = string.trim();
emit('changed'); emit('changed');
close(); close();
}, },

2
io.sc.platform.core.frontend/src/platform/components/math/dialog/VariableEditorDialog.vue

@ -11,7 +11,7 @@
click: () => { click: () => {
let string = modelValueRef; let string = modelValueRef;
string = string.replace(/\$\{(.+?)\}/g, '$1'); string = string.replace(/\$\{(.+?)\}/g, '$1');
targetElementRef.innerHTML = string; targetElementRef.innerHTML = string.trim();
emit('changed'); emit('changed');
close(); close();
}, },

24
io.sc.platform.core.frontend/src/platform/components/math/dialog/XmlDialog.vue

@ -1,7 +1,22 @@
<template> <template>
<w-dialog ref="dialogRef" :title="$t('xml')" width="800px" :can-maximize="false"> <w-dialog
ref="dialogRef"
:title="$t('xml')"
width="800px"
:can-maximize="false"
:buttons="[
{
label: $t('confirm'),
noCaps: true,
click: () => {
modelValueRef = xmlRef;
close();
},
},
]"
>
<div class="py-1"></div> <div class="py-1"></div>
<w-code-mirror v-model="xmlRef" outlined :rows="20" lang="xml" line-number /> <w-code-mirror v-model="xmlRef" outlined :rows="20" lang="xml" line-number :toolbar="false" />
</w-dialog> </w-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -30,7 +45,12 @@ const open = () => {
dialogRef.value.show(); dialogRef.value.show();
}; };
const close = () => {
dialogRef.value.hide();
};
defineExpose({ defineExpose({
open, open,
close,
}); });
</script> </script>

4
io.sc.platform.core.frontend/src/platform/components/math/toolbar/Toolbar.vue

@ -27,7 +27,7 @@
<q-separator vertical /> <q-separator vertical />
<!-- 数学 --> <!-- 数学 -->
<q-btn :label="$t('math.toolbar.math')" stretch flat dense padding="0px 10px" icon-right="arrow_drop_down"> <q-btn :label="$t('math.toolbar.math')" stretch flat dense no-caps padding="0px 10px" icon-right="arrow_drop_down">
<q-menu> <q-menu>
<q-list dense> <q-list dense>
<q-item v-close-popup clickable> <q-item v-close-popup clickable>
@ -68,7 +68,7 @@
</q-btn> </q-btn>
<!-- 函数 --> <!-- 函数 -->
<q-btn :label="$t('math.toolbar.functions')" stretch flat dense padding="0px 10px" icon-right="arrow_drop_down"> <q-btn :label="$t('math.toolbar.functions')" stretch flat dense no-caps padding="0px 10px" icon-right="arrow_drop_down">
<q-menu> <q-menu>
<q-list> <q-list>
<!-- 特殊值值处理函数 --> <!-- 特殊值值处理函数 -->

2
io.sc.platform.core.frontend/src/platform/components/math/toolbar/actions/Xml.vue

@ -4,7 +4,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import XmlDialog from '@/platform/components/expression/dialog/XmlDialog.vue'; import XmlDialog from '@/platform/components/math/dialog/XmlDialog.vue';
const modelValueRef = defineModel({ type: String, default: '' }); const modelValueRef = defineModel({ type: String, default: '' });

2
io.sc.platform.core.frontend/src/platform/components/math/toolbar/base/Addition.vue

@ -1,5 +1,5 @@
<template> <template>
<q-btn :title="$t('math.toolbar.base.addition')" stretch flat size="16px" padding="0px 6px" draggable="true" @dragstart="dragstart" @click="append"> <q-btn :title="$t('math.toolbar.base.addition')" stretch flat no-caps size="16px" padding="0px 6px" draggable="true" @dragstart="dragstart" @click="append">
<math display="inline"> <math display="inline">
<mrow> <mrow>
<mo>+</mo> <mo>+</mo>

6
io.sc.platform.core.frontend/src/platform/components/math/toolbar/base/NumberConst.vue

@ -1,14 +1,14 @@
<template> <template>
<q-btn :title="$t('math.toolbar.base.number')" stretch flat size="16px" padding="0px 10px" draggable="true" @dragstart="dragstart" @click="append"> <q-btn :title="$t('math.toolbar.base.number')" stretch flat no-caps size="16px" padding="0px 10px" draggable="true" @dragstart="dragstart" @click="append">
<math display="inline"> <math display="inline">
<mn>N</mn> <mn>n</mn>
</math> </math>
</q-btn> </q-btn>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const xmlData = ` const xmlData = `
<mspace></mspace> <mspace></mspace>
<mn>N</mn> <mn>n</mn>
<mspace></mspace> <mspace></mspace>
`; `;

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

@ -263,5 +263,10 @@
"math.toolbar.functions.formater.comma": "Thousandth place, leave the y digits after the x decimal point", "math.toolbar.functions.formater.comma": "Thousandth place, leave the y digits after the x decimal point",
"math.toolbar.functions.formater.percent": "percentage, leave the y digits after the x decimal point", "math.toolbar.functions.formater.percent": "percentage, leave the y digits after the x decimal point",
"math.tools": "Tools" "math.tools": "Tools",
"math.contextMenu.miTomn": "Variable -> Const",
"math.contextMenu.mnTomi": "Const -> Variable",
"math.contextMenu.mnTo0": "Set to 0",
"math.contextMenu.mnTo1": "Set to 1"
} }

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

@ -263,5 +263,10 @@
"math.toolbar.functions.formater.comma": "千分位, 保留 x 小數點後 y 位", "math.toolbar.functions.formater.comma": "千分位, 保留 x 小數點後 y 位",
"math.toolbar.functions.formater.percent": "百分數, 保留 x 小數點後 y 位", "math.toolbar.functions.formater.percent": "百分數, 保留 x 小數點後 y 位",
"math.tools": "工具" "math.tools": "工具",
"math.contextMenu.miTomn": "變量 -> 常量",
"math.contextMenu.mnTomi": "常量 -> 變量",
"math.contextMenu.mnTo0": "設置為 0",
"math.contextMenu.mnTo1": "設置為 1"
} }

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

@ -263,5 +263,10 @@
"math.toolbar.functions.formater.comma": "千分位, 保留 x 小数点后 y 位", "math.toolbar.functions.formater.comma": "千分位, 保留 x 小数点后 y 位",
"math.toolbar.functions.formater.percent": "百分数, 保留 x 小数点后 y 位", "math.toolbar.functions.formater.percent": "百分数, 保留 x 小数点后 y 位",
"math.tools": "工具" "math.tools": "工具",
"math.contextMenu.miTomn": "变量 -> 常量",
"math.contextMenu.mnTomi": "常量 -> 变量",
"math.contextMenu.mnTo0": "设置为 0",
"math.contextMenu.mnTo1": "设置为 1"
} }

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

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

170
io.sc.platform.core.frontend/template-project/src/views/testcase/math/AutoCompletionManager.ts

@ -0,0 +1,170 @@
import { Tools } from '@/platform';
class AutoCompletionManager {
parameters: object[];
valueTypes: object[];
public setParameters(parameters) {
this.parameters = parameters;
}
public setValueTypes(valueTypes) {
this.valueTypes = valueTypes;
}
public getOptions(path: string): any {
if (!path) {
return this.getParameterOptions();
}
if (path.endsWith('.')) {
path = path.substring(0, path.length - 1);
}
const names = path.split('.');
if (!names) {
return this.getParameterOptions();
}
//参数
const parameter = this.findParmeter(names[0]);
if (!parameter) {
return null;
}
const valueTypeString = parameter.valueType;
const valueTypeVersion = parameter.valueTypeVersion;
let valueType = this.findValueType(valueTypeString, valueTypeVersion);
if (!valueType || !valueType.properties || valueType.properties.length <= 0) {
return null;
}
let index = 1;
while (index < names.length) {
valueType = this.findValueTypeByProperty(valueType.code, valueType.version, names[index++]);
}
const options = [];
for (const property of valueType.properties) {
const propertyValueType = this.findValueType(property.valueType, property.valueTypeVersion);
if (!propertyValueType) {
continue;
}
const info = propertyValueType.version ? propertyValueType.name + '(V' + propertyValueType.version + ')' : propertyValueType.name;
options.push({ label: property.name, type: 'property', apply: '${' + property.name + '}', info: info });
}
return options;
}
public findParmeter(parameterName) {
for (const parameter of this.parameters) {
if (parameter.name === parameterName) {
return parameter;
}
}
return null;
}
public findValueType(valueTypeString, valueTypeVersion) {
for (const valueType of this.valueTypes) {
if (valueType.code === valueTypeString && valueType.version === valueTypeVersion) {
return valueType;
}
}
return null;
}
public findValueTypeByProperty(valueTypeString, valueTypeVersion, propertyName) {
const valueType = this.findValueType(valueTypeString, valueTypeVersion);
if (!valueType) {
return null;
}
for (const property of valueType.properties) {
if (property.name === propertyName) {
return this.findValueType(property.valueType, property.valueTypeVersion);
}
}
}
public getParameterOptions(): any {
const options = [];
for (const parameter of this.parameters) {
const valueType = this.findValueType(parameter.valueType, parameter.valueTypeVersion);
const info = valueType.version ? valueType.name + '(V' + valueType.version + ')' : valueType.name;
options.push({ label: parameter.name, type: 'variable', apply: '${' + parameter.name + '}', info: info });
}
return options;
}
public getPropertyOptions(parameterName: string): any {
let parameterType = undefined;
for (const parameter of this.parameters) {
if (parameter.name === parameterName) {
parameterType = parameter.valueType;
}
}
if (!parameterType) {
return null;
}
for (const type of this.valueTypes) {
if (type.code === parameterType) {
parameterType = type;
}
}
if (!parameterType) {
return null;
}
if (parameterType.properties && parameterType.properties.length > 0) {
const options = [];
for (const property of parameterType.properties) {
options.push({ label: property.name, type: 'property', apply: '${' + property.name + '}', detail: this.findValueTypeInfo(property.valueType) });
}
return options;
}
}
public autoCompletionParameters(to, matchedText): any {
return {
from: to,
options: this.getParameterOptions(),
validFor: /(.*)?/,
};
}
public autoCompletionProperties(to, matchedText): any {
const matchedTextReverse = Tools.reverseString(matchedText);
const regReverse = /(\.\}(.+?)\{\$)+/g; //匹配 '.}xxx{$' 模式
const matcheds = matchedTextReverse.match(regReverse);
if (Tools.isUndefinedOrNull(matcheds) || matcheds.length <= 0) {
return null;
}
const matched = Tools.reverseString(matcheds[0]);
const parameterName = matched.replace(/\$\{(.+?)\}/g, '$1');
if (Tools.isUndefinedOrNull(parameterName)) {
return null;
}
const options = this.getOptions(parameterName);
if (Tools.isUndefinedOrNull(options)) {
return null;
}
return {
from: to,
options: options,
validFor: /^(.*)?$/,
};
}
public autoCompletion(context): any {
const beforeMatched = context.matchBefore(/(.+?)/g);
if (Tools.isUndefinedOrNull(beforeMatched)) {
return null;
}
const beforeText = beforeMatched.text || '';
if (beforeText.endsWith('.')) {
//匹配属性
return this.autoCompletionProperties(beforeMatched.to, beforeText);
} else if (beforeText.endsWith(' ')) {
//匹配参数
return this.autoCompletionParameters(beforeMatched.to);
} else {
return null;
}
}
}
export { AutoCompletionManager };

15
io.sc.platform.core.frontend/template-project/src/views/testcase/math/MathEditor.vue

@ -1,11 +1,24 @@
<template> <template>
<div> <div>
<w-expression v-model="formulaRef" v-model:zoom="zoomRef"></w-expression> <w-math v-model="formulaRef" v-model:zoom="zoomRef" :auto-completion="autoCompletion"></w-math>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { axios, Environment } from '@/platform'; import { axios, Environment } from '@/platform';
import { AutoCompletionManager } from './AutoCompletionManager';
const autoCompletionManager = new AutoCompletionManager();
const autoCompletion = (context) => {
return autoCompletionManager.autoCompletion(context);
};
//
axios.get(Environment.apiContextPath('/api/re/common/listParameterAndValueTypeByParameterId/8153516a-a88e-4d19-b145-e49862e73b0b')).then((response) => {
autoCompletionManager.setParameters(response.data.parameters);
autoCompletionManager.setValueTypes(response.data.valueTypes);
});
const zoomRef = ref(10); const zoomRef = ref(10);
const formula = ''; const formula = '';

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

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

@ -38,7 +38,7 @@ application_version=1.0.0
platform_group=io.sc platform_group=io.sc
platform_version=8.1.44 platform_version=8.1.44
platform_plugin_version=8.1.44 platform_plugin_version=8.1.44
platform_core_frontend_version=8.1.275 platform_core_frontend_version=8.1.279
########################################################### ###########################################################
# dependencies version # dependencies version

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

1
io.sc.platform.monitor/src/main/java/io/sc/platform/monitor/service/impl/SystemMonitorImpl.java

@ -2,6 +2,7 @@ package io.sc.platform.monitor.service.impl;
import io.sc.platform.monitor.service.SystemMonitor; import io.sc.platform.monitor.service.SystemMonitor;
import io.sc.platform.monitor.service.support.ServerInfo; import io.sc.platform.monitor.service.support.ServerInfo;
import org.springframework.beans.factory.annotation.Autowired;
public class SystemMonitorImpl implements SystemMonitor { public class SystemMonitorImpl implements SystemMonitor {
@Override @Override

18
io.sc.platform.monitor/src/main/java/io/sc/platform/monitor/service/support/ServerInfo.java

@ -10,6 +10,8 @@ public class ServerInfo {
private Disk disk; private Disk disk;
private Jvm jvm; private Jvm jvm;
private int onlineUserCount; private int onlineUserCount;
private long serviceRequestSuccessCount;
private long serviceRequestFailedCount;
public static ServerInfo info(){ public static ServerInfo info(){
SystemInfo si = new SystemInfo(); SystemInfo si = new SystemInfo();
@ -79,4 +81,20 @@ public class ServerInfo {
public void setOnlineUserCount(int onlineUserCount) { public void setOnlineUserCount(int onlineUserCount) {
this.onlineUserCount = onlineUserCount; this.onlineUserCount = onlineUserCount;
} }
public long getServiceRequestSuccessCount() {
return serviceRequestSuccessCount;
}
public void setServiceRequestSuccessCount(long serviceRequestSuccessCount) {
this.serviceRequestSuccessCount = serviceRequestSuccessCount;
}
public long getServiceRequestFailedCount() {
return serviceRequestFailedCount;
}
public void setServiceRequestFailedCount(long serviceRequestFailedCount) {
this.serviceRequestFailedCount = serviceRequestFailedCount;
}
} }

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

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

@ -93,7 +93,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.14.5", "quasar": "2.14.5",
"tailwindcss": "3.4.0", "tailwindcss": "3.4.0",
"vue": "3.4.3", "vue": "3.4.3",

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

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

@ -161,4 +161,28 @@
"system.monitor.serverInfo.os.name":"Name", "system.monitor.serverInfo.os.name":"Name",
"system.monitor.serverInfo.os.version":"Version", "system.monitor.serverInfo.os.version":"Version",
"system.monitor.serverInfo.os.arch":"Architecture", "system.monitor.serverInfo.os.arch":"Architecture",
"system.monitor.serverInfo.os.manufacturer":"Manufacturer",
"system.monitor.serverInfo.os.bootTime":"Boot Time",
"system.monitor.serverInfo.os.upTime":"Up Time",
"system.monitor.serverInfo.jvm":"Java Virtual Machine",
"system.monitor.serverInfo.jvm.total":"Total Memory Used",
"system.monitor.serverInfo.jvm.max":"Max Memory Available",
"system.monitor.serverInfo.jvm.free":"Free Memory",
"system.monitor.serverInfo.jvm.version":"JDK Version",
"system.monitor.serverInfo.jvm.home":"JDK Path",
"system.monitor.serverInfo.cpu":"CPU",
"system.monitor.serverInfo.cpu.system":"System",
"system.monitor.serverInfo.cpu.user":"User",
"system.monitor.serverInfo.memory":"Memory",
"system.monitor.serverInfo.disk":"Disk",
"system.monitor.serverInfo.disk.used":"Used",
"system.monitor.serverInfo.disk.free":"Free",
"system.monitor.serverInfo.online":"Online",
"system.monitor.serverInfo.serviceRequest": "Service Request"
} }

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

@ -138,4 +138,28 @@
"system.monitor.serverInfo.os.name":"名稱", "system.monitor.serverInfo.os.name":"名稱",
"system.monitor.serverInfo.os.version":"版本", "system.monitor.serverInfo.os.version":"版本",
"system.monitor.serverInfo.os.arch":"架構", "system.monitor.serverInfo.os.arch":"架構",
"system.monitor.serverInfo.os.manufacturer":"生產商",
"system.monitor.serverInfo.os.bootTime":"上次啟動日期",
"system.monitor.serverInfo.os.upTime":"持續運行天數",
"system.monitor.serverInfo.jvm":"Java 虛擬機",
"system.monitor.serverInfo.jvm.total":"當前佔用的內存總數",
"system.monitor.serverInfo.jvm.max":"最大可用內存總數",
"system.monitor.serverInfo.jvm.free":"空閒內存",
"system.monitor.serverInfo.jvm.version":"JDK 版本",
"system.monitor.serverInfo.jvm.home":"JDK 路徑",
"system.monitor.serverInfo.cpu":"CPU",
"system.monitor.serverInfo.cpu.system":"系統",
"system.monitor.serverInfo.cpu.user":"用戶",
"system.monitor.serverInfo.memory":"內存",
"system.monitor.serverInfo.disk":"存儲",
"system.monitor.serverInfo.disk.used":"已用",
"system.monitor.serverInfo.disk.free":"空閒",
"system.monitor.serverInfo.online":"在線用戶",
"system.monitor.serverInfo.serviceRequest": "服務請求"
} }

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

@ -190,4 +190,6 @@
"system.monitor.serverInfo.disk.free":"空闲", "system.monitor.serverInfo.disk.free":"空闲",
"system.monitor.serverInfo.online":"在线用户", "system.monitor.serverInfo.online":"在线用户",
"system.monitor.serverInfo.serviceRequest": "服务请求"
} }

50
io.sc.platform.system.frontend/src/views/monitor/ServerInfo.vue

@ -86,14 +86,21 @@
</q-card-section> </q-card-section>
</q-card> </q-card>
</div> </div>
<div class="col-4 px-4"></div> <div class="col-4 px-4">
<q-card>
<q-card-section>
<div class="text-h6">{{ $t('system.monitor.serverInfo.serviceRequest') }}</div>
<w-echarts ref="serviceRequestEchartsRef" style="width: 100%; height: 250px" :option="serviceRequestOption"></w-echarts>
</q-card-section>
</q-card>
</div>
<div class="col-4 px-4"></div> <div class="col-4 px-4"></div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, onActivated, onDeactivated } from 'vue'; import { ref, onMounted, onActivated, onDeactivated } from 'vue';
import { axios, Environment, t } from 'platform-core'; import { axios, Environment, t, Formater } from 'platform-core';
const serverInfo = ref(); const serverInfo = ref();
const cpuEchartsRef = ref(); const cpuEchartsRef = ref();
@ -161,6 +168,40 @@ const onlineOption = {
series: [{ type: 'line', stack: 'Total', showSymbol: false, smooth: true, data: [] }], series: [{ type: 'line', stack: 'Total', showSymbol: false, smooth: true, data: [] }],
}; };
const serviceRequestEchartsRef = ref();
const serviceRequestOption = {
animation: false,
legend: {},
tooltip: {
trigger: 'item',
formatter: (params) => {
return Formater.thousands()(params.value);
},
},
series: [
{
type: 'pie',
top: 50,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
data: [
{ value: 0, name: t('failed') },
{ value: 0, name: t('success') },
],
},
],
};
const refresh = () => { const refresh = () => {
axios.get(Environment.apiContextPath('/api/monitor/metrics')).then((response) => { axios.get(Environment.apiContextPath('/api/monitor/metrics')).then((response) => {
const data = response.data; const data = response.data;
@ -196,6 +237,11 @@ const refresh = () => {
onlineOption.series[0].data.shift(); onlineOption.series[0].data.shift();
} }
onlineEchartsRef.value.setOption(onlineOption); onlineEchartsRef.value.setOption(onlineOption);
// serviceRequest
serviceRequestOption.series[0].data[0].value = data.serviceRequestFailedCount;
serviceRequestOption.series[0].data[1].value = data.serviceRequestSuccessCount;
serviceRequestEchartsRef.value.setOption(serviceRequestOption);
}); });
}; };

5
io.sc.platform.system/src/main/java/io/sc/platform/system/auditlog/service/AuditLogService.java

@ -5,4 +5,9 @@ import io.sc.platform.system.auditlog.jpa.entity.AuditLogEntity;
import io.sc.platform.system.auditlog.jpa.repository.AuditLogRepository; import io.sc.platform.system.auditlog.jpa.repository.AuditLogRepository;
public interface AuditLogService extends DaoService<AuditLogEntity, String, AuditLogRepository> { public interface AuditLogService extends DaoService<AuditLogEntity, String, AuditLogRepository> {
/**
* 获取服务请求成功和失败的次数
* @return [0]: failed; [1]: success
*/
public long[] getServiceRequestSuccessAndFailedCount();
} }

28
io.sc.platform.system/src/main/java/io/sc/platform/system/auditlog/service/impl/AuditLogServiceImpl.java

@ -4,9 +4,37 @@ import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.system.auditlog.jpa.entity.AuditLogEntity; import io.sc.platform.system.auditlog.jpa.entity.AuditLogEntity;
import io.sc.platform.system.auditlog.jpa.repository.AuditLogRepository; import io.sc.platform.system.auditlog.jpa.repository.AuditLogRepository;
import io.sc.platform.system.auditlog.service.AuditLogService; import io.sc.platform.system.auditlog.service.AuditLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.sql.ResultSet;
import java.sql.SQLException;
@Service @Service
public class AuditLogServiceImpl extends DaoServiceImpl<AuditLogEntity, String, AuditLogRepository> implements AuditLogService { public class AuditLogServiceImpl extends DaoServiceImpl<AuditLogEntity, String, AuditLogRepository> implements AuditLogService {
@Autowired private JdbcTemplate jdbcTemplate;
@Override
public long[] getServiceRequestSuccessAndFailedCount() {
return jdbcTemplate.query("select STATUS_ STATUS,count(*) COUNT from SYS_AUDIT_LOG group by STATUS order by STATUS", new ResultSetExtractor<long[]>(){
@Override
public long[] extractData(ResultSet rs) throws SQLException, DataAccessException {
long[] result =new long[2];
while(rs.next()){
String key =rs.getString("STATUS");
if("success".equalsIgnoreCase(key)){
result[1] =rs.getLong("COUNT");
}else if("failed".equalsIgnoreCase(key)){
result[0] =rs.getLong("COUNT");
}
}
return result;
}
});
}
} }

7
io.sc.platform.system/src/main/java/io/sc/platform/system/monitor/controller/MetricsWebController.java

@ -4,6 +4,8 @@ import io.sc.platform.monitor.service.SystemMonitor;
import io.sc.platform.monitor.service.impl.SystemMonitorImpl; import io.sc.platform.monitor.service.impl.SystemMonitorImpl;
import io.sc.platform.monitor.service.support.ServerInfo; import io.sc.platform.monitor.service.support.ServerInfo;
import io.sc.platform.mvc.autoconfigure.support.OnlineUserCounterInterceptor; import io.sc.platform.mvc.autoconfigure.support.OnlineUserCounterInterceptor;
import io.sc.platform.system.auditlog.service.AuditLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -11,11 +13,16 @@ import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/api/monitor") @RequestMapping("/api/monitor")
public class MetricsWebController { public class MetricsWebController {
@Autowired private AuditLogService auditLogService;
@GetMapping("metrics") @GetMapping("metrics")
public ServerInfo metrics() throws Exception { public ServerInfo metrics() throws Exception {
SystemMonitor monitor =new SystemMonitorImpl(); SystemMonitor monitor =new SystemMonitorImpl();
ServerInfo serverInfo =monitor.getServerInfo(); ServerInfo serverInfo =monitor.getServerInfo();
serverInfo.setOnlineUserCount(OnlineUserCounterInterceptor.count()); serverInfo.setOnlineUserCount(OnlineUserCounterInterceptor.count());
long[] counter =auditLogService.getServiceRequestSuccessAndFailedCount();
serverInfo.setServiceRequestFailedCount(counter[0]);
serverInfo.setServiceRequestSuccessCount(counter[1]);
return serverInfo; return serverInfo;
} }
} }

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

@ -92,7 +92,7 @@
"luckyexcel": "1.0.1", "luckyexcel": "1.0.1",
"mockjs": "1.1.0", "mockjs": "1.1.0",
"pinia": "2.1.7", "pinia": "2.1.7",
"platform-core": "8.1.275", "platform-core": "8.1.279",
"quasar": "2.15.4", "quasar": "2.15.4",
"tailwindcss": "3.4.4", "tailwindcss": "3.4.4",
"vue": "3.4.31", "vue": "3.4.31",

Loading…
Cancel
Save