Compare commits

...

55 Commits
paid ... master

Author SHA1 Message Date
zsmj1994 03eac54abd DEC-17971 feat: redis数据集加密 4 years ago
operation e3fab11a21 Merge pull request 'DEC-17168 更换redis插件前端展示的图片' (#8) from alan/demo-tabledata-redis:master into master 4 years ago
alan 85b03e625d DEC-17168 更换redis插件的图片 4 years ago
operation 1edd7bac51 Merge pull request '更换平台图片' (#7) from Roger.Chen/demo-tabledata-redis:master into master 4 years ago
Roger.Chen c823a2940e DEC-17168 fix: 替换一下redis数据集的图片,之前那样替换会导致设计器图片变大 4 years ago
Roger.Chen e063102897 Merge branch 'master' of https://code.fanruan.com/Roger.Chen/demo-tabledata-redis 4 years ago
Roger.Chen c36533c0e7 DEC-17168 fix: 替换一下redis数据集的图片,之前那样替换会导致设计器图片变大 4 years ago
richie 9479176385 Merge pull request 'WIP:修改参数选择公式时的问题,并更换redis.png图片' (#5) from Roger.Chen/demo-tabledata-redis:master into master 4 years ago
Roger.Chen 967b3ae527 DEC-16606 fix: 平台数据集参数公式识别错误 使用fine-kitjar包中的类 4 years ago
Roger.Chen 34b349434d DEC-17168 fix: 替换一下redis数据集的图片 4 years ago
Roger.Chen a7e537312f DEC-16606 fix: 平台数据集参数公式识别错误 4 years ago
richie 428d99baa3 Merge pull request 'KERNEL-6540 类型引用规范化' (#3) from youki/demo-tabledata-redis:master into master 4 years ago
youki 151179763f KERNEL-6540 rafactor: 类型引用规范化 4 years ago
youki 4c1e427b20 KERNEL-6540 chore: 更新依赖配置 4 years ago
richie 60b7cf1d52 Merge pull request 'REPORT-43364 fix: 官网的redis插件连接失败' (#1) from Roger.Chen/demo-tabledata-redis:master into master 4 years ago
Roger.Chen 1ca357677c REPORT-43364 fix: 官网的redis插件连接失败 4 years ago
Roger.Chen 3f549f3922 REPORT-43364 fix: 官网的redis插件连接失败 4 years ago
richie 779743633f 版本号 4 years ago
richie 83e78f2e2f 支持单一主机的集群模式 4 years ago
richie efc0bb85fc 打包脚本 4 years ago
richie 6cd8fabf35 REPORT-34809 参数没有动态计算的问题 4 years ago
richie 923290e4d2 Merge branch 'master' of Jimmy.Chai/demo-tabledata-redis into master 4 years ago
Jimmy.Chai f85211619d 报表平台支持键值按编号搜索 4 years ago
Jimmy.Chai 0d7c7f6deb 报表平台支持键值按编号搜索 4 years ago
Jimmy.Chai d60fc192cd Merge branch 'master' of https://git.fanruan.com/Jimmy.Chai/demo-tabledata-redis into refactor 4 years ago
Jimmy.Chai 16209de366 Merge branch 'master' of https://git.fanruan.com/fanruan/demo-tabledata-redis 4 years ago
richie 7308a07466 更新 4 years ago
richie 3a3124a20b 重复关闭redis连接的问题 4 years ago
Jimmy.Chai d898e82518 pull master 4 years ago
Jimmy.Chai a704a6c452 更新配置 4 years ago
richie c4b6a2c774 修复hkeys问题 4 years ago
richie 697e116b7e 一个引用的问题 5 years ago
richie 9b2c1b0dd5 redis连接没有关闭的问题 5 years ago
richie b2a1466484 readme 5 years ago
richie dfb28e10a4 打包脚本问题 5 years ago
richie 2e600bbe6c gradle构建 5 years ago
richie b119c21410 查key的时候可以选数据库 5 years ago
richie 99b14b115c gradle构建脚本 5 years ago
richie 55c724bb70 移除付费标记 5 years ago
richie a2b55fc862 redis集群问题 5 years ago
richie 9a5ec86fba Merge branch 'refactor' of Elijah/demo-tabledata-redis into refactor 5 years ago
Elijah 3891cf53b4 DEC-11133 fix 5 years ago
richie 88d337fe50 删除不需要的zip包 5 years ago
richie 0b201dd7e2 Merge branch 'refactor' of git.fanruan.com:fanruan/demo-tabledata-redis into refactor 5 years ago
richie 004a4da48b 修复一个常量引用问题 5 years ago
richie a97a627538 Merge branch 'refactor' of alan/demo-tabledata-redis into refactor 5 years ago
richie 1af53ffcff 数据集接口 5 years ago
richie d53d61a0e2 Merge branch 'refactor' of Elijah/demo-tabledata-redis into refactor 5 years ago
Elijah 47ee543dcf KERNEL-1749 redis数据集适配 5 years ago
alan 7d828c2fd7 fix: 更新数据连接接口 5 years ago
alan 4863086bb1 fix: 修改切换公式时的bug 5 years ago
alan 57e70eb0a5 fix: 修改bug 5 years ago
alan bb8d5caf54 fix: 删除无用组件 5 years ago
alan 485427080a fix: 与后台接口对接,加入公式编辑器。 5 years ago
alan cb1e3db73f feat: 调整布局,对接后端 5 years ago
  1. 7
      .gitignore
  2. 128
      build.gradle
  3. 13
      encrypt.xml
  4. BIN
      gradle/wrapper/gradle-wrapper.jar
  5. 5
      gradle/wrapper/gradle-wrapper.properties
  6. 183
      gradlew
  7. 103
      gradlew.bat
  8. BIN
      lib/finekit-10.0.jar
  9. 15
      plugin.xml
  10. 4
      readme.md
  11. 5
      settings.gradle
  12. 9
      src/main/java/com/fr/plugin/db/redis/RedisConnectionComponent.java
  13. 3
      src/main/java/com/fr/plugin/db/redis/RedisLocaleFinder.java
  14. 13
      src/main/java/com/fr/plugin/db/redis/RedisScriptUniversalTableDataImpl.java
  15. 6
      src/main/java/com/fr/plugin/db/redis/RedisUniversalConnectionImpl.java
  16. 13
      src/main/java/com/fr/plugin/db/redis/RedisUniversalTableDataImpl.java
  17. 5
      src/main/java/com/fr/plugin/db/redis/action/SearchKeysAction.java
  18. 17
      src/main/java/com/fr/plugin/db/redis/bean/ParameterBean.java
  19. 32
      src/main/java/com/fr/plugin/db/redis/core/RedisDatabaseConnection.java
  20. 6
      src/main/java/com/fr/plugin/db/redis/core/RedisPool.java
  21. 1
      src/main/java/com/fr/plugin/db/redis/core/RedisScriptTableData.java
  22. 18
      src/main/java/com/fr/plugin/db/redis/core/RedisScriptTableDataModel.java
  23. 3
      src/main/java/com/fr/plugin/db/redis/core/RedisTableData.java
  24. 8
      src/main/java/com/fr/plugin/db/redis/core/RedisTableDataModel.java
  25. 5
      src/main/java/com/fr/plugin/db/redis/core/accessor/category/ClusterRedisClient.java
  26. 2
      src/main/java/com/fr/plugin/db/redis/help/client/BaseRedisClient.java
  27. 12
      src/main/java/com/fr/plugin/db/redis/ui/RedisConnectionPane.java
  28. 14
      src/main/java/com/fr/plugin/db/redis/ui/RedisDBConnectionChosePane.java
  29. 11
      src/main/java/com/fr/plugin/db/redis/util/RedisUtils.java
  30. BIN
      src/main/resources/com/fr/plugin/db/redis/images/redis.jpg
  31. 2
      src/main/resources/com/fr/plugin/db/redis/locale/redis.properties
  32. 7
      src/main/resources/com/fr/plugin/db/redis/locale/redis_en_US.properties
  33. 17
      src/main/resources/com/fr/plugin/db/redis/locale/redis_zh_CN.properties
  34. BIN
      src/main/resources/com/fr/plugin/db/redis/web/demo-tabledate-redis-web.zip
  35. 2030
      src/main/resources/com/fr/plugin/db/redis/web/redis.css
  36. 16
      src/main/resources/com/fr/plugin/db/redis/web/redis.js
  37. 1
      src/web/.npmrc
  38. 19
      src/web/assets/scripts/dec.js
  39. 30
      src/web/babel.config.js
  40. 16
      src/web/index.html
  41. 17
      src/web/package.json
  42. 210
      src/web/private/i18n.ts
  43. 38
      src/web/src/index.ts
  44. 2
      src/web/src/less/background.less
  45. 9
      src/web/src/less/font.less
  46. 7
      src/web/src/less/lib/font.less
  47. 2
      src/web/src/less/utils.less
  48. 33
      src/web/src/modules/app.constant.ts
  49. 222
      src/web/src/modules/app.dataset.ts
  50. 33
      src/web/src/modules/app.edit.ts
  51. 7
      src/web/src/modules/app.less
  52. 47
      src/web/src/modules/app.model.ts
  53. 254
      src/web/src/modules/app.program.ts
  54. 31
      src/web/src/modules/app.show.ts
  55. 22
      src/web/src/modules/components/database_index/database_index.model.ts
  56. 44
      src/web/src/modules/components/database_index/database_index.service.ts
  57. 85
      src/web/src/modules/components/database_index/database_index.ts
  58. 5
      src/web/src/modules/components/form_item/form_item.ts
  59. 40
      src/web/src/modules/components/parameter/parameter.model.ts
  60. 172
      src/web/src/modules/components/parameter/parameter.ts
  61. 9
      src/web/src/modules/components/parameter/parameter.typings.d.ts
  62. 20
      src/web/src/modules/components/parameter/parameter_input/input/input.service.ts
  63. 6
      src/web/src/modules/components/parameter/parameter_input/input/input.ts
  64. 41
      src/web/src/modules/components/parameter/parameter_input/input/input_boolean.ts
  65. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_date.ts
  66. 45
      src/web/src/modules/components/parameter/parameter_input/input/input_formula.ts
  67. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_int.ts
  68. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_number.ts
  69. 41
      src/web/src/modules/components/parameter/parameter_input/input/input_string.ts
  70. 5
      src/web/src/modules/components/parameter/parameter_input/parameter_input.less
  71. 40
      src/web/src/modules/components/parameter/parameter_input/parameter_input.model.ts
  72. 165
      src/web/src/modules/components/parameter/parameter_input/parameter_input.ts
  73. 15
      src/web/src/modules/components/pool/pool.ts
  74. 15
      src/web/src/modules/components/pool/pool_edit.ts
  75. 20
      src/web/src/modules/components/preview/preview.model.ts
  76. 31
      src/web/src/modules/components/preview/preview.ts
  77. 19
      src/web/src/modules/components/proxy/proxy.ts
  78. 19
      src/web/src/modules/components/proxy/proxy_edit.ts
  79. 4
      src/web/src/modules/constants/env.ts
  80. 59
      src/web/src/modules/crud/crud.request.ts
  81. 130
      src/web/src/modules/crud/crud.service.ts
  82. 549
      src/web/src/modules/crud/formulaData.ts
  83. 39
      src/web/src/modules/table_list/list_item.ts
  84. 40
      src/web/src/modules/table_list/table_list.model.ts
  85. 154
      src/web/src/modules/table_list/table_list.ts
  86. 77
      src/web/src/ui/fineui.ts
  87. 1
      src/web/src/ui/index.ts
  88. 1
      src/web/tsconfig.json
  89. 2
      src/web/types/globals.d.ts
  90. 2
      src/web/webpack/webpack.common.js
  91. 6
      src/web/webpack/webpack.dev.js
  92. 6
      src/web/webpack/webpack.prod.js
  93. 1687
      src/web/yarn.lock

7
.gitignore vendored

@ -2,4 +2,9 @@
.idea/
lib/report/*.jar
target/
.DS_Store
.DS_Store
.gradle
build
local.properties
classes/
transform-classes/

128
build.gradle

@ -0,0 +1,128 @@
apply plugin: 'java'
ext {
/**
* jar的路径
* 1.jar需要打包到zip中,lib根目录下
* 2.jar仅仅是编译时需要lib下子目录下即可
*/
libPath = "$projectDir/../webroot/WEB-INF/lib"
/**
* class进行加密保护
*/
guard = false
def pluginInfo = getPluginInfo()
pluginPre = "fine-plugin"
pluginName = pluginInfo.id
pluginVersion = pluginInfo.version
privateLib = "$projectDir/../webroot/WEB-INF/plugins/plugin-" + pluginName + "-1.0"
outputPath = privateLib + "/classes"
}
group = 'com.fr.plugin'
version = '10.0'
sourceCompatibility = '8'
sourceSets {
main {
java.outputDir = file(outputPath)
output.resourcesDir = file(outputPath)
}
}
ant.importBuild("encrypt.xml")
//ant变量
ant.projectDir = projectDir
ant.references["compile.classpath"] = ant.path {
fileset(dir: libPath, includes: '**/*.jar')
fileset(dir: ".",includes:"**/*.jar" )
}
classes.dependsOn('clean')
task copyFiles(type: Copy,dependsOn: 'classes'){
from outputPath
into "$projectDir/classes"
}
task preJar(type:Copy,dependsOn: guard ? 'compile_encrypt_javas' : 'compile_plain_javas'){
from "$projectDir/classes"
into "$projectDir/transform-classes"
include "**/*.*"
}
jar.dependsOn("preJar")
task makeJar(type: Jar,dependsOn: preJar){
from fileTree(dir: "$projectDir/transform-classes")
baseName pluginPre
appendix pluginName
version pluginVersion
destinationDir = file("$buildDir/libs")
doLast(){
delete file("$projectDir/classes")
delete file("$projectDir/transform-classes")
}
}
task copyFile(type: Copy,dependsOn: ["makeJar"]){
from "$buildDir/libs"
from("$projectDir/lib") {
include "*.jar"
}
from "$projectDir/plugin.xml"
into file("$buildDir/temp/plugin")
}
task zip(type:Zip,dependsOn:["copyFile"]){
from "$buildDir/temp/plugin"
destinationDir file("$buildDir/install")
baseName pluginPre
appendix pluginName
version pluginVersion
}
//build时包含哪些文件,
processResources {
// exclude everything
// *.css没效果
// exclude '**/*.css'
// except this file
// include 'xx.xml'
}
/*读取plugin.xml中的version*/
def getPluginInfo(){
def xmlFile = file("plugin.xml")
if (!xmlFile.exists()) {
return ["id":"none", "version":"1.0.0"]
}
def plugin = new XmlParser().parse(xmlFile)
def version = plugin.version[0].text()
def id = plugin.id[0].text()
return ["id":id,"version":version]
}
repositories {
mavenLocal()
maven {
url = uri('http://mvn.finedevelop.com/repository/maven-public/')
}
}
task prepare(type: Copy) {
into privateLib
from configurations.runtimeClasspath
}
dependencies {
//使jar
implementation fileTree(dir: 'lib', include: ['**/*.jar'])
implementation fileTree(dir: libPath, include: ['**/*.jar'])
}

13
encrypt.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<target name="compile_encrypt_javas" depends="copyFiles">
<echo message="加密文件"/>
<echo message="${projectDir}"/>
<taskdef name="pretreatment" classname="com.fr.plugin.pack.PluginPretreatmentTask">
<classpath refid="compile.classpath"/>
</taskdef>
<pretreatment baseDir="${projectDir}"/>
</target>
<target name="compile_plain_javas" depends="copyFiles">
</target>
</project>

BIN
gradle/wrapper/gradle-wrapper.jar vendored

Binary file not shown.

5
gradle/wrapper/gradle-wrapper.properties vendored

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://downloads.gradle-dn.com/distributions/gradle-6.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

183
gradlew vendored

@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

103
gradlew.bat vendored

@ -0,0 +1,103 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

BIN
lib/finekit-10.0.jar

Binary file not shown.

15
plugin.xml

@ -3,12 +3,23 @@
<id>com.fr.solution.plugin.db.redis.v10</id>
<name><![CDATA[Redis数据集]]></name>
<active>yes</active>
<version>7.2</version>
<version>7.4.3</version>
<env-version>10.0</env-version>
<jartime>2019-03-29</jartime>
<jartime>2020-01-20</jartime>
<vendor>richie</vendor>
<description><![CDATA[可以连接Redis数据库,支持哈希表、列表、集合以及有序集合]]></description>
<change-notes><![CDATA[
[2021-2-4]更换平台redis图片。<br/>
[2020-12-29]解决平台数据集参数公式识别错误。<br/>
[2020-11-16]修复保存数据连接后平台测试连接报错的问题。<br/>
[2020-10-28]支持单一主机的集群模式连接选项。<br/>
[2020-07-07]修复了数据集没有随着参数的变化而变化的问题。<br>
[2020-06-30]修复了一个失误导致连接被重复关闭的问题。<br/>
[2020-06-22]修改hkeys没能正确调用的问题。<br/>
[2020-06-09]修复redis连接没有正确关闭的问题。<br/>
[2020-06-05]搜索key的时候可以选择不同的数据库。<br>
[2020-04-26]修复插件被标记为需要付费的问题。<br/>
[2020-04-21]修复redis集群下的一个问题。<br/>
[2019-10-30]适配新服务器数据集接口,在决策平台可以直接定义<br/>
[2019-09-29]修复无法兼容老版本的问题。<br/>
[2019-09-18]支持手动选择不同JavaScript脚本引擎。<br/>

4
readme.md

@ -1,8 +1,8 @@
# 帆软报表连接redis缓存数据库插件
## 插件编译
进入插件源码目录,执行命令
`ant -f build.xml jar`
即可
`gradle zip`
即可在build/install下获得插件安装包
## 插件安装
使用帆软设计器自带的插件管理器即可安装。

5
settings.gradle

@ -0,0 +1,5 @@
/*
* This file was generated by the Gradle 'init' task.
*/
rootProject.name = 'demo-tabledata-redis'

9
src/main/java/com/fr/plugin/db/redis/RedisConnectionComponent.java

@ -2,12 +2,19 @@ package com.fr.plugin.db.redis;
import com.fr.web.struct.Component;
import com.fr.web.struct.browser.RequestClient;
import com.fr.web.struct.category.ParserType;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
public class RedisConnectionComponent extends Component {
public static final RedisConnectionComponent KEY = new RedisConnectionComponent();
@Override
public ScriptPath script(RequestClient req) {
return ScriptPath.build("com/fr/plugin/db/redis/web/redis.js");
return ScriptPath.build("com/fr/plugin/db/redis/web/redis.js", ParserType.DYNAMIC);
}
@Override
public StylePath style(RequestClient req) {
return StylePath.build("com/fr/plugin/db/redis/web/redis.css", ParserType.DYNAMIC);
}
}

3
src/main/java/com/fr/plugin/db/redis/RedisLocaleFinder.java

@ -1,11 +1,8 @@
package com.fr.plugin.db.redis;
import com.fr.plugin.db.redis.core.RedisConstants;
import com.fr.stable.fun.Authorize;
import com.fr.stable.fun.impl.AbstractLocaleFinder;
@Authorize(callSignKey = RedisConstants.PLUGIN_ID)
public class RedisLocaleFinder extends AbstractLocaleFinder {
@Override
public String find() {

13
src/main/java/com/fr/plugin/db/redis/RedisScriptUniversalTableDataImpl.java

@ -2,7 +2,6 @@ package com.fr.plugin.db.redis;
import com.fanruan.api.cal.FormulaKit;
import com.fanruan.api.data.ConnectionKit;
import com.fanruan.api.data.TableDataKit;
import com.fanruan.api.util.StringKit;
import com.fr.data.impl.Connection;
import com.fr.decision.fun.impl.AbstractUniversalServerTableDataProvider;
@ -40,7 +39,11 @@ public class RedisScriptUniversalTableDataImpl extends AbstractUniversalServerTa
JSONObject data = new JSONObject();
Connection database = redisScriptTableData.getDatabase();
data.put(RedisConstants.DATABASE, database instanceof NameReference ? ((NameReference) database).getName() : StringKit.EMPTY);
data.put(RedisConstants.ORDER, redisScriptTableData.getOrderValue().toString());
if (redisScriptTableData.getOrderValue() instanceof FormulaOrderValue) {
data.put(RedisConstants.ORDER, redisScriptTableData.getOrderValue().toString());
} else {
data.put(RedisConstants.ORDER, redisScriptTableData.getOrderValue().getValue());
}
data.put(RedisConstants.SCRIPT, redisScriptTableData.getScript());
data.put(RedisConstants.ENGINE, redisScriptTableData.getEngineType().getType());
data.put(RedisConstants.PARAMETERS, ParameterBean.createParameterBeans(redisScriptTableData.getParameters(Calculator.createCalculator())));
@ -52,7 +55,7 @@ public class RedisScriptUniversalTableDataImpl extends AbstractUniversalServerTa
RedisScriptTableData newTableData = new RedisScriptTableData();
String databaseName = data.getString(RedisConstants.DATABASE);
String script = data.getString(RedisConstants.SCRIPT);
if (!StringKit.isEmpty(databaseName) && TableDataKit.findTableData(databaseName) != null) {
if (StringKit.isNotEmpty(databaseName) && ConnectionKit.getConnection(databaseName) != null) {
newTableData.setDatabase(ConnectionKit.createNameConnection(databaseName));
}
newTableData.setEngineType(EngineType.parse(data.getInt(RedisConstants.ENGINE)));
@ -63,9 +66,7 @@ public class RedisScriptUniversalTableDataImpl extends AbstractUniversalServerTa
} else {
newTableData.setOrderValue(new FormulaOrderValue(FormulaKit.newFormula(order)));
}
newTableData.setParameters(RedisUtils.analyzeParameter(oldTableData.getParameters(Calculator.createCalculator()), newTableData.getOrderValue(), script));
newTableData.setParameters(RedisUtils.analyzeParameter(data.getJSONArray(RedisConstants.PARAMETERS), newTableData.getOrderValue(), script));
return newTableData;
}

6
src/main/java/com/fr/plugin/db/redis/RedisUniversalConnectionImpl.java

@ -27,7 +27,7 @@ public class RedisUniversalConnectionImpl extends AbstractUniversalConnectionPro
@Override
public String iconPathForConnection() {
return "/com/fr/plugin/db/redis/images/redis.png";
return "/com/fr/plugin/db/redis/images/redis.jpg";
}
@Override
@ -44,7 +44,9 @@ public class RedisUniversalConnectionImpl extends AbstractUniversalConnectionPro
public JSONObject serialize(RedisDatabaseConnection connection) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put(BASIC_INFO, JSONObject.mapFrom(connection.clone()));
JSONObject basicInfo = JSONObject.mapFrom(connection.clone());
basicInfo.put("password", DecisionServiceConstants.DEFAULT_PASSWORD);
jsonObject.put(BASIC_INFO, basicInfo);
//将ConnectionPoolConfig和RedisConnectionProxyConfig也一次塞给前台展示
jsonObject.put(POOL_INFO, JSONObject.mapFrom(RedisConnectionPoolConfig.getInstance().clone()));
JSONObject proxy = JSONObject.mapFrom(RedisConnectionProxyConfig.getInstance().clone());

13
src/main/java/com/fr/plugin/db/redis/RedisUniversalTableDataImpl.java

@ -2,7 +2,6 @@ package com.fr.plugin.db.redis;
import com.fanruan.api.cal.FormulaKit;
import com.fanruan.api.data.ConnectionKit;
import com.fanruan.api.data.TableDataKit;
import com.fanruan.api.util.StringKit;
import com.fr.data.impl.Connection;
import com.fr.decision.fun.impl.AbstractUniversalServerTableDataProvider;
@ -39,7 +38,11 @@ public class RedisUniversalTableDataImpl extends AbstractUniversalServerTableDat
JSONObject data = new JSONObject();
Connection database = redisTableData.getDatabase();
data.put(RedisConstants.DATABASE, database instanceof NameReference ? ((NameReference) database).getName() : StringKit.EMPTY);
data.put(RedisConstants.ORDER, redisTableData.getOrderValue().toString());
if (redisTableData.getOrderValue() instanceof FormulaOrderValue) {
data.put(RedisConstants.ORDER, redisTableData.getOrderValue().toString());
} else {
data.put(RedisConstants.ORDER, redisTableData.getOrderValue().getValue());
}
data.put(RedisConstants.SCRIPT, redisTableData.getScript());
data.put(RedisConstants.QUERY, redisTableData.getQuery());
data.put(RedisConstants.PARAMETERS, ParameterBean.createParameterBeans(redisTableData.getParameters(Calculator.createCalculator())));
@ -48,11 +51,11 @@ public class RedisUniversalTableDataImpl extends AbstractUniversalServerTableDat
@Override
public RedisTableData deserialize(RedisTableData oldTableData, JSONObject data) {
RedisTableData newTableData = oldTableData;
RedisTableData newTableData = new RedisTableData();
String databaseName = data.getString(RedisConstants.DATABASE);
String script = data.getString(RedisConstants.SCRIPT);
String query = data.getString(RedisConstants.QUERY);
if (!StringKit.isEmpty(databaseName) && TableDataKit.findTableData(databaseName) != null) {
if (StringKit.isNotEmpty(databaseName) && ConnectionKit.getConnection(databaseName) != null) {
newTableData.setDatabase(ConnectionKit.createNameConnection(databaseName));
}
newTableData.setScript(script);
@ -64,7 +67,7 @@ public class RedisUniversalTableDataImpl extends AbstractUniversalServerTableDat
} else {
newTableData.setOrderValue(new FormulaOrderValue(FormulaKit.newFormula(order)));
}
newTableData.setParameters(RedisUtils.analyzeParameter(oldTableData.getParameters(Calculator.createCalculator()), newTableData.getOrderValue(), script, query));
newTableData.setParameters(RedisUtils.analyzeParameter(data.getJSONArray(RedisConstants.PARAMETERS), newTableData.getOrderValue(), script, query));
return newTableData;
}

5
src/main/java/com/fr/plugin/db/redis/action/SearchKeysAction.java

@ -40,10 +40,11 @@ public class SearchKeysAction extends BaseHttpHandler {
String[] keys = new String[0];
String pattern = request.getParameter("pattern");
String connectionName = request.getParameter("database");
if (StringKit.isNotEmpty(pattern) && StringKit.isNotEmpty(connectionName)) {
String orderValue = request.getParameter("orderValue");
if (StringKit.isNotEmpty(pattern) && StringKit.isNotEmpty(connectionName) && StringKit.isNotEmpty(orderValue)) {
Connection connection = ConnectionKit.getConnection(connectionName);
if (connection instanceof RedisDatabaseConnection) {
keys = connection.summary(pattern);
keys = connection.summary(pattern, orderValue);
}
}
FlushKit.printAsJSON(response, JSONFactory.createJSON(Arrays.asList(keys)));

17
src/main/java/com/fr/plugin/db/redis/bean/ParameterBean.java

@ -1,6 +1,9 @@
package com.fr.plugin.db.redis.bean;
import com.fr.base.ParameterTypeHandler;
import com.fanruan.api.cal.ParameterKit;
import com.fanruan.api.util.GeneralKit;
import com.fanruan.api.util.StringKit;
import com.fr.general.GeneralUtils;
import com.fr.stable.ParameterProvider;
import java.util.ArrayList;
@ -11,12 +14,12 @@ import java.util.List;
* @version 10.0.4
* Created by Elijah on 2019/10/30
*/
public class ParameterBean{
public class ParameterBean {
public static final String TYPE = "type";
public static final String NAME = "name";
public static final String VALUE = "value";
private String type = ParameterTypeHandler.String.name();
private String type = ParameterKit.Type.TYPE_STRING;
private String name;
private String value;
@ -59,12 +62,16 @@ public class ParameterBean{
}
public static ParameterBean createBean(ParameterProvider parameterProvider) {
return new ParameterBean(parameterProvider.getClass().getSimpleName(),parameterProvider.getName(), parameterProvider.valueToString());
if (parameterProvider.getValue() != null) {
return new ParameterBean(parameterProvider.getValue().getClass().getSimpleName(), parameterProvider.getName(), GeneralKit.objectToString(parameterProvider.getValue()));
} else {
return new ParameterBean(String.class.getSimpleName(), parameterProvider.getName(), StringKit.EMPTY);
}
}
public static List<ParameterBean> createParameterBeans(ParameterProvider[] parameterProviders) {
List<ParameterBean> parameterBeans = new ArrayList<ParameterBean>();
for (ParameterProvider parameterProvider: parameterProviders) {
for (ParameterProvider parameterProvider : parameterProviders) {
parameterBeans.add(ParameterBean.createBean(parameterProvider));
}
return parameterBeans;

32
src/main/java/com/fr/plugin/db/redis/core/RedisDatabaseConnection.java

@ -9,6 +9,7 @@ import com.fanruan.api.util.StringKit;
import com.fanruan.api.util.TypeKit;
import com.fr.config.holder.Conf;
import com.fr.data.impl.Connection;
import com.fr.plugin.db.redis.core.accessor.EmbedRedis;
import com.fr.plugin.db.redis.core.emb.Redis;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader;
@ -25,6 +26,7 @@ public class RedisDatabaseConnection extends BaseConnection {
private Conf<String> host = HolderKit.simple(StringKit.EMPTY);
private Conf<String> port = HolderKit.simple(String.valueOf(DEFAULT_REDIS_PORT));
private Conf<String> password = HolderKit.simple(StringKit.EMPTY);
private Conf<Boolean> cluster = HolderKit.simple(false);
public RedisDatabaseConnection() {
@ -54,6 +56,13 @@ public class RedisDatabaseConnection extends BaseConnection {
this.password.set(password);
}
public boolean isCluster() {
return cluster.get();
}
public void setCluster(boolean cluster) {
this.cluster.set(cluster);
}
@Override
public void testConnection() throws Exception {
@ -70,7 +79,7 @@ public class RedisDatabaseConnection extends BaseConnection {
}
public Redis createRedisClient() {
return RedisPool.getFinal(getHost(), getPort(), getPassword());
return RedisPool.getFinal(isCluster(), getHost(), getPort(), getPassword());
}
@Override
@ -79,10 +88,18 @@ public class RedisDatabaseConnection extends BaseConnection {
return ArrayKit.EMPTY_STRING_ARRAY;
} else {
Redis redis = createRedisClient();
Set<String> keys = redis.getClient().keys(args[0]);
String[] array = keys.toArray(new String[0]);
redis.close();
return array;
try {
EmbedRedis embedRedis = redis.getClient();
int len = ArrayKit.getLength(args);
if (len > 1) {
int dbIndex = Integer.parseInt(args[1]);
embedRedis.select(dbIndex);
}
Set<String> keys = embedRedis.keys(args[0]);
return keys.toArray(new String[0]);
} finally {
redis.close();
}
}
}
@ -142,6 +159,7 @@ public class RedisDatabaseConnection extends BaseConnection {
if (StringKit.isNotEmpty(pwd)) {
setPassword(SecurityKit.encrypt(pwd));
}
setCluster(reader.getAttrAsBoolean("cluster", false));
}
}
}
@ -155,15 +173,17 @@ public class RedisDatabaseConnection extends BaseConnection {
if (StringKit.isNotEmpty(getPassword())) {
writer.attr("password", SecurityKit.decrypt(getPassword()));
}
writer.attr("cluster", isCluster());
writer.end();
}
@Override
public Object clone() throws CloneNotSupportedException {
com.fr.plugin.db.redis.core.RedisDatabaseConnection cloned = (com.fr.plugin.db.redis.core.RedisDatabaseConnection) super.clone();
com.fr.plugin.db.redis.core.RedisDatabaseConnection cloned = (RedisDatabaseConnection) super.clone();
cloned.host = (Conf<String>) host.clone();
cloned.port = (Conf<String>) port.clone();
cloned.password = (Conf<String>) password.clone();
cloned.cluster = (Conf<Boolean>) cluster.clone();
return cloned;
}
}

6
src/main/java/com/fr/plugin/db/redis/core/RedisPool.java

@ -61,9 +61,11 @@ public class RedisPool {
jedisPoolMap.clear();
}
public static Redis getFinal(String host, String port, String password) {
public static Redis getFinal(boolean isCluster, String host, String port, String password) {
List<Pair<String, Integer>> pairs = findAllHostAndPassword(host, port);
if (pairs.size() == 1) {
if (isCluster) {
return pool.getJedisCluster(pairs, password);
} else if (pairs.size() == 1) {
return pool.getStandaloneResource(pairs.get(0), password);
} else {
return pool.getJedisCluster(pairs, password);

1
src/main/java/com/fr/plugin/db/redis/core/RedisScriptTableData.java

@ -18,7 +18,6 @@ import com.fr.plugin.db.redis.core.script.EngineType;
import com.fr.plugin.db.redis.util.RedisUtils;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.script.Calculator;
import com.fr.stable.NameReference;
import com.fr.stable.ParameterProvider;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader;

18
src/main/java/com/fr/plugin/db/redis/core/RedisScriptTableDataModel.java

@ -38,13 +38,17 @@ public class RedisScriptTableDataModel extends BaseDataModel {
return;
}
Redis redis = mc.createRedisClient();
redis.getClient().select(dbIndex);
RedisClient redisClient = RedisClientSelector.select(redis, engineType);
SimpleDataModel simple = redisClient.build(redis, script, rowCount);
if (simple != null) {
this.columnNames = simple.getColumnNames();
this.data = simple.getData();
this.rowCount = simple.getRowCount();
try {
redis.getClient().select(dbIndex);
RedisClient redisClient = RedisClientSelector.select(redis, engineType);
SimpleDataModel simple = redisClient.build(redis, script, rowCount);
if (simple != null) {
this.columnNames = simple.getColumnNames();
this.data = simple.getData();
this.rowCount = simple.getRowCount();
}
} finally {
redis.close();
}
}

3
src/main/java/com/fr/plugin/db/redis/core/RedisTableData.java

@ -77,7 +77,8 @@ public class RedisTableData extends BaseTableData {
@Focus(id = RedisConstants.PLUGIN_ID, text = "Plugin-Redis_DB", source = Original.PLUGIN)
public DataModel createDataModel(Calculator calculator, int rowCount) {
long start = System.currentTimeMillis();
ParameterProvider[] ps = getParameters(calculator);
ParameterProvider[] providers = getParameters(calculator);
ParameterProvider[] ps = Calculator.processParameters(calculator, providers);
Connection connection = database.get();
String name = RedisUtils.getName(connection);
if (StringKit.isNotEmpty(name)) {

8
src/main/java/com/fr/plugin/db/redis/core/RedisTableDataModel.java

@ -28,18 +28,18 @@ public class RedisTableDataModel extends BaseDataModel {
return;
}
Redis redis = mc.createRedisClient();
redis.getClient().select(dbIndex);
LogKit.info("Connect to redis and select database:" + dbIndex);
try {
redis.getClient().select(dbIndex);
LogKit.info("Connect to redis and select database:" + dbIndex);
long start = System.currentTimeMillis();
DataWrapper<Object> wrapper = VisitorFactory.getKeyValueResult(calculator, ps, redis.getClient(), query, rowCount);
LogKit.info("Fetch data from redis spend time {} ms.", System.currentTimeMillis() - start);
wrapper.transform(script);
data = wrapper.getData();
columnNames = wrapper.getColumnNames();
redis.close();
} catch (Exception e) {
throw new RuntimeException(e.getCause());
} finally {
redis.close();
}
}

5
src/main/java/com/fr/plugin/db/redis/core/accessor/category/ClusterRedisClient.java

@ -91,7 +91,10 @@ public class ClusterRedisClient implements EmbedRedis {
@Override
public void select(int index) {
jedisCluster.select(index);
Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
entry.getValue().getResource().select(index);
}
}
@Override

2
src/main/java/com/fr/plugin/db/redis/help/client/BaseRedisClient.java

@ -50,7 +50,7 @@ public abstract class BaseRedisClient<A> implements RedisClient<A> {
@ScriptBridge
public String hkeys(String key) {
long start = System.currentTimeMillis();
Set<String> set = jedis.keys(key);
Set<String> set = jedis.hkeys(key);
LogKit.info("Fetch data from redis spend time {} ms.", System.currentTimeMillis() - start);
return object2JSONString(set);
}

12
src/main/java/com/fr/plugin/db/redis/ui/RedisConnectionPane.java

@ -4,6 +4,7 @@ import com.fanruan.api.conf.ConfigurationKit;
import com.fanruan.api.design.DesignKit;
import com.fanruan.api.design.ui.component.UIActionLabel;
import com.fanruan.api.design.ui.component.UIButton;
import com.fanruan.api.design.ui.component.UICheckBox;
import com.fanruan.api.design.ui.component.UILabel;
import com.fanruan.api.design.ui.component.UIPasswordField;
import com.fanruan.api.design.ui.component.UITextField;
@ -31,6 +32,7 @@ public class RedisConnectionPane extends DatabaseConnectionPane<RedisDatabaseCon
private UITextField hostTextField;
private UITextField portNumberField;
private UIPasswordField passwordTextField;
private UICheckBox clusterModeCheckBox;
@Override
@ -40,7 +42,7 @@ public class RedisConnectionPane extends DatabaseConnectionPane<RedisDatabaseCon
hostTextField = new UITextField();
portNumberField = new UITextField();
passwordTextField = new UIPasswordField();
clusterModeCheckBox = new UICheckBox(DesignKit.i18nText("Plugin-Redis_Cluster_Mode"), false);
JPanel globalConfigPane = new JPanel();
GridLayout gridLayout = new GridLayout(1, 2);
@ -63,7 +65,11 @@ public class RedisConnectionPane extends DatabaseConnectionPane<RedisDatabaseCon
Component[][] components = new Component[][]{
{new UILabel(DesignKit.i18nText("Plugin-Redis_Host") + ":"),
GUICoreKit.createBorderLayoutPane(hostTextField, BorderLayout.CENTER, helpButton, BorderLayout.EAST)},
GUICoreKit.createBorderLayoutPane(hostTextField, BorderLayout.CENTER,
GUICoreKit.createBorderLayoutPane(
clusterModeCheckBox, BorderLayout.CENTER,
helpButton, BorderLayout.EAST
), BorderLayout.EAST)},
{new UILabel(DesignKit.i18nText("Plugin-Redis_Port") + ":"), portNumberField},
{new UILabel(DesignKit.i18nText("Plugin-Redis_Password") + ":"), passwordTextField},
{null, globalConfigPane}
@ -135,6 +141,7 @@ public class RedisConnectionPane extends DatabaseConnectionPane<RedisDatabaseCon
hostTextField.setText(ob.getHost());
portNumberField.setText(ob.getPort());
passwordTextField.setText(ob.getPassword());
clusterModeCheckBox.setSelected(ob.isCluster());
}
@Override
@ -143,6 +150,7 @@ public class RedisConnectionPane extends DatabaseConnectionPane<RedisDatabaseCon
connection.setHost(hostTextField.getText());
connection.setPort(portNumberField.getText());
connection.setPassword(passwordTextField.getText());
connection.setCluster(clusterModeCheckBox.isSelected());
return connection;
}

14
src/main/java/com/fr/plugin/db/redis/ui/RedisDBConnectionChosePane.java

@ -1,5 +1,7 @@
package com.fr.plugin.db.redis.ui;
import com.fanruan.api.design.ui.component.UIIntNumberField;
import com.fanruan.api.design.ui.component.UILabel;
import com.fanruan.api.design.work.ConnectionComboBoxPanel;
import com.fr.data.impl.Connection;
import com.fr.data.operator.DataOperator;
@ -29,6 +31,7 @@ public class RedisDBConnectionChosePane extends BasicPane {
private DefaultListModel listModel = new DefaultListModel();
private List<DataLoadedListener> listeners = new ArrayList<DataLoadedListener>();
private UIPlaceholderTextField keysPatternTextField;
private UIIntNumberField dbIndexNumberField;
public RedisDBConnectionChosePane() {
setLayout(new BorderLayout(4, 4));
@ -51,6 +54,10 @@ public class RedisDBConnectionChosePane extends BasicPane {
keysPatternTextField = new UIPlaceholderTextField(10);
keysPatternTextField.setPlaceholder(DesignKit.i18nText("Plugin-Redis_Keys_Pattern"));
dbIndexNumberField = new UIIntNumberField();
dbIndexNumberField.setColumns(2);
dbIndexNumberField.setInt(0);
JPanel centerPane = new JPanel(new BorderLayout());
UIButton searchButton = new UIButton(DesignKit.i18nText("Plugin-Redis_Keys_Pattern_Search"));
@ -63,6 +70,10 @@ public class RedisDBConnectionChosePane extends BasicPane {
centerPane.add(GUICoreKit.createBorderLayoutPane(
keysPatternTextField, BorderLayout.CENTER,
GUICoreKit.createBorderLayoutPane(
new UILabel(DesignKit.i18nText("Plugin-Redis_DB_Simple_Index")), BorderLayout.WEST,
dbIndexNumberField, BorderLayout.CENTER
), BorderLayout.WEST,
searchButton, BorderLayout.EAST), BorderLayout.NORTH);
centerPane.add(list, BorderLayout.CENTER);
@ -97,7 +108,8 @@ public class RedisDBConnectionChosePane extends BasicPane {
if (StringKit.isEmpty(keysPattern)) {
return ArrayKit.EMPTY_STRING_ARRAY;
} else {
return DataOperator.getInstance().getTableSummary(connection, keysPattern);
String dbIndex = String.valueOf(dbIndexNumberField.getInt());
return DataOperator.getInstance().getTableSummary(connection, keysPattern, dbIndex);
}
}

11
src/main/java/com/fr/plugin/db/redis/util/RedisUtils.java

@ -6,6 +6,7 @@ import com.fanruan.api.util.ArrayKit;
import com.fanruan.api.util.GeneralKit;
import com.fanruan.api.util.RenderKit;
import com.fanruan.api.util.StringKit;
import com.fr.json.JSONArray;
import com.fr.plugin.db.redis.core.order.OrderValue;
import com.fr.plugin.db.redis.help.ScriptBridge;
import com.fr.stable.ParameterProvider;
@ -72,14 +73,18 @@ public class RedisUtils {
}
}
public static ParameterProvider[] analyzeParameter(ParameterProvider[] oldParameters, OrderValue orderValue, String ...parameterTexts) {
public static ParameterProvider[] analyzeParameter(JSONArray existParameters, OrderValue orderValue, String... parameterTexts) {
ParameterProvider[] oldParameters = new ParameterProvider[existParameters.size()];
for (int i = 0; i < existParameters.size(); i++) {
oldParameters[i] = ParameterKit.json2Parameter(existParameters.getJSONObject(i));
}
ParameterProvider[] newParameters = ParameterKit.analyzeAndUnionSameParameters(parameterTexts, oldParameters);
ParameterProvider[] newOrderParameters = orderValue.analyze4Parameters();
Map<String, ParameterProvider> parameterProviderMap = new HashMap<String, ParameterProvider>();
for (ParameterProvider parameterProvider: oldParameters) {
for (ParameterProvider parameterProvider : oldParameters) {
parameterProviderMap.put(parameterProvider.getName(), parameterProvider);
}
for (ParameterProvider parameterProvider: newOrderParameters) {
for (ParameterProvider parameterProvider : newOrderParameters) {
if (parameterProviderMap.containsKey(parameterProvider.getName())) {
parameterProvider.setValue(parameterProviderMap.get(parameterProvider.getName()).getValue());
}

BIN
src/main/resources/com/fr/plugin/db/redis/images/redis.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

2
src/main/resources/com/fr/plugin/db/redis/locale/redis.properties

@ -9,6 +9,7 @@ Plugin-Redis_Help=Help Doc
Plugin-Redis_Keys_Pattern=Keys Pattern
Plugin-Redis_Keys_Pattern_Search=Search
Plugin-Redis_DB_Index=DB Index
Plugin-Redis_DB_Simple_Index=Index
Plugin-Redis_Preview=Preview
Plugin-Redis_Refresh=Refresh
Plugin-Redis_Formula=Formula
@ -38,3 +39,4 @@ Plugin-Redis_Cluster_Config_Description=Input multiple hosts with commas separat
Plugin-Redis_Script_Engine_Type=Script Engine Type
Plugin-Redis_Script_Engine_Type_Default=Default
Plugin-Redis_Script_Engine_Type_V8=V8
Plugin-Redis_Cluster_Mode=Cluster Mode

7
src/main/resources/com/fr/plugin/db/redis/locale/redis_en_US.properties

@ -9,6 +9,7 @@ Plugin-Redis_Help=Help Doc
Plugin-Redis_Keys_Pattern=Keys Pattern
Plugin-Redis_Keys_Pattern_Search=Search
Plugin-Redis_DB_Index=DB Index
Plugin-Redis_DB_Simple_Index=Index
Plugin-Redis_Preview=Preview
Plugin-Redis_Refresh=Refresh
Plugin-Redis_Formula=Formula
@ -38,3 +39,9 @@ Plugin-Redis_Cluster_Config_Description=Input multiple hosts with commas separat
Plugin-Redis_Script_Engine_Type=Script Engine Type
Plugin-Redis_Script_Engine_Type_Default=Default
Plugin-Redis_Script_Engine_Type_V8=V8
Plugin-Redis_Cluster_Mode=Cluster Mode
Plugin-Redis_Index=Index
Plugin-Redis_Set_Parameter=Parameter
Plugin-Redis_Set_Parameter_Name=Parameter Name
Plugin-Redis_Set_Parameter_Type=Parameter Type
Plugin-Redis_Set_Parameter_Value=Parameter Value

17
src/main/resources/com/fr/plugin/db/redis/locale/redis_zh_CN.properties

@ -9,6 +9,7 @@ Plugin-Redis_Help=\u5E2E\u52A9\u6587\u6863
Plugin-Redis_Keys_Pattern=\u952E\u503C\u7684\u6B63\u5219\u8868\u8FBE\u5F0F
Plugin-Redis_Keys_Pattern_Search=\u641C\u7D22
Plugin-Redis_DB_Index=\u6570\u636E\u5E93\u7F16\u53F7
Plugin-Redis_DB_Simple_Index=\u7F16\u53F7
Plugin-Redis_Preview=\u9884\u89C8
Plugin-Redis_Refresh=\u5237\u65B0
Plugin-Redis_Formula=\u516C\u5F0F
@ -38,9 +39,10 @@ Plugin-Redis_Cluster_Config_Description=1\u3001\u4F7F\u7528\u9017\u53F7\u5206\u5
Plugin-Redis_Script_Engine_Type=\u811A\u672C\u5F15\u64CE
Plugin-Redis_Script_Engine_Type_Default=\u9ED8\u8BA4
Plugin-Redis_Script_Engine_Type_V8=V8\u9AD8\u901F\u5F15\u64CE
Plugin-Redis_Proxy_Private_Key_Path_Mark=\u8bf7\u8f93\u5165\u670d\u52a1\u5668\u6587\u4ef6\u8def\u5f84
Plugin-Redis_Connection_Form_OriginalCharsetName= \u7f16\u7801
Plugin-Redis_Check_Integer=\u8bf7\u8f93\u5165\u4e0d\u5c0f\u4e8e\u0030\u7684\u6574\u6570
Plugin-Redis_Cluster_Mode=\u96C6\u7FA4\u6A21\u5F0F
Plugin-Redis_Proxy_Private_Key_Path_Mark=\u8BF7\u8F93\u5165\u670D\u52A1\u5668\u6587\u4EF6\u8DEF\u5F84
Plugin-Redis_Connection_Form_OriginalCharsetName= \u7F16\u7801
Plugin-Redis_Check_Integer=\u8BF7\u8F93\u5165\u4E0D\u5C0F\u4E8E0\u7684\u6574\u6570
Plugin-Redis_Parameter_Insert=\u63D2\u5165
Plugin-Redis_Parameter_Delete=\u5220\u9664
Plugin-Redis_Parameter_Move_Up=\u4E0A\u79FB
@ -57,5 +59,10 @@ Plugin-Redis_Parameter_Type_Boolean=\u5E03\u5C14\u578B
Plugin-Redis_Parameter_Type_Formula=\u516C\u5F0F
Plugin-Redis_Parameter_Delete_Confirm=\u4F60\u786E\u5B9A\u51B3\u5B9A\u5220\u9664\u9009\u4E2D\u7684\u9879\uFF1F
Plugin-Redis_Parameter_Delete_Alert=\u5F53\u524D\u5217\u8868\u4E3A\u7A7A\u6216\u8005\u4F60\u6CA1\u6709\u9009\u4E2D\u4EFB\u4F55\u9879
Plugin-Redis_View=\u89c6\u56fe
Plugin-Redis_Table=\u8868
Plugin-Redis_View=\u89C6\u56FE
Plugin-Redis_Table=\u8868
Plugin-Redis_Index=\u7F16\u53F7
Plugin-Redis_Set_Parameter=\u53C2\u6570
Plugin-Redis_Set_Parameter_Name=\u53C2\u6570\u540D
Plugin-Redis_Set_Parameter_Type=\u53C2\u6570\u7C7B\u578B
Plugin-Redis_Set_Parameter_Value=\u53C2\u6570\u503C

BIN
src/main/resources/com/fr/plugin/db/redis/web/demo-tabledate-redis-web.zip

Binary file not shown.

2030
src/main/resources/com/fr/plugin/db/redis/web/redis.css

File diff suppressed because it is too large Load Diff

16
src/main/resources/com/fr/plugin/db/redis/web/redis.js

File diff suppressed because one or more lines are too long

1
src/web/.npmrc

@ -0,0 +1 @@
@fui:registry=https://npm.fineres.com/

19
src/web/assets/scripts/dec.js

@ -0,0 +1,19 @@
window.DecCst = {
Schedule: {
Parameter: {
Type: {
BOOLEAN: "Boolean",
DATA_SET: "TableColumn",
DATE: "Date",
DOUBLE: "Double",
FORMULA: "Formula",
INTEGER: "Integer",
STRING: "String",
}
}
}
};
window.Dec = {
fineServletURL: '/webroot/decision',
}

30
src/web/babel.config.js

@ -1,29 +1 @@
module.exports = function(api) {
api.cache(true);
const presets = [
[
'@babel/preset-env',
{
targets: {
ie: 9,
chrome: 47,
},
},
],
'@babel/preset-typescript',
];
const plugins = [
[
'@babel/plugin-proposal-decorators',
{
legacy: true,
},
],
'@babel/plugin-proposal-class-properties',
];
return {
presets,
plugins,
};
};
module.exports = require('@fui/babel-preset-fineui').configs.base;

16
src/web/index.html

@ -6,7 +6,7 @@
<!--核心css文件-->
<link
rel="preload"
href="./node_modules/fineui/dist/font/iconfont.woff"
href="./node_modules/@fui/core/dist/font/iconfont.woff"
as="font"
type="font/woff"
crossorigin=""
@ -14,23 +14,19 @@
<link
rel="stylesheet"
type="text/css"
href="./node_modules/fineui/dist/fineui.css"
href="./node_modules/@fui/core/dist/2.0/fineui.min.css"
/>
<link
rel="stylesheet"
type="text/css"
href="./node_modules/fineui-materials/docs/materials.min.css"
href="./node_modules/@fui/materials/docs/materials.min.css"
/>
</head>
<script>
var DecCst = null;
var Dec = null;
</script>
<body id="body">
<div id="wrapper"></div>
<script src="./node_modules/fineui/dist/fineui.js"></script>
<script src="./node_modules/fineui-materials/docs/materials.min.js"></script>
<script src="./node_modules/fineui/i18n/i18n.cn.js"></script>
<script src="./assets/scripts/dec.js"></script>
<script src="./node_modules/@fui/core/dist/fineui.js"></script>
<script src="./node_modules/@fui/materials/docs/materials.min.js"></script>
</body>
</html>

17
src/web/package.json

@ -7,6 +7,9 @@
"author": "alan",
"license": "MIT",
"dependencies": {
"@fui/babel-preset-fineui": "^1.0.0",
"@fui/core": "^2.0.0",
"@fui/materials": "10.0.0-release - 10.0.0-release.99999999999999",
"@types/jss": "9.5.8",
"autoprefixer": "^9.6.1",
"es6-promise": "4.2.6",
@ -18,15 +21,9 @@
"optimize-css-assets-webpack-plugin": "^5.0.3"
},
"devDependencies": {
"@babel/core": "7.4.5",
"@babel/plugin-proposal-class-properties": "^7.5.0",
"@babel/plugin-proposal-decorators": "7.4.4",
"@babel/polyfill": "7.4.4",
"@babel/preset-env": "7.4.5",
"@babel/preset-typescript": "7.3.3",
"@types/jest": "24.0.11",
"@typescript-eslint/eslint-plugin": "1.7.0",
"@typescript-eslint/parser": "1.7.0",
"@typescript-eslint/eslint-plugin": "2.33.0",
"@typescript-eslint/parser": "2.33.0",
"axios": "0.18.0",
"babel-loader": "8.0.6",
"body-parser": "1.18.3",
@ -58,10 +55,6 @@
"webpack-dev-server": "3.7.2",
"webpack-merge": "4.2.1"
},
"optionalDependencies": {
"fineui": "git+ssh://git@cloud.finedevelop.com:7999/visual/fineui.git",
"fineui-materials": "git+ssh://git@cloud.finedevelop.com:7999/fui/fineui-materials.git#release/10.0"
},
"scripts": {
"dev": "cross-env NODE_ENV=mock webpack-dev-server -p --progress --config=webpack/webpack.dev.js --mode development --open",
"build": "webpack -p --progress --config=webpack/webpack.prod.js --mode production",

210
src/web/private/i18n.ts

@ -9,7 +9,12 @@ export const i18n = {
'Plugin-Redis_Help': '帮助文档',
'Plugin-Redis_Keys_Pattern': '键值的正则表达式',
'Plugin-Redis_Keys_Pattern_Search': '搜索',
'Plugin-Redis_Set_Parameter': '参数',
'Plugin-Redis_Set_Parameter_Name': '参数名',
'Plugin-Redis_Set_Parameter_Type': '参数类型',
'Plugin-Redis_Set_Parameter_Value': '参数值',
'Plugin-Redis_DB_Index': '数据库编号',
'Plugin-Redis_Index': '编号',
'Plugin-Redis_Preview': '预览',
'Plugin-Redis_Refresh': '刷新',
'Plugin-Redis_Formula': '公式',
@ -42,22 +47,195 @@ export const i18n = {
'Plugin-Redis_Proxy_Private_Key_Path_Mark': '请输入服务器文件路径',
'Plugin-Redis_Connection_Form_OriginalCharsetName': '编码',
'Plugin-Redis_Check_Integer': '请输入不小于0的整数',
'Plugin-Redis_Parameter_Insert': '插入',
'Plugin-Redis_Parameter_Delete': '删除',
'Plugin-Redis_Parameter_Move_Up': '上移',
'Plugin-Redis_Parameter_Move_Down': '下移',
'Plugin-Redis_Parameter_Refresh': '刷新',
'Plugin-Redis_Dataset_Parameter_Name': '参数',
'Plugin-Redis_Dataset_Parameter_Value': '值',
'Plugin-Redis_Parameter_Please_Set_Parameter_Name': '请先设置参数名',
'Plugin-Redis_Parameter_Type_String': '字符串',
'Plugin-Redis_Parameter_Type_Int': '整型',
'Plugin-Redis_Parameter_Type_Number': '双精度型',
'Plugin-Redis_Parameter_Type_Date': '日期',
'Plugin-Redis_Parameter_Type_Boolean': '布尔型',
'Plugin-Redis_Parameter_Type_Formula': '公式',
'Plugin-Redis_Parameter_Delete_Confirm': '你确定决定删除选中的项?',
'Plugin-Redis_Parameter_Delete_Alert': '当前列表为空或者你没有选中任何项',
'Plugin-Redis_View': '视图',
'Plugin-Redis_Table': '表',
'BI-Multi_Date_Quarter_End': '季度末',
'BI-Multi_Date_Month_Begin': '月初',
'BI-Multi_Date_YMD': '年月日',
'BI-Custom_Color': '自定义颜色',
'BI-Numerical_Interval_Input_Data': '请输入数值',
'BI-Please_Input_Natural_Number': '请输入非负整数',
'BI-No_More_Data': '无更多数据',
'BI-Basic_Altogether': '共',
'BI-Basic_Sunday': '星期日',
'BI-Widget_Background_Colour': '组件背景',
'BI-Color_Picker_Error_Text': '请输入0~255的正整数',
'BI-Multi_Date_Month': '月',
'BI-No_Selected_Item': '没有可选项',
'BI-Multi_Date_Year_Begin': '年初',
'BI-Quarter_1': '第1季度',
'BI-Quarter_2': '第2季度',
'BI-Quarter_3': '第3季度',
'BI-Quarter_4': '第4季度',
'BI-Multi_Date_Year_Next': '年后',
'BI-Multi_Date_Month_Prev': '个月前',
'BI-Month_Trigger_Error_Text': '请输入1~12的正整数',
'BI-Less_And_Equal': '小于等于',
'BI-Year_Trigger_Invalid_Text': '请输入有效时间',
'BI-Multi_Date_Week_Next': '周后',
'BI-Font_Size': '字号',
'BI-Basic_Total': '共',
'BI-Already_Selected': '已选择',
'BI-Formula_Insert': '插入',
'BI-Select_All': '全选',
'BI-Basic_Tuesday': '星期二',
'BI-Multi_Date_Month_End': '月末',
'BI-Load_More': '点击加载更多数据',
'BI-Basic_September': '九月',
'BI-Current_Is_Last_Page': '当前已是最后一页',
'BI-Basic_Auto': '自动',
'BI-Basic_Count': '个',
'BI-Basic_Value': '值',
'BI-Basic_Unrestricted': '无限制',
'BI-Quarter_Trigger_Error_Text': '请输入1~4的正整数',
'BI-Basic_More': '更多',
'BI-Basic_Wednesday': '星期三',
'BI-Basic_Bold': '加粗',
'BI-Basic_Simple_Saturday': '六',
'BI-Multi_Date_Month_Next': '个月后',
'BI-Basic_March': '三月',
'BI-Current_Is_First_Page': '当前已是第一页',
'BI-Basic_Thursday': '星期四',
'BI-Basic_Prompt': '提示',
'BI-Multi_Date_Today': '今天',
'BI-Multi_Date_Quarter_Prev': '个季度前',
'BI-Row_Header': '行表头',
'BI-Date_Trigger_Error_Text': '日期格式示例:2015-3-11',
'BI-Basic_Cancel': '取消',
'BI-Basic_January': '一月',
'BI-Basic_June': '六月',
'BI-Basic_July': '七月',
'BI-Basic_April': '四月',
'BI-Multi_Date_Quarter_Begin': '季度初',
'BI-Multi_Date_Week': '周',
'BI-Click_Blank_To_Select': '点击\\空格键\\选中完全匹配项',
'BI-Basic_August': '八月',
'BI-Word_Align_Left': '文字居左',
'BI-Basic_November': '十一月',
'BI-Font_Colour': '字体颜色',
'BI-Multi_Date_Day_Prev': '天前',
'BI-Select_Part': '部分选择',
'BI-Multi_Date_Day_Next': '天后',
'BI-Less_Than': '小于',
'BI-Basic_February': '二月',
'BI-Multi_Date_Year': '年',
'BI-Number_Index': '序号',
'BI-Multi_Date_Week_Prev': '周前',
'BI-Next_Page': '下一页',
'BI-Right_Page': '向右翻页',
'BI-Numerical_Interval_Signal_Value': '前后值相等,请将操作符改为“≤”',
'BI-Basic_December': '十二月',
'BI-Basic_Saturday': '星期六',
'BI-Basic_Simple_Wednesday': '三',
'BI-Multi_Date_Quarter_Next': '个季度后',
'BI-Basic_October': '十月',
'BI-Basic_Simple_Friday': '五',
'BI-Basic_Save': '保存',
'BI-Numerical_Interval_Number_Value': '请保证前面的数值小于/等于后面的数值',
'BI-Previous_Page': '上一页',
'BI-No_Select': '搜索结果为空',
'BI-Basic_Clears': '清空',
'BI-Created_By_Me': '我创建的',
'BI-Basic_Simple_Tuesday': '二',
'BI-Word_Align_Right': '文字居右',
'BI-Summary_Values': '汇总',
'BI-Basic_Clear': '清除',
'BI-Upload_File_Size_Error': '文件大小不支持',
'BI-Up_Page': '向上翻页',
'BI-Basic_Simple_Sunday': '日',
'BI-Multi_Date_Relative_Current_Time': '相对当前时间',
'BI-Selected_Data': '已选数据:',
'BI-Multi_Date_Quarter': '季度',
'BI-Check_Selected': '查看已选',
'BI-Basic_Search': '搜索',
'BI-Basic_May': '五月',
'BI-Continue_Select': '继续选择',
'BI-Please_Input_Positive_Integer': '请输入正整数',
'BI-Upload_File_Type_Error': '文件类型不支持',
'BI-Upload_File_Error': '文件上传失败',
'BI-Basic_Friday': '星期五',
'BI-Down_Page': '向下翻页',
'BI-Basic_Monday': '星期一',
'BI-Left_Page': '向左翻页',
'BI-Transparent_Color': '透明',
'BI-Basic_Simple_Monday': '一',
'BI-Multi_Date_Year_End': '年末',
'BI-Time_Interval_Error_Text': '请保证开始时间早于/等于结束时间',
'BI-Basic_Time': '时间',
'BI-Basic_OK': '确定',
'BI-Basic_Sure': '确定',
'BI-Basic_Simple_Thursday': '四',
'BI-Multi_Date_Year_Prev': '年前',
'BI-Tiao_Data': '条数据',
'BI-Basic_Italic': '斜体',
'BI-Basic_Dynamic_Title': '动态时间',
'BI-Basic_Year': '年',
'BI-Basic_Single_Quarter': '季',
'BI-Basic_Month': '月',
'BI-Basic_Week': '周',
'BI-Basic_Day': '天',
'BI-Basic_Work_Day': '工作日',
'BI-Basic_Front': '前',
'BI-Basic_Behind': '后',
'BI-Basic_Empty': '空',
'BI-Basic_Month_End': '月末',
'BI-Basic_Month_Begin': '月初',
'BI-Basic_Year_End': '年末',
'BI-Basic_Year_Begin': '年初',
'BI-Basic_Quarter_End': '季末',
'BI-Basic_Quarter_Begin': '季初',
'BI-Basic_Week_End': '周末',
'BI-Basic_Week_Begin': '周初',
'BI-Basic_Current_Day': '当天',
'BI-Basic_Begin_Start': '初',
'BI-Basic_End_Stop': '末',
'BI-Basic_Current_Year': '今年',
'BI-Basic_Year_Fen': '年份',
'BI-Basic_Current_Month': '本月',
'BI-Basic_Current_Quarter': '本季度',
'BI-Basic_Year_Month': '年月',
'BI-Basic_Year_Quarter': '年季度',
'BI-Basic_Input_Can_Not_Null': '输入框不能为空',
'BI-Basic_Date_Time_Error_Text': '日期格式示例:2015-3-11 00:00:00',
'BI-Basic_Input_From_To_Number': '请输入{R1}的数值',
'BI-Basic_Or': '或',
'BI-Basic_And': '且',
'BI-Conf_Add_Formula': '添加公式',
'BI-Conf_Add_Condition': '添加条件',
'BI-Conf_Formula_And': '且公式条件',
'BI-Conf_Formula_Or': '或公式条件',
'BI-Conf_Condition_And': '且条件',
'BI-Conf_Condition_Or': '或条件',
'BI-Microsoft_YaHei': '微软雅黑',
'BI-Apple_Light': '苹方-light',
'BI-Font_Family': '字体',
'BI-Basic_Please_Input_Content': '请输入内容',
'BI-Word_Align_Center': '文字居中',
'BI-Basic_Please_Enter_Number_Between': '请输入{R1}-{R2}的值',
'BI-More_Than': '大于',
'BI-More_And_Equal': '大于等于',
'BI-Please_Enter_SQL': '请输入SQL',
'BI-Basic_Click_To_Add_Text': '+点击新增\\{R1}\\',
'BI-Basic_Please_Select': '请选择',
'BI-Basic_Font_Color': '文字颜色',
'BI-Basic_Background_Color': '背景色',
'BI-Basic_Underline': '下划线',
'BI-Basic_Param_Month': '{R1}月',
'BI-Basic_Param_Day': '{R1}日',
'BI-Basic_Param_Quarter': '{R1}季度',
'BI-Basic_Param_Week_Count': '第{R1}周',
'BI-Basic_Param_Hour': '{R1}时',
'BI-Basic_Param_Minute': '{R1}分',
'BI-Basic_Param_Second': '{R1}秒',
'BI-Basic_Param_Year': '{R1}年',
'BI-Basic_Date_Day': '日',
'BI-Basic_Hour_Sin': '时',
'BI-Basic_Seconds': '秒',
'BI-Basic_Minute': '分',
'BI-Basic_Wan': '万',
'BI-Basic_Million': '百万',
'BI-Basic_Billion': '亿',
'BI-Basic_Quarter': '季度',
'BI-Basic_No_Select': '不选',
'BI-Basic_Now': '此刻',
};

38
src/web/src/index.ts

@ -1,16 +1,32 @@
import { RedisShow } from './modules/app.show';
import { RedisEdit } from './modules/app.edit';
const ConstantRedisType = 'dec.constant.database.conf.connect.types';
const ConstantRedisShow = 'dec.constant.database.conf.connect.form.Redis.show';
const ConstantRedisEdit = 'dec.constant.database.conf.connect.form.Redis.edit';
import { RedisDataset } from './modules/app.dataset';
import { RedisProgram } from './modules/app.program';
BI.DOM.ready(() => {
BI.config(ConstantRedisType, datas => [...datas, {
text: 'Redis',
databaseType: 'Redis',
iconUrl: 'com/fr/plugin/db/redis/images/redis.png',
}]);
BI.constant(ConstantRedisShow, RedisShow.xtype);
BI.constant(ConstantRedisEdit, RedisEdit.xtype);
BI.config('dec.connection.provider.datebase', provider => {
provider.registerDatabaseType({
text: 'Redis',
databaseType: 'Redis',
iconUrl: 'com/fr/plugin/db/redis/images/redis.jpg',
edit: RedisEdit.xtype,
show: RedisShow.xtype,
});
});
BI.config('dec.provider.data.set', provider => {
provider.registerDataSetType({
value: 'Redis',
text: 'Redis数据集',
cardType: RedisDataset.xtype,
});
});
BI.config('dec.provider.data.set', provider => {
provider.registerDataSetType({
value: 'RedisScript',
text: 'Redis程序数据集',
cardType: RedisProgram.xtype,
});
});
});

2
src/web/src/less/background.less

@ -1,2 +1,2 @@
@import "../../node_modules/fineui/src/less/image.less";
@import "../../node_modules/@fui/core/src/less/image.less";
@import "./lib/background.less";

9
src/web/src/less/font.less

@ -1,12 +1,13 @@
@import "../../node_modules/fineui/src/less/resource/font.less";
@import "../../node_modules/@fui/core/src/less/resource/font.less";
@import "./lib/font.less";
.font(refresh-font, @font-refresh);
.font(redis-refresh-font, @font-redis-refresh);
.font(input-string-font, @font-input-string);
.font(input-formula-font, @font-input-formula);
.font(input-date-font, @font-input-date);
.font(input-boolean-font, @font-input-boolean);
.font(input-int-font, @font-input-int);
.font(input-number-font, @font-input-number);
.font(site-font, @font-site);
.font(column-font, @font-column);
.font(redis-site-font, @font-redis-site);
.font(redis-column-font, @font-redis-column);
.font(redis-preview-font, @font-redis-preview);

7
src/web/src/less/lib/font.less

@ -2,12 +2,13 @@
@fontReportUrl: '$fontReportUrl/';
@fontName: "report";
@font-refresh: "e6ef";
@font-redis-refresh: "e6ef";
@font-input-string: "e6e9";
@font-input-formula: "e6c6";
@font-input-date: "e733";
@font-input-boolean: "e656";
@font-input-int: "e7c2";
@font-input-number: "e60b";
@font-site: "e7c5";
@font-column: "e76f";
@font-redis-site: "e7c5";
@font-redis-column: "e76f";
@font-redis-preview: "e6f2";

2
src/web/src/less/utils.less

@ -1 +1 @@
@import '../../node_modules/fineui/src/less/visual.less';
@import '../../node_modules/@fui/core/src/less/visual.less';

33
src/web/src/modules/app.constant.ts

@ -0,0 +1,33 @@
export const redisParamHeader = [{
text: BI.i18nText('Plugin-Redis_Set_Parameter_Name'),
}, {
text: BI.i18nText('Plugin-Redis_Set_Parameter_Type'),
}, {
text: BI.i18nText('Plugin-Redis_Set_Parameter_Value'),
}];
export const redisField = [{
text: BI.i18nText('Dec-Basic_String'),
value: DecCst.Schedule.Parameter.Type.STRING,
iconCls: 'string-field-font',
}, {
text: BI.i18nText('Dec-Basic_Integer'),
value: DecCst.Schedule.Parameter.Type.INTEGER,
iconCls: 'number-field-font',
}, {
text: BI.i18nText('Dec-Basic_Double'),
value: DecCst.Schedule.Parameter.Type.DOUBLE,
iconCls: 'number-field-font',
}, {
text: BI.i18nText('Dec-Basic_Date'),
value: DecCst.Schedule.Parameter.Type.DATE,
iconCls: 'date-field-font',
}, {
text: BI.i18nText('Dec-Basic_Boolean'),
value: DecCst.Schedule.Parameter.Type.BOOLEAN,
iconCls: 'string-field-font',
}, {
text: BI.i18nText('Dec-Basic_Formula'),
value: DecCst.Schedule.Parameter.Type.FORMULA,
iconCls: 'string-field-font',
}];

222
src/web/src/modules/app.dataset.ts

@ -1,47 +1,89 @@
import { shortcut } from '@core/core';
import { VerticalXtype, TextEditorXtype, HtapeXtype, LabelXtype, IconComboXtype, TabXtype, CodeEditorXtype } from 'ui';
import { Parameter } from './components/parameter/parameter';
import { TableList } from './table_list/table_list';
import {shortcut, store} from '@core/core';
import {TableList} from './table_list/table_list';
import '../less/index.less';
import {DatabaseIndex} from './components/database_index/database_index';
import {RedisModel, ParameterType} from './app.model';
import {Preview} from './components/preview/preview';
import './app.less';
import {redisField} from './app.constant';
@shortcut()
@store(RedisModel)
export class RedisDataset extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.dataset'
private textWidth = 100;
databaseNoTab: any;
databaseIndex: DatabaseIndex;
iconCombo: any;
queryCondition: any;
tableList: TableList;
parameterEditor: any;
previewButton: any;
store: RedisModel['store']
model: RedisModel['model']
props = {
value: {
datasetData: {
database: '',
orderValue: 0,
query: '',
parameters: [],
},
},
}
watch = {
parameters: () => {
this.parameterEditor.populate(this.renderItems(), [this.model.paramHeader]);
},
ableSave: (ableSave: boolean) => {
this.previewButton.setEnable(ableSave);
},
}
render() {
const {database = '', orderValue = 0, query = '', parameters = []} = this.options.value.datasetData || {};
this.store.setParameters(parameters);
const plainQuery = BI.Providers.getProvider("dec.provider.cipher").getPlain(query);
this.store.setAbleSave(!!plainQuery);
const inputType = typeof orderValue === 'string' ? 'formula' : 'int';
return {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
tgap: 15,
items: [{
el: {
type: TableList.xtype,
cls: 'bi-border-right',
database,
ref: (_ref: any) => {
this.tableList = _ref;
},
},
width: 300,
}, {
type: VerticalXtype,
hgap: 5,
vgap: 10,
type: BI.VerticalLayout.xtype,
lgap: 5,
bgap: 10,
items: [{
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
height: 22,
items: [{
el: {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_DB_Index'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
items: [{
el: {
type: IconComboXtype,
type: BI.IconCombo.xtype,
height: 22,
width: 28,
value: 'int',
value: inputType,
items: [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
@ -58,59 +100,157 @@ export class RedisDataset extends BI.Widget {
eventName: 'EVENT_CHANGE',
action: () => {
const typeValue = this.iconCombo.getValue()[0];
this.databaseNoTab.setSelect(typeValue);
this.databaseIndex.setSelect(typeValue);
},
}],
},
width: 28,
}, {
type: TabXtype,
single: true,
showIndex: 'int',
type: DatabaseIndex.xtype,
rgap: 11,
value: orderValue,
inputType,
ref: (_ref: any) => {
this.databaseNoTab = _ref;
},
cardCreator: (index: 'int'|'formula') => {
if (index === 'int') {
return {
type: TextEditorXtype,
warningTitle: '',
value: 0,
validationChecker: (v: string) => this.checkInteger(v),
errorText: BI.i18nText('Plugin-Redis_Check_Integer'),
};
}
return {
type: TextEditorXtype,
allowBlank: true,
};
this.databaseIndex = _ref;
},
}],
}],
}, {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
height: 200,
rgap: 5,
items: [{
el: {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Query_Condition'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: CodeEditorXtype,
type: BI.TextAreaEditor.xtype,
cls: 'bi-border',
height: 200,
allowBlank: true,
value: plainQuery,
ref: (_ref: any) => {
this.queryCondition = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
const value = this.queryCondition.getValue();
this.store.setAbleSave(!!value);
},
}],
}],
}, {
type: Parameter.xtype,
type: BI.HTapeLayout.xtype,
height: 24,
rgap: 5,
items: [{
type: BI.Label.xtype,
height: 24,
text: BI.i18nText('Plugin-Redis_Set_Parameter'),
textAlign: 'left',
}, {
el: {
type: BI.Button.xtype,
text: BI.i18nText('Plugin-Redis_Refresh'),
level: 'ignore',
handler: () => {
Dec.Utils.getDataSetParameters(this.getParamSearchValue(), res => {
const newParameters = BI.Services.getService('dec.service.data.set').getParameters(res.data, this.model.parameters);
this.store.setParameters(newParameters);
});
},
},
width: 80,
}, {
el: {
type: BI.Button.xtype,
text: BI.i18nText('Plugin-Redis_Preview'),
disabled: !BI.get(this.model, 'ableSave'),
handler: () => {
this.openPreview();
},
ref: (_ref: any) => {
this.previewButton = _ref;
},
},
width: 80,
}],
}, {
type: BI.StyleTable.xtype,
cls: 'param-table',
height: 200,
columnSize: [300, 300, ''],
items: this.renderItems(),
header: [this.model.paramHeader],
ref: (_ref: any) => {
this.parameterEditor = _ref;
},
}],
}],
};
}
private checkInteger(value: string) {
return /^[\d]+$/.test(value);
private renderItems() {
const self = this;
return this.model.parameters.map((item, index) => [{
type: BI.Label.xtype,
text: item.name,
textAlign: 'left',
height: 30,
lgap: 10,
}, {
type: BI.IconTextValueCombo.xtype,
cls: 'field-type-change',
height: 30,
items: redisField,
value: item.type,
listeners: [{
eventName: BI.IconTextValueCombo.EVENT_CHANGE,
action() {
self.store.setParamType(index, this.getValue()[0]);
},
}],
}, this.createParameterValueItem(item, (value: string) => {
self.store.setParamValue(index, value);
})]);
}
private createParameterValueItem(param: ParameterType, cb: Function) {
return BI.Services.getService('dec.service.data.set').createParameterValueItem(param, cb);
}
public getValue() {
return {
database: this.tableList.getSelectedDatabase(),
orderValue: this.databaseIndex.getValue(),
query: BI.Providers.getProvider("dec.provider.cipher").getCipher(this.queryCondition.getValue()),
parameters: this.model.parameters,
};
}
private getParamSearchValue() {
return {
datasetType: 'Redis',
datasetName: BI.get(this.model, 'dataSetName'),
datasetData: this.getValue(),
};
}
private openPreview() {
const id = BI.UUID();
BI.Popovers.create(id, {
type: 'bi.popover',
width: 800,
height: 500,
body: {
type: Preview.xtype,
previewedDataSet: this.getParamSearchValue(),
},
}).open(id);
}
}

33
src/web/src/modules/app.edit.ts

@ -1,6 +1,5 @@
import { shortcut } from '@core/core';
import { POOL_CONFIG, PROXY_CONFIG, BASIC_CONFIG, CONNECT_CHARSET } from '@constants/constant';
import { VerticalXtype, TextEditorXtype, TextValueComboXtype, LeftXtype, TextButtonXtype, BarPopOverXtype, EditorXtype } from 'ui';
import { FormItem } from './components/form_item/form_item';
import { PoolEdit } from './components/pool/pool_edit';
import { ProxyEdit } from './components/proxy/proxy_edit';
@ -8,7 +7,7 @@ import { ProxyEdit } from './components/proxy/proxy_edit';
export class RedisEdit extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.edit';
props = {
formData: {
value: {
basicConfig : {
...BASIC_CONFIG,
},
@ -33,17 +32,17 @@ export class RedisEdit extends BI.Widget {
oldPassword = '';
render() {
const formData = BI.get(this.options, 'formData');
const basicConfig = BI.get(formData, 'basicConfig', BASIC_CONFIG);
const poolConfig = BI.get(formData, 'poolConfig', POOL_CONFIG);
const proxyConfig = BI.get(formData, 'proxyConfig', PROXY_CONFIG);
const value = BI.get(this.options, 'value');
const basicConfig = BI.get(value, 'basicConfig', BASIC_CONFIG);
const poolConfig = BI.get(value, 'poolConfig', POOL_CONFIG);
const proxyConfig = BI.get(value, 'proxyConfig', PROXY_CONFIG);
const { host, port, password, originalCharsetName } = basicConfig;
this.poolConfigData = poolConfig;
this.proxyConfigData = proxyConfig;
this.oldPassword = password;
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -51,7 +50,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Host'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
ref: _ref => {
@ -64,7 +63,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Port'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
ref: _ref => {
@ -77,7 +76,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Password'),
forms: [{
type: EditorXtype,
type: BI.Editor.xtype,
cls: 'bi-border',
height: 20,
width: 300,
@ -90,17 +89,17 @@ export class RedisEdit extends BI.Widget {
}],
},
{
type: LeftXtype,
type: BI.FloatLeftLayout.xtype,
hgap: 20,
items: [
{
type: TextButtonXtype,
type: BI.TextButton.xtype,
cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Pool_Config'),
handler: () => {
const id = BI.UUID();
BI.Popovers.create(id, {
type: BarPopOverXtype,
type: BI.BarPopover.xtype,
width: 500,
height: 320,
header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -121,13 +120,13 @@ export class RedisEdit extends BI.Widget {
},
},
{
type: TextButtonXtype,
type: BI.TextButton.xtype,
cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Proxy_Config'),
handler: () => {
const id = BI.UUID();
BI.Popovers.create(id, {
type: BarPopOverXtype,
type: BI.BarPopover.xtype,
width: 650,
height: 320,
header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -153,7 +152,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'),
forms: [{
type: TextValueComboXtype,
type: BI.TextValueCombo.xtype,
width: 300,
value: originalCharsetName ? originalCharsetName : '',
items: CONNECT_CHARSET,
@ -166,7 +165,7 @@ export class RedisEdit extends BI.Widget {
};
}
public getSubmitValue() {
public getValue() {
const originalCharsetName = this.originalCharsetName.getValue()[0] || '';
return {

7
src/web/src/modules/app.less

@ -0,0 +1,7 @@
@import '../less/index.less';
.param-table {
.dec-dynamic-date-combo .even-row {
background-color: @background-color-default;
}
}

47
src/web/src/modules/app.model.ts

@ -0,0 +1,47 @@
import { model, Model } from './core/core';
import { redisParamHeader } from './app.constant';
@model()
export class RedisModel extends Model {
static xtype = 'dec.model.dcm.connection.plugin.redis'
context = ['dataSetName', 'ableSave']
state() {
return {
parameters: [] as ParameterType[],
};
}
actions = {
setAbleSave(ableSave: boolean) {
this.model.ableSave = ableSave;
},
setParameters: (parameters: ParameterType[]) => {
this.model.parameters = parameters;
},
setParamType: (index: number, type: string) => {
if (this.model.parameters[index].type !== type) {
this.model.parameters[index].type = type;
this.model.parameters[index].value = BI.Services.getService('dec.service.data.set').getDefaultValueByType(type);
this.model.parameters.splice(0, 0);
}
},
setParamValue: (index: number, val: string) => {
this.model.parameters[index].value = val;
},
}
computed = {
paramHeader: () => redisParamHeader.map(item => BI.extend({
textAlign: 'left',
height: 30,
hgap: 10,
}, item)),
}
}
export interface ParameterType {
name: string;
type: string;
value: string;
}

254
src/web/src/modules/app.program.ts

@ -1,47 +1,97 @@
import { shortcut } from '@core/core';
import { VerticalXtype, TextEditorXtype, HtapeXtype, LabelXtype, IconComboXtype, TabXtype, CodeEditorXtype, TextValueComboXtype } from 'ui';
import { Parameter } from './components/parameter/parameter';
import { TableList } from './table_list/table_list';
import {shortcut, store} from '@core/core';
import {TableList} from './table_list/table_list';
import '../less/index.less';
import {DatabaseIndex} from './components/database_index/database_index';
import {RedisModel, ParameterType} from './app.model';
import './app.less';
import {redisField} from './app.constant';
import {Preview} from './components/preview/preview';
@shortcut()
@store(RedisModel)
export class RedisProgram extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.program'
private textWidth = 100;
databaseNoTab: any;
databaseIndex: DatabaseIndex;
iconCombo: any;
queryCondition: any;
tableList: TableList;
parameterEditor: any;
engineTypeSelect: any;
previewButton: any;
store: RedisModel['store']
model: RedisModel['model']
props = {
value: {
datasetData: {
database: '',
orderValue: 0,
script: '',
engineType: 0,
parameters: [],
},
},
}
watch = {
parameters: () => {
this.parameterEditor.populate(this.renderItems(), [this.model.paramHeader]);
},
ableSave: (ableSave: boolean) => {
this.previewButton.setEnable(ableSave);
},
}
render() {
const {
database = '',
orderValue = 0,
script = '',
parameters = [],
engineType = 0
} = this.options.value.datasetData || {};
this.store.setParameters(parameters);
const inputType = typeof orderValue === 'string' ? 'formula' : 'int';
const plainScript = BI.Providers.getProvider("dec.provider.cipher").getPlain(script);
return {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
tgap: 15,
items: [{
el: {
type: TableList.xtype,
cls: 'bi-border-right',
database,
ref: (_ref: any) => {
this.tableList = _ref;
},
},
width: 300,
}, {
type: VerticalXtype,
hgap: 5,
vgap: 10,
type: BI.VerticalLayout.xtype,
lgap: 5,
bgap: 10,
items: [{
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
height: 22,
items: [{
el: {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_DB_Index'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
items: [{
el: {
type: IconComboXtype,
type: BI.IconCombo.xtype,
height: 22,
width: 28,
value: 'int',
value: inputType,
items: [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
@ -58,79 +108,189 @@ export class RedisProgram extends BI.Widget {
eventName: 'EVENT_CHANGE',
action: () => {
const typeValue = this.iconCombo.getValue()[0];
this.databaseNoTab.setSelect(typeValue);
this.databaseIndex.setSelect(typeValue);
},
}],
},
width: 28,
}, {
type: TabXtype,
single: true,
showIndex: 'int',
type: DatabaseIndex.xtype,
rgap: 11,
value: orderValue,
inputType,
ref: (_ref: any) => {
this.databaseNoTab = _ref;
},
cardCreator: (index: 'int'|'formula') => {
if (index === 'int') {
return {
type: TextEditorXtype,
warningTitle: '',
value: 0,
validationChecker: (v: string) => this.checkInteger(v),
errorText: BI.i18nText('Plugin-Redis_Check_Integer'),
};
}
return {
type: TextEditorXtype,
allowBlank: true,
};
this.databaseIndex = _ref;
},
}],
}],
}, {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
height: 22,
rgap: 5,
items: [{
el: {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Script_Engine_Type'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: TextValueComboXtype,
type: BI.TextValueCombo.xtype,
value: engineType,
ref: (_ref: any) => {
this.engineTypeSelect = _ref;
},
items: [{
text: BI.i18nText('Plugin-Redis_Script_Engine_Type_Default'),
value: '',
value: 0,
}, {
text: BI.i18nText('Plugin-Redis_Script_Engine_Type_V8'),
value: 'v8',
value: 1,
}],
}],
}, {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
height: 200,
rgap: 5,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Query_Condition'),
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Script_Query_Text'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: CodeEditorXtype,
type: BI.TextAreaEditor.xtype,
cls: 'bi-border',
height: 200,
allowBlank: true,
value: plainScript,
ref: (_ref: any) => {
this.queryCondition = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
const value = this.queryCondition.getValue();
this.store.setAbleSave(!!value);
},
}],
}],
}, {
type: Parameter.xtype,
type: BI.HTapeLayout.xtype,
height: 24,
rgap: 5,
items: [{
type: BI.Label.xtype,
height: 24,
text: BI.i18nText('Plugin-Redis_Set_Parameter'),
textAlign: 'left',
}, {
el: {
type: BI.Button.xtype,
text: BI.i18nText('Plugin-Redis_Refresh'),
level: 'ignore',
handler: () => {
Dec.Utils.getDataSetParameters(this.getParamSearchValue(), res => {
const newParameters = BI.Services.getService('dec.service.data.set').getParameters(res.data, this.model.parameters);
this.store.setParameters(newParameters);
});
},
},
width: 80,
}, {
el: {
type: BI.Button.xtype,
text: BI.i18nText('Plugin-Redis_Preview'),
disabled: !BI.get(this.model, 'ableSave'),
handler: () => {
this.openPreview();
},
ref: (_ref: any) => {
this.previewButton = _ref;
},
},
width: 80,
}],
}, {
type: BI.StyleTable.xtype,
cls: 'param-table',
height: 200,
columnSize: [300, 300, ''],
items: this.renderItems(),
header: [this.model.paramHeader],
ref: (_ref: any) => {
this.parameterEditor = _ref;
},
}],
}],
};
}
private checkInteger(value: string) {
return /^[\d]+$/.test(value);
private renderItems() {
const self = this;
return this.model.parameters.map((item, index) => [{
type: BI.Label.xtype,
text: item.name,
textAlign: 'left',
height: 30,
lgap: 10,
}, {
type: BI.IconTextValueCombo.xtype,
cls: 'field-type-change',
height: 30,
items: redisField,
value: item.type,
listeners: [{
eventName: BI.IconTextValueCombo.EVENT_CHANGE,
action() {
self.store.setParamType(index, this.getValue()[0]);
},
}],
}, {
type: BI.Label.xtype,
text: item.name,
textAlign: 'left',
height: 30,
lgap: 10,
}, this.createParameterValueItem(item, (value: string) => {
self.store.setParamValue(index, value);
})]);
}
private createParameterValueItem(param: ParameterType, cb: Function) {
return BI.Services.getService('dec.service.data.set').createParameterValueItem(param, cb);
}
public getValue() {
return {
database: this.tableList.getSelectedDatabase(),
orderValue: this.databaseIndex.getValue(),
script: BI.Providers.getProvider("dec.provider.cipher").getCipher(this.queryCondition.getValue()),
engineType: this.engineTypeSelect.getValue()[0],
parameters: this.model.parameters,
};
}
private getParamSearchValue() {
return {
datasetType: 'RedisScript',
datasetName: BI.get(this.model, 'dataSetName'),
datasetData: this.getValue(),
};
}
private openPreview() {
const id = BI.UUID();
BI.Popovers.create(id, {
type: 'bi.popover',
width: 800,
height: 500,
body: {
type: Preview.xtype,
previewedDataSet: this.getParamSearchValue(),
},
}).open(id);
}
}

31
src/web/src/modules/app.show.ts

@ -1,5 +1,4 @@
import { shortcut } from '@core/core';
import { LabelXtype, VerticalXtype, LeftXtype, TextButtonXtype, BarPopOverXtype } from 'ui';
import { FormItem } from './components/form_item/form_item';
import { PoolConfig } from './components/pool/pool';
import { ProxyConfig } from './components/proxy/proxy';
@ -9,7 +8,7 @@ import { POOL_CONFIG, PROXY_CONFIG, BASIC_CONFIG } from '@constants/constant';
export class RedisShow extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.show'
props = {
formData: {
value: {
basicConfig : {
...BASIC_CONFIG,
},
@ -22,14 +21,14 @@ export class RedisShow extends BI.Widget {
},
}
render() {
const formData = BI.get(this.options, 'formData');
const basicConfig = BI.get(formData, 'basicConfig', BASIC_CONFIG);
const poolConfig = BI.get(formData, 'poolConfig', POOL_CONFIG);
const proxyConfig = BI.get(formData, 'proxyConfig', PROXY_CONFIG);
const value = BI.get(this.options, 'value');
const basicConfig = BI.get(value, 'basicConfig', BASIC_CONFIG);
const poolConfig = BI.get(value, 'poolConfig', POOL_CONFIG);
const proxyConfig = BI.get(value, 'proxyConfig', PROXY_CONFIG);
const { host, port, newCharsetName } = basicConfig;
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -37,7 +36,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Host'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: host,
}],
},
@ -45,7 +44,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Port'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: port,
}],
},
@ -53,22 +52,22 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Password'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: '*****',
}],
},
{
type: LeftXtype,
type: BI.FloatLeftLayout.xtype,
hgap: 20,
items: [
{
type: TextButtonXtype,
type: BI.TextButton.xtype,
cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Pool_Config'),
handler: () => {
const id = BI.UUID();
BI.Popovers.create(id, {
type: BarPopOverXtype,
type: BI.BarPopover.xtype,
width: 400,
height: 300,
header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -81,13 +80,13 @@ export class RedisShow extends BI.Widget {
},
},
{
type: TextButtonXtype,
type: BI.TextButton.xtype,
cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Proxy_Config'),
handler: () => {
const id = BI.UUID();
BI.Popovers.create(id, {
type: BarPopOverXtype,
type: BI.BarPopover.xtype,
width: 650,
height: 280,
header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -105,7 +104,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: newCharsetName ? newCharsetName : BI.i18nText('BI-Basic_Auto'),
}],
},

22
src/web/src/modules/components/database_index/database_index.model.ts

@ -0,0 +1,22 @@
import { model, Model } from '../../core/core';
@model()
export class DatabaseIndexModel extends Model {
static xtype = 'plugin.model.report.redis.components.database_index'
state() {
return {
inputValue: '' as string | number,
inputType: 'int',
};
}
actions = {
setInpueValue: (value: string | number) => {
this.model.inputValue = value;
},
setInputType: (value: string) => {
this.model.inputType = value;
},
}
}

44
src/web/src/modules/components/database_index/database_index.service.ts

@ -0,0 +1,44 @@
import { FormulaOpeartingPanel } from '@fui/materials';
import { fetchFormulaConfig } from '../../crud/crud.request';
/**
*
*/
export function openFormulaPopover<T extends {formula: string}>(value: T, inserterType: string = BI.RegularFormulaInserter.xtype): Promise<T> {
return new Promise((resolve, reject) => {
const id = BI.UUID();
let formulaPane: FormulaOpeartingPanel;
BI.Popovers.create(id, {
type: BI.BarPopover.xtype,
width: 900,
height: 600,
header: BI.i18nText('Plugin-JSON_Function_Definition'),
body: {
type: BI.FormulaOpeartingPanel.xtype,
configLoader: fetchFormulaConfig,
ref: (_ref: FormulaOpeartingPanel) => {
formulaPane = _ref;
},
inserterType,
value,
},
listeners: [{
eventName: BI.Popover.EVENT_CANCEL,
action: () => {
reject();
BI.Popovers.remove(id);
},
}, {
eventName: BI.Popover.EVENT_CONFIRM,
action: () => {
resolve(formulaPane.getValue() as T);
BI.Popovers.remove(id);
},
}],
}).open(id);
});
}

85
src/web/src/modules/components/database_index/database_index.ts

@ -0,0 +1,85 @@
import { shortcut, store } from '@core/core';
import { DatabaseIndexModel } from './database_index.model';
import { openFormulaPopover } from './database_index.service';
@shortcut()
@store(DatabaseIndexModel)
export class DatabaseIndex extends BI.Widget {
static xtype = 'plugin.report.redis.components.database_index'
databaseIndexTab: any;
textEditor: any;
formulaPane: any;
model: DatabaseIndexModel['model']
store: DatabaseIndexModel['store']
props = {
value: '',
inputType: 'int',
}
render() {
const { value, inputType } = this.options;
this.store.setInpueValue(value);
this.store.setInputType(inputType);
return {
type: BI.Tab.xtype,
single: true,
showIndex: this.model.inputType,
ref: (_ref: any) => {
this.databaseIndexTab = _ref;
},
cardCreator: (index: 'int'|'formula') => {
if (index === 'int') {
return {
type: BI.TextEditor.xtype,
warningTitle: '',
value: parseInt(this.model.inputValue as string, 10) || 0,
validationChecker: (v: string) => this.checkInteger(v),
errorText: BI.i18nText('Plugin-Redis_Check_Integer'),
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
this.store.setInpueValue(parseInt(this.textEditor.getValue(), 10));
},
}],
ref: (_ref: any) => {
this.textEditor = _ref;
},
};
}
return {
type: BI.TextEditor.xtype,
allowBlank: true,
value: this.model.inputValue,
ref: (_ref: any) => {
this.formulaPane = _ref;
},
};
},
};
}
private checkInteger(value: string) {
return /^[\d]+$/.test(value);
}
public setSelect(value: string) {
this.databaseIndexTab.setSelect(value);
this.store.setInputType(value);
if (value === 'formula') {
openFormulaPopover({
formula: this.model.inputValue === 0 ? '' : this.model.inputValue as string,
}, BI.ComplexFormulaInserter.xtype).then(value => {
this.store.setInpueValue(value.formula);
this.formulaPane.setValue(value.formula);
});
}
}
public getValue() {
return this.model.inputType === 'int' ? parseInt(`${this.model.inputValue}`, 10) : this.model.inputValue;
}
}

5
src/web/src/modules/components/form_item/form_item.ts

@ -1,5 +1,4 @@
import { shortcut } from '@core/core';
import { LabelXtype, LeftXtype } from 'ui';
@shortcut()
export class FormItem extends BI.Widget {
@ -13,10 +12,10 @@ export class FormItem extends BI.Widget {
render () {
return {
type: LeftXtype,
type: BI.FloatLeftLayout.xtype,
items: [
{
type: LabelXtype,
type: BI.Label.xtype,
cls: 'bi-font-bold',
width: this.options.nameWidth,
textAlign: 'left',

40
src/web/src/modules/components/parameter/parameter.model.ts

@ -1,40 +0,0 @@
import { model, Model } from '../../core/core';
import { ParametersType } from './parameter.typings';
@model()
export class ParameterModel extends Model {
static xtype = 'plugin.model.report.json.components.parameter';
childContext = <const>['selectedId', 'parameters'];
state() {
return {
parameters: [] as ParametersType[],
selectedId: '',
};
}
actions = {
setParameters: (parameters: ParametersType[]) => {
this.model.parameters = parameters;
},
removeSelectedParameter: () => {
this.setParameters(this.model.parameters.filter(item => item.id !== this.model.selectedId));
},
move: (type: 'up'|'down') => {
if (this.model.selectedId) {
const index = this.model.parameters.findIndex(item => item.id === this.model.selectedId);
if (type === 'up' && index > 0) {
const oldItem = this.model.parameters.splice(index, 1)[0];
this.model.parameters.splice(index - 1, 0, oldItem);
}
if (type === 'down' && index < this.model.parameters.length - 1) {
const oldItem = this.model.parameters.splice(index, 1)[0];
this.model.parameters.splice(index + 1, 0, oldItem);
}
}
},
}
}

172
src/web/src/modules/components/parameter/parameter.ts

@ -1,172 +0,0 @@
import { shortcut, store } from '../../core/core';
import { VtapeXtype, LabelXtype, HtapeXtype, LeftRightVerticalAdaptLayoutXtype, IconButtonXtype, ButtonGroupXtype, VerticalXtype } from 'ui';
import { ParameterInput } from './parameter_input/parameter_input';
import { ParameterModel } from './parameter.model';
import { ParametersType } from './parameter.typings';
@shortcut()
@store(ParameterModel)
export class Parameter extends BI.Widget {
static xtype = 'plugin.report.redis.components.parameter';
props = {
title: '',
showRefresh: true,
height: 200,
value: [] as ParametersType[],
}
parameterInputs: any;
model: ParameterModel['model']
store: ParameterModel['store']
watch = {
parameters: () => {
this.parameterInputs.populate(this.renderParameterInputs());
},
selectedId: (id: string) => {
this.parameterInputs.setValue(id);
},
}
render() {
const { title, showRefresh } = this.options;
this.setDefalue();
return {
type: VtapeXtype,
items: [{
el: {
type: LeftRightVerticalAdaptLayoutXtype,
items: {
left: [{
type: LabelXtype,
lgap: 2,
text: title,
textAlign: 'left',
}],
right: [{
type: IconButtonXtype,
cls: 'text-add-tip-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Insert'),
handler: () => {
this.store.setParameters([{
name: '',
value: '',
id: BI.UUID(),
type: 'string',
}, ...this.model.parameters]);
},
}, {
type: IconButtonXtype,
cls: 'close-font bi-error',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Delete'),
handler: () => {
if (this.model.selectedId) {
BI.Msg.confirm(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Plugin-Redis_Parameter_Delete_Confirm'), (re: boolean) => {
if (re) {
this.store.removeSelectedParameter();
}
});
} else {
BI.Msg.alert(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Plugin-Redis_Parameter_Delete_Alert'));
}
},
}, {
type: IconButtonXtype,
cls: 'add-up-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Move_Up'),
handler: () => {
this.store.move('up');
},
}, {
type: IconButtonXtype,
cls: 'minus-down-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Move_Down'),
handler: () => {
this.store.move('down');
},
}, showRefresh ? {
type: IconButtonXtype,
cls: 'refresh-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Refresh'),
handler: () => {
this.setDefalue();
},
} : null],
},
},
height: 25,
}, {
el: {
type: HtapeXtype,
cls: 'bi-border',
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Dataset_Parameter_Name'),
},
width: 0.5,
}, {
el: {
type: LabelXtype,
cls: 'bi-border-left',
text: BI.i18nText('Plugin-Redis_Dataset_Parameter_Value'),
},
width: 0.5,
}],
},
height: 25,
}, {
type: ButtonGroupXtype,
cls: 'bi-border',
layouts: [{
type: VerticalXtype,
}],
items: this.renderParameterInputs(),
ref: (_ref: any) => {
this.parameterInputs = _ref;
},
}],
};
}
public getValue() {
return this.model.parameters.map(item => {
return {
name: item.name,
value: item.value,
type: item.type,
};
});
}
private setDefalue() {
const { value = [] } = this.options;
this.store.setParameters(value.map(item => {
return {
...item,
id: BI.UUID(),
};
}));
}
private renderParameterInputs() {
return this.model.parameters.map(item => {
return {
type: ParameterInput.xtype,
inputName: item.name,
inputValue: item.value,
id: item.id,
value: item.id,
selected: item.id === this.model.selectedId,
};
});
}
}

9
src/web/src/modules/components/parameter/parameter.typings.d.ts vendored

@ -1,9 +0,0 @@
export interface ParametersType {
name: string;
value: string;
id?: string;
type: inputTypes;
}
export type inputTypes = 'string' | 'int' | 'number' | 'date' | 'boolean' | 'formula'

20
src/web/src/modules/components/parameter/parameter_input/input/input.service.ts

@ -1,20 +0,0 @@
import { inputTypes } from '../../parameter.typings';
const inputs: {
[key: string]: any;
} = {};
export function input(key: inputTypes): ClassDecorator {
return (target: object) => {
inputs[key] = target;
};
}
export function getInput(type: inputTypes): string {
const inputWidget = inputs[type];
if (BI.isNull(inputWidget)) {
throw new TypeError();
}
return inputWidget.xtype;
}

6
src/web/src/modules/components/parameter/parameter_input/input/input.ts

@ -1,6 +0,0 @@
import './input_boolean';
import './input_date';
import './input_int';
import './input_number';
import './input_string';
import './input_formula';

41
src/web/src/modules/components/parameter/parameter_input/input/input_boolean.ts

@ -1,41 +0,0 @@
import { shortcut } from '../../../../core/core';
import { MultiSelectItemXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('boolean')
export class InputBoolean extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.boolean'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: MultiSelectItemXtype,
width: 80,
selected: !!value,
text: 'true',
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_date.ts

@ -1,42 +0,0 @@
import { shortcut } from '../../../../core/core';
import { DynamicDateComboXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('date')
export class InputDate extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.date'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: DynamicDateComboXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isNumeric(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

45
src/web/src/modules/components/parameter/parameter_input/input/input_formula.ts

@ -1,45 +0,0 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('formula')
export class InputFormula extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.formula'
props = {
value: '',
}
input: any;
mounted() {
}
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_int.ts

@ -1,42 +0,0 @@
import { shortcut } from '../../../../core/core';
import { NumberEditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('int')
export class InputInt extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.int'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: NumberEditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isInteger(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_number.ts

@ -1,42 +0,0 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('number')
export class InputNumber extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.number'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isNumeric(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

41
src/web/src/modules/components/parameter/parameter_input/input/input_string.ts

@ -1,41 +0,0 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('string')
export class InputString extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.string'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

5
src/web/src/modules/components/parameter/parameter_input/parameter_input.less

@ -1,5 +0,0 @@
@import '../../../../less/index.less';
.plugin-report-json-parameter-input.active{
background-color: @color-bi-light-blue-60;
}

40
src/web/src/modules/components/parameter/parameter_input/parameter_input.model.ts

@ -1,40 +0,0 @@
import { model, Model } from '../../../core/core';
import { ParameterModel } from '../parameter.model';
import { inputTypes } from '../parameter.typings';
@model()
export class ParameterInputModel extends Model<{
types: {
selectedId: ParameterModel['TYPE']['selectedId'];
parameters: ParameterModel['TYPE']['parameters'];
},
context: ParameterInputModel['context'];
}> {
static xtype = 'plugin.model.report.json.components.parameter_input';
context = <const>['selectedId', 'parameters'];
actions = {
setSelectedId: (id: string) => {
this.model.selectedId = id;
},
setParameterName: (id: string, name: string) => {
const thisParameter = this.getParameter(id);
if (thisParameter) {
thisParameter.name = name;
}
},
setParameterValue: (id: string, value: string, type: inputTypes) => {
const thisParameter = this.getParameter(id);
if (thisParameter) {
thisParameter.value = value;
thisParameter.type = type;
}
},
}
private getParameter(id: string) {
return this.model.parameters.find(item => item.id === id);
}
}

165
src/web/src/modules/components/parameter/parameter_input/parameter_input.ts

@ -1,165 +0,0 @@
import { shortcut, store } from '../../../core/core';
import { HtapeXtype, EditorXtype, TextButtonXtype, TabXtype, IconComboXtype } from 'ui';
import { ParameterInputModel } from './parameter_input.model';
import { inputTypes } from '../parameter.typings';
import { getInput } from './input/input.service';
import './input/input';
import './parameter_input.less';
@shortcut()
@store(ParameterInputModel)
export class ParameterInput extends BI.BasicButton {
static xtype = 'plugin.report.json.components.parameter_input'
props = {
inputName: '',
inputValue: '',
height: 22,
id: '',
baseCls: 'plugin-report-json-parameter-input',
}
store: ParameterInputModel['store']
model: ParameterInputModel['model']
tab: any;
parameterName: any;
parameterValue: any;
iconCombo: any;
render() {
let { inputName, inputValue } = this.options;
const { id } = this.options;
return {
type: HtapeXtype,
cls: 'bi-border',
items: [{
el: {
type: EditorXtype,
height: 22,
allowBlank: true,
value: inputName,
ref: (_ref: any) => {
this.parameterName = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
inputName = this.parameterName.getValue();
this.tab.setSelect(inputName ? 'string' : 'tip');
inputValue = inputName ? inputValue : '';
this.store.setParameterName(id, inputName);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.store.setSelectedId(id);
},
}],
},
width: 0.5,
}, {
el: {
type: HtapeXtype,
items: [{
type: TabXtype,
single: true,
showIndex: inputName ? 'string' : 'tip',
ref: (_ref: any) => {
this.tab = _ref;
},
cardCreator: (index: inputTypes | 'tip') => this.renderInputs(index),
}],
},
width: 0.5,
}],
};
}
private renderInputs(type: inputTypes | 'tip') {
const { inputValue, id } = this.options;
if (type === 'tip') {
return {
type: TextButtonXtype,
cls: 'bi-error bi-border-left',
text: BI.i18nText('Plugin-Redis_Parameter_Please_Set_Parameter_Name'),
handler: () => {
this.parameterName.focus();
},
};
}
const xtype = getInput(type);
return {
type: HtapeXtype,
items: [{
el: {
type: IconComboXtype,
cls: 'bi-border-left bi-border-right',
height: 22,
width: 25,
value: type,
items: this.renderDownList(),
ref: (_ref: any) => {
this.iconCombo = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
this.tab.setSelect('tip');
const typeValue = this.iconCombo.getValue()[0];
if (typeValue) {
this.tab.setSelect(typeValue);
}
},
}],
},
width: 25,
}, {
type: xtype,
value: inputValue,
listeners: [{
eventName: 'EVENT_CHANGE',
action: (value: string) => {
const type = this.iconCombo.getValue()[0];
this.store.setParameterValue(id, value, type);
},
}, {
eventName: 'EVENT_FOCUS',
action: () => {
this.store.setSelectedId(id);
},
}],
}],
};
}
private renderDownList() {
return [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_String'),
value: 'string',
iconCls: 'input-string-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
iconCls: 'input-int-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Number'),
value: 'number',
iconCls: 'input-number-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Date'),
value: 'date',
iconCls: 'input-date-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Boolean'),
value: 'boolean',
iconCls: 'input-boolean-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Formula'),
value: 'formula',
iconCls: 'input-formula-font',
}];
}
}

15
src/web/src/modules/components/pool/pool.ts

@ -1,5 +1,4 @@
import { shortcut } from '@core/core';
import { LabelXtype, VerticalXtype, MultiSelectItemXtype } from 'ui';
import { POOL_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item';
@shortcut()
@ -16,7 +15,7 @@ export class PoolConfig extends BI.Widget {
const { maxTotal, maxWait, maxIdle, blockWhenExhausted, lifo, timeout } = this.options.poolConfig;
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -24,7 +23,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Total'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: maxTotal,
}],
},
@ -32,7 +31,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: maxWait,
}],
},
@ -40,7 +39,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: maxIdle,
}],
},
@ -48,7 +47,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'),
forms: [{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
selected: blockWhenExhausted,
}],
},
@ -56,7 +55,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Lifo'),
forms: [{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
selected: lifo,
}],
},
@ -64,7 +63,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Timeout'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: timeout,
}],
},

15
src/web/src/modules/components/pool/pool_edit.ts

@ -1,5 +1,4 @@
import { shortcut, store } from '@core/core';
import { VerticalXtype, MultiSelectItemXtype, TextEditorXtype } from 'ui';
import { POOL_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item';
import { PoolEditModel } from './pool_edit.model';
@ -33,7 +32,7 @@ export class PoolEdit extends BI.Widget {
this.store.setLifo(lifo);
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -41,7 +40,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Total'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: maxTotal,
@ -54,7 +53,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: maxWait,
@ -67,7 +66,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: maxIdle,
@ -80,7 +79,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'),
forms: [{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
selected: blockWhenExhausted,
ref: (_ref: any) => {
this.form.blockWhenExhausted = _ref;
@ -94,7 +93,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Lifo'),
forms: [{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
selected: lifo,
ref: (_ref: any) => {
this.form.lifo = _ref;
@ -108,7 +107,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Timeout'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: timeout,

20
src/web/src/modules/components/preview/preview.model.ts

@ -0,0 +1,20 @@
import { model, Model } from '@core/core';
@model()
export class PreviewModel extends Model {
static xtype = 'plugin.model.report.redis.components.preview';
childContext = <const>['previewAble', 'previewedDataSet'];
state() {
return {
previewAble: true,
previewedDataSet: {},
};
}
actions = {
setPreviewedDataSet: (value: any) => {
this.model.previewedDataSet = value;
},
}
}

31
src/web/src/modules/components/preview/preview.ts

@ -0,0 +1,31 @@
import { shortcut, store } from '@core/core';
import { PreviewModel } from './preview.model';
@shortcut()
@store(PreviewModel)
export class Preview extends BI.Widget {
static xtype = 'plugin.report.redis.components.preview'
store: PreviewModel['store']
model: PreviewModel['model']
previewPane: any
props = {
previewedDataSet: {},
}
render() {
this.store.setPreviewedDataSet(this.options.previewedDataSet);
return {
type: 'dec.data.set.preview',
ref: (_ref: any) => {
this.previewPane = _ref;
},
};
}
created() {
this.previewPane.previewData();
}
}

19
src/web/src/modules/components/proxy/proxy.ts

@ -1,5 +1,4 @@
import { shortcut } from '@core/core';
import { LabelXtype, VerticalXtype, MultiSelectItemXtype, CenterAdaptXtype } from 'ui';
import { PROXY_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item';
@shortcut()
@ -16,7 +15,7 @@ export class ProxyConfig extends BI.Widget {
const { open, host, port, username, password, privateKeyPath } = this.options.proxyConfig;
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -24,14 +23,14 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Open'),
forms: [{
type: CenterAdaptXtype,
type: BI.CenterAdaptLayout.xtype,
items: [
{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
width: 30,
selected: open,
}, {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Proxy_Description'),
},
],
@ -41,7 +40,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Host'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: host,
}],
},
@ -49,7 +48,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Port'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: port,
}],
},
@ -57,7 +56,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Username'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: username,
}],
},
@ -65,7 +64,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Password'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: password,
}],
},
@ -73,7 +72,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'),
forms: [{
type: LabelXtype,
type: BI.Label.xtype,
text: privateKeyPath,
}],
},

19
src/web/src/modules/components/proxy/proxy_edit.ts

@ -1,5 +1,4 @@
import { shortcut } from '@core/core';
import { LabelXtype, VerticalXtype, MultiSelectItemXtype, CenterAdaptXtype, TextEditorXtype, EditorXtype } from 'ui';
import { PROXY_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item';
@shortcut()
@ -30,7 +29,7 @@ export class ProxyEdit extends BI.Widget {
this.oldPassword = password;
return {
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
hgap: 15,
vgap: 10,
items: [
@ -38,17 +37,17 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Open'),
forms: [{
type: CenterAdaptXtype,
type: BI.CenterAdaptLayout.xtype,
items: [
{
type: MultiSelectItemXtype,
type: BI.MultiSelectItem.xtype,
width: 30,
selected: this.isOpen,
handler: () => {
this.isOpen = !this.isOpen;
},
}, {
type: LabelXtype,
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Proxy_Description'),
},
],
@ -58,7 +57,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Host'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: host,
@ -71,7 +70,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Port'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: port,
@ -84,7 +83,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Username'),
forms: [{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: username,
@ -97,7 +96,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Password'),
forms: [{
type: EditorXtype,
type: BI.Editor.xtype,
cls: 'bi-border',
width: 300,
height: 20,
@ -114,7 +113,7 @@ export class ProxyEdit extends BI.Widget {
name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'),
forms: [
{
type: TextEditorXtype,
type: BI.TextEditor.xtype,
width: 300,
allowBlank: true,
value: privateKeyPath,

4
src/web/src/modules/constants/env.ts

@ -0,0 +1,4 @@
export const fineServletURL = Dec.fineServletURL;
export const ReqPrefix = `${fineServletURL}/v10/config/connection`;
export const ImgPrefix = `${fineServletURL}/resources?path=/com/fr/web/resources/dist/images/2x/icon/database/`;
export const PluginImgPrefix = `${fineServletURL}/resources?path=`;

59
src/web/src/modules/crud/crud.request.ts

@ -0,0 +1,59 @@
import { requestGet } from './crud.service';
import { formulaData } from './formulaData';
export function getConnectionlist(): Promise<{data?: Connection[]}> {
return requestGet('/v10/config/connection/list');
}
export function getTableList(database: string, pattern = '', orderValue: string | number): Promise<string[]> {
return requestGet('plugin/private/com.fr.solution.plugin.db.redis.v10/redis/keys', {
database,
pattern,
orderValue,
});
}
/**
*
*/
export function fetchFormulaConfig(): Promise<{
vars: {
text: string;
value: string;
type: string;
def: string;
}[];
JSONs: {
def: string;
name: string;
type: string;
}[];
}> {
// TODO 后台接口待完成
return new Promise(resolve => {
resolve(formulaData);
});
}
/**
*
* @param formulaStr
*/
export function validateForumula(formulaStr: string): Promise<{
validation: boolean;
}> {
// TODO 后台接口待完成
return new Promise(resolve => {
resolve({ validation: true });
});
}
export interface Connection {
connectionId: string;
connectionType: string;
connectionName: string;
creator?: string;
privilegeDetailBeanList?: {
privilegeType: number;
privilegeValue: number;
}[]
}

130
src/web/src/modules/crud/crud.service.ts

@ -0,0 +1,130 @@
import 'es6-promise/auto';
import axios, { AxiosResponse, AxiosError } from 'axios';
import { fineServletURL } from '../constants/env';
const defaultHeaders = {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
};
export function paramsSerializer(params: { [key: string]: any }) {
return Object.keys(params || {})
.map(paramKey => {
const paramValue = params[paramKey];
let value = '';
if (BI.isObject(paramValue)) {
value = encodeURIComponent(JSON.stringify(paramValue));
} else {
value = paramValue;
}
return BI.isNull(value) ? '' : `${paramKey}=${value}`;
})
.filter(v => v !== '')
.join('&');
}
function getCookieByName(name: string):string {
let value = null;
const regExpName = new RegExp(name);
document.cookie.split(';').forEach((item: string) => {
if (item.match(regExpName)) {
value = item.split(`${name}=`)[1];
return false;
}
});
return value;
}
function checkStatus(response: AxiosResponse) {
const status = response.status;
const resData = status === 200
? typeof response.data === 'string'
? BI.jsonDecode(response.data)
: response.data
: {};
return resData;
}
export async function request(reqOptions: CrudReqOpts = {}): Promise<any> {
const { url, type, headers, data, params } = reqOptions;
return axios
.request({
url,
baseURL: fineServletURL,
method: type,
headers: {
...defaultHeaders,
...headers,
Authorization: `Bearer ${getCookieByName('fine_auth_token')}`,
'Content-Type': 'application/json;charset=UTF-8',
},
params,
paramsSerializer,
data,
})
.then(checkStatus)
.catch((error: AxiosError) => {
console.log(error);
});
}
export function requestGet(url: string, params: CrudParams = {}) {
const timeStamp = new Date().getTime();
return request({
url,
type: 'GET',
params: {
...params,
_: timeStamp,
},
});
}
export function requestPost(url: string, data = {}, params: CrudParams = {}) {
return request({
url,
type: 'POST',
data,
params,
});
}
export function requestDelete(url: string, data = {}) {
return request({
url,
type: 'DELETE',
data,
});
}
export function requestPut(url: string, data = {}, params: CrudParams = {}) {
return request({
url,
type: 'PUT',
data,
params,
});
}
interface CrudReqOpts {
url?: string;
type?: 'GET' | 'POST' | 'DELETE' | 'PUT';
data?: any;
headers?: {
[key: string]: string;
};
noProgress?: boolean;
params?: CrudParams;
}
interface CrudParams {
[key: string]: string | number | { [key: string]: any };
}

549
src/web/src/modules/crud/formulaData.ts

@ -0,0 +1,549 @@
// 后期统一放置公式数据
export const formulaData = {
vars: [
{
text: '$$page_number',
value: '$$page_number',
type: 'VARS',
def: '当前的页数。',
},
{
text: '$$totalPage_number',
value: '$$totalPage_number',
type: 'VARS',
def: '总页数。',
},
],
JSONs: [
{
def: 'ABS(number): 返回指定数字的绝对值。绝对值是指没有正负符号的数值。Number:需要求出绝对值的任意实数。示例:ABS(-1.5)等于1.5。ABS(0)等于0。ABS(2.5)等于2.5。',
name: 'ABS',
type: 'MATH',
},
{
def: 'ABS(number): 返回指定数字的绝对值。绝对值是指没有正负符号的数值。Number:需要求出绝对值的任意实数。示例:ABS(-1.5)等于1.5。ABS(0)等于0。ABS(2.5)等于2.5。',
name: 'ABS',
type: 'COMMON',
},
{
def: 'acc_sum(x_agg(array),range)根据横纵轴或行列维度添加的字段对指标进行跨行累计的计算。第一个参数为用户计算的指标,该指标必须为聚合函数或聚合指标;第二个参数range为用户设置计算的范围,0为对所有行进行累计,1为对组内所有行进行累计示例:acc_sum(sum_agg(array),0)用户横轴轴拖拽销售日期(年分组),则该指标计算结果为,根据销售日期(年)对销量进行分组汇总,然后根据对所有行从上到下进行累加,获得每年的累计销量',
name: 'ACC_SUM',
type: 'TABLE_CAL',
},
{
def: 'ACOS(number): 返回指定数值的反余弦值。反余弦值为一个角度,返回角度以弧度形式表示。Number:需要返回角度的余弦值。备注: 函数的参数必须在-1和1之间,包括-1和1。 返回的角度值在0和Pi之间。 如果要把返回的角度用度数来表示,用180/PI()乘返回值即可。示例:ACOS(1)等于0(弧度)。ACOS(0.5)等于1.047197551(Pi/3弧度)。ACOS(0.5)*180/PI()等于60(度)。',
name: 'ACOS',
type: 'MATH',
},
{
def: 'AND(logical1,logical2,…): 当所有参数的值为真时,返回TRUE;当任意参数的值为假时,返回FALSE。Logical1,logical2,…:指1到30个需要检验TRUE或FALSE的条件值。备注: 参数必须是逻辑值,或是含有逻辑值的数组或引用。 如果数组或引用中含有文本或空的单元格,则忽略其值。 如果在指定的单元格区域中没有逻辑值,AND函数将返回错误信息*NAME?。示例:AND(1+7=8,5+7=12)等于TRUE。AND(1+7=8,5+7=11)等于FALSE。如果单元格A1到A4的值分别为TRUE、TRUE、FALSE和TRUE,则:AND(A1:A4)等于FALSE。如果单元格A5的值在0~50之间,则: AND(0<A5,A5<50)等于TRUE。',
name: 'AND',
type: 'LOGIC',
},
{
def: 'ASIN(number): 返回指定数值的反正弦值。反正弦值为一个角度,返回角度以弧度形式表示。Number:需要返回角度的正弦值。备注: 指定数值必须在-1到1之间(含1与-1)。 返回角度在-pi/2到pi/2之间(含-pi/2与pi/2)。 用角度形式返回数值时,返回数值乘以180/PI()。示例:ASIN(0.5)等于0.523598776(pi/6弧度)。ASIN(1)等于1.570796327(pi/2弧度)。ASIN(0.5)*180/PI()等于30(度)。',
name: 'ASIN',
type: 'MATH',
},
{
def: 'ATAN(number): 计算指定数值的反正切值。指定数值是返回角度的正切值,返回角度以弧度形式表示。Number:返回角度的正切。备注: 返回角度在-pi/2到pi/2之间。 如果返回角度等于-pi/2或pi/2,ATAN将返回错误信息*NUM!。 用角度形式返回数值时,返回数值乘以180/PI()。示例:ATAN(-1)等于-0.785398163(-pi/4弧度)。ATAN(0)等于0(弧度)。ATAN(2)*180/PI()等于63.43494882(度)。',
name: 'ATAN',
type: 'MATH',
},
{
def: 'ATAN2(x_num,y_num): 返回x、y坐标的反正切值。返回角度为x轴与过(x_num,y_num)与坐标原点(0,0)的一条直线形成的角度。该角度以弧度显示。X_num:指定点的x坐标。Y_num:指定点的y坐标。备注: 正值表示从x轴开始以逆时针方式所得的角度;负值表示从x轴开始以顺时针方式所得的角度。a > 0,b > 0 or a > 0, b < 0时,公式直接成立;a < 0,b > 0, ATAN2(a,b)=PI()-ABS(ATAN(b/a))a < 0,b < 0, ATAN2(a,b)=ABS(ATAN(b/a))-PI() 当x_num与y_num都为0时,ATAN2返回错误信息*DIV/0!。 用角度制显示返回数值时,把返回数值乘以180/PI()。 返回值以弧度表示(返回值大于-pi且小于等于pi)。示例:ATAN2(-2,2)等于2.356194490192345(弧度制的3*pi/4)。ATAN2(2,2)等于0.785398163(弧度制的pi/4)。ATAN2(-2,2)*180/PI()等于135(角度制)。',
name: 'ATAN2',
type: 'MATH',
},
{
def: 'AVG_AGG(array): 根据当前分析维度,动态返回指标字段的汇总平均值,生成结果为一动态数据列,行数与当前分析维度行数一致。\n array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。 \n 示例:用户横轴为维度字段\'日\'时,纵轴的计算字段AVG_AGG(销量)返回的值为每日的平均销量;当用户横轴为维度字段\'月\'时,AVG_AGG(销量)返回的值为每月的平均销量。',
name: 'AVG_AGG',
type: 'AGG',
},
{
def: 'CEILING(number): 将参数number沿绝对值增大的方向,舍入为最接近的整数Number:指待舍入的数值。CEILING(-2.5)等于-3。CEILING(0.5)等于1。',
name: 'CEILING',
type: 'MATH',
},
{
def: 'CHAR(number): 根据指定数字返回对应的字符。CHAR函数可将计算机其他类型的数字代码转换为字符。Number:用于指定字符的数字,介于1~65535之间(包括1和65535)。示例:CHAR(88)等于“X”。CHAR(45)等于“-”。',
name: 'CHAR',
type: 'TEXT',
},
{
def: 'CODE(text): 计算文本串中第一个字符的数字代码。返回的代码对应于计算机使用的字符集。Text:需要计算第一个字符代码的文本或单元格引用。示例:CODE("S")等于83。CODE("Spreadsheet")等于83。',
name: 'CODE',
type: 'TEXT',
},
{
def: 'CONCATENATE(text1,text2,...): 将数个字符串合并成一个字符串。Text1,text2,...:需要合并成单个文本的文本项,可以是字符,数字或是单元格引用。示例:CONCATENATE("Average ","Price")等于“Average Price”。CONCATENATE("1","2")等于12。',
name: 'CONCATENATE',
type: 'TEXT',
},
{
def: 'COS(number): 返回一个角度的余弦值。Number:以弧度表示的需要求余弦值的角度。备注: 要把一个角度转换成弧度值,将角度乘于PI()/180。 COS(n*2*PI()+number)=COS(number)(其中n为整数,number从-pi到pi)。示例:COS(0.5)等于0.877582562。COS(30*PI()/180)等于0.866025404。',
name: 'COS',
type: 'MATH',
},
{
def: 'COUNTD_AGG(array): 根据当前分析维度,动态返回某字段的去重计数,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段COUNTD_AGG(销量)返回的值为每日的销量的去重个数;当用户横轴为维度字段\'月\'时,COUNTD_AGG(销量)返回的值为每月的销量的去重个数。"',
name: 'COUNTD_AGG',
type: 'AGG',
},
{
def: 'COUNT_AGG(array): 根据当前分析维度,动态返回某字段的计数,生成结果为一动态数据列,行数与当前分析维度行数一致。\n array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n 示例:用户横轴为维度字段\'日\'时,纵轴的计算字段COUNT_AGG(销量)返回的值为每日的销量的个数;当用户横轴为维度字段\'月\'时,COUNT_AGG(销量)返回的值为每月的销量的个数。',
name: 'COUNT_AGG',
type: 'AGG',
},
{
def: 'DATE(year,month,day): 返回一个表示某一特定日期的系列数。Year:代表年,可为一到四位数。Month:代表月份。若1 month 12,则函数把参数值作为月。若month>12,则函数从年的一月份开始往上累加。例如: DATE(2000,25,2)等于2002年1月2日的系列数。Day:代表日。若日期小于等于某指定月的天数,则函数将此参数值作为日。若日期大于某指定月的天数,则函数从指定月份的第一天开始往上累加。若日期大于两个或多个月的总天数,则函数把减去两个月或多个月的余数加到第三或第四个月上,依此类推。例如:DATE(2000,3,35)等于2000年4月4日的系列数。备注: 若需要处理公式中日期的一部分,如年或月等,则可用此公式。 若年,月和日是函数而不是函数中的常量,则此公式最能体现其作用。示例:DATE(1978, 9, 19) 等于1978-09-19.DATE(1211, 12, 1) 等于1211-12-01. ',
name: 'DATE',
type: 'DATETIME',
},
{
def: 'DATEDELTA(date, deltadays):返回一个日期date后deltadays的日期。deltaDays可以为正值,负值,零。示例:DATEDELTA("2008-08-08", -10)等于2008-07-29。DATEDELTA("2008-08-08", 10)等于2008-08-18。',
name: 'DATEDELTA',
type: 'DATETIME',
},
{
def: 'DATEDIF(start_date,end_date,unit):返回两个指定日期间的天数、月数或年数。Start_date:代表所指定时间段的初始日期。End_date:代表所指定时间段的终止日期。Unit:函数返回信息的类型。若unit=“Y”,则DATEDIF返回指定时间段的年差数。若unit=“M”,则DATEDIF返回指定时间段的月差数。若unit=“D”,则DATEDIF返回指定时间段的日差数。若unit=“MD”,则DATEDIF忽略年和月,返回指定时间段的日差数。若unit=“YM”,则DATEDIF忽略年和日,返回指定时间段的月差数。若unit=“YD”,则DATEDIF忽略年,返回指定时间段的日差数。示例:DATEDIF("2001/2/28","2004/3/20","Y")等于3,即在2001年2月28日与2004年3月20日之间有3个整年。DATEDIF("2001/2/28","2004/3/20","M")等于37,即在2001年2月28日与2004年3月20日之间有36个整月。DATEDIF("2001/2/28","2004/3/20","D")等于1116,即在2001年2月28日与2004年3月20日之间有1116个整天。DATEDIF("2001/2/28","2004/3/20","MD")等于8,即忽略月和年后,2001年2月28日与2004年3月20日的差为8天。DATEDIF("2001/1/28","2004/3/20","YM")等于2,即忽略日和年后,2001年1月28日与2004年3月20日的差为2个月。DATEDIF("2001/2/28","2004/3/20","YD")等于21,即忽略年后,2001年2月28日与2004年3月20日的差为21天。',
name: 'DATEDIF',
type: 'DATETIME',
},
{
def: 'DATESUBDATE(date1, date2, op):返回两个日期之间的时间差。op表示返回的时间单位:"s",以秒为单位。"m",以分钟为单位。"h",以小时为单位。"d",以天为单位。"w",以周为单位。示例:DATESUBDATE("2008-08-08", "2008-06-06","h")等于1512。',
name: 'DATESUBDATE',
type: 'DATETIME',
},
{
def: 'DATETONUMBER(date):返回自 1970 年 1 月 1 日 00:00:00 GMT 经过的毫秒数。示例:DATETONUMBER("2008-08-08")等于1218124800000。',
name: 'DATETONUMBER',
type: 'DATETIME',
},
{
def: 'DAY:(serial_number)返回日期中的日。DAY是介于1和31之间的一个数。Serial_number:含有所求的年的日期.备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。示例:DAY("2000/1/1")等于1。DAY("2006/05/05")等于5。DAY("1997/04/20")等于20。DAY("2000-1-1", "yyyy-MM-dd")等于1。DAY("2006-05-05", "yyyy-MM-dd")等于5。DAY("1997-04-20", "yyyy-MM-dd")等于20。DAY(35796)等于1。',
name: 'DAY',
type: 'DATETIME',
},
{
def: 'DAYS360(start_date,end_date,method):按照一年 360 天的算法(每个月以 30 天计,一年共计 12 个月),返回两日期间相差的天数,这在会计计算中将会用到。如果财务系统是基于一年 12 个月,每月 30 天,可用此函数帮助计算支付款项。Start_date 和 end_date :是用于计算期间天数的起止日期。Method : 它指定了在计算中是采用欧洲方法还是美国方法。Method 定义 :FALSE或忽略 美国方法 (NASD)。如果起始日期是一个月的 31 号,则等于同月的 30 号。如果终止日期是一个月的31号,并且起始日期早于 30 号,则终止日期等于下一个月的 1 号,否则,终止日期等于本月的 30 号。TRUE 欧洲方法。无论是起始日期还是终止日期为一个月的 31 号,都将等于本月的 30 号。备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。示例:DAYS360("1998/1/30", "1998/2/1") 等于 1',
name: 'DAYS360',
type: 'DATETIME',
},
{
def: 'DAYSOFMONTH(date):返回从1900年1月后某年某月包含的天数。示例:DAYSOFMONTH("1900-02-01")等于28。DAYSOFMONTH("2008/04/04")等于30。',
name: 'DAYSOFMONTH',
type: 'DATETIME',
},
{
def: 'DAYSOFQUARTER(date): 返回从1900年1月后某年某季度的天数。示例:DAYSOFQUARTER("2009-02-01")等于90。DAYSOFQUARTER("2009/05/05")等于91。',
name: 'DAYSOFQUARTER',
type: 'DATETIME',
},
{
def: 'DAYSOFYEAR(year):返回某年包含的天数。示例:DAYSOFYEAR(2008)等于365,等价于DAYSOFYEAR("2008-01-01")。',
name: 'DAYSOFYEAR',
type: 'DATETIME',
},
{
def: 'DAYVALUE(date):返回1900年至 date日期所经历的天数。示例:DAYVALUE("2008/08/08")等于39669。',
name: 'DAYVALUE',
type: 'DATETIME',
},
{
def: 'DEGREES(angle): 将弧度转化为度。angle:待转换的弧度角。示例:DEGREES(PI()/2)等于90。DEGREES(3.1415926)等于179.9999969。',
name: 'DEGREES',
type: 'MATH',
},
{
def: 'ENDWITH(str1,str2):判断字符串str1是否以str2结束。备注: str1和str2都是大小写敏感的。示例:ENDWITH("FineReport","Report")等于true。ENDWITH("FineReport","Fine")等于false。ENDWITH("FineReport","report")等于false。',
name: 'ENDWITH',
type: 'TEXT',
},
{
def: 'EXACT(text1,text2): 检测两组文本是否相同。如果完全相同,EXACT函数返回TRUE;否则,返回FALSE。EXACT函数可以区分大小写,但忽略格式的不同。同时也可以利用EXACT函数来检测输入文档的文字。Text1:需要比较的第一组文本。Text2:需要比较的第二组文本。示例:EXACT("Spreadsheet","Spreadsheet")等于TRUE。EXACT("Spreadsheet","S preadsheet")等于FALSE。EXACT("Spreadsheet","spreadsheet")等于FALSE。',
name: 'EXACT',
type: 'TEXT',
},
{
def: 'EXP(number): 返回e的n次幂。常数e为自然对数的底数,等于2.71828182845904。Number:为任意实数,作为常数e的指数。备注: 如果要返回其他常数作为底数的幂,可以使用指数运算符(^)。例如: 在4^2中,4是底数,而2是指数。 EXP函数与LN函数互为反函数。示例:EXP(0)等于1。EXP(3)等于20.08553692。EXP(LN(2))等于2。',
name: 'EXP',
type: 'MATH',
},
{
def: 'FACT(number):返回数的阶乘,一个数的阶乘等于 1*2*3*...*该数。number:要计算其阶乘的非负数。如果输入的 number 不是整数,则截尾取整。示例:FACT(1) 等于 1FACT(1.9) 等于 FACT(1) 等于 1FACT(0) 等于 1FACT(5) 等于 1*2*3*4*5 等于 120',
name: 'FACT',
type: 'MATH',
},
{
def: 'FIND(find_text,within_text,start_num):从指定的索引(start_num)处开始,返回第一次出现的指定子字符串(find_text)在此字符串(within_text)中的索引。Find_text:需要查找的文本或包含文本的单元格引用。Within_text:包含需要查找文本的文本或单元格引用。Start_num:指定进行查找字符的索引位置。within_text里的索引从1开始。如果省略start_num,则假设值为1。备注: 如果find_text不在within_text中,FIND函数返回值为0。 如果start_num不大于0,FIND函数返回错误信息*VALUE!。 如果start_num大于within_text的长度,FIND函数返回值为0。 如果find_text是空白文本,FIND函数将在搜索串中匹配第一个字符(即编号为start_num或1的字符)。示例:FIND("I","Information")等于1。FIND("i","Information")等于9。FIND("o","Information",2)等于4。FIND("o","Information",12)等于0。FIND("o","Information",-1)等于*VALUE!。',
name: 'FIND',
type: 'TEXT',
},
{
def: 'FLOOR(number): 将参数number沿绝对值减小的方向去尾舍入。Number:待舍入的数值。示例:FLOOR(-2.5)等于-2。FLOOR(2.5)等于2。',
name: 'FLOOR',
type: 'MATH',
},
{
def: 'FORMAT(object,format) : 返回object的format格式。object 需要被格式化对象,可以是String,数字,Object(常用的有Date, Time)。format 格式化的样式。示例FORMAT(1234.5, "#,##0.00") => 1234.50FORMAT(1234.5, "#,##0") => 1234FORMAT(1234.5, "¥#,##0.00") => ¥1234.50FORMAT(1.5, "0%") => 150%FORMAT(1.5, "0.000%") => 150.000%FORMAT(6789, "##0.0E0") => 6.789E3FORMAT(6789, "0.00E00") => 6.79E03FORMAT(date(2007,1,1), "EEEEE, MMMMM dd, yyyy") => 星期一,一月 01,2007FORMAT(date(2007,1,13), "MM/dd/yyyy") => 01/13/2007FORMAT(date(2007,1,13), "M-d-yy") => 1-13-07FORMAT(time(16,23,56), "h:mm:ss a") => 4:23:56 下午',
name: 'FORMAT',
type: 'TEXT',
},
{
def: 'HOUR(serial_number):返回某一指定时间的小时数。函数指定HOUR为0(0:00)到23(23:00)之间的一个整数。Serial_number:包含所求小时的时间。示例:HOUR("11:32:40")等于11。HOUR("11:32:40", "HH:mm:ss")等于11。',
name: 'HOUR',
type: 'DATETIME',
},
{
def: 'IF(boolean,number1/string1,number2/string2):判断函数,boolean为true时返回第二个参数,为false时返回第三个。boolean: 用于判断的布尔值,true或者false。number1/string1: 第一个参数,如果boolean为ture,返回这个值。number2/string2: 第二个参数,如果boolean为false,返回这个值。示例:IF(true,2,8)等于2IF(false,"first","second")等于secondIF(true,"first",7)等于first',
name: 'IF',
type: 'LOGIC',
},
{
def: 'IF(boolean,number1/string1,number2/string2):判断函数,boolean为true时返回第二个参数,为false时返回第三个。boolean: 用于判断的布尔值,true或者false。number1/string1: 第一个参数,如果boolean为ture,返回这个值。number2/string2: 第二个参数,如果boolean为false,返回这个值。示例:IF(true,2,8)等于2IF(false,"first","second")等于secondIF(true,"first",7)等于first',
name: 'IF',
type: 'COMMON',
},
{
def: 'INDEXOF(str1,index):返回字符串str1在index位置上的字符。备注: index是从0开始计数的。示例:INDEXOF("FineReport",0)等于\'F\'。INDEXOF("FineReport",2)等于\'n\'。INDEXOF("FineReport",9)等于\'t\'。INDEXOF(array, index):返回数组在index位置上的元素。备注: index是从1开始计数的。示例:String[] array = {"a", "b", "c"}INDEXOF(array, 1)等于"a".',
name: 'INDEXOF',
type: 'TEXT',
},
{
def: 'INT(number): 返回数字下舍入(数值减小的方向)后最接近的整数值。Number:需要下舍入为整数的实数。示例:INT(4.8)等于4。INT(-4.8)等于-5。INT(4.3)等于4。INT(-4.3)等于-5。公式INT(A1)将返回A1单元格中的一个正实数的整数数部分。',
name: 'INT',
type: 'MATH',
},
{
def: 'INT(number): 返回数字下舍入(数值减小的方向)后最接近的整数值。Number:需要下舍入为整数的实数。示例:INT(4.8)等于4。INT(-4.8)等于-5。INT(4.3)等于4。INT(-4.3)等于-5。公式INT(A1)将返回A1单元格中的一个正实数的整数数部分。',
name: 'INT',
type: 'COMMON',
},
{
def: 'ISNULL(object):判断对象中所有的值是否全部都是NULL或者为空字符串。',
name: 'ISNULL',
type: 'OTHER',
},
{
def: 'LEFT(text,num_chars): 根据指定的字符数返回文本串中的第一个或前几个字符。Text:包含需要选取字符的文本串或单元格引用。Num_chars:指定返回的字符串长度。备注: Num_chars的值必须等于或大于0。 如果num_chars大于整个文本的长度,LEFT函数将返回所有的文本。 如果省略num_chars,则默认值为1。示例:LEFT("Fine software",8)等于“Fine sof”。LEFT("Fine software")等于“F”。如果单元格A3中含有“China”,则LEFT(A3,2)等于“Ch”。',
name: 'LEFT',
type: 'TEXT',
},
{
def: 'LEN(args): 返回文本串中的字符数或者数组的长度。需要注意的是:参数args为文本串时,空格也计为字符。参数args为数组时,直接返回数组长度。示例:LEN("Evermore software")等于17。LEN(" ")等于1。LEN([\'a\',\'b\'])等于2。',
name: 'LEN',
type: 'TEXT',
},
{
def: 'LN(number):返回一个数的自然对数。自然对数以常数项 e(2.71828182845904)为底。number:是用于计算其自然对数的正实数。示例:LN(86) 等于 4.45437LN(2.7182818) 等于 1LN(EXP(3)) 等于 3EXP(LN(4)) 等于 4',
name: 'LN',
type: 'MATH',
},
{
def: 'LOG(number,base): 按指定的任意底数,返回数值的对数。Number:需要求对数的正实数。Base:对数的底数。如果省略底数,默认值为10。示例:LOG(16,2)等于4。LOG(10)等于1。LOG(24,3)等于2.892789261。',
name: 'LOG',
type: 'MATH',
},
{
def: 'LOG10(number):返回以 10 为底的对数。number: 用于常用对数计算的正实数。示例:LOG10(86) 等于 1.934498451LOG10(10) 等于 1LOG10(1E5) 等于 5',
name: 'LOG10',
type: 'MATH',
},
{
def: 'LOWER(text): 将所有的大写字母转化为小写字母。Text:需要转化为小写字母的文本串。LOWER函数不转化文本串中非字母的字符。示例:LOWER("A.M.10:30")等于“a.m.10:30”。LOWER("China")等于“china”。',
name: 'LOWER',
type: 'TEXT',
},
{
def: 'LUNAR(year,day,month): 返回当前日期对应的农历时间。year,month,day:分别对应年月日。示例:如果需要查询2011年7月21日对应的农历时间,则只需输入LUNAR(2011,7,21)结果将显示为:辛卯年六月廿一同样,如输入LUNAR(2001,7,21),则显示:辛巳年六月初一 。本公式支持的时间段为1900-2100年。',
name: 'LUNAR',
type: 'DATETIME',
},
{
def: 'MAX(number1,number2,…): 返回参数列表中的最大值。Number1,number2,…:1到30个需要找出最大值的参数。备注: 参数可以是数字、空白单元格、逻辑值或数字的文本表达式。 如果数组或引用参数中包含可解析文本值,逻辑值,零值或空白单元格,这些值都将参与计算,而不可解析的文本值忽略不计。 如果参数中没有任何数字,MAX将返回0。示例:MAX(0.1,0,1.2)等于1.2。',
name: 'MAX',
type: 'MATH',
},
{
def: 'MAX_AGG(array): 根据当前分析维度,动态返回指标字段的最大值,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段MAX_AGG(销量)返回的值为每日的最大值销量;当用户横轴为维度字段\'月\'时,MAX_AGG(销量)返回的值为每月的最大值销量。',
name: 'MAX_AGG',
type: 'AGG',
},
{
def: 'MEDIAN_AGG(array): 根据当前分析维度,动态返回指标字段的中位数,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段MEDIAN_AGG(销量)返回的值为每日的中位数销量;当用户横轴为维度字段\'月\'时,MEDIAN_AGG(销量)返回的值为每月的中位数销量。',
name: 'MEDIAN_AGG',
type: 'AGG',
},
{
def: 'MID(text,start_num,num_chars): 返回文本串中从指定位置开始的一定数目的字符,该数目由用户指定。Text:包含要提取字符的文本串。Start_num:文本中需要提取字符的起始位置。文本中第一个字符的start_num为1,依此类推。Num_chars:返回字符的长度。备注: 如果start_num大于文本长度,MID函数返回“”(空文本)。 如果start_num小于文本长度,并且start_num加上num_chars大于文本长度,MID函数将从start_num指定的起始字符直至文本末的所有字符。 如果start_num小于1,MID函数返回错误信息*VALUE!。 如果num_chars是负数,MID函数返回错误信息*VALUE!。示例:MID("Finemore software",10,8)返回“software”。MID("Finemore software",30,5)返回“”(空文本)。MID("Finemore software",0,8)返回*VALUE!。MID("Finemore software",5,-1)返回*VALUE!。',
name: 'MID',
type: 'TEXT',
},
{
def: 'MIN(number1,number2,…): 返回参数列表中的最小值。Number1,number2,…:1到30个需要找出最小值的参数。备注: 若参数中没有数字,函数MIN将返回0。 参数应为数字、空白单元格、逻辑值或是表示数值的文本串。如果参数是错误值时,MIN将返回错误信息。 如果数组或引用参数中包含可解析文本值,逻辑值,零值或空白单元格,这些值都将参与计算,而不可解析的文本值忽略不计。示例:如果B1:B4包含3,6,9,12,则:MIN(B1:B4)等于3。MIN(B1:B4,0)等于0。',
name: 'MIN',
type: 'MATH',
},
{
def: 'MINUTE(serial_number):返回某一指定时间的分钟数,其值是介于0与59之间的一个整数。serial_number:包含所求分钟数的时间。示例:MINUTE("15:36:25")等于36。MINUTE("15:36:25", "HH:mm:ss")等于36。',
name: 'MINUTE',
type: 'DATETIME',
},
{
def: 'MIN_AGG(array): 根据当前分析维度,动态返回指标字段的最小值,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段MIN_AGG(销量)返回的值为每日的最小值销量;当用户横轴为维度字段\'月\'时,MIN_AGG(销量)返回的值为每月的最小值销量。',
name: 'MIN_AGG',
type: 'AGG',
},
{
def: 'MOD(number,divisor):返回两数相除的余数。结果的正负号与除数相同。number:为被除数。divisor:为除数。示例:MOD(3, 2) 等于 1MOD(-3, 2) 等于 1MOD(3, -2) 等于 -1MOD(-3, -2) 等于 -1',
name: 'MOD',
type: 'MATH',
},
{
def: 'MONTH:(serial_number)返回日期中的月。月是介于1和12之间的一个数。Serial_number:含有所求的月的日期.备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。示例:MONTH("2000/1/1")等于1。MONTH("2006/05/05")等于5。MONTH("1997/04/20")等于4。MONTH("2000-1-1", "yyyy-MM-dd")等于1。MONTH("2006-05-05", "yyyy-MM-dd")等于5。MONTH("1997-04-20", "yyyy-MM-dd")等于4。MONTH(35796)等于1。',
name: 'MONTH',
type: 'DATETIME',
},
{
def: 'MONTHDELTA(date,delta):返回指定日期date后delta个月的日期。示例:MONTHDELTA("2008-08-08", 4)等于2008-12-08。',
name: 'MONTHDELTA',
type: 'DATETIME',
},
{
def: 'NOW():获取当前时间。示例:如果系统时间是2012年5月12日 15点18分38秒则NOW()等于2012-05-12 15:18:36。',
name: 'NOW',
type: 'DATETIME',
},
{
def: 'NUMTO(number,bool)或NUMTO(number):返回number的中文表示。其中bool用于选择中文表示的方式,当没有bool时采用默认方式显示。示例:NUMTO(2345,true)等于二三四五。示例:NUMTO(2345,false)等于二千三百四十五。示例:NUMTO(2345)等于二千三百四十五。',
name: 'NUMTO',
type: 'TEXT',
},
{
def: 'NVL(value1,value2,value3,...):在所有参数中返回第一个不是null的值value1:可以为任意数,也可以为null。value2:可以为任意数,也可以为null。当字符串长度为0时, 返回也为null示例:NVL(12,20)等于12。NVL(null,12)等于12。NVL(null,null)等于null。NVL(20,null)等于20。NVL(null,null,10)等于10。',
name: 'NVL',
type: 'OTHER',
},
{
def: 'OR(logical1,logical2,…): 当所有参数的值为假时,返回FALSE;当任意参数的值为真时,返回TRUE。Logical1,logical2,…:指1到30个需要检验TRUE或FALSE的条件值。备注: 参数必须是逻辑值,或是含有逻辑值的数组或引用。 如果数组或引用中含有文本或空的单元格,则忽略其值。 如果在指定的单元格区域中没有逻辑值,AND函数将返回错误信息*NAME?。示例:OR(1+7=9,5+7=11)等于FALSE。OR(1+7=8,5+7=11)等于TRUE。',
name: 'OR',
type: 'LOGIC',
},
{
def: 'period_anls(x_agg(array),datepart)根据横纵轴或行列维度添加的日期字段进行上期末的计算。第一个参数为用于计算的指标,该指标必须为聚合函数或聚合指标;第二个参数用于配置计算的上期末为上年期末或者上月期末。横纵轴拖拽的字段不满足函数的计算要求时,该指标会标红。示例:period_anls(sum_agg(amount),"Y") 用户横纵轴拖拽销售日期(年月日分组),则该指标计算结果为,根据年月日对销量进行分组汇总,然后计算出该日数据上年年末的销量;如果参数2为“M”,则计算结果为该日销量上月月末的销量。',
name: 'PERIOD_ANLS',
type: 'TABLE_CAL',
},
{
def: 'PI(number): 是一个数学常量函数,当number为空时,函数返回精确到15位的数值3.141592653589793;当参数不为空时,number表示PI的倍数。示例:SIN(PI()/2)等于1。计算圆的面积的公式: S=PI()*(r^2),其中S为圆的面积,R为圆的半径。PI(3)等于9.42477796076938。',
name: 'PI',
type: 'MATH',
},
{
def: 'POWER(number,power): 返回指定数字的乘幂。Number:底数,可以为任意实数。Power:指数。参数number按照该指数次幂乘方。备注: 可以使用符号“^”代替POWER,如: POWER(5,2)等于5^2。示例:POWER(6,2)等于36。POWER(14,5)等于537824。POWER(4,2/3)等于2.519842100。POWER(3,-2.3)等于0.079913677。',
name: 'POWER',
type: 'MATH',
},
{
def: 'previous_period(x_agg(array))根据横纵轴或行列维度添加的日期字段进行环期值的计算。参数为用于计算的指标,该指标必须为聚合函数或聚合指标。横纵轴拖拽的字段不满足函数的计算要求时,该指标会标红。示例:previous_period(sum_agg(amount)) 用户横纵轴拖拽销售日期(年月日分组),则该指标计算结果为,根据年月日对销量进行分组汇总,然后计算出该日数据上一日的销量。',
name: 'PREVIOUS_PERIOD',
type: 'TABLE_CAL',
},
{
def: 'PROMOTION(value1,value2):返回value2在value1上提升的比例。示例:PROMOTION(12, 14)等于0.166666666,即提升了16.6666666%.PROMOTION(-12, 14)等于2.166666666,即提升了216.6666666%.',
name: 'PROMOTION',
type: 'MATH',
},
{
def: 'PROPER(text): 将文本中的第一个字母和所有非字母字符后的第一个字母转化成大写,其他字母变为小写。Text:需要转化为文本的公式、由双引号引用的文本串或是单元格引用。示例:PROPER("Finemore Integrated Office")等于“Finemore Integrated Office”。PROPER("100 percent")等于“100 Percent”。PROPER("SpreaDSheEt")等于“Spreadsheet”。',
name: 'PROPER',
type: 'TEXT',
},
{
def: 'RADIANS(angle): 将角度转换成弧度。Angle:需要转换为弧度的角度。示例:RADIANS(90)等于1.570796327。',
name: 'RADIANS',
type: 'MATH',
},
{
def: 'RAND(): 返回均匀分布的随机数。每计算一次工作表,函数都会返回一个新的随机数值。备注: 要生成一个位于a和b之间的随机数,可以使用以下的公式: C=RAND()*(b-a)+a。 如果要使一个随机产生的数值不随单元格的重计算而改变,可以在编辑框中输入=RAND()并保持编辑状态,然后按F9,将公式永久性地改为随机数。示例:假如需要生成一个大于等于0,小于60的随机数,使用公式: =RAND()*60。假如需要生成一个大于等于0,小于19的随机数,使用公式: =RAND()*19。假如需要生成一个大于等于0,小于50的随机数,使用公式: =RAND()*50。',
name: 'RAND',
type: 'MATH',
},
{
def: 'RANDBETWEEN(value1,value2):返回value1和value2之间的一个随机整数。示例:RANDBETWEEN(12.333, 13.233)只会返回13。RANDBETWEEN(11.2, 13.3)有可能返回12或者13。',
name: 'RANDBETWEEN',
type: 'MATH',
},
{
def: 'rank_anls(x_agg(array),range,order)根据横纵轴或行列维度添加的字段对指标进行跨行排名的计算。第一个参数为用户计算的指标,该指标必须为聚合函数或聚合指标;第二个参数range为用户设置计算的范围,0为对所有行进行排名,1为对组内所有行进行排名;第三个参数order为排名的计算规则,"asc"为升序排名,"desc"为降序排名。示例:rank_anls(sum_agg(amount),0,"asc")用户横轴轴拖拽省份,则该指标计算结果为,根据省份对销量进行分组汇总,然后计算每个省份的销量在所有省份中的升序排名情况。',
name: 'RANK_ANLS',
type: 'TABLE_CAL',
},
{
def: 'REGEXP(str, pattern):字符串str是否与正则表达式pattern相匹配。示例:REGEXP("aaaaac","a*c")等于true。REGEXP("abc","a*c")等于false。REGEXP(str, pattern, intNumber):字符串str是否与具有给定模式 intNumber的正则表达式pattern相匹配。示例:CASE_INSENSITIVE = 0 启用不区分大小写的匹配。 默认情况下,不区分大小写的匹配假定仅匹配 US-ASCII 字符集中的字符。可以通过指 定 UNICODE_CASE 标志连同此标志来启用 Unicode 感知的、不区分大小写的匹配。 MULTILINE = 1 启用多行模式。DOTALL = 2 启用 dotall 模式。在 dotall 模式中,表达式 . 可以匹配任何字符,包括行结束符。默认情况下,此表达式不匹配行 结束符。UNICODE_CASE = 3 启用 Unicode 感知的大小写折叠。指定此标志后,由 CASE_INSENSITIVE 标志启用时,不区分大小写的匹配将以 符合 Unicode Standard 的方式完成。CANON_EQ = 4 启用规范等价。 指定此标志后,当且仅当其完整规范分解匹配时,两个字符才可视为匹配。UNIX_LINES = 5 启用 Unix 行模式。 在此模式中,.、^ 和 $ 的行为中仅识别 \'\n\' 行结束符。LITERAL = 6 启用模式的字面值解析。 指定此标志后,指定模式的输入字符串就会作为字面值字符序列来对待。输入序列中的 元字符或转义序列不具有任何特殊意义。 标志 CASE_INSENSITIVE 和 UNICODE_CASE 在与此标志一起使用时将 对匹配产生影响。其他标志都变得多余了。COMMENTS = 7 模式中允许空白和注释。 此模式将忽略空白和在结束行之前以 # 开头的嵌入式注释。 REGEXP("Aaaaabbbbc","a*b*c", 3)等于true。REGEXP("Aaaaabbbbc","a*b*c", 1)等于false。',
name: 'REGEXP',
type: 'TEXT',
},
{
def: 'REPEAT(text,number_times): 根据指定的次数重复显示文本。REPEAT函数可用来显示同一字符串,并对单元格进行填充。Text:需要重复显示的文本或包含文本的单元格引用。Number_times:指定文本重复的次数,且为正数。如果number_times为0,REPEAT函数将返回“”(空文本)。如果number_times不是整数,将被取整。REPEAT函数的最终结果通常不大于32767个字符。备注: 该函数可被用于在工作表中创建简单的直方图。示例:REPEAT("$",4)等于“$$$$”。如果单元格B10的内容为“你好”,REPEAT(B10,3)等于“你好你好你好”。',
name: 'REPEAT',
type: 'TEXT',
},
{
def: 'REPLACE(text, texttoreplace, replacetext):根据指定字符串,用其他文本来代替原始文本中的内容。text:需要被替换部分字符的文本或单元格引用。texttoreplace:指定的字符串。replacetext:需要替换部分旧文本的文本。示例:REPLACE("abcd", "a", "re")等于"rebcd"。REPLACE("a**d", "**d", "rose")等于"arose"。REPLACE(old_text,start_num,num_chars,new_text): 根据指定的字符数,用其他文本串来替换某个文本串中的部分内容。Old_text:需要被替换部分字符的文本或单元格引用。Start_num:需要用new_text来替换old_text中字符的起始位置。Num_chars:需要用new_text来替换old_text中字符的个数。New_text:需要替换部分旧文本的文本。示例:REPLACE("0123456789",5,4,"*")等于“0123*89”。REPLACE("1980",3,2,"99")等于“1999”。',
name: 'REPLACE',
type: 'TEXT',
},
{
def: 'RIGHT(text,num_chars): 根据指定的字符数从右开始返回文本串中的最后一个或几个字符。Text:包含需要提取字符的文本串或单元格引用。Num_chars:指定RIGHT函数从文本串中提取的字符数。Num_chars不能小于0。如果num_chars大于文本串长度,RIGHT函数将返回整个文本。如果不指定num_chars,则默认值为1。示例:RIGHT("It is interesting",6)等于“esting”。RIGHT("Share Holder")等于“r”。RIGHT("Huge sale",4)等于“sale”。',
name: 'RIGHT',
type: 'TEXT',
},
{
def: 'ROUND(number,num_digits):返回某个数字按指定位数舍入后的数字。number:需要进行舍入的数字。num_digits:指定的位数,按此位数进行舍入。如果 num_digits 大于 0,则舍入到指定的小数位。如果 num_digits 等于 0,则舍入到最接近的整数。如果 num_digits 小于 0,则在小数点左侧进行舍入。示例:ROUND(2.15, 1) 等于 2.2ROUND(2.149, 1) 等于 2.1ROUND(-1.475, 2) 等于 -1.48ROUND(21.5, -1) 等于 20因浮点数存在精度计算丢失问题, 导致计算结果里可能带上9999, 0000这些, 因此加入第三个参数来控制是否需要去除9999. true表示需要过滤9999, 0000这些数据.',
name: 'ROUND',
type: 'MATH',
},
{
def: 'ROUND(number,num_digits):返回某个数字按指定位数舍入后的数字。number:需要进行舍入的数字。num_digits:指定的位数,按此位数进行舍入。如果 num_digits 大于 0,则舍入到指定的小数位。如果 num_digits 等于 0,则舍入到最接近的整数。如果 num_digits 小于 0,则在小数点左侧进行舍入。示例:ROUND(2.15, 1) 等于 2.2ROUND(2.149, 1) 等于 2.1ROUND(-1.475, 2) 等于 -1.48ROUND(21.5, -1) 等于 20因浮点数存在精度计算丢失问题, 导致计算结果里可能带上9999, 0000这些, 因此加入第三个参数来控制是否需要去除9999. true表示需要过滤9999, 0000这些数据.',
name: 'ROUND',
type: 'COMMON',
},
{
def: 'same_period(x_agg(array),datepart)根据横纵轴或行列维度添加的日期字段进行同期值的计算。第一个参数为用于计算的指标,该指标必须为聚合函数或聚合指标;第二个参数用于配置计算同期时计算某日的年同期或者某日的月同期。横纵轴拖拽的字段不满足函数的计算要求时,该指标会标红。示例:same_period(sum_agg(amount),"Y") 用户横纵轴拖拽销售日期(年月日分组),则该指标计算结果为,根据年月日对销量进行分组汇总,然后计算出该日数据上年同日的销量;如果参数2为“M”,则计算结果为该日销量上月同日的销量。',
name: 'SAME_PERIOD',
type: 'TABLE_CAL',
},
{
def: 'SECOND(serial_number):返回某一指定时间的秒数,其值是介于0与59之间的一个整数。Serial_number:包含所求秒数的时间。示例:SECOND("15:36:25")等于25。SECOND("15:36:25", "HH:mm:ss")等于25。',
name: 'SECOND',
type: 'DATETIME',
},
{
def: 'SIGN(number):返回数字的符号。当数字为正数时返回 1,为零时返回 0,为负数时返回 -1。Number:为任意实数。示例:SIGN(10) 等于 1SIGN(4-4) 等于 0SIGN(-0.00001) 等于 -1',
name: 'SIGN',
type: 'MATH',
},
{
def: 'SIN(number): 计算给定角度的正弦值。Number:待求正弦值的以弧度表示的角度。备注: 如果参数的单位是度,将其乘以PI()/180即可转换成弧度。示例:SIN(10)等于-0.5440211108893698。SIN(45*PI()/180)等于0.707106781。',
name: 'SIN',
type: 'MATH',
},
{
def: 'SPLIT(String1,String2):返回由String2分割String1组成的字符串数组。String1:以双引号表示的字符串。String2:以双引号表示的分隔符。例如逗号","示例:SPLIT("hello,world,yes",",") = ["hello","world","yes"]。SPLIT("this is very good"," ") = ["this","is","very","good"]。备注:如果只有一个参数,则返回一个错误。如果有多个参数,则只有前两个起作用。',
name: 'SPLIT',
type: 'TEXT',
},
{
def: 'SQRT(number): 返回一个正数的平方根。Number:要求其平方根的任一正数。备注:Number必须是一个正数,否则函数返回错误信息*NUM!。示例:SQRT(64)等于8。SQRT(-64)返回*NUM!。',
name: 'SQRT',
type: 'MATH',
},
{
def: 'STARTWITH(str1,str2):判断字符串str1是否以str2开始。备注: str1和str2都是大小写敏感的。示例:STARTWITH("FineReport","Fine")等于true。STARTWITH("FineReport","Report")等于false。STARTWITH("FineReport","fine")等于false。',
name: 'STARTWITH',
type: 'TEXT',
},
{
def: 'STDEV_AGG(array): 根据当前分析维度,动态返回指标字段的标准差,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段STDEV_AGG(销量)返回的值为每日的销量标准差;当用户横轴为维度字段\'月\'时,STDEV_AGG(销量)返回的值为每月的销量标准差。',
name: 'STDEV_AGG',
type: 'AGG',
},
{
def: 'SUBSTITUTE(text,old_text,new_text,instance_num): 用new_text替换文本串中的old_text。Text:需要被替换字符的文本,或含有文本的单元格引用。Old_text:需要被替换的部分文本。New_text:用于替换old_text的文本。Instance_num:指定用new_text来替换第几次出现的old_text。如果指定了instance_num,则只有指定位置上的old_text被替换,否则文字串中出现的所有old_text都被new_text替换。备注: 如果需要替换文本串中的指定文本,则使用SUBSTITUTE函数;如果需要替换文本串中指定位置上的任意文本,则使用REPLACE函数。示例:SUBSTITUTE("data base","base","model")等于“data model”。SUBSTITUTE("July 28, 2000","2","1",1)等于“July 18, 2000”。SUBSTITUTE("July 28, 2000","2","1")等于“July 18, 1000”。SUBSTITUTE("July 28, 2000","2","1",2)等于“July 28, 1000”。 ',
name: 'SUBSTITUTE',
type: 'TEXT',
},
{
def: 'SUM_AGG(array):根据当前分析维度,动态返回指标字段的汇总求和值,生成结果为一动态数据列,行数与当前分析维度行数一致。\n array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n 示例:用户横轴为维度字段\'日\'时,纵轴的计算字段SUM_AGG(销量)返回的值为每日的汇总销量;当用户横轴为维度字段\'月\'时,SUM_AGG(销量)返回的值为每月的汇总销量。',
name: 'SUM_AGG',
type: 'AGG',
},
{
def: 'switch(表达式, 值1, 结果1, 值2, 结果2, ...)如果表达式的结果是值1,整个函数返回结果1如果表达式的结果是值2,整个函数返回结果2如果表达式的结果是值3,整个函数返回结果3等等',
name: 'SWITCH',
type: 'LOGIC',
},
{
def: 'TAN(number): 返回指定角度的正切值。Number:待求正切值的角度,以弧度表示。如果参数是以度为单位的,乘以Pi()/180后转换为弧度。示例:TAN(0.8)等于1.029638557。TAN(45*Pi()/180)等于1。',
name: 'TAN',
type: 'MATH',
},
{
def: 'TIME(hour,minute,second): 返回代表指定时间的小数。介于0:00:00(12:00:00 A.M.)与23:59:59(11:59:59 P.M.)之间的时间可返回0到0.99999999之间的对应数值。Hour:介于0到23之间的数。Minute:介于0到59之间的数。Second:介于0到59之间的数。示例:TIME(14,40,0)等于2:40 PM。TIME(19,43,24)等于7:43 PM。',
name: 'TIME',
type: 'DATETIME',
},
{
def: 'TODATE()函数可以将各种日期形式的参数转换为日期类型。它有三种参数的形式:1 参数是一个日期型的参数,那么直接将这个参数返回。示例:TODATE(DATE(2007,12,12))返回2007年12月12日组成的日期。2 参数是以从1970年1月1日0时0分0秒开始的毫秒数,返回对应的时间。示例:TODATE(1023542354746)返回2002年6月8日。3 参数是日期格式的文本,那么返回这个文本对应的日期。示例:TODATE("2007/10/15")返回2007年10月5日组成的日期。TODATE("2007-6-8")返回2007年6月8日组成的日期。4 有两个参数,第一个参数是一个日期格式的文本,第二个参数是用来解析日期的格式。示例:TODATE("1/15/07","mm/dd/yy")返回07年1月15日组成的日期。特别的,"yyyyMMdd"是用来解析形如“20081230”之类的日期格式的。比如TODATE("20110830","yyyyMMdd")返回11年08月30日组成的日期5 有三个参数,第一个参数是一个日期格式的文本,第二个参数是用来解析日期的格式,第三个参数为解析日期的语言,如:zh(中文),en(英文)。示例:TODATE("星期三 1/15/07","EEE mm/dd/yy", "zh")返回07年1月15日组成的日期,使用“zh(中文)”才能够正常解析“星期三”这个字符串。',
name: 'TODATE',
type: 'DATETIME',
},
{
def: 'TODAY():获取当前日期。示例:如果系统日期是2005年9月10日则TODAY()等于2005-9-10。',
name: 'TODAY',
type: 'DATETIME',
},
{
def: 'TODOUBLE(text): 将文本转换成Double对象。Text:需要转换的文本。示例:TODOUBLE("123.21")等于 new Double(123.21)。',
name: 'TODOUBLE',
type: 'TEXT',
},
{
def: 'TOINTEGER(text): 将文本转换成Integer对象。Text:需要转换的文本。示例:TOINTEGER("123")等于 new Integer(123)。',
name: 'TOINTEGER',
type: 'TEXT',
},
{
def: 'total(x_agg(array),range,agg)根据横纵轴或行列维度添加的字段对指标进行跨行汇总的计算。第一个参数为用户计算的指标,该指标必须为聚合函数或聚合指标;第二个参数range为用户设置计算的范围,0为对所有行进行汇总,1为对组内所有行进行汇总;第三个参数agg为汇总的计算规则,"sum"为求和;"avg"为求平均,"max"为求最大值,"min"为求最小值示例:total(sum_agg(array),0,"avg")用户横纵轴拖拽省份,则该指标计算结果为,根据省份对销量进行分组汇总,然后计算平均每个省份的销量',
name: 'TOTAL',
type: 'TABLE_CAL',
},
{
def: 'TRIM(text): 清除文本中所有空格,单词间的单个空格除外,也可用于带有不规则空格的文本。Text:需要清除空格的文本。示例:TRIM(" Monthly Report")等于Monthly Report。',
name: 'TRIM',
type: 'TEXT',
},
{
def: 'TRUNC(number,num_digits):将数字的小数部分截去,返回整数。number:需要截尾取整的数字。num_digits:用于指定取整精度的数字。示例:TRUNC(8.9) 等于 8TRUNC(-8.9) 等于 -8TRUNC(PI()) 等于 3',
name: 'TRUNC',
type: 'MATH',
},
{
def: 'UPPER(text): 将文本中所有的字符转化为大写。Text:需要转化为大写字符的文本,或是包含文本的单元格引用。示例:UPPER("notes")等于“NOTES”。如果单元格E5的值为“Examples”,则UPPER(E5)等于“EXAMPLES”。',
name: 'UPPER',
type: 'TEXT',
},
{
def: 'VAR_AGG(array): 根据当前分析维度,动态返回指标字段的方差,生成结果为一动态数据列,行数与当前分析维度行数一致。\n "array必须为非聚合函数公式返回的结果,可以是某指标字段、维度或指标字段与普通公式的计算结果。\n "示例:用户横轴为维度字段\'日\'时,纵轴的计算字段VAR_AGG(销量)返回的值为每日的销量方差;当用户横轴为维度字段\'月\'时,VAR_AGG(销量)返回的值为每月的销量方差。',
name: 'VAR_AGG',
type: 'AGG',
},
{
def: 'WEEK(serial_num):返回一个代表一年中的第几周的数字。Serial_num:表示输入的日期。备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。示例:WEEK("2010/1/1")等于52。WEEK("2010/1/6")等于1。WEEK(35796)等于1。',
name: 'WEEK',
type: 'DATETIME',
},
{
def: 'weekdate(year,month,weekOfMonth,dayOfWeek): 返回指定年月的指定周的周几的具体日期。示例:weekdate(2009,10,2,1)返回的是2009年的10月的第二个周的第一天即星期天的日期,返回的是2009-10-04最后一个参数dayOfWeek为-1时,表示这个周的最后一天示例:weekdate(2009,12,1,-1)返回的是2009年的12月的第一个周的最后一天即星期六的日期,返回的是2009-12-05',
name: 'WEEKDATE',
type: 'DATETIME',
},
{
def: 'WEEKDAY(Serial_number):获取日期并返回星期数。返回值为介于0到6之间的某一整数,分别代表星期中的某一天(从星期日到星期六)。Serial_number:输入的日期备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。举例:WEEKDAY("2005/9/10")等于6(星期六)。WEEKDAY("2005/9/11")等于0(星期日)。WEEKDAY(35796)等于4(星期四)。',
name: 'WEEKDAY',
type: 'DATETIME',
},
{
def: 'YEAR:(serial_number)返回日期中的年。Year是介于1900和9999之间的一个数。Serial_number:含有所求的年的日期.备注:FineReport将日期保存为系列数,一个系列数代表一个与之匹配的日期,以方便用户对日期进行数值式计算。在1900年日期系统中,FineReport电子表格将1900年1月1日保存为系列数2,将1900年1月2日保存为系列数3,将1900年1月3日保存为系列数4……依此类推。如在1900年日期系统,1998年1月1日存为系列数35796。示例:YEAR("2000/1/1")等于2000。YEAR("2006/05/05")等于2006。YEAR("1997/04/20")等于1997。YEAR("2000-1-1", "yyyy-MM-dd")等于2000。YEAR("2006-05-05", "yyyy-MM-dd")等于2006。YEAR("1997-04-20", "yyyy-MM-dd")等于1997。YEAR(35796)等于1998。',
name: 'YEAR',
type: 'DATETIME',
},
{
def: 'YEARDELTA(date, delta):返回指定日期后delta年的日期。示例:YEARDELTA("2008-10-10",10)等于2018-10-10。',
name: 'YEARDELTA',
type: 'DATETIME',
},
],
};

39
src/web/src/modules/table_list/list_item.ts

@ -1,29 +1,38 @@
import { shortcut } from '@core/core';
import { HtapeXtype, IconLabelXtype, LabelXtype } from 'ui';
@shortcut()
export class ListItem extends BI.BasicButton {
static xtype = 'dec.dcm.connection.plugin.redis.table_list.list_item'
props = {
text: '',
height: 20,
showIcon: false,
baseCls: 'bi-list-item-active',
}
render() {
const { text } = this.options;
return {
type: HtapeXtype,
items: [{
el: {
type: IconLabelXtype,
cls: 'column-font',
},
width: 25,
}, {
type: LabelXtype,
const { text, showIcon } = this.options;
if(showIcon){
return {
type: BI.HTapeLayout.xtype,
items: [{
el: {
type: BI.IconLabel.xtype,
cls: 'redis-column-font',
},
width: 25,
}, {
type: BI.Label.xtype,
textAlign: 'left',
text,
}],
};
}else{
return {
type: BI.Label.xtype,
textAlign: 'left',
lgap: 5,
text,
}],
};
}
}
}
}

40
src/web/src/modules/table_list/table_list.model.ts

@ -0,0 +1,40 @@
import { model, Model } from '@core/core';
import { getConnectionlist, getTableList } from '../crud/crud.request';
@model()
export class TableModelModel extends Model {
static xtype = 'dec.model.dcm.connection.plugin.redis.table_list';
state() {
return {
connections: [] as string[],
tables: [] as string[],
search: '',
orderValue: '',
selectedConnection: '',
};
}
actions = {
initData: () => {
getConnectionlist().then(re => {
this.model.connections = re.data.filter(item => item.connectionType === 'Redis').map(item => item.connectionName);
});
},
initTableList: () => {
if (this.model.selectedConnection) {
getTableList(this.model.selectedConnection, this.model.search, this.model.orderValue).then(re => {
this.model.tables = re ? re : [];
});
} else {
this.model.tables = [];
}
},
setSearch(value: string, orderValue: string | number) {
this.model.search = value;
this.model.orderValue = orderValue;
},
setSelectedConnection(name: string) {
this.model.selectedConnection = name;
},
}
}

154
src/web/src/modules/table_list/table_list.ts

@ -1,29 +1,88 @@
import { shortcut } from '@core/core';
import { VtapeXtype, HtapeXtype, IconButtonXtype, TextValueComboXtype, ButtonXtype, TextEditorXtype, ButtonGroupXtype, VerticalXtype, MultiSelectItemXtype, LeftXtype } from 'ui';
import { shortcut, store } from '@core/core';
import { ListItem } from './list_item';
import { TableModelModel } from './table_list.model';
import { fineServletURL } from '@constants/env';
import { DatabaseIndex } from '../components/database_index/database_index';
@shortcut()
@store(TableModelModel)
export class TableList extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.table_list'
store: TableModelModel['store']
model: TableModelModel['model']
databaseIndex: DatabaseIndex;
buttonGroup: any;
connectionTextValue: any;
searchText: any;
props = {
database: '',
value: {
datasetData: {
orderValue: 0,
},
},
}
watch = {
connections: () => {
this.connectionTextValue.populate(this.renderConnectionList());
const name = this.model.connections.length > 0 ? this.model.connections[0] : '';
this.connectionTextValue.setValue(name);
this.store.setSelectedConnection(name);
},
'selectedConnection || search || orderValue': () => {
this.store.initTableList();
},
tables: (tables: string[]) => {
this.buttonGroup.populate(this.renderTableList());
},
}
render() {
const { orderValue = 0 } = this.options.value.datasetData || {};
const inputType = typeof orderValue === 'string' ? 'formula' : 'int';
return {
type: VtapeXtype,
type: BI.VTapeLayout.xtype,
hgap: 10,
bgap: 5,
items: [{
el: {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
items: [{
type: TextValueComboXtype,
type: BI.TextValueCombo.xtype,
ref: (_ref: any) => {
this.connectionTextValue = _ref;
},
items: [],
listeners: [{
eventName: BI.TextValueCombo.EVENT_CHANGE,
action: () => {
const name = this.connectionTextValue.getValue()[0];
this.store.setSelectedConnection(name);
},
}],
}, {
el: {
type: IconButtonXtype,
cls: 'site-font',
type: BI.IconButton.xtype,
cls: 'redis-site-font',
title: BI.i18nText('Plugin-Redis_Data_Connection'),
handler: () => {
window.location.href = `${fineServletURL}#management/connection`;
},
},
width: 25,
}, {
el: {
type: IconButtonXtype,
cls: 'refresh-font',
type: BI.IconButton.xtype,
cls: 'redis-refresh-font',
title: BI.i18nText('Plugin-Redis_Refresh'),
handler: () => {
this.store.initData();
},
},
width: 25,
}],
@ -31,54 +90,71 @@ export class TableList extends BI.Widget {
height: 25,
}, {
el: {
type: HtapeXtype,
type: BI.HTapeLayout.xtype,
items: [{
type: TextEditorXtype,
el: {
type: BI.Label.xtype,
text: BI.i18nText('Plugin-Redis_Index'),
textAlign: 'left',
},
width: 24,
}, {
type: DatabaseIndex.xtype,
value: orderValue,
inputType,
ref: (_ref: any) => {
this.databaseIndex = _ref;
},
width: 24,
height: 22,
}, {
type: BI.TextEditor.xtype,
height: 24,
watermark: BI.i18nText('Plugin-Redis_Keys_Pattern'),
ref: (_ref: any) => {
this.searchText = _ref;
},
}, {
el: {
type: ButtonXtype,
type: BI.Button.xtype,
minWidth: 50,
text: BI.i18nText('Plugin-Redis_Keys_Pattern_Search'),
handler: () => {
this.store.setSearch(this.searchText.getValue(), this.databaseIndex.getValue());
},
},
width: 50,
}],
},
height: 25,
}, {
type: VtapeXtype,
type: BI.VTapeLayout.xtype,
items: [{
type: ButtonGroupXtype,
type: BI.ButtonGroup.xtype,
chooseType: BI.Selection.None,
layouts: [{
type: VerticalXtype,
type: BI.VerticalLayout.xtype,
}],
items: this.renderList(),
}, {
el: {
type: LeftXtype,
height: 25,
hgap: 40,
items: [{
type: MultiSelectItemXtype,
width: 80,
selected: true,
text: BI.i18nText('Plugin-Redis_Table'),
}, {
type: MultiSelectItemXtype,
width: 80,
selected: true,
text: BI.i18nText('Plugin-Redis_View'),
}],
items: [],
ref: (_ref: any) => {
this.buttonGroup = _ref;
},
height: 25,
}],
}],
};
}
private renderList() {
return ['demo1', 'demo2'].map(item => {
private renderConnectionList() {
return this.model.connections.map(item => {
return {
text: item,
value: item,
};
});
}
private renderTableList() {
return this.model.tables.map(item => {
return {
type: ListItem.xtype,
text: item,
@ -86,4 +162,12 @@ export class TableList extends BI.Widget {
};
});
}
mounted() {
this.store.initData();
}
public getSelectedDatabase() {
return this.model.selectedConnection;
}
}

77
src/web/src/ui/fineui.ts

@ -1,77 +0,0 @@
export const IconXtype = 'bi.icon';
export const IconTextItemXtype = 'bi.icon_text_item';
export const IconTextIconItemXtype = 'bi.icon_text_icon_item';
export const IconButtonXtype = 'bi.icon_button';
export const IconChangeButtonXtype = 'bi.icon_change_button';
export const TextButtonXtype = 'bi.text_button';
export const DownListComboXtype = 'bi.down_list_combo';
export const LabelXtype = 'bi.label';
export const SmallTextEditorXtype = 'bi.small_text_editor';
export const MultiFileEditorXtype = 'bi.multifile_editor';
export const SignEditorXtype = 'bi.sign_editor';
export const ButtonXtype = 'bi.button';
export const TextEditorXtype = 'bi.text_editor';
export const MultiSelectInsertComboXtype = 'bi.multi_select_insert_combo';
export const MultiSelectComboXtype = 'bi.multi_select_combo';
export const ButtonGroupXtype = 'bi.button_group';
export const AllValueChooserComboXtype = 'bi.all_value_chooser_combo';
export const TextAreaEditorXtype = 'bi.textarea_editor';
export const MultiSelectItemXtype = 'bi.multi_select_item';
export const BarPopOverXtype = 'bi.bar_popover';
export const DynamicDateComboXtype = 'bi.dynamic_date_combo';
export const DynamicDateTimeComboXtype = 'bi.dynamic_date_time_combo';
export const MultiTreeComboXtype = 'bi.multi_tree_combo';
export const RichEditorXtype = 'bi.rich_editor';
export const NicEditorXtype = 'bi.nic_editor';
export const EditorXtype = 'bi.editor';
export const MultiTreePopupViewXtype = 'bi.multi_tree_popup_view';
export const SingleSelectRadioItemXtype = 'bi.single_select_radio_item';
export const SingleSelectInsertComboXtype = 'bi.single_select_insert_combo';
export const SingleSelectComboXtype = 'bi.single_select_combo';
export const TabXtype = 'bi.tab';
export const DynamicYearMonthComboXtype = 'bi.dynamic_year_month_combo';
export const TextXtype = 'bi.text';
export const ComboXtype = 'bi.combo';
export const TimeComboXtype = 'bi.time_combo';
export const IFrameXtype = 'bi.iframe';
export const MultiTreeInsertComboXtype = 'bi.multi_tree_insert_combo';
export const MultiTreeListComboXtype = 'bi.multi_tree_list_combo';
export const MultilayerSingleTreeComboXtype = 'bi.multilayer_single_tree_combo';
export const MultilayerSelectTreeComboXtype = 'bi.multilayer_select_tree_combo';
export const AsyncTreeXtype = 'bi.async_tree';
export const ListAsyncTreeXtype = 'bi.list_async_tree';
export const MultilayerSingleTreePopupXtype = 'bi.multilayer_single_tree_popup';
export const MultilayerSelectTreePopupXtype = 'bi.multilayer_select_tree_popup';
export const IconLabelXtype = 'bi.icon_label';
export const RadioXtype = 'bi.radio';
export const LinearSegmentXtype = 'bi.linear_segment';
export const SearchEditorXtype = 'bi.search_editor';
export const ImgXtype = 'bi.img';
export const BubbleComboXtype = 'bi.bubble_combo';
export const TextBubblePopupBarViewXtype = 'bi.text_bubble_bar_popup_view';
export const TextValueComboXtype = 'bi.text_value_combo';
export const FileXtype = 'bi.file';
export const IconComboXtype = 'bi.icon_combo';
export const NumberEditorXtype = 'bi.number_editor';
export const CodeEditorXtype = 'bi.code_editor';
// 布局
export const VerticalAdaptXtype = 'bi.vertical_adapt';
export const VtapeXtype = 'bi.vtape';
export const CenterAdaptXtype = 'bi.center_adapt';
export const HtapeXtype = 'bi.htape';
export const LayoutXtype = 'bi.layout';
export const AbsoluteXtype = 'bi.absolute';
export const VerticalXtype = 'bi.vertical';
export const LeftXtype = 'bi.left';
export const RightXtype = 'bi.right';
export const HorizontalAdaptXtype = 'bi.horizontal_adapt';
export const AbsoluteCenterAdaptXtype = 'bi.absolute_center_adapt';
export const TableAdaptXtype = 'bi.table_adapt';
export const RightVerticalAdaptXtype = 'bi.right_vertical_adapt';
export const LeftRightVerticalAdaptXtype = 'bi.left_right_vertical_adapt';
export const ListViewXtype = 'bi.list_view';
export const VirtualGroupXtype = 'bi.virtual_group';
export const HorizotalAutoXtype = 'bi.horizontal_auto';
export const HorizotalXtype = 'bi.horizontal';
export const FloatCenterXtype = 'bi.float_center';
export const LeftRightVerticalAdaptLayoutXtype = 'bi.left_right_vertical_adapt';

1
src/web/src/ui/index.ts

@ -1 +0,0 @@
export * from './fineui';

1
src/web/tsconfig.json

@ -18,6 +18,7 @@
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noImplicitReturns": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"paths": {
"ui": ["./src/ui"],

2
src/web/types/globals.d.ts vendored

@ -2,7 +2,7 @@ interface Obj {
[key: string]: any;
}
declare let BI: Obj & import('fineui')._BI;
declare let BI: Obj & import('@fui/core').BI & import('@fui/materials').BI;
declare const Fix: Obj;
declare const DecCst: Obj;
declare const Dec: Obj;

2
src/web/webpack/webpack.common.js

@ -49,7 +49,7 @@ module.exports = {
options: {
plugins: [vars({
variables: {
fontUrl: '../node_modules/fineui/dist/font/',
fontUrl: '../node_modules/@fui/core/dist/font/',
imageUrl: '/webroot/decision/resources?path=/com/fr/web/resources/dist/images/1x',
image2xUrl: '/webroot/decision/resources?path=/com/fr/web/resources/dist/images/2x',
}

6
src/web/webpack/webpack.dev.js

@ -54,6 +54,12 @@ module.exports = merge(common, {
contentBase: path.join(__dirname, '..'),
port: 10004,
liveReload: true,
proxy: {
'/webroot/decision': {
target: 'http://localhost:8075',
secure: false,
},
},
},
plugins: [
new MiniCssExtractPlugin({

6
src/web/webpack/webpack.prod.js

@ -38,9 +38,9 @@ module.exports = merge.smart(common, {
options: {
plugins: [vars({
variables: {
fontUrl: '/webroot/decision/resources?path=/com/fr/web/ui/font',
imageUrl: '/webroot/decision/resources?path=/com/fr/web/resources/dist/images/1x',
image2xUrl: '/webroot/decision/resources?path=/com/fr/web/resources/dist/images/2x',
fontUrl: '${fineServletURL}/resources?path=/com/fr/web/ui/font',
imageUrl: '${fineServletURL}/resources?path=/com/fr/web/resources/dist/images/1x',
image2xUrl: '${fineServletURL}/resources?path=/com/fr/web/resources/dist/images/2x',
}
})]
},

1687
src/web/yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save