rsbi 4 роки тому
батько
коміт
b189684a28
100 змінених файлів з 12570 додано та 0 видалено
  1. 34 0
      .gitignore
  2. BIN
      libs/ext3-1.4.jar
  3. BIN
      libs/ojdbc6-12.1.0.2.jar
  4. 310 0
      mvnw
  5. 182 0
      mvnw.cmd
  6. 176 0
      pom.xml
  7. BIN
      src/main/.DS_Store
  8. BIN
      src/main/java/com/.DS_Store
  9. 28 0
      src/main/java/com/ruisitech/bi/RsbiOsApplication.java
  10. 13 0
      src/main/java/com/ruisitech/bi/ServletInitializer.java
  11. 52 0
      src/main/java/com/ruisitech/bi/entity/app/Collect.java
  12. 40 0
      src/main/java/com/ruisitech/bi/entity/bireport/Area.java
  13. 198 0
      src/main/java/com/ruisitech/bi/entity/bireport/ChartJSONDto.java
  14. 60 0
      src/main/java/com/ruisitech/bi/entity/bireport/ChartQueryDto.java
  15. 274 0
      src/main/java/com/ruisitech/bi/entity/bireport/DimDto.java
  16. 195 0
      src/main/java/com/ruisitech/bi/entity/bireport/KpiDto.java
  17. 44 0
      src/main/java/com/ruisitech/bi/entity/bireport/KpiFilterDto.java
  18. 64 0
      src/main/java/com/ruisitech/bi/entity/bireport/OlapInfo.java
  19. 173 0
      src/main/java/com/ruisitech/bi/entity/bireport/ParamDto.java
  20. 37 0
      src/main/java/com/ruisitech/bi/entity/bireport/QueryDayDto.java
  21. 42 0
      src/main/java/com/ruisitech/bi/entity/bireport/QueryMonthDto.java
  22. 44 0
      src/main/java/com/ruisitech/bi/entity/bireport/TableDetailDto.java
  23. 129 0
      src/main/java/com/ruisitech/bi/entity/bireport/TableQueryDto.java
  24. 20 0
      src/main/java/com/ruisitech/bi/entity/common/BaseEntity.java
  25. 62 0
      src/main/java/com/ruisitech/bi/entity/common/DSColumn.java
  26. 46 0
      src/main/java/com/ruisitech/bi/entity/common/PageParam.java
  27. 18 0
      src/main/java/com/ruisitech/bi/entity/common/RequestStatus.java
  28. 65 0
      src/main/java/com/ruisitech/bi/entity/common/Result.java
  29. 96 0
      src/main/java/com/ruisitech/bi/entity/frame/Menu.java
  30. 71 0
      src/main/java/com/ruisitech/bi/entity/frame/Role.java
  31. 35 0
      src/main/java/com/ruisitech/bi/entity/frame/TreeNode.java
  32. 159 0
      src/main/java/com/ruisitech/bi/entity/frame/User.java
  33. 103 0
      src/main/java/com/ruisitech/bi/entity/model/Cube.java
  34. 99 0
      src/main/java/com/ruisitech/bi/entity/model/CubeColMeta.java
  35. 86 0
      src/main/java/com/ruisitech/bi/entity/model/DataSource.java
  36. 77 0
      src/main/java/com/ruisitech/bi/entity/model/Dataset.java
  37. 99 0
      src/main/java/com/ruisitech/bi/entity/model/Dimension.java
  38. 74 0
      src/main/java/com/ruisitech/bi/entity/model/Measure.java
  39. 78 0
      src/main/java/com/ruisitech/bi/entity/portal/BoxQuery.java
  40. 95 0
      src/main/java/com/ruisitech/bi/entity/portal/CompParamDto.java
  41. 76 0
      src/main/java/com/ruisitech/bi/entity/portal/GridColDto.java
  42. 100 0
      src/main/java/com/ruisitech/bi/entity/portal/GridQuery.java
  43. 88 0
      src/main/java/com/ruisitech/bi/entity/portal/LinkAcceptDto.java
  44. 73 0
      src/main/java/com/ruisitech/bi/entity/portal/MobReportType.java
  45. 86 0
      src/main/java/com/ruisitech/bi/entity/portal/Portal.java
  46. 119 0
      src/main/java/com/ruisitech/bi/entity/portal/PortalChartQuery.java
  47. 107 0
      src/main/java/com/ruisitech/bi/entity/portal/PortalParamDto.java
  48. 156 0
      src/main/java/com/ruisitech/bi/entity/portal/PortalTableQuery.java
  49. 19 0
      src/main/java/com/ruisitech/bi/mapper/app/CollectMapper.java
  50. 14 0
      src/main/java/com/ruisitech/bi/mapper/bireport/AreaMapper.java
  51. 32 0
      src/main/java/com/ruisitech/bi/mapper/bireport/OlapMapper.java
  52. 37 0
      src/main/java/com/ruisitech/bi/mapper/frame/MenuMapper.java
  53. 27 0
      src/main/java/com/ruisitech/bi/mapper/frame/RoleMapper.java
  54. 36 0
      src/main/java/com/ruisitech/bi/mapper/frame/UserMapper.java
  55. 19 0
      src/main/java/com/ruisitech/bi/mapper/model/CubeColMetaMapper.java
  56. 32 0
      src/main/java/com/ruisitech/bi/mapper/model/CubeMapper.java
  57. 21 0
      src/main/java/com/ruisitech/bi/mapper/model/DataSourceMapper.java
  58. 23 0
      src/main/java/com/ruisitech/bi/mapper/model/DatasetMapper.java
  59. 32 0
      src/main/java/com/ruisitech/bi/mapper/model/DimensionMapper.java
  60. 16 0
      src/main/java/com/ruisitech/bi/mapper/model/MeasureMapper.java
  61. 25 0
      src/main/java/com/ruisitech/bi/mapper/portal/MobReportTypeMapper.java
  62. 30 0
      src/main/java/com/ruisitech/bi/mapper/portal/PortalMapper.java
  63. 38 0
      src/main/java/com/ruisitech/bi/service/app/CollectService.java
  64. 371 0
      src/main/java/com/ruisitech/bi/service/bireport/BaseCompService.java
  65. 579 0
      src/main/java/com/ruisitech/bi/service/bireport/ChartService.java
  66. 73 0
      src/main/java/com/ruisitech/bi/service/bireport/ModelCacheService.java
  67. 142 0
      src/main/java/com/ruisitech/bi/service/bireport/OlapService.java
  68. 296 0
      src/main/java/com/ruisitech/bi/service/bireport/ReportService.java
  69. 223 0
      src/main/java/com/ruisitech/bi/service/bireport/TableDetailService.java
  70. 1247 0
      src/main/java/com/ruisitech/bi/service/bireport/TableService.java
  71. 32 0
      src/main/java/com/ruisitech/bi/service/frame/DaoHelperConfig.java
  72. 157 0
      src/main/java/com/ruisitech/bi/service/frame/MenuService.java
  73. 215 0
      src/main/java/com/ruisitech/bi/service/frame/RoleService.java
  74. 58 0
      src/main/java/com/ruisitech/bi/service/frame/SessionAuthcFilter.java
  75. 74 0
      src/main/java/com/ruisitech/bi/service/frame/ShiroConfig.java
  76. 73 0
      src/main/java/com/ruisitech/bi/service/frame/ShiroDbRealm.java
  77. 209 0
      src/main/java/com/ruisitech/bi/service/frame/UserService.java
  78. 418 0
      src/main/java/com/ruisitech/bi/service/model/CubeService.java
  79. 255 0
      src/main/java/com/ruisitech/bi/service/model/DataSourceService.java
  80. 309 0
      src/main/java/com/ruisitech/bi/service/model/DatasetService.java
  81. 17 0
      src/main/java/com/ruisitech/bi/service/model/DimensionService.java
  82. 191 0
      src/main/java/com/ruisitech/bi/service/portal/BoxService.java
  83. 293 0
      src/main/java/com/ruisitech/bi/service/portal/GridService.java
  84. 43 0
      src/main/java/com/ruisitech/bi/service/portal/MobReportTypeService.java
  85. 563 0
      src/main/java/com/ruisitech/bi/service/portal/PortalChartService.java
  86. 759 0
      src/main/java/com/ruisitech/bi/service/portal/PortalPageService.java
  87. 52 0
      src/main/java/com/ruisitech/bi/service/portal/PortalService.java
  88. 459 0
      src/main/java/com/ruisitech/bi/service/portal/PortalTableService.java
  89. 27 0
      src/main/java/com/ruisitech/bi/util/BaseController.java
  90. 167 0
      src/main/java/com/ruisitech/bi/util/CompPreviewService.java
  91. 48 0
      src/main/java/com/ruisitech/bi/util/HeadFilter.java
  92. 63 0
      src/main/java/com/ruisitech/bi/util/MVCleanListener.java
  93. 260 0
      src/main/java/com/ruisitech/bi/util/RSBIUtils.java
  94. 34 0
      src/main/java/com/ruisitech/bi/util/SqliteHelperImpl.java
  95. 10 0
      src/main/java/com/ruisitech/bi/util/TreeInterface.java
  96. 150 0
      src/main/java/com/ruisitech/bi/util/TreeService.java
  97. 33 0
      src/main/java/com/ruisitech/bi/web/LoginController.java
  98. 26 0
      src/main/java/com/ruisitech/bi/web/LogoutController.java
  99. 60 0
      src/main/java/com/ruisitech/bi/web/app/AppLoginController.java
  100. 0 0
      src/main/java/com/ruisitech/bi/web/app/AppMenuController.java

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+.mvn

BIN
libs/ext3-1.4.jar


BIN
libs/ojdbc6-12.1.0.2.jar


+ 310 - 0
mvnw

@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  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
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  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
+  else
+    JAVACMD="`which java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 182 - 0
mvnw.cmd

@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  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,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%

+ 176 - 0
pom.xml

@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.3.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.ruisitch</groupId>
+    <artifactId>rsbi-os</artifactId>
+    <version>4.7</version>
+    <packaging>war</packaging>
+    <name>rsbi-os</name>
+    <description>rsbi开源版</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <mysql.version>8.0.11</mysql.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.3</version>
+        </dependency>
+        <!-- jdbcTemplate 依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>${mysql.version}</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-core</artifactId>
+            <version>1.5.3</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+            <version>1.5.3</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.5.3</version>
+        </dependency>
+        <!-- 本地jar -->
+        <dependency>
+            <groupId>com.ruisi.ext</groupId>
+            <artifactId>ext3</artifactId>
+            <version>1.4</version>
+            <type>jar</type>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/libs/ext3-1.4.jar</systemPath>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.25</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper</artifactId>
+            <version>5.0.1</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl -->
+        <dependency>
+            <groupId>net.sourceforge.jexcelapi</groupId>
+            <artifactId>jxl</artifactId>
+            <version>2.6.12</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.3.3</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/commons-digester/commons-digester -->
+        <dependency>
+            <groupId>commons-digester</groupId>
+            <artifactId>commons-digester</artifactId>
+            <version>2.1</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+            <version>1.6.4</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.2.5</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet.jsp</groupId>
+            <artifactId>jsp-api</artifactId>
+            <version>2.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.yml</include>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.yml</include>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

BIN
src/main/.DS_Store


BIN
src/main/java/com/.DS_Store


+ 28 - 0
src/main/java/com/ruisitech/bi/RsbiOsApplication.java

@@ -0,0 +1,28 @@
+package com.ruisitech.bi;
+
+import com.ruisi.ext.engine.control.ExtContextLoaderListener;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
+import org.springframework.context.annotation.Bean;
+
+@ServletComponentScan
+@SpringBootApplication
+@MapperScan("com.ruisitech.bi.mapper")//使用MapperScan批量扫描所有的Mapper接口;
+public class RsbiOsApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(RsbiOsApplication.class, args);
+    }
+
+
+    @Bean
+    public ServletListenerRegistrationBean servletListenerRegistrationBean() {
+        ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
+        servletListenerRegistrationBean.setListener(new ExtContextLoaderListener());
+        return servletListenerRegistrationBean;
+    }
+}
+

+ 13 - 0
src/main/java/com/ruisitech/bi/ServletInitializer.java

@@ -0,0 +1,13 @@
+package com.ruisitech.bi;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+public class ServletInitializer extends SpringBootServletInitializer {
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(RsbiOsApplication.class);
+    }
+
+}

+ 52 - 0
src/main/java/com/ruisitech/bi/entity/app/Collect.java

@@ -0,0 +1,52 @@
+package com.ruisitech.bi.entity.app;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+
+public class Collect extends BaseEntity {
+	
+	private String rid;
+	private Integer userId;
+	private Date crtdate;
+	private String title;
+	private String url;
+	public String getRid() {
+		return rid;
+	}
+	public void setRid(String rid) {
+		this.rid = rid;
+	}
+	public Integer getUserId() {
+		return userId;
+	}
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+	public Date getCrtdate() {
+		return crtdate;
+	}
+	public void setCrtdate(Date crtdate) {
+		this.crtdate = crtdate;
+	}
+	public String getTitle() {
+		return title;
+	}
+	public void setTitle(String title) {
+		this.title = title;
+	}
+	public String getUrl() {
+		return url;
+	}
+	public void setUrl(String url) {
+		this.url = url;
+	}
+	
+	@Override
+	public void validate() {
+		this.title = RSBIUtils.htmlEscape(this.title);
+		this.rid = RSBIUtils.htmlEscape(this.rid);
+		this.url = RSBIUtils.htmlEscape(this.url);
+	}
+}

+ 40 - 0
src/main/java/com/ruisitech/bi/entity/bireport/Area.java

@@ -0,0 +1,40 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+public class Area extends BaseEntity {
+	
+	private Integer id;
+	private String code;
+	private String provName;
+	private String cityName;
+	public Integer getId() {
+		return id;
+	}
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	public String getCode() {
+		return code;
+	}
+	public void setCode(String code) {
+		this.code = code;
+	}
+	public String getProvName() {
+		return provName;
+	}
+	public void setProvName(String provName) {
+		this.provName = provName;
+	}
+	public String getCityName() {
+		return cityName;
+	}
+	public void setCityName(String cityName) {
+		this.cityName = cityName;
+	}
+	
+	@Override
+	public void validate() {
+		
+	}
+}

+ 198 - 0
src/main/java/com/ruisitech/bi/entity/bireport/ChartJSONDto.java

@@ -0,0 +1,198 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.portal.LinkAcceptDto;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class ChartJSONDto {
+	
+	private String type;
+	private Integer typeIndex;
+	private List<DimDto> params;
+	private String label;
+	private DimDto xcol;
+	private DimDto scol;
+	private DimDto ycol; //"ycol":{"type":"kpi"}
+	private Map<String, Object> link;
+	private LinkAcceptDto linkAccept;
+	
+	private String maparea;
+	private String mapAreaName;
+	private String height;
+	private String width;
+	private String showLegend;
+	private String legendLayout;
+	private String legendpos;
+	private String legendPosition;
+	private String dataLabel;
+	private String marginLeft;
+	private String marginRight;
+	private String markerEnabled;
+	
+	public List<DimDto> getDims(){
+		List<DimDto> ret = new ArrayList<DimDto>();
+		if(this.getXcol() != null && this.getXcol().getId() != null){
+			ret.add(this.getXcol());
+		}
+		if(this.getScol() != null && this.getScol().getId() != null){
+			ret.add(this.getScol());
+		}
+		if(this.getParams() != null && this.getParams().size() > 0){
+			ret.addAll(this.getParams());
+		}
+		return ret;
+	}
+	
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	
+	public List<DimDto> getParams() {
+		return params;
+	}
+	public void setParams(List<DimDto> params) {
+		this.params = params;
+	}
+	public String getLabel() {
+		return label;
+	}
+	public void setLabel(String label) {
+		this.label = label;
+	}
+	public DimDto getXcol() {
+		return xcol;
+	}
+	public void setXcol(DimDto xcol) {
+		this.xcol = xcol;
+	}
+	public DimDto getScol() {
+		return scol;
+	}
+	public void setScol(DimDto scol) {
+		this.scol = scol;
+	}
+	public DimDto getYcol() {
+		return ycol;
+	}
+	public void setYcol(DimDto ycol) {
+		this.ycol = ycol;
+	}
+	public Map<String, Object> getLink() {
+		return link;
+	}
+	public void setLink(Map<String, Object> link) {
+		this.link = link;
+	}
+	
+	public LinkAcceptDto getLinkAccept() {
+		return linkAccept;
+	}
+
+	public void setLinkAccept(LinkAcceptDto linkAccept) {
+		this.linkAccept = linkAccept;
+	}
+
+	public String getMaparea() {
+		return maparea;
+	}
+	public void setMaparea(String maparea) {
+		this.maparea = maparea;
+	}
+	public String getMapAreaName() {
+		return mapAreaName;
+	}
+	public void setMapAreaName(String mapAreaName) {
+		this.mapAreaName = mapAreaName;
+	}
+	public Integer getTypeIndex() {
+		return typeIndex;
+	}
+	public void setTypeIndex(Integer typeIndex) {
+		this.typeIndex = typeIndex;
+	}
+	public String getHeight() {
+		return height;
+	}
+
+	public void setHeight(String height) {
+		this.height = height;
+	}
+
+	public String getWidth() {
+		return width;
+	}
+
+	public void setWidth(String width) {
+		this.width = width;
+	}
+
+	public String getShowLegend() {
+		return showLegend;
+	}
+
+	public void setShowLegend(String showLegend) {
+		this.showLegend = showLegend;
+	}
+
+	public String getLegendLayout() {
+		return legendLayout;
+	}
+
+	public void setLegendLayout(String legendLayout) {
+		this.legendLayout = legendLayout;
+	}
+
+	public String getLegendpos() {
+		return legendpos;
+	}
+
+	public void setLegendpos(String legendpos) {
+		this.legendpos = legendpos;
+	}
+
+	public String getLegendPosition() {
+		return legendPosition;
+	}
+
+	public void setLegendPosition(String legendPosition) {
+		this.legendPosition = legendPosition;
+	}
+
+	public String getDataLabel() {
+		return dataLabel;
+	}
+
+	public void setDataLabel(String dataLabel) {
+		this.dataLabel = dataLabel;
+	}
+
+	public String getMarginLeft() {
+		return marginLeft;
+	}
+
+	public void setMarginLeft(String marginLeft) {
+		this.marginLeft = marginLeft;
+	}
+
+	public String getMarginRight() {
+		return marginRight;
+	}
+
+	public void setMarginRight(String marginRight) {
+		this.marginRight = marginRight;
+	}
+
+	public String getMarkerEnabled() {
+		return markerEnabled;
+	}
+
+	public void setMarkerEnabled(String markerEnabled) {
+		this.markerEnabled = markerEnabled;
+	}
+	
+}

+ 60 - 0
src/main/java/com/ruisitech/bi/entity/bireport/ChartQueryDto.java

@@ -0,0 +1,60 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.util.List;
+
+public class ChartQueryDto extends BaseEntity {
+
+	private String dsid;
+	private String dsetId;
+	private Integer compId;
+	
+	private List<KpiDto> kpiJson;
+	
+	private ChartJSONDto chartJson;
+	
+	private List<ParamDto> params;
+	
+	public Integer getCompId() {
+		return compId;
+	}
+	public void setCompId(Integer compId) {
+		this.compId = compId;
+	}
+	public List<KpiDto> getKpiJson() {
+		return kpiJson;
+	}
+	public void setKpiJson(List<KpiDto> kpiJson) {
+		this.kpiJson = kpiJson;
+	}
+	public ChartJSONDto getChartJson() {
+		return chartJson;
+	}
+	public void setChartJson(ChartJSONDto chartJson) {
+		this.chartJson = chartJson;
+	}
+	public List<ParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<ParamDto> params) {
+		this.params = params;
+	}
+	
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	@Override
+	public void validate() {
+		 
+	}
+}

+ 274 - 0
src/main/java/com/ruisitech/bi/entity/bireport/DimDto.java

@@ -0,0 +1,274 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+public class DimDto extends BaseEntity {
+
+	private Integer id;
+	private String type;
+	private String colname; //码表在事实表中对应的字段名
+	private String alias; //别名
+	private String vals; //码表的限制维
+	private String valDesc; //码表限制维的名称
+	private String issum; //y,n两值
+	private String tname; //维度所在表name
+	private Integer calc;  //是否计算列
+	private String tableName; //维度码表表名
+	private String tableColKey; //码表表KEY字段
+	private String tableColName; //码表表name字段
+	
+	private String dimord; //维度排序方式
+	private String ordcol; //维度排序字段
+	private String dimdesc; //维度名称
+	private String valType; //维度value 字段的类型,用在拼接sql中,判断是否增加单引号
+	
+	private String dimpos; //维度所在位置,行维度还是列维度
+	private String pos; //col还是row, 用在图形中表示钻取维度的来源
+	private String dateformat; //如果是时间维度,设置时间类型
+	private String grouptype;
+	private String iscas;
+	private Integer top;
+	private String topType;
+	private String aggre;
+	private Integer filtertype;
+	private String startmt;
+	private String endmt;
+	private String startdt;
+	private String enddt;
+	private Integer cubeId;
+	private String xdispName;
+	private String tickInterval;
+	private String routeXaxisLable;
+	
+	private QueryDayDto day;
+	private QueryMonthDto month;
+	
+	public String getOrdcol() {
+		return ordcol;
+	}
+	public void setOrdcol(String ordcol) {
+		this.ordcol = ordcol;
+	}
+	public Integer getId() {
+		return id;
+	}
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getColname() {
+		return colname;
+	}
+	public void setColname(String colname) {
+		this.colname = colname;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public String getVals() {
+		return vals;
+	}
+	public void setVals(String vals) {
+		this.vals = vals;
+	}
+	public String getValDesc() {
+		return valDesc;
+	}
+	public void setValDesc(String valDesc) {
+		this.valDesc = valDesc;
+	}
+	public String getIssum() {
+		return issum;
+	}
+	public void setIssum(String issum) {
+		this.issum = issum;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public Integer getCalc() {
+		return calc;
+	}
+	public void setCalc(Integer calc) {
+		this.calc = calc;
+	}
+	public String getTableName() {
+		return tableName;
+	}
+	public void setTableName(String tableName) {
+		this.tableName = tableName;
+	}
+	public String getTableColKey() {
+		return tableColKey;
+	}
+	public void setTableColKey(String tableColKey) {
+		this.tableColKey = tableColKey;
+	}
+	public String getTableColName() {
+		return tableColName;
+	}
+	public void setTableColName(String tableColName) {
+		this.tableColName = tableColName;
+	}
+	public String getDimord() {
+		return dimord;
+	}
+	public void setDimord(String dimord) {
+		this.dimord = dimord;
+	}
+	public String getDimdesc() {
+		return dimdesc;
+	}
+	public void setDimdesc(String dimdesc) {
+		this.dimdesc = dimdesc;
+	}
+	public String getValType() {
+		return valType;
+	}
+	public void setValType(String valType) {
+		this.valType = valType;
+	}
+	public String getDimpos() {
+		return dimpos;
+	}
+	public void setDimpos(String dimpos) {
+		this.dimpos = dimpos;
+	}
+	public String getPos() {
+		return pos;
+	}
+	public void setPos(String pos) {
+		this.pos = pos;
+	}
+	public String getDateformat() {
+		return dateformat;
+	}
+	public void setDateformat(String dateformat) {
+		this.dateformat = dateformat;
+	}
+	public String getGrouptype() {
+		return grouptype;
+	}
+	public void setGrouptype(String grouptype) {
+		this.grouptype = grouptype;
+	}
+	public String getIscas() {
+		return iscas;
+	}
+	public void setIscas(String iscas) {
+		this.iscas = iscas;
+	}
+	public QueryDayDto getDay() {
+		if(day == null){
+			if(startdt != null && startdt.length() > 0 && enddt != null && enddt.length() > 0){
+				day = new QueryDayDto();
+				day.setStartDay(this.startdt);
+				day.setEndDay(this.enddt);
+			}
+		}
+		return day;
+	}
+	public void setDay(QueryDayDto day) {
+		this.day = day;
+	}
+	public QueryMonthDto getMonth() {
+		if(month == null){
+			if(startmt != null && startmt.length() > 0 && endmt != null && endmt.length() > 0){
+				month = new QueryMonthDto();
+				month.setStartMonth(startmt);
+				month.setEndMonth(endmt);
+			}
+		}
+		return month;
+	}
+	public void setMonth(QueryMonthDto month) {
+		this.month = month;
+	}
+	public Integer getTop() {
+		return top;
+	}
+	public void setTop(Integer top) {
+		this.top = top;
+	}
+	public String getTopType() {
+		return topType;
+	}
+	public void setTopType(String topType) {
+		this.topType = topType;
+	}
+	public String getAggre() {
+		return aggre;
+	}
+	public void setAggre(String aggre) {
+		this.aggre = aggre;
+	}
+	public Integer getFiltertype() {
+		return filtertype;
+	}
+	public void setFiltertype(Integer filtertype) {
+		this.filtertype = filtertype;
+	}
+	public String getStartmt() {
+		return startmt;
+	}
+	public void setStartmt(String startmt) {
+		this.startmt = startmt;
+	}
+	public String getEndmt() {
+		return endmt;
+	}
+	public void setEndmt(String endmt) {
+		this.endmt = endmt;
+	}
+	public String getStartdt() {
+		return startdt;
+	}
+	public void setStartdt(String startdt) {
+		this.startdt = startdt;
+	}
+	public String getEnddt() {
+		return enddt;
+	}
+	public void setEnddt(String enddt) {
+		this.enddt = enddt;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getXdispName() {
+		return xdispName;
+	}
+	public void setXdispName(String xdispName) {
+		this.xdispName = xdispName;
+	}
+	public String getTickInterval() {
+		return tickInterval;
+	}
+	public void setTickInterval(String tickInterval) {
+		this.tickInterval = tickInterval;
+	}
+	public String getRouteXaxisLable() {
+		return routeXaxisLable;
+	}
+	public void setRouteXaxisLable(String routeXaxisLable) {
+		this.routeXaxisLable = routeXaxisLable;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 195 - 0
src/main/java/com/ruisitech/bi/entity/bireport/KpiDto.java

@@ -0,0 +1,195 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.util.Map;
+
+public class KpiDto extends BaseEntity {
+	
+	private String aggre;
+	private String col_name;
+	private String fmt;
+	private String alias;
+	private String kpi_name;
+	private String ydispName;
+	private String tname; //指标所在表名称
+	private String descKey; //指标解释KEY
+	private Integer rate; //指标倍率
+	private String unit; //指标单位
+	private Integer kpi_id; //指标ID
+	private String sort; //指标排序方式,用在SQL中
+	private String order; //客户端排序
+	private Integer min; //y轴最小值
+	private Integer max; //Y轴最大值,用在仪表盘中
+	
+	private Integer calc;  //是否计算指标
+	
+	private KpiFilterDto filter; //对指标进行过滤
+	
+	private Map<String, Object> style; //指标样式
+	private Map<String, Object> warning;  //指标预警
+	private String compute; //指标计算方式(同比、环比、占比、排名等计算)
+	
+	private String funcname;  //回调函数名称
+	private String code;  //回调函数内容
+	private Boolean mergeData; //合并第二纵轴的数据
+	private String tfontcolor;
+	private Integer tfontsize;  //字体大小
+	
+	public String getAggre() {
+		return aggre;
+	}
+	public void setAggre(String aggre) {
+		this.aggre = aggre;
+	}
+	public String getFmt() {
+		return fmt;
+	}
+	public void setFmt(String fmt) {
+		this.fmt = fmt;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public String getYdispName() {
+		return ydispName;
+	}
+	public void setYdispName(String ydispName) {
+		this.ydispName = ydispName;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getDescKey() {
+		return descKey;
+	}
+	public void setDescKey(String descKey) {
+		this.descKey = descKey;
+	}
+	public Integer getRate() {
+		return rate;
+	}
+	public void setRate(Integer rate) {
+		this.rate = rate;
+	}
+	public String getUnit() {
+		return unit;
+	}
+	public void setUnit(String unit) {
+		this.unit = unit;
+	}
+	public String getSort() {
+		return sort;
+	}
+	public void setSort(String sort) {
+		this.sort = sort;
+	}
+	public String getOrder() {
+		return order;
+	}
+	public void setOrder(String order) {
+		this.order = order;
+	}
+	public Integer getCalc() {
+		return calc;
+	}
+	public void setCalc(Integer calc) {
+		this.calc = calc;
+	}
+	public KpiFilterDto getFilter() {
+		return filter;
+	}
+	public void setFilter(KpiFilterDto filter) {
+		this.filter = filter;
+	}
+	
+	public Map<String, Object> getStyle() {
+		return style;
+	}
+	public void setStyle(Map<String, Object> style) {
+		this.style = style;
+	}
+	
+	public Map<String, Object> getWarning() {
+		return warning;
+	}
+	public void setWarning(Map<String, Object> warning) {
+		this.warning = warning;
+	}
+	public String getCompute() {
+		return compute;
+	}
+	public void setCompute(String compute) {
+		this.compute = compute;
+	}
+	public String getFuncname() {
+		return funcname;
+	}
+	public void setFuncname(String funcname) {
+		this.funcname = funcname;
+	}
+	public String getCode() {
+		return code;
+	}
+	public void setCode(String code) {
+		this.code = code;
+	}
+	public Boolean getMergeData() {
+		return mergeData;
+	}
+	public void setMergeData(Boolean mergeData) {
+		this.mergeData = mergeData;
+	}
+	public Integer getMax() {
+		return max;
+	}
+	public void setMax(Integer max) {
+		this.max = max;
+	}
+	public Integer getMin() {
+		return min;
+	}
+	public void setMin(Integer min) {
+		this.min = min;
+	}
+	public String getKpi_name() {
+		return kpi_name;
+	}
+	public void setKpi_name(String kpi_name) {
+		this.kpi_name = kpi_name;
+	}
+	public Integer getKpi_id() {
+		return kpi_id;
+	}
+	public void setKpi_id(Integer kpi_id) {
+		this.kpi_id = kpi_id;
+	}
+	public String getCol_name() {
+		return col_name;
+	}
+	public void setCol_name(String col_name) {
+		this.col_name = col_name;
+	}
+	public String getTfontcolor() {
+		return tfontcolor;
+	}
+	public void setTfontcolor(String tfontcolor) {
+		this.tfontcolor = tfontcolor;
+	}
+	public Integer getTfontsize() {
+		return tfontsize;
+	}
+	public void setTfontsize(Integer tfontsize) {
+		this.tfontsize = tfontsize;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 44 - 0
src/main/java/com/ruisitech/bi/entity/bireport/KpiFilterDto.java

@@ -0,0 +1,44 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+public class KpiFilterDto extends BaseEntity {
+
+	private Integer kpi;
+	private String filterType; //>,<,=,qj 四种
+	private Double val1;
+	private Double val2; //在区间匹配的时候,需要val2
+	
+	
+	public String getFilterType() {
+		return filterType;
+	}
+	
+	public Integer getKpi() {
+		return kpi;
+	}
+
+	public void setKpi(Integer kpi) {
+		this.kpi = kpi;
+	}
+
+	public void setFilterType(String filterType) {
+		this.filterType = filterType;
+	}
+	public Double getVal1() {
+		return val1;
+	}
+	public Double getVal2() {
+		return val2;
+	}
+	public void setVal1(Double val1) {
+		this.val1 = val1;
+	}
+	public void setVal2(Double val2) {
+		this.val2 = val2;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 64 - 0
src/main/java/com/ruisitech/bi/entity/bireport/OlapInfo.java

@@ -0,0 +1,64 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+
+public class OlapInfo extends BaseEntity {
+
+	private Integer pageId;
+	private Integer userId;
+	private String pageInfo;
+	private String pageName;
+	private Date crtDate;
+	private Date updateDate;
+	private String crtuser;
+	
+	public Integer getPageId() {
+		return pageId;
+	}
+	public void setPageId(Integer pageId) {
+		this.pageId = pageId;
+	}
+	public Integer getUserId() {
+		return userId;
+	}
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+	public String getPageInfo() {
+		return pageInfo;
+	}
+	public void setPageInfo(String pageInfo) {
+		this.pageInfo = pageInfo;
+	}
+	public String getPageName() {
+		return pageName;
+	}
+	public void setPageName(String pageName) {
+		this.pageName = pageName;
+	}
+	public Date getCrtDate() {
+		return crtDate;
+	}
+	public void setCrtDate(Date crtDate) {
+		this.crtDate = crtDate;
+	}
+	public Date getUpdateDate() {
+		return updateDate;
+	}
+	public void setUpdateDate(Date updateDate) {
+		this.updateDate = updateDate;
+	}
+	public String getCrtuser() {
+		return crtuser;
+	}
+	public void setCrtuser(String crtuser) {
+		this.crtuser = crtuser;
+	}
+	@Override
+	public void validate() {
+		this.pageName = RSBIUtils.htmlEscape(this.pageName);
+	}
+}

+ 173 - 0
src/main/java/com/ruisitech/bi/entity/bireport/ParamDto.java

@@ -0,0 +1,173 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+public class ParamDto extends BaseEntity {
+
+	private String type;
+	private String colname;
+	private String alias;
+	private String valType;
+	private String dateformat;
+	private String tname;
+	private String st;
+	private String end;
+	private String vals;
+	private String valStrs;
+	private String valDesc;
+	private Integer id;
+	private Integer cubeId;
+	private String colDesc;
+	private String tableName;
+	private String dimord;
+	private String tableColKey;
+	private String tableColName;
+	private String dsid;
+	private String grouptype;
+	private String name;
+	private Integer filtertype;
+	private Integer calc; //是否动态指标
+	
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getColname() {
+		return colname;
+	}
+	public void setColname(String colname) {
+		this.colname = colname;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public String getValType() {
+		return valType;
+	}
+	public void setValType(String valType) {
+		this.valType = valType;
+	}
+	public String getDateformat() {
+		return dateformat;
+	}
+	public void setDateformat(String dateformat) {
+		this.dateformat = dateformat;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getSt() {
+		return st;
+	}
+	public void setSt(String st) {
+		this.st = st;
+	}
+	public String getEnd() {
+		return end;
+	}
+	public void setEnd(String end) {
+		this.end = end;
+	}
+	public String getVals() {
+		return vals;
+	}
+	public void setVals(String vals) {
+		this.vals = vals;
+	}
+	public Integer getId() {
+		return id;
+	}
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	public String getValDesc() {
+		return valDesc;
+	}
+	public void setValDesc(String valDesc) {
+		this.valDesc = valDesc;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getColDesc() {
+		return colDesc;
+	}
+	public void setColDesc(String colDesc) {
+		this.colDesc = colDesc;
+	}
+	public String getTableName() {
+		return tableName;
+	}
+	public void setTableName(String tableName) {
+		this.tableName = tableName;
+	}
+	public String getDimord() {
+		return dimord;
+	}
+	public void setDimord(String dimord) {
+		this.dimord = dimord;
+	}
+	public String getTableColKey() {
+		return tableColKey;
+	}
+	public void setTableColKey(String tableColKey) {
+		this.tableColKey = tableColKey;
+	}
+	public String getTableColName() {
+		return tableColName;
+	}
+	public void setTableColName(String tableColName) {
+		this.tableColName = tableColName;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getValStrs() {
+		return valStrs;
+	}
+	public void setValStrs(String valStrs) {
+		this.valStrs = valStrs;
+	}
+	public String getGrouptype() {
+		return grouptype;
+	}
+	public void setGrouptype(String grouptype) {
+		this.grouptype = grouptype;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public Integer getFiltertype() {
+		return filtertype;
+	}
+	public void setFiltertype(Integer filtertype) {
+		this.filtertype = filtertype;
+	}
+	public Integer getCalc() {
+		return calc;
+	}
+	public void setCalc(Integer calc) {
+		this.calc = calc;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 37 - 0
src/main/java/com/ruisitech/bi/entity/bireport/QueryDayDto.java

@@ -0,0 +1,37 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+public class QueryDayDto extends BaseEntity {
+
+	private String startDay;
+	private String endDay;
+	public String getStartDay() {
+		return startDay;
+	}
+	public void setStartDay(String startDay) {
+		this.startDay = startDay;
+	}
+	public String getEndDay() {
+		return endDay;
+	}
+	public void setEndDay(String endDay) {
+		this.endDay = endDay;
+	}
+	
+	public int getBetweenDay() throws ParseException{
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");		
+		long l1 = sdf.parse(this.startDay).getTime();		
+		long l2 = sdf.parse(this.endDay).getTime();	
+		long result = Math.abs(l1 - l2) / (24 * 60 * 60 * 1000);
+		return (int)result;
+	}
+	
+	@Override
+	public void validate() {
+		 
+	}
+}

+ 42 - 0
src/main/java/com/ruisitech/bi/entity/bireport/QueryMonthDto.java

@@ -0,0 +1,42 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.text.ParseException;
+
+public class QueryMonthDto extends BaseEntity {
+
+	private String startMonth;
+	private String endMonth;
+	public String getStartMonth() {
+		return startMonth;
+	}
+	public void setStartMonth(String startMonth) {
+		this.startMonth = startMonth;
+	}
+	public String getEndMonth() {
+		return endMonth;
+	}
+	public void setEndMonth(String endMonth) {
+		this.endMonth = endMonth;
+	}
+	
+	public int getBetweenMonth() throws ParseException{
+		int year1 = Integer.parseInt(this.startMonth.substring(0,4));
+		int year2 = Integer.parseInt(this.endMonth.substring(0,4));
+		
+		int month1 = Integer.parseInt(this.startMonth.substring(4,6));
+		int month2 = Integer.parseInt(this.endMonth.substring(4,6));
+		
+		int betweenMonth = month2 - month1;
+		int betweenYear = year2 - year1;
+		
+		
+		return betweenYear * 12 + betweenMonth;
+	}
+	
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 44 - 0
src/main/java/com/ruisitech/bi/entity/bireport/TableDetailDto.java

@@ -0,0 +1,44 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.PageParam;
+
+import java.util.Map;
+
+/**
+ * 明细提取dto
+ * @author hq
+ *
+ */
+public class TableDetailDto extends PageParam {
+	
+	private Map<String, String> pms;
+	
+	private String dsetId;
+	private String dsid;
+
+	public Map<String, String> getPms() {
+		return pms;
+	}
+
+	public void setPms(Map<String, String> pms) {
+		this.pms = pms;
+	}
+
+	public String getDsetId() {
+		return dsetId;
+	}
+
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+
+	public String getDsid() {
+		return dsid;
+	}
+
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+
+
+}

+ 129 - 0
src/main/java/com/ruisitech/bi/entity/bireport/TableQueryDto.java

@@ -0,0 +1,129 @@
+package com.ruisitech.bi.entity.bireport;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class TableQueryDto extends BaseEntity {
+
+	private String dsid;
+	private String dsetId;
+	private String compId;
+	
+	private List<KpiDto> kpiJson;
+	private List<DimDto> cols;
+	private List<DimDto> rows;
+	private List<ParamDto> params;
+	
+	private Map<String, Object> link;
+	private Map<String, Object> linkAccept;
+	private List<Map<String, Object>> drillDim;
+	
+	
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+
+	public String getCompId() {
+		return compId;
+	}
+	public void setCompId(String compId) {
+		this.compId = compId;
+	}
+	public List<KpiDto> getKpiJson() {
+		return kpiJson;
+	}
+	public void setKpiJson(List<KpiDto> kpiJson) {
+		this.kpiJson = kpiJson;
+	}
+	public List<DimDto> getCols() {
+		return cols;
+	}
+	public void setCols(List<DimDto> cols) {
+		this.cols = cols;
+	}
+	public List<DimDto> getRows() {
+		return rows;
+	}
+	public void setRows(List<DimDto> rows) {
+		this.rows = rows;
+	}
+	public List<ParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<ParamDto> params) {
+		this.params = params;
+	}
+	
+	/**
+	 * 获取kpi的计算方式,是计算上期值、还是计算同期值、还是都计算
+	 * 
+	 * @return 返回 0(都不计算),1(上期值), 2(同期值), 3 (都计算) 
+	 */
+	public int getKpiComputeType(){
+		boolean sq = false;
+		boolean tq = false;
+		for(KpiDto kpi : kpiJson){
+			String compute = kpi.getCompute();
+			if(compute != null && compute.length() > 0){
+				String[] jss = compute.split(",");
+				for(String js : jss){
+					if("sq".equals(js) || "zje".equals(js) || "hb".equals(js)){
+						sq = true;
+					}else if("tq".equals(js) || "tb".equals(js)){
+						tq = true;
+					}
+				}
+			}
+		}
+		if(sq && tq){
+			return 3;
+		}else if(sq){
+			return 1;
+		}else if(tq){
+			return 2;
+		}else{
+			return 0;
+		}
+	}
+	public Map<String, Object> getLink() {
+		return link;
+	}
+	public void setLink(Map<String, Object> link) {
+		this.link = link;
+	}
+	public Map<String, Object> getLinkAccept() {
+		return linkAccept;
+	}
+	public void setLinkAccept(Map<String, Object> linkAccept) {
+		this.linkAccept = linkAccept;
+	}
+	public List<Map<String, Object>> getDrillDim() {
+		return drillDim;
+	}
+	public void setDrillDim(List<Map<String, Object>> drillDim) {
+		this.drillDim = drillDim;
+	}
+	
+	public List<DimDto> getDims(){
+		List<DimDto> ret = new ArrayList<DimDto>();
+		ret.addAll(this.cols);
+		ret.addAll(this.rows);
+		return ret;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 20 - 0
src/main/java/com/ruisitech/bi/entity/common/BaseEntity.java

@@ -0,0 +1,20 @@
+package com.ruisitech.bi.entity.common;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ruisitech.bi.util.RSBIUtils;
+
+public abstract class BaseEntity {
+	
+	public abstract void validate();
+
+	@JsonIgnore
+	private String dbName = RSBIUtils.getConstant("dbName");
+
+	public String getDbName() {
+		return dbName;
+	}
+
+	public void setDbName(String dbName) {
+		this.dbName = dbName;
+	}
+}

+ 62 - 0
src/main/java/com/ruisitech/bi/entity/common/DSColumn.java

@@ -0,0 +1,62 @@
+package com.ruisitech.bi.entity.common;
+
+public class DSColumn {
+	private Integer idx;
+	private String name;
+	private String type;
+	private String dispName;
+	private Integer length; //字段长度
+	private String tname; 
+	private Boolean isshow = true; //是否显示字段
+	private String expression;
+	
+	public String getName() {
+		return name;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getDispName() {
+		return dispName;
+	}
+	public void setDispName(String dispName) {
+		this.dispName = dispName;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public Integer getIdx() {
+		return idx;
+	}
+	public void setIdx(Integer idx) {
+		this.idx = idx;
+	}
+	public Boolean getIsshow() {
+		return isshow;
+	}
+	public void setIsshow(Boolean isshow) {
+		this.isshow = isshow;
+	}
+	public Integer getLength() {
+		return length;
+	}
+	public void setLength(Integer length) {
+		this.length = length;
+	}
+	public String getExpression() {
+		return expression;
+	}
+	public void setExpression(String expression) {
+		this.expression = expression;
+	}
+	
+}

+ 46 - 0
src/main/java/com/ruisitech/bi/entity/common/PageParam.java

@@ -0,0 +1,46 @@
+package com.ruisitech.bi.entity.common;
+
+
+public class PageParam {
+	/**
+	 * 分页参数
+	 */
+	private Integer total;
+	private Integer page;
+	private Integer rows;
+
+	//搜索
+	private String search;
+
+	public Integer getTotal() {
+		if(total==null){
+			total = 0;
+		}
+		return total;
+	}
+	public void setTotal(Integer total) {
+		this.total = total;
+	}
+	
+	public Integer getPage() {
+		return page;
+	}
+	public void setPage(Integer page) {
+		this.page = page;
+	}
+	public Integer getRows() {
+		return rows;
+	}
+	public void setRows(Integer rows) {
+		this.rows = rows;
+	}
+	@Override
+	public String toString() {
+		return "PageParam [total=" + total + ", pageIndex=" + page
+				+ ", pageSize=" + rows + "]";
+	}
+
+	public String getSearch() {
+		return search;
+	}
+}

+ 18 - 0
src/main/java/com/ruisitech/bi/entity/common/RequestStatus.java

@@ -0,0 +1,18 @@
+package com.ruisitech.bi.entity.common;
+
+public enum RequestStatus {
+	SUCCESS(1),//成功
+	FAIL_FIELD(0);//失败
+
+	private Integer status;
+
+	private RequestStatus(int status) {
+		this.status=status;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+	
+	
+}

+ 65 - 0
src/main/java/com/ruisitech/bi/entity/common/Result.java

@@ -0,0 +1,65 @@
+package com.ruisitech.bi.entity.common;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+public class Result {
+
+	/** 状态 */
+    private Integer result;
+    /** 消息 */
+    private String msg;
+    /** 数据 */
+    @JsonInclude(Include.NON_NULL)
+    private Object rows;
+    
+    private long total;
+    
+    public Result(){
+    	
+    }
+    
+    public Result(Integer result, String msg, Object rows){
+    	this.result = result;
+    	this.msg = msg;
+    	this.rows = rows;
+    }
+    
+    public Result(Integer result, String msg, Object rows, long total){
+    	this.result = result;
+    	this.msg = msg;
+    	this.rows = rows;
+    	this.total = total;
+    }
+    
+	public Integer getResult() {
+		return result;
+	}
+	public void setResult(Integer result) {
+		this.result = result;
+	}
+	public String getMsg() {
+		return msg;
+	}
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public Object getRows() {
+		return rows;
+	}
+
+	public void setRows(Object rows) {
+		this.rows = rows;
+	}
+
+	public long getTotal() {
+		return total;
+	}
+
+	public void setTotal(long total) {
+		this.total = total;
+	}
+	
+	
+}

+ 96 - 0
src/main/java/com/ruisitech/bi/entity/frame/Menu.java

@@ -0,0 +1,96 @@
+package com.ruisitech.bi.entity.frame;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+import java.util.List;
+
+public class Menu extends BaseEntity {
+	
+	private Integer menuId;
+	private Integer menuPid;
+	private String menuName;
+	private String menuDesc;
+	private Date menuDate;
+	private Integer menuOrder;
+	private String menuUrl;
+	private String urls;
+	private String mvs;
+	private String avatar;
+	
+	private List<Menu> children;
+	
+	public Integer getMenuId() {
+		return menuId;
+	}
+	public void setMenuId(Integer menuId) {
+		this.menuId = menuId;
+	}
+	public Integer getMenuPid() {
+		return menuPid;
+	}
+	public void setMenuPid(Integer menuPid) {
+		this.menuPid = menuPid;
+	}
+	public String getMenuName() {
+		return menuName;
+	}
+	public void setMenuName(String menuName) {
+		this.menuName = menuName;
+	}
+	public String getMenuDesc() {
+		return menuDesc;
+	}
+	public void setMenuDesc(String menuDesc) {
+		this.menuDesc = menuDesc;
+	}
+	public Date getMenuDate() {
+		return menuDate;
+	}
+	public void setMenuDate(Date menuDate) {
+		this.menuDate = menuDate;
+	}
+	public Integer getMenuOrder() {
+		return menuOrder;
+	}
+	public void setMenuOrder(Integer menuOrder) {
+		this.menuOrder = menuOrder;
+	}
+	public String getMenuUrl() {
+		return menuUrl;
+	}
+	public void setMenuUrl(String menuUrl) {
+		this.menuUrl = menuUrl;
+	}
+	public String getUrls() {
+		return urls;
+	}
+	public void setUrls(String urls) {
+		this.urls = urls;
+	}
+	public String getMvs() {
+		return mvs;
+	}
+	public void setMvs(String mvs) {
+		this.mvs = mvs;
+	}
+	public String getAvatar() {
+		return avatar;
+	}
+	public void setAvatar(String avatar) {
+		this.avatar = avatar;
+	}
+	public List<Menu> getChildren() {
+		return children;
+	}
+	public void setChildren(List<Menu> children) {
+		this.children = children;
+	}
+	
+	 @Override
+	public void validate() {
+		this.menuName = RSBIUtils.htmlEscape(this.menuName);
+		this.menuDesc = RSBIUtils.htmlEscape(this.menuDesc);
+	}
+}

+ 71 - 0
src/main/java/com/ruisitech/bi/entity/frame/Role.java

@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有 
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.entity.frame;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.util.Date;
+
+public class Role extends BaseEntity {
+
+	private Integer roleId;
+	private String roleName;
+	private String roleDesc;
+	@JsonFormat(pattern = "yyyy-MM-dd")
+	private Date createDate;
+	private String createUser;
+	private Integer ord;
+	private Integer userId; //角色所属用户ID
+	
+	public Integer getRoleId() {
+		return roleId;
+	}
+	public void setRoleId(Integer roleId) {
+		this.roleId = roleId;
+	}
+	public String getRoleName() {
+		return roleName;
+	}
+	public void setRoleName(String roleName) {
+		this.roleName = roleName;
+	}
+	public String getRoleDesc() {
+		return roleDesc;
+	}
+	public void setRoleDesc(String roleDesc) {
+		this.roleDesc = roleDesc;
+	}
+	public Date getCreateDate() {
+		return createDate;
+	}
+	public void setCreateDate(Date createDate) {
+		this.createDate = createDate;
+	}
+	public String getCreateUser() {
+		return createUser;
+	}
+	public void setCreateUser(String createUser) {
+		this.createUser = createUser;
+	}
+	public Integer getOrd() {
+		return ord;
+	}
+	public void setOrd(Integer ord) {
+		this.ord = ord;
+	}
+	public Integer getUserId() {
+		return userId;
+	}
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+
+	@Override
+	public void validate() {
+
+	}
+}

+ 35 - 0
src/main/java/com/ruisitech/bi/entity/frame/TreeNode.java

@@ -0,0 +1,35 @@
+package com.ruisitech.bi.entity.frame;
+
+
+public class TreeNode {
+	
+	private String id;
+	
+	private String pid;
+	
+	private String userId;
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getPid() {
+		return pid;
+	}
+
+	public void setPid(String pid) {
+		this.pid = pid;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+}

+ 159 - 0
src/main/java/com/ruisitech/bi/entity/frame/User.java

@@ -0,0 +1,159 @@
+package com.ruisitech.bi.entity.frame;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public final class User extends BaseEntity implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 6096757156465671644L;
+	
+	private Integer userId;
+	private String staffId;
+
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
+	private Date loginTime;
+	private Date lastActive;
+	private String loginIp;
+	private String sessionId;
+
+	@JsonFormat(pattern = "yyyy-MM-dd")
+	private Date logoutTime;
+	private Integer logCnt;
+	private String loginName;
+
+	private String password;
+	private String password2;  //在修改密码时使用
+
+	private String gender;
+	private String mobilePhone;
+	private String email;
+	private String officeTel;
+	private int state; //1 为启用, 0为停用。
+		
+	public int getState() {
+		return state;
+	}
+	public void setState(int state) {
+		this.state = state;
+	}
+	public User() {
+		
+	}
+	public String getStaffId() {
+		return staffId;
+	}
+	public void setStaffId(String staffId) {
+		this.staffId = staffId;
+	}
+	public Date getLoginTime() {
+		return loginTime;
+	}
+	public void setLoginTime(Date loginTime) {
+		this.loginTime = loginTime;
+	}
+	public Date getLastActive() {
+		return lastActive;
+	}
+	public void setLastActive(Date lastActive) {
+		this.lastActive = lastActive;
+	}
+	public String getLoginIp() {
+		return loginIp;
+	}
+	public void setLoginIp(String loginIp) {
+		this.loginIp = loginIp;
+	}
+	public String getSessionId() {
+		return sessionId;
+	}
+	public void setSessionId(String sessionId) {
+		this.sessionId = sessionId;
+	}
+	public Date getLogoutTime() {
+		return logoutTime;
+	}
+	public void setLogoutTime(Date logoutTime) {
+		this.logoutTime = logoutTime;
+	}
+
+	@JsonIgnore
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	public String getGender() {
+		return gender;
+	}
+	public void setGender(String gender) {
+		this.gender = gender;
+	}
+	
+	public String getEmail() {
+		return email;
+	}
+	public void setEmail(String email) {
+		this.email = email;
+	}
+	public String getLoginName() {
+		return loginName;
+	}
+	
+	public void setLoginName(String loginName) {
+		this.loginName = loginName;
+	}
+	public String getMobilePhone() {
+		return mobilePhone;
+	}
+	public void setMobilePhone(String mobilePhone) {
+		this.mobilePhone = mobilePhone;
+	}
+	public String getOfficeTel() {
+		return officeTel;
+	}
+	public void setOfficeTel(String officeTel) {
+		this.officeTel = officeTel;
+	}
+	
+	@Override
+	public String toString() {
+		return "id = " + this.userId + ", name = " + this.loginName;
+	}
+	public Integer getUserId() {
+		return userId;
+	}
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+	public Integer getLogCnt() {
+		return logCnt;
+	}
+	public void setLogCnt(Integer logCnt) {
+		this.logCnt = logCnt;
+	}
+	
+	@Override
+	public void validate() {
+		this.staffId = RSBIUtils.htmlEscape(this.staffId);
+		this.loginName = RSBIUtils.htmlEscape(this.loginName);
+	}
+
+	@JsonIgnore
+	public String getPassword2() {
+		return password2;
+	}
+
+	public void setPassword2(String password2) {
+		this.password2 = password2;
+	}
+}

+ 103 - 0
src/main/java/com/ruisitech/bi/entity/model/Cube.java

@@ -0,0 +1,103 @@
+package com.ruisitech.bi.entity.model;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.List;
+import java.util.Map;
+
+public class Cube extends BaseEntity  {
+	
+	private Integer cubeId;
+	private String cubeName;
+	private String desc;
+	/**
+	 * 数据集名称
+	 */
+	private String dsetName; 
+	private String dsetId;
+	/**
+	 * 数据源ID
+	 */
+	private String dsId;
+	/**
+	 * 主表
+	 */
+	private String priTable;
+	
+	private List<Dimension> dims;
+	private List<Measure> kpis;
+	
+	/**
+	 * 需要删除的对象, 包含 id, type
+	 */
+	private List<Map<String, Object>> delObj;
+
+	
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getCubeName() {
+		return cubeName;
+	}
+	public void setCubeName(String cubeName) {
+		this.cubeName = cubeName;
+	}
+	public String getDesc() {
+		return desc;
+	}
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+	public String getDsetName() {
+		return dsetName;
+	}
+	public void setDsetName(String dsetName) {
+		this.dsetName = dsetName;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public String getDsId() {
+		return dsId;
+	}
+	public void setDsId(String dsId) {
+		this.dsId = dsId;
+	}
+	public List<Dimension> getDims() {
+		return dims;
+	}
+	public void setDims(List<Dimension> dims) {
+		this.dims = dims;
+	}
+	public List<Measure> getKpis() {
+		return kpis;
+	}
+	public void setKpis(List<Measure> kpis) {
+		this.kpis = kpis;
+	}
+	public String getPriTable() {
+		return priTable;
+	}
+	public void setPriTable(String priTable) {
+		this.priTable = priTable;
+	}
+	public List<Map<String, Object>> getDelObj() {
+		return delObj;
+	}
+	public void setDelObj(List<Map<String, Object>> delObj) {
+		this.delObj = delObj;
+	}
+	
+	 @Override
+	public void validate() {
+		 this.cubeName = RSBIUtils.htmlEscape(this.cubeName);
+		 this.desc = RSBIUtils.htmlEscape(this.desc);
+	 }
+}

+ 99 - 0
src/main/java/com/ruisitech/bi/entity/model/CubeColMeta.java

@@ -0,0 +1,99 @@
+package com.ruisitech.bi.entity.model;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+public class CubeColMeta extends BaseEntity {
+	
+	private Integer rid;
+	private Integer cubeId;
+	/**
+	 * 1 维度,2 度量
+	 */
+	private Integer colType; 
+	private Integer colId;
+	private String tname;
+	private String col;
+	private String alias;
+	/**
+	 * 1 是, 0 否
+	 */
+	private Integer calc;
+	private Integer ord;
+	private Integer targetId;
+	/**
+	 * 维度或度量是否被修改
+	 */
+	private String isupdate; 
+	
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public Integer getColType() {
+		return colType;
+	}
+	public void setColType(Integer colType) {
+		this.colType = colType;
+	}
+	public Integer getColId() {
+		return colId;
+	}
+	public void setColId(Integer colId) {
+		this.colId = colId;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getCol() {
+		return col;
+	}
+	public void setCol(String col) {
+		this.col = col;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public Integer getCalc() {
+		return calc;
+	}
+	public void setCalc(Integer calc) {
+		this.calc = calc;
+	}
+	public Integer getOrd() {
+		return ord;
+	}
+	public void setOrd(Integer ord) {
+		this.ord = ord;
+	}
+	public Integer getRid() {
+		return rid;
+	}
+	public void setRid(Integer rid) {
+		this.rid = rid;
+	}
+	public Integer getTargetId() {
+		return targetId;
+	}
+	public void setTargetId(Integer targetId) {
+		this.targetId = targetId;
+	}
+	public String getIsupdate() {
+		return isupdate;
+	}
+	public void setIsupdate(String isupdate) {
+		this.isupdate = isupdate;
+	}
+	
+	@Override
+	public void validate() {
+		 
+	}
+}

+ 86 - 0
src/main/java/com/ruisitech/bi/entity/model/DataSource.java

@@ -0,0 +1,86 @@
+package com.ruisitech.bi.entity.model;
+
+import com.ruisi.ext.engine.dao.DatabaseHelper;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.engine.view.exception.ExtConfigException;
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+public class DataSource extends BaseEntity {
+	
+	private String linkType;
+	private String linkName;
+	private String linkPwd;
+	private String linkUrl;
+	private String dsname;
+	private String jndiName;
+	private String use; //使用jdbc/jndi
+	private String dsid;
+	
+	/**
+	 * 获取驱动类
+	 * @return
+	 * @throws ExtConfigException 
+	 */
+	public String getClazz() throws ExtConfigException{
+		String linktype = this.getLinkType();
+		DatabaseHelper db = ExtContext.getInstance().getDatabaseHelper(linktype);
+		return db.getClazz();
+	}
+	
+	public String getLinkType() {
+		return linkType;
+	}
+	public void setLinkType(String linkType) {
+		this.linkType = linkType;
+	}
+	public String getLinkName() {
+		return linkName;
+	}
+	public void setLinkName(String linkName) {
+		this.linkName = linkName;
+	}
+	public String getLinkPwd() {
+		return linkPwd;
+	}
+	public void setLinkPwd(String linkPwd) {
+		this.linkPwd = linkPwd;
+	}
+	public String getLinkUrl() {
+		return linkUrl;
+	}
+	public void setLinkUrl(String linkUrl) {
+		this.linkUrl = linkUrl;
+	}
+	public String getDsname() {
+		return dsname;
+	}
+	public void setDsname(String dsname) {
+		this.dsname = dsname;
+	}
+	
+	public String getJndiName() {
+		return jndiName;
+	}
+	public void setJndiName(String jndiName) {
+		this.jndiName = jndiName;
+	}
+	public String getUse() {
+		return use;
+	}
+	public void setUse(String use) {
+		this.use = use;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	
+	@Override
+	public void validate() {
+		this.dsname = RSBIUtils.htmlEscape(this.dsname);
+		this.jndiName = RSBIUtils.htmlEscape(this.jndiName);
+	}
+}

+ 77 - 0
src/main/java/com/ruisitech/bi/entity/model/Dataset.java

@@ -0,0 +1,77 @@
+package com.ruisitech.bi.entity.model;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+
+public class Dataset extends BaseEntity {
+	
+	private String dsetId;
+	/**
+	 * 数据源ID
+	 */
+	private String dsid;
+	private String dsname;
+	/**
+	 * 数据源链接方式
+	 */
+	private String useType;
+	private String name;
+	private String cfg;
+	private Date crtdate;
+	private String priTable;
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getCfg() {
+		return cfg;
+	}
+	public void setCfg(String cfg) {
+		this.cfg = cfg;
+	}
+	public Date getCrtdate() {
+		return crtdate;
+	}
+	public void setCrtdate(Date crtdate) {
+		this.crtdate = crtdate;
+	}
+	public String getPriTable() {
+		return priTable;
+	}
+	public void setPriTable(String priTable) {
+		this.priTable = priTable;
+	}
+	public String getDsname() {
+		return dsname;
+	}
+	public void setDsname(String dsname) {
+		this.dsname = dsname;
+	}
+	public String getUseType() {
+		return useType;
+	}
+	public void setUseType(String useType) {
+		this.useType = useType;
+	}
+	@Override
+	public void validate() {
+		this.dsname = RSBIUtils.htmlEscape(this.dsname);
+		this.name = RSBIUtils.htmlEscape(this.name);
+	}
+}

+ 99 - 0
src/main/java/com/ruisitech/bi/entity/model/Dimension.java

@@ -0,0 +1,99 @@
+package com.ruisitech.bi.entity.model;
+
+
+public class Dimension extends CubeColMeta {
+	
+	private Integer dimId;
+	private String name;
+	private String type;
+	private String colkey;
+	private String coltext;
+	private String dimord;
+	private String ordcol;
+	private String vtype;
+	private String colTable;
+	private Integer cubeId;
+	private String groupId;
+	private String groupName;
+	private String dateformat;
+	
+	public Integer getDimId() {
+		return dimId;
+	}
+	public void setDimId(Integer dimId) {
+		this.dimId = dimId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getColkey() {
+		return colkey;
+	}
+	public void setColkey(String colkey) {
+		this.colkey = colkey;
+	}
+	public String getColtext() {
+		return coltext;
+	}
+	public void setColtext(String coltext) {
+		this.coltext = coltext;
+	}
+	public String getDimord() {
+		return dimord;
+	}
+	public void setDimord(String dimord) {
+		this.dimord = dimord;
+	}
+	public String getVtype() {
+		return vtype;
+	}
+	public void setVtype(String vtype) {
+		this.vtype = vtype;
+	}
+	public String getColTable() {
+		return colTable;
+	}
+	public void setColTable(String colTable) {
+		this.colTable = colTable;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getGroupId() {
+		return groupId;
+	}
+	public void setGroupId(String groupId) {
+		this.groupId = groupId;
+	}
+	public String getDateformat() {
+		return dateformat;
+	}
+	public void setDateformat(String dateformat) {
+		this.dateformat = dateformat;
+	}
+	public String getGroupName() {
+		return groupName;
+	}
+	public void setGroupName(String groupName) {
+		this.groupName = groupName;
+	}
+	public String getOrdcol() {
+		return ordcol;
+	}
+	public void setOrdcol(String ordcol) {
+		this.ordcol = ordcol;
+	}
+
+}

+ 74 - 0
src/main/java/com/ruisitech/bi/entity/model/Measure.java

@@ -0,0 +1,74 @@
+package com.ruisitech.bi.entity.model;
+
+public class Measure extends CubeColMeta {
+	
+	private Integer kpiId;
+	private String name;
+	private String kpinote;
+	private String unit;
+	private String fmt;
+	private String aggre;
+	/**
+	 * 0否,1是
+	 */
+	private Integer calcKpi;
+	private Integer cubeId;
+	public Integer getKpiId() {
+		return kpiId;
+	}
+	public void setKpiId(Integer kpiId) {
+		this.kpiId = kpiId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getKpinote() {
+		return kpinote;
+	}
+	public void setKpinote(String kpinote) {
+		this.kpinote = kpinote;
+	}
+	public String getUnit() {
+		return unit;
+	}
+	public void setUnit(String unit) {
+		this.unit = unit;
+	}
+	public String getFmt() {
+		return fmt;
+	}
+	public void setFmt(String fmt) {
+		this.fmt = fmt;
+	}
+	public String getAggre() {
+		return aggre;
+	}
+	//获取聚合字段字符串
+	public String getAggreCol() {
+		if("count(distinct)".equals(aggre)){  //需要特殊处理
+			return "count(distinct " + super.getCol() + ")";
+		}else{  //sum/avg/max/min/count 不需要特殊处理
+			return aggre +"(" + super.getCol() +")";
+		}
+	}
+	public void setAggre(String aggre) {
+		this.aggre = aggre;
+	}
+	public Integer getCalcKpi() {
+		return calcKpi;
+	}
+	public void setCalcKpi(Integer calcKpi) {
+		this.calcKpi = calcKpi;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+
+	
+}

+ 78 - 0
src/main/java/com/ruisitech/bi/entity/portal/BoxQuery.java

@@ -0,0 +1,78 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.List;
+
+public class BoxQuery extends BaseEntity {
+
+	private String id;
+	private Integer height; //通过 line-height 控制文字高度
+	private String type;
+	private String name;
+	private String dsetId;
+	private String dsid;
+	private KpiDto kpiJson;
+	private List<PortalParamDto> portalParams;
+	private List<CompParamDto> params;
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public KpiDto getKpiJson() {
+		return kpiJson;
+	}
+	public void setKpiJson(KpiDto kpiJson) {
+		this.kpiJson = kpiJson;
+	}
+	public List<PortalParamDto> getPortalParams() {
+		return portalParams;
+	}
+	public void setPortalParams(List<PortalParamDto> portalParams) {
+		this.portalParams = portalParams;
+	}
+	public List<CompParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<CompParamDto> params) {
+		this.params = params;
+	}
+	public Integer getHeight() {
+		return height;
+	}
+	public void setHeight(Integer height) {
+		this.height = height;
+	}
+	@Override
+	public void validate() {
+		this.name = RSBIUtils.htmlEscape(this.name);
+	}
+}

+ 95 - 0
src/main/java/com/ruisitech/bi/entity/portal/CompParamDto.java

@@ -0,0 +1,95 @@
+package com.ruisitech.bi.entity.portal;
+
+/**
+ * 组件参数dto
+ * @author hq
+ *
+ */
+public class CompParamDto {
+	
+	private String id;
+	private String col;
+	private String tname;
+	private String expression;
+	private String type;
+	private String val;
+	private String val2;
+	private String vtype;
+	private String valuetype;
+	private String usetype;
+	private String linkparam;
+	private String linkparam2;
+	public String getCol() {
+		return col;
+	}
+	public void setCol(String col) {
+		this.col = col;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getExpression() {
+		return expression;
+	}
+	public void setExpression(String expression) {
+		this.expression = expression;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getVal() {
+		return val;
+	}
+	public void setVal(String val) {
+		this.val = val;
+	}
+	public String getVal2() {
+		return val2;
+	}
+	public void setVal2(String val2) {
+		this.val2 = val2;
+	}
+	public String getValuetype() {
+		return valuetype;
+	}
+	public void setValuetype(String valuetype) {
+		this.valuetype = valuetype;
+	}
+	public String getUsetype() {
+		return usetype;
+	}
+	public void setUsetype(String usetype) {
+		this.usetype = usetype;
+	}
+	public String getLinkparam() {
+		return linkparam;
+	}
+	public void setLinkparam(String linkparam) {
+		this.linkparam = linkparam;
+	}
+	public String getLinkparam2() {
+		return linkparam2;
+	}
+	public void setLinkparam2(String linkparam2) {
+		this.linkparam2 = linkparam2;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getVtype() {
+		return vtype;
+	}
+	public void setVtype(String vtype) {
+		this.vtype = vtype;
+	}
+	
+}

+ 76 - 0
src/main/java/com/ruisitech/bi/entity/portal/GridColDto.java

@@ -0,0 +1,76 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+public class GridColDto extends BaseEntity {
+
+	private String id;
+	private String name;
+	private String dispName;
+	private String tname;
+	private String type;
+	private String expression;
+	private String fmt;
+	private String align;
+	private String sort;
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getExpression() {
+		return expression;
+	}
+	public void setExpression(String expression) {
+		this.expression = expression;
+	}
+	public String getDispName() {
+		return dispName;
+	}
+	public void setDispName(String dispName) {
+		this.dispName = dispName;
+	}
+	public String getFmt() {
+		return fmt;
+	}
+	public void setFmt(String fmt) {
+		this.fmt = fmt;
+	}
+	public String getAlign() {
+		return align;
+	}
+	public void setAlign(String align) {
+		this.align = align;
+	}
+	public String getSort() {
+		return sort;
+	}
+	public void setSort(String sort) {
+		this.sort = sort;
+	}
+	@Override
+	public void validate() {
+		this.name = RSBIUtils.htmlEscape(this.name);
+		this.dispName = RSBIUtils.htmlEscape(this.dispName);
+	}
+}

+ 100 - 0
src/main/java/com/ruisitech/bi/entity/portal/GridQuery.java

@@ -0,0 +1,100 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.List;
+
+public class GridQuery extends BaseEntity {
+
+	private String id;
+	private String type;
+	private String name;
+	private String dsetId;
+	private String dsid;
+	private List<GridColDto> cols;
+	private List<PortalParamDto> portalParams;
+	private List<CompParamDto> params;
+	
+	private String lockhead;
+	private Integer height;
+	private Integer pageSize;
+	private String isnotfy;
+	
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public List<GridColDto> getCols() {
+		return cols;
+	}
+	public void setCols(List<GridColDto> cols) {
+		this.cols = cols;
+	}
+	public List<PortalParamDto> getPortalParams() {
+		return portalParams;
+	}
+	public void setPortalParams(List<PortalParamDto> portalParams) {
+		this.portalParams = portalParams;
+	}
+	public List<CompParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<CompParamDto> params) {
+		this.params = params;
+	}
+	public String getLockhead() {
+		return lockhead;
+	}
+	public void setLockhead(String lockhead) {
+		this.lockhead = lockhead;
+	}
+	public Integer getHeight() {
+		return height;
+	}
+	public void setHeight(Integer height) {
+		this.height = height;
+	}
+	public Integer getPageSize() {
+		return pageSize;
+	}
+	public void setPageSize(Integer pageSize) {
+		this.pageSize = pageSize;
+	}
+	public String getIsnotfy() {
+		return isnotfy;
+	}
+	public void setIsnotfy(String isnotfy) {
+		this.isnotfy = isnotfy;
+	}
+	@Override
+	public void validate() {
+		this.name = RSBIUtils.htmlEscape(this.name);
+	}
+}

+ 88 - 0
src/main/java/com/ruisitech/bi/entity/portal/LinkAcceptDto.java

@@ -0,0 +1,88 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+/**
+ * 事件接收
+ * @author hq
+ *
+ */
+public class LinkAcceptDto extends BaseEntity {
+
+	private Integer id;
+	private String col;
+	private String tableColKey;
+	private String alias;
+	private String type;
+	private String dftval;
+	private String valType;
+	private Integer calc;
+	private String tname;
+	private String dimTname;
+	
+	public Integer getId() {
+		return id;
+	}
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	public String getCol() {
+		return col;
+	}
+	public void setCol(String col) {
+		this.col = col;
+	}
+	public String getTableColKey() {
+		return tableColKey;
+	}
+	public void setTableColKey(String tableColKey) {
+		this.tableColKey = tableColKey;
+	}
+	public String getAlias() {
+		return alias;
+	}
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getDftval() {
+		return dftval;
+	}
+	public void setDftval(String dftval) {
+		this.dftval = dftval;
+	}
+	public String getValType() {
+		return valType;
+	}
+	public void setValType(String valType) {
+		this.valType = valType;
+	}
+	public Integer getCalc() {
+		return calc;
+	}
+	public void setCalc(Integer calc) {
+		this.calc = calc;
+	}
+	public String getTname() {
+		return tname;
+	}
+	public void setTname(String tname) {
+		this.tname = tname;
+	}
+	public String getDimTname() {
+		return dimTname;
+	}
+	public void setDimTname(String dimTname) {
+		this.dimTname = dimTname;
+	}
+	@Override
+	public void validate() {
+		
+	}
+	
+}

+ 73 - 0
src/main/java/com/ruisitech/bi/entity/portal/MobReportType.java

@@ -0,0 +1,73 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+
+public class MobReportType extends BaseEntity {
+
+	private Integer id;
+	private String name;
+	private String text;
+	private String note;
+	private Integer crtUser;
+	private Date crtDate;
+	private Integer ord;
+	private String iconCls;
+	public Integer getId() {
+		return id;
+	}
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getNote() {
+		return note;
+	}
+	public void setNote(String note) {
+		this.note = note;
+	}
+
+	public Integer getCrtUser() {
+		return crtUser;
+	}
+	public void setCrtUser(Integer crtUser) {
+		this.crtUser = crtUser;
+	}
+	public Date getCrtDate() {
+		return crtDate;
+	}
+	public void setCrtDate(Date crtDate) {
+		this.crtDate = crtDate;
+	}
+	public Integer getOrd() {
+		return ord;
+	}
+	public void setOrd(Integer ord) {
+		this.ord = ord;
+	}
+	public String getText() {
+		return text;
+	}
+	public void setText(String text) {
+		this.text = text;
+	}
+	public String getIconCls() {
+		return iconCls;
+	}
+	public void setIconCls(String iconCls) {
+		this.iconCls = iconCls;
+	}
+	@Override
+	public void validate() {
+		this.name = RSBIUtils.htmlEscape(this.name);
+		this.note = RSBIUtils.htmlEscape(this.note);
+		this.text = RSBIUtils.htmlEscape(this.text);
+	}
+}

+ 86 - 0
src/main/java/com/ruisitech/bi/entity/portal/Portal.java

@@ -0,0 +1,86 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.Date;
+
+public class Portal extends BaseEntity {
+	
+	private String pageId;
+	private Integer userId;
+	private String userName;
+	private String pageInfo;
+	private String pageName;
+	private String is3g;
+	private Integer cataId;
+	private String cataName;
+	private Date crtDate;
+	private Date updateDate;
+	
+	public String getPageId() {
+		return pageId;
+	}
+	public void setPageId(String pageId) {
+		this.pageId = pageId;
+	}
+	public Integer getUserId() {
+		return userId;
+	}
+	public void setUserId(Integer userId) {
+		this.userId = userId;
+	}
+	public String getPageInfo() {
+		return pageInfo;
+	}
+	public void setPageInfo(String pageInfo) {
+		this.pageInfo = pageInfo;
+	}
+	public String getPageName() {
+		return pageName;
+	}
+	public void setPageName(String pageName) {
+		this.pageName = pageName;
+	}
+	public String getIs3g() {
+		return is3g;
+	}
+	public void setIs3g(String is3g) {
+		this.is3g = is3g;
+	}
+	public Integer getCataId() {
+		return cataId;
+	}
+	public void setCataId(Integer cataId) {
+		this.cataId = cataId;
+	}
+	public Date getCrtDate() {
+		return crtDate;
+	}
+	public void setCrtDate(Date crtDate) {
+		this.crtDate = crtDate;
+	}
+	public Date getUpdateDate() {
+		return updateDate;
+	}
+	public void setUpdateDate(Date updateDate) {
+		this.updateDate = updateDate;
+	}
+	public String getUserName() {
+		return userName;
+	}
+	public void setUserName(String userName) {
+		this.userName = userName;
+	}
+	public String getCataName() {
+		return cataName;
+	}
+	public void setCataName(String cataName) {
+		this.cataName = cataName;
+	}
+	@Override
+	public void validate() {
+		this.pageName = RSBIUtils.htmlEscape(this.pageName);
+		this.pageId = RSBIUtils.htmlEscape(this.pageId);
+	}
+}

+ 119 - 0
src/main/java/com/ruisitech/bi/entity/portal/PortalChartQuery.java

@@ -0,0 +1,119 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.bireport.ChartJSONDto;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class PortalChartQuery {
+	
+	private String dsid;
+	private String dsetId;
+	private Integer compId;
+	private List<KpiDto> kpiJson;
+	/**
+	 * 提出 kpiJson 中 为 null的数据
+	 */
+	private List<KpiDto> useKpiJson;
+	private ChartJSONDto chartJson;
+	private List<PortalParamDto> portalParams;
+	private List<CompParamDto> params;
+	private String id;
+	private Integer cubeId;
+	private String name;
+	private String type;
+	
+	private Map<String, Object> style = new HashMap<String, Object>();
+	private Map<String, Integer> colors;  //系列颜色
+	
+	public List<PortalParamDto> getPortalParams() {
+		return portalParams;
+	}
+	public void setPortalParams(List<PortalParamDto> portalParams) {
+		this.portalParams = portalParams;
+	}
+	public List<CompParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<CompParamDto> params) {
+		this.params = params;
+	}
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public Integer getCompId() {
+		return compId;
+	}
+	public void setCompId(Integer compId) {
+		this.compId = compId;
+	}
+	public List<KpiDto> getKpiJson() {
+		if(useKpiJson == null){
+			useKpiJson = new ArrayList<KpiDto>();
+			for(KpiDto kpi: this.kpiJson){
+				if(kpi != null){
+					useKpiJson.add(kpi);
+				}
+			}
+		}
+		return useKpiJson;
+	}
+	public void setKpiJson(List<KpiDto> kpiJson) {
+		this.kpiJson = kpiJson;
+	}
+	public ChartJSONDto getChartJson() {
+		return chartJson;
+	}
+	public void setChartJson(ChartJSONDto chartJson) {
+		this.chartJson = chartJson;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public Map<String, Object> getStyle() {
+		return style;
+	}
+	public void setStyle(Map<String, Object> style) {
+		this.style = style;
+	}
+	public Map<String, Integer> getColors() {
+		return colors;
+	}
+	public void setColors(Map<String, Integer> colors) {
+		this.colors = colors;
+	}
+	
+}

+ 107 - 0
src/main/java/com/ruisitech/bi/entity/portal/PortalParamDto.java

@@ -0,0 +1,107 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.util.RSBIUtils;
+
+import java.util.List;
+import java.util.Map;
+
+public class PortalParamDto extends BaseEntity {
+
+	private String paramid;
+	private String defvalue;
+	private String type;
+	private String dtformat;
+	private String name;
+	private String valtype;
+	private String hiddenprm;
+	private String maxval;
+	private String minval;
+	private String id;
+	private Integer size;
+	private Map<String, Object> option;
+	private List<Map<String, Object>> values;
+	public String getParamid() {
+		return paramid;
+	}
+	public void setParamid(String paramid) {
+		this.paramid = paramid;
+	}
+	public String getDefvalue() {
+		return defvalue;
+	}
+	public void setDefvalue(String defvalue) {
+		this.defvalue = defvalue;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getDtformat() {
+		return dtformat;
+	}
+	public void setDtformat(String dtformat) {
+		this.dtformat = dtformat;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getValtype() {
+		return valtype;
+	}
+	public void setValtype(String valtype) {
+		this.valtype = valtype;
+	}
+	public String getHiddenprm() {
+		return hiddenprm;
+	}
+	public void setHiddenprm(String hiddenprm) {
+		this.hiddenprm = hiddenprm;
+	}
+	public String getMaxval() {
+		return maxval;
+	}
+	public void setMaxval(String maxval) {
+		this.maxval = maxval;
+	}
+	public String getMinval() {
+		return minval;
+	}
+	public void setMinval(String minval) {
+		this.minval = minval;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public Integer getSize() {
+		return size;
+	}
+	public void setSize(Integer size) {
+		this.size = size;
+	}
+	public Map<String, Object> getOption() {
+		return option;
+	}
+	public void setOption(Map<String, Object> option) {
+		this.option = option;
+	}
+	public List<Map<String, Object>> getValues() {
+		return values;
+	}
+	public void setValues(List<Map<String, Object>> values) {
+		this.values = values;
+	}
+	@Override
+	public void validate() {
+		this.name = RSBIUtils.htmlEscape(this.name);
+	}
+	
+}

+ 156 - 0
src/main/java/com/ruisitech/bi/entity/portal/PortalTableQuery.java

@@ -0,0 +1,156 @@
+package com.ruisitech.bi.entity.portal;
+
+import com.ruisitech.bi.entity.bireport.DimDto;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.common.BaseEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PortalTableQuery extends BaseEntity {
+
+	private String dsid;
+	private String dsetId;
+	private String id;
+	private Integer cubeId;
+	private String name;
+	private String type;
+	
+	private List<KpiDto> kpiJson;
+	private List<DimDto> cols;
+	private List<DimDto> rows;
+	
+	private Map<String, Object> link;
+	private LinkAcceptDto linkAccept;
+	
+	private List<PortalParamDto> portalParams;
+	private List<CompParamDto> params;
+	private String lockhead;
+	private String height;
+	private String showtitle;
+	private Map<String, Object> style;
+	
+	private List<Map<String, Object>> drillDim;
+	
+	public String getDsid() {
+		return dsid;
+	}
+	public void setDsid(String dsid) {
+		this.dsid = dsid;
+	}
+	public String getDsetId() {
+		return dsetId;
+	}
+	public void setDsetId(String dsetId) {
+		this.dsetId = dsetId;
+	}
+	public String getId() {
+		return id;
+	}
+	public void setId(String id) {
+		this.id = id;
+	}
+	public List<KpiDto> getKpiJson() {
+		return kpiJson;
+	}
+	public void setKpiJson(List<KpiDto> kpiJson) {
+		this.kpiJson = kpiJson;
+	}
+	public List<DimDto> getCols() {
+		return cols;
+	}
+	public void setCols(List<DimDto> cols) {
+		this.cols = cols;
+	}
+	public List<DimDto> getRows() {
+		return rows;
+	}
+	public void setRows(List<DimDto> rows) {
+		this.rows = rows;
+	}
+	public Map<String, Object> getLink() {
+		return link;
+	}
+	public void setLink(Map<String, Object> link) {
+		this.link = link;
+	}
+	
+	public LinkAcceptDto getLinkAccept() {
+		return linkAccept;
+	}
+	public void setLinkAccept(LinkAcceptDto linkAccept) {
+		this.linkAccept = linkAccept;
+	}
+	public List<PortalParamDto> getPortalParams() {
+		return portalParams;
+	}
+	public void setPortalParams(List<PortalParamDto> portalParams) {
+		this.portalParams = portalParams;
+	}
+	public List<CompParamDto> getParams() {
+		return params;
+	}
+	public void setParams(List<CompParamDto> params) {
+		this.params = params;
+	}
+	public Integer getCubeId() {
+		return cubeId;
+	}
+	public void setCubeId(Integer cubeId) {
+		this.cubeId = cubeId;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	
+	public List<Map<String, Object>> getDrillDim() {
+		return drillDim;
+	}
+	public void setDrillDim(List<Map<String, Object>> drillDim) {
+		this.drillDim = drillDim;
+	}
+	public String getLockhead() {
+		return lockhead;
+	}
+	public void setLockhead(String lockhead) {
+		this.lockhead = lockhead;
+	}
+	public String getHeight() {
+		return height;
+	}
+	public void setHeight(String height) {
+		this.height = height;
+	}
+	public List<DimDto> getDims(){
+		List<DimDto> ret = new ArrayList<DimDto>();
+		ret.addAll(this.cols);
+		ret.addAll(this.rows);
+		return ret;
+	}
+	public Map<String, Object> getStyle() {
+		return style;
+	}
+	public void setStyle(Map<String, Object> style) {
+		this.style = style;
+	}
+	public String getShowtitle() {
+		return showtitle;
+	}
+	public void setShowtitle(String showtitle) {
+		this.showtitle = showtitle;
+	}
+	@Override
+	public void validate() {
+		 
+	 }
+}

+ 19 - 0
src/main/java/com/ruisitech/bi/mapper/app/CollectMapper.java

@@ -0,0 +1,19 @@
+package com.ruisitech.bi.mapper.app;
+
+import com.ruisitech.bi.entity.app.Collect;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface CollectMapper {
+	
+	List<Collect> listCollect(@Param("userId") Integer userId);
+	
+	Integer collectExist(Collect collect);
+	
+	void addCollect(Collect collect);
+	
+	void delCollect(Collect collect);
+}

+ 14 - 0
src/main/java/com/ruisitech/bi/mapper/bireport/AreaMapper.java

@@ -0,0 +1,14 @@
+package com.ruisitech.bi.mapper.bireport;
+
+import com.ruisitech.bi.entity.bireport.Area;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface AreaMapper {
+	
+	List<Area> listCityByProvCode(@Param("code") String code);
+
+}

+ 32 - 0
src/main/java/com/ruisitech/bi/mapper/bireport/OlapMapper.java

@@ -0,0 +1,32 @@
+package com.ruisitech.bi.mapper.bireport;
+
+import com.ruisitech.bi.entity.bireport.OlapInfo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface OlapMapper {
+
+	List<Map<String, Object>> listDims(@Param("cubeId") Integer cubeId);
+	
+	OlapInfo getOlap(@Param("pageId") Integer pageId);
+	
+	List<OlapInfo> listreport(@Param("keyword") String keyword);
+	
+	void deleteOlap(@Param("pageId") Integer pageId);
+	
+	void insertOlap(OlapInfo olap);
+	
+	void renameOlap(OlapInfo olap);
+	
+	void updateOlap(OlapInfo olap);
+	
+	Integer maxOlapId();
+	
+	Integer olapExist(@Param("pageName") String pageName);
+	
+	List<Map<String, Object>> listKpiDesc(@Param("cubeId") Integer cubeId);
+}

+ 37 - 0
src/main/java/com/ruisitech/bi/mapper/frame/MenuMapper.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有 
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.mapper.frame;
+
+import com.ruisitech.bi.entity.frame.Menu;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface MenuMapper {
+	
+	List<Menu> listUserMenus(@Param("userId") Integer userId);
+
+	/**
+	 * 查询角色名称
+	 * @param roleIds
+	 * @return
+	 */
+	List<Menu> listRolesMenus(@Param("roleIds") List<Integer> roleIds);
+
+	/**
+	 * 根据角色名称获取角色ID列表
+	 * @param names
+	 * @return
+	 */
+	List<Integer> listRoleIdsByNames(@Param("names") List<String> names);
+
+	List<Map<String, Object>> listMenuByPid(@Param("pid") Integer pid);
+
+	Menu getById(@Param("menuId") Integer menuId);
+}

+ 27 - 0
src/main/java/com/ruisitech/bi/mapper/frame/RoleMapper.java

@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有 
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.mapper.frame;
+
+import com.ruisitech.bi.entity.frame.Role;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface RoleMapper {
+	
+	List<Map<String, Object>> listRoleMenus(@Param("roleId") Integer roleId);
+	
+	List<Map<String, Object>> roledata(@Param("roleId") Integer roleId);
+	
+	List<Role> list(@Param("keyword") String keyword);
+	
+	List<Role> listUserRole(@Param("userId") Integer userId);
+	
+	Role getById(@Param("roleId") Integer roleId);
+}

+ 36 - 0
src/main/java/com/ruisitech/bi/mapper/frame/UserMapper.java

@@ -0,0 +1,36 @@
+package com.ruisitech.bi.mapper.frame;
+
+import com.ruisitech.bi.entity.frame.User;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface UserMapper {
+
+	User getUserByStaffId(String staffId);
+	
+	User getUserById(@Param("userId") Integer userId);
+	
+	void updateuser(User user);
+	
+	void insertuser(User user);
+	
+	List<Map<String, Object>> listUserMenus(@Param("userId") Integer userId);
+
+	List<User> listUsers(@Param("keyword") String keyword);
+
+	void updateLogDateAndCnt(@Param("userId") Integer userId, @Param("dbName") String dbName);
+	
+	String checkPsd(@Param("userId") Integer userId);
+	
+	void modPsd(User user);
+	
+	Map<String, Object> appUserinfo(@Param("userId") Integer userId);
+
+	int userExist(@Param("staffId") String staffId);
+
+	int maxUserId( );
+}

+ 19 - 0
src/main/java/com/ruisitech/bi/mapper/model/CubeColMetaMapper.java

@@ -0,0 +1,19 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.CubeColMeta;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface CubeColMetaMapper {
+	
+	void insertMeta(CubeColMeta meta);
+	
+	Integer getMaxRid();
+
+	void deleteKpiMeta(@Param("cubeId") Integer cubeId);
+	
+	void deleteDimMeta(@Param("cubeId") Integer cubeId);
+	
+	void deleteByCubeId(@Param("cubeId") Integer cubeId);
+}

+ 32 - 0
src/main/java/com/ruisitech/bi/mapper/model/CubeMapper.java

@@ -0,0 +1,32 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.Cube;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface CubeMapper {
+
+	List<Cube> listCube(@Param("keyword") String keyword);
+	
+	Integer getMaxCubeId();
+	
+	void insertCube(Cube cube);
+	
+	void updateCube(Cube cube);
+	
+	void deleteCube(@Param("cubeId") Integer cubeId);
+	
+	Cube getCubeById(@Param("cubeId") Integer cubeId);
+	
+	List<Map<String, Object>> getCubeDims(@Param("cubeId") Integer cubeId);
+	
+	List<Map<String, Object>> getCubeKpis(@Param("cubeId") Integer cubeId);
+	
+	List<Map<String, Object>> listCubeMeta(@Param("cubeId") Integer cubeId);
+	
+	List<Map<String, Object>> listDs(@Param("selectDsIds") String selectDsIds);
+}

+ 21 - 0
src/main/java/com/ruisitech/bi/mapper/model/DataSourceMapper.java

@@ -0,0 +1,21 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.DataSource;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface DataSourceMapper {
+
+	List<DataSource> listDataSource();
+	
+	void insertDataSource(DataSource ds);
+	
+	void updateDataSource(DataSource ds);
+	
+	void deleteDataSource(@Param("dsid") String dsid);
+	
+	DataSource getDataSource(@Param("dsid") String dsid);
+}

+ 23 - 0
src/main/java/com/ruisitech/bi/mapper/model/DatasetMapper.java

@@ -0,0 +1,23 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.Dataset;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface DatasetMapper {
+
+	List<Dataset> listDataset();
+	
+	void updateDset(Dataset ds);
+	
+	void insertDset(Dataset ds);
+	
+	void deleteDset(@Param("dsetId") String dsetId);
+	
+	String getDatasetCfg(@Param("dsetId") String dsetId);
+	
+	void updateDsetCfg(Dataset ds);
+}

+ 32 - 0
src/main/java/com/ruisitech/bi/mapper/model/DimensionMapper.java

@@ -0,0 +1,32 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.Dimension;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface DimensionMapper {
+	
+	void insertDim(Dimension dim);
+	
+	void updatedim(Dimension dim);
+	
+	void deleteDim(Dimension dim);
+	
+	void insertGroup(Dimension dim);
+	
+	Integer getMaxDimId();
+	
+	void deleteGroupById(@Param("groupId") String groupId);
+		
+	void deleteGroupByCubeId(@Param("cubeId") Integer cubeId);
+	
+	List<String> listGroup(@Param("cubeId") Integer cubeId);
+	
+	Dimension getDimInfo(@Param("dimId") Integer dimId, @Param("cubeId") Integer cubeId);
+	
+	void updateColType(Map<String, Object> dim);
+}

+ 16 - 0
src/main/java/com/ruisitech/bi/mapper/model/MeasureMapper.java

@@ -0,0 +1,16 @@
+package com.ruisitech.bi.mapper.model;
+
+import com.ruisitech.bi.entity.model.Measure;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MeasureMapper {
+
+	void insertKpi(Measure kpi);
+	
+	void updateKpi(Measure kpi);
+	
+	void deleteKpi(Measure kpi);
+	
+	int getMaxKpiId();
+}

+ 25 - 0
src/main/java/com/ruisitech/bi/mapper/portal/MobReportTypeMapper.java

@@ -0,0 +1,25 @@
+package com.ruisitech.bi.mapper.portal;
+
+import com.ruisitech.bi.entity.portal.MobReportType;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface MobReportTypeMapper {
+
+	List<MobReportType> listcataTree();
+	
+	void insertType(MobReportType type);
+	
+	void updateType(MobReportType type);
+	
+	void deleleType(@Param("id") Integer id);
+	
+	MobReportType getType(@Param("id") Integer id);
+	
+	Integer cntReport(@Param("id") Integer id);
+	
+	Integer maxTypeId();
+}

+ 30 - 0
src/main/java/com/ruisitech/bi/mapper/portal/PortalMapper.java

@@ -0,0 +1,30 @@
+package com.ruisitech.bi.mapper.portal;
+
+import com.ruisitech.bi.entity.portal.Portal;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface PortalMapper {
+
+	List<Portal> listPortal();
+	
+	String getPortalCfg(@Param("pageId") String pageId);
+	
+	List<Portal> list3g(@Param("cataId") Integer cataId);
+	
+	void insertPortal(Portal portal);
+	
+	Portal getPortal(@Param("pageId") String pageId);
+	
+	void updatePortal(Portal portal);
+	
+	void deletePortal(@Param("pageId") String pageId);
+	
+	void renamePortal(Portal portal);
+	
+	List<Map<String, Object>> listAppReport(@Param("userId") Integer userId, @Param("cataId") Integer cataId);
+}

+ 38 - 0
src/main/java/com/ruisitech/bi/service/app/CollectService.java

@@ -0,0 +1,38 @@
+package com.ruisitech.bi.service.app;
+
+import com.ruisitech.bi.entity.app.Collect;
+import com.ruisitech.bi.mapper.app.CollectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class CollectService {
+
+	@Autowired
+	private CollectMapper mapper;
+	
+	public List<Collect> listCollect(Integer userId, String basePath){
+		List<Collect> ls = mapper.listCollect(userId);
+		for(int i=0; i<ls.size(); i++){
+			Collect m = ls.get(i);
+			String url = basePath + "app/Report!view.action?rid=" + m.getRid();
+			m.setUrl(url);
+		}
+		return ls;
+	}
+	
+	public Integer collectExist(Collect collect){
+		return mapper.collectExist(collect);
+	}
+	
+	public void addCollect(Collect collect){
+		mapper.addCollect(collect);
+	}
+	
+	public void delCollect(Collect collect){
+		mapper.delCollect(collect);
+	}
+	
+}

+ 371 - 0
src/main/java/com/ruisitech/bi/service/bireport/BaseCompService.java

@@ -0,0 +1,371 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.dsource.DataSourceContext;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisi.ext.engine.view.context.form.TextFieldContext;
+import com.ruisi.ext.engine.view.context.form.TextFieldContextImpl;
+import com.ruisi.ext.engine.view.exception.ExtConfigException;
+import com.ruisi.ispire.dc.grid.GridShift;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.model.DataSource;
+import com.ruisitech.bi.entity.portal.CompParamDto;
+import com.ruisitech.bi.entity.portal.PortalChartQuery;
+import com.ruisitech.bi.entity.portal.PortalParamDto;
+import com.ruisitech.bi.entity.portal.PortalTableQuery;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 组件基类Service
+ * @author hq
+ *
+ */
+public abstract class BaseCompService {
+	
+	protected JSONObject pageBody; //页面配置信息
+
+	public Map<String, String> createTableAlias(JSONObject dset){
+		Map<String, String> tableAlias = new HashMap<String, String>();
+		tableAlias.put(dset.getString("master"), "a0");
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		for(int i=0; joinTabs != null && i<joinTabs.size(); i++){
+			JSONObject tab = joinTabs.getJSONObject(i);
+			tableAlias.put(tab.getString("ref"), "a" + (i+1));
+		}
+		return tableAlias;
+	}
+	
+	public String createDsource(DataSource ds, MVContext mv){
+		DataSourceContext dsource = new DataSourceContext();
+		dsource.putProperty("id", ds.getDsid());
+		String use = dsource.getUse();
+		dsource.putProperty("usetype", use);
+		if(use == null || "jdbc".equalsIgnoreCase(use.toString())){
+			String linktype = ds.getLinkType();
+			dsource.putProperty("linktype", linktype);
+			dsource.putProperty("linkname", ds.getLinkName());
+			dsource.putProperty("linkpwd", ds.getLinkPwd());
+			dsource.putProperty("linkurl", ds.getLinkUrl());
+		}else{
+			dsource.putProperty("jndiname", ds.getJndiName());
+		}
+		//放入MV
+		if(mv.getDsources() == null){
+			mv.setDsources(new HashMap<String, DataSourceContext>());
+		}
+		mv.getDsources().put(dsource.getId(), dsource);
+		return dsource.getId();
+	}
+	
+	public int type2value(String tp){
+		int curDate = 4;;
+		if(tp.equals("year")){
+			curDate = 4;
+		}else if(tp.equals("quarter")){
+			curDate = 3;
+		}else if(tp.equals("month")){
+			curDate = 2;
+		}else if(tp.equals("day")){
+			curDate = 1;
+		}
+		return curDate;
+	}
+	
+	public String loadFieldName(String aggre) {
+		if("sum".equalsIgnoreCase(aggre)){
+			return "合计值";
+		}else if("avg".equalsIgnoreCase(aggre)){
+			return "均值";
+		}else if("max".equalsIgnoreCase(aggre)){
+			return "最大值";
+		}else if("min".equalsIgnoreCase(aggre)){
+			return "最小值";
+		}else if("count".equalsIgnoreCase(aggre)){
+			return "计数";
+		}else if("var".equalsIgnoreCase(aggre)){
+			return "方差";
+		}else if("sd".equalsIgnoreCase(aggre)){
+			return "标准差";
+		}else if("middle".equalsIgnoreCase(aggre)){
+			return "中位数";
+		}else{
+			return "合计";
+		}
+	}
+	
+	public String resetVals(String inputval, String type, String dateFormat, int jstype){
+		if(jstype == 0){
+			return inputval;
+		}
+		String[] vals = inputval.split(",");
+		List<String> rets = new ArrayList<String>();
+		for(String val : vals){
+			//先添加他自己
+			if(!rets.contains(val)){
+				rets.add(val);
+			}
+			if(jstype == 1 || jstype == 3){ //上期
+				String nval = GridShift.getDateShiftValue(val, type, dateFormat, "sq");
+				if(!rets.contains(nval)){
+					rets.add(nval);
+				}
+			}
+			if(jstype == 2 || jstype == 3){ //同期
+				String nval = GridShift.getDateShiftValue(val, type, dateFormat, "tq");
+				if(!rets.contains(nval)){
+					rets.add(nval);
+				}
+			}
+		}
+		return list2String(rets);
+	}
+	
+	public String list2String(List<String> rets){
+		StringBuffer sb = new StringBuffer();
+		for(int i=0; i<rets.size(); i++){
+			String ret = rets.get(i);
+			sb.append(ret);
+			if(i != rets.size() - 1){
+				sb.append(",");
+			}
+		}
+		return sb.toString();
+	}
+	
+	/**
+	 * 根据指标计算的值筛选,从新设置时间字段的数据区间,主要针对日、月份的数据区间控制
+	 */
+	public String[] resetBetween(String start, String end, String type, String dateFormat, int jstype){
+		if(jstype == 0){ //无计算
+			return new String[]{start, end};
+		}
+		if("day".equals(type)){
+			if(jstype == 1 || jstype == 3){ //上期
+				String nval = GridShift.getDateShiftValue(start, type, dateFormat, "sq");
+				start = nval;
+			}
+			if(jstype == 2 || jstype == 3){ //同期
+				String nval2 = GridShift.getDateShiftValue(start, type, dateFormat, "tq");
+				start = nval2;
+			}
+			return new String[]{start, end};
+		}else if("month".equals(type)){
+			if(jstype == 1 || jstype == 3){ //上期
+				String nval = GridShift.getDateShiftValue(start, type, dateFormat, "sq");
+				start = nval;
+			}
+			if(jstype == 2 || jstype == 3){ //同期
+				String nval = GridShift.getDateShiftValue(start, type, dateFormat, "tq");
+				start = nval;
+			}
+			return new String[]{start, end};
+		}else{
+			return null;
+		}
+	}
+	
+	//输出单位比例
+	public String writerUnit(Integer bd){
+		if(bd == null){
+			return "";
+		}else{
+			int v = bd.intValue();
+			if(v == 1){
+				return "";
+			}else if(v == 100){
+				return "百";
+			}else if(v == 1000){
+				return "千";
+			}else if(v == 10000){
+				return "万";
+			}else if(v == 1000000){
+				return "百万";
+			}else if(v == 100000000){
+				return "亿";
+			}else{
+				return "*" + v;
+			}
+		}
+	}
+	
+	public void parserHiddenParam(List<PortalParamDto> params, MVContext mv, Map<String, InputField> mvParams) throws ExtConfigException {
+		if(params != null){
+			for(int i=0; i<params.size(); i++){
+				PortalParamDto param = params.get(i);
+				TextFieldContext target = new TextFieldContextImpl();
+				target.setId(param.getParamid());
+				String defvalue = param.getDefvalue();
+				String type = param.getType();
+				String dtformat = param.getDtformat();
+				if(("dateselect".equals(type) || "monthselect".equals(type) || "yearselect".equals(type) )&& "now".equals(defvalue)){
+					defvalue = new SimpleDateFormat(dtformat).format(new Date());
+				}
+				target.setValue(defvalue);
+				target.setType("hidden");
+				mvParams.put(target.getId(), target);
+				ExtContext.getInstance().putServiceParam(mv.getMvid(), target.getId(), target);
+				
+				
+				mv.getChildren().add(target);
+				target.setParent(mv);
+			}
+		}
+	}
+	
+	/**
+	 * nodetype 表示筛选的类型,分为维度筛选和指标筛选两类,维度筛选和指标筛选对应的SQL位置不一样,维度放where 后, 指标放 having 后
+	 * @param params
+	 * @param nodetype
+	 * @return
+	 */
+	public String dealCubeParams(List<CompParamDto> params, Map<String, String> tableAlias){
+		StringBuffer sb = new StringBuffer("");
+		for(int i=0; params != null && i<params.size(); i++){
+			CompParamDto param = params.get(i);
+
+			String col = param.getCol();
+			String type = param.getType();
+			String val = param.getVal();
+			String val2 = param.getVal2();
+			String valuetype = param.getValuetype();
+			String usetype = param.getUsetype();
+			String linkparam = param.getLinkparam();
+			String linkparam2 = param.getLinkparam2();
+			String tname = param.getTname();
+			col = tableAlias.get(tname)+"." + col;  //加上别名
+			
+			if(type.equals("like")){
+				if(val != null){
+					val = "%"+val+"%";
+				}
+				if(val2 != null){
+					val2 = "%"+val2+"%";
+				}
+			}
+			if("string".equals(valuetype)){
+				if(val != null){
+					if("in".equals(type)){  //in需要把数据用逗号分隔的重新生成
+						String[] vls = val.split(",");
+						val = "";
+						for(int j=0; j<vls.length; j++){
+							val = val + "'" + vls[j] + "'";
+							if(j != vls.length - 1){
+								val = val + ",";
+							}
+						}
+					}else{
+						val = "'" + val + "'";
+					}
+				}
+				if(val2 != null){
+					val2 = "'" + val2 + "'";
+				}
+			}
+			if(type.equals("between")){
+				if(usetype.equals("gdz")){
+					sb.append(" and " +  col + " " + type + " " + val + " and " + val2);
+				}else{
+					sb.append("#if([x]"+linkparam+" != '' && [x]"+linkparam2+" != '') ");
+					sb.append(" and "  + col + " " + type + " " + ("string".equals(valuetype)?"'":"") + "[x]"+linkparam +("string".equals(valuetype)?"'":"") + " and " + ("string".equals(valuetype)?"'":"")+ "[x]"+linkparam2 + ("string".equals(valuetype)?"'":"") + " #end");
+				}
+			}else if(type.equals("in")){
+				if(usetype.equals("gdz")){
+					sb.append(" and " + col + " in (" + val + ")");
+				}else{
+					sb.append("#if([x]"+linkparam+" != '') ");
+					sb.append(" and " + col + " in (" + "$extUtils.printVals([x]"+linkparam + ", '"+valuetype+"'))");
+					sb.append("  #end");
+				}
+			}else{
+				if(usetype.equals("gdz")){
+					sb.append(" and " + col + " " + type + " " + val);
+				}else{
+					sb.append("#if([x]"+linkparam+" != '') ");
+					sb.append(" and " + col + " "+type+" " + ("string".equals(valuetype) ? "'"+("like".equals(type)?"%":"")+""+"[x]"+linkparam+""+("like".equals(type)?"%":"")+"'":"[x]"+linkparam) + "");
+					sb.append("  #end");
+				}
+			}
+		}
+		return sb.toString().replaceAll("\\[x\\]", "\\$");
+	}
+	
+	/**
+	 * 获取字段别名
+	 * @param kpi
+	 * @param tableAlias
+	 * @return
+	 */
+	public String convertKpiName(KpiDto kpi, Map<String, String> tableAlias){
+		String colName = kpi.getCol_name();
+		String tname = kpi.getTname();
+		if(tname == null || tname.length() == 0){
+			return colName;
+		}
+		String alias = tableAlias.get(kpi.getTname()) + ".";
+		String name = colName.replaceAll("\\((\\S+)\\)", "(" + alias+"$1" + ")");
+		return name;
+	}
+	
+	/**
+	 * 组件联动时,获取 paranName
+	 * @param compId
+	 * @return
+	 */
+	public String findEventParamName(String compId){
+		if(pageBody == null){
+			throw new RuntimeException("pageBody 未初始化...");
+		}
+		String paramName = null;
+		for(int i=1; true; i++){
+			Object tmp = pageBody.get("tr" + i);
+			if(tmp == null){
+				break;
+			}
+			JSONArray trs = (JSONArray)tmp;
+			for(int j=0; j<trs.size(); j++){
+				JSONObject td = trs.getJSONObject(j);
+				Object cldTmp = td.get("children");
+				if(cldTmp != null){
+					JSONArray children = (JSONArray)cldTmp;
+					for(int k=0; k<children.size(); k++){
+						JSONObject comp = children.getJSONObject(k);
+						String type = comp.getString("type");
+						if("chart".equals(type)){
+							PortalChartQuery chart = JSONObject.toJavaObject(comp, PortalChartQuery.class);
+							Map<String, Object> link = chart.getChartJson().getLink();
+							if(link != null){
+								String target = (String)link.get("target");
+								if(target != null && target.indexOf(compId) >= 0){
+									paramName = (String)link.get("paramName");
+									break;
+								}
+							}
+						}else if("table".equals(type)){
+							PortalTableQuery table = JSONObject.toJavaObject(comp, PortalTableQuery.class);
+							Map<String, Object> link =  table.getLink();
+							if(link != null){
+								String target = (String)link.get("target");
+								if(target != null && target.indexOf(compId) >= 0){
+									paramName = (String)link.get("paramName");
+									break;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		return paramName;
+	}
+
+	public void setPageBody(JSONObject pageBody) {
+		this.pageBody = pageBody;
+	}
+	
+	
+}

+ 579 - 0
src/main/java/com/ruisitech/bi/service/bireport/ChartService.java

@@ -0,0 +1,579 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.bi.engine.view.context.chart.ChartContext;
+import com.ruisi.bi.engine.view.context.chart.ChartContextImpl;
+import com.ruisi.bi.engine.view.context.chart.ChartKeyContext;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContextImpl;
+import com.ruisi.ext.engine.view.context.dc.grid.GridFilterContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridSetConfContext;
+import com.ruisi.ext.engine.view.context.html.TextContext;
+import com.ruisi.ext.engine.view.context.html.TextContextImpl;
+import com.ruisi.ispire.dc.grid.GridFilter;
+import com.ruisitech.bi.entity.bireport.*;
+import com.ruisitech.bi.mapper.bireport.AreaMapper;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.ext.service.DataControlInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Scope("prototype")
+public class ChartService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.chart.tmp";
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	@Autowired
+	private AreaMapper areaMapper;
+	@Autowired
+	private DataControlInterface dataControl; //数据权限控制
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		
+	}
+	
+	public MVContext json2MV(ChartQueryDto chart, boolean xlsdata) throws Exception{
+		
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		
+	
+		if(!xlsdata){
+			//创建图形钻取项
+			this.createChartDrill(mv, chart);
+		}
+		
+		//创建chart
+		ChartContext cr = this.json2Chart(chart.getChartJson(), chart.getKpiJson(), false);
+		cr.setXlsData(xlsdata);
+		
+		String sql = this.createSql(chart, 0);
+		GridDataCenterContext dc = this.createDataCenter(chart.getChartJson(), sql);
+		cr.setRefDataCenter(dc.getId());
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		
+		Map<String, ChartContext> crs = new HashMap<String, ChartContext>();
+		crs.put(cr.getId(), cr);
+		mv.setCharts(crs);
+		
+		String dsid = createDsource(cacheService.getDsource(chart.getDsid()), mv);
+		dc.getConf().setRefDsource(dsid);
+		
+		return mv;
+	}
+	
+	public ChartContext json2Chart(ChartJSONDto chartJson, List<KpiDto> kpiJson, boolean is3g){
+		ChartContext ctx = new ChartContextImpl();
+		ctx.setLabel(chartJson.getLabel());
+		//设置x
+		DimDto xcol = chartJson.getXcol();
+		if(xcol != null){
+			String tp = xcol.getType();
+			String alias = xcol.getAlias();
+			String key = xcol.getTableColKey();
+			String txt = xcol.getTableColName();
+			if("day".equals(tp)){
+				ctx.setDateType(tp);
+				ctx.setDateTypeFmt(xcol.getDateformat());
+			}
+			if(key != null && key.length() > 0 && txt != null && txt.length() > 0){  //只有在维度关联了维度表后才进行判断
+				ctx.setXcolDesc(key); //用来关联ID,用在钻取中
+				ctx.setXcol(txt);
+			}else{
+				ctx.setXcolDesc(alias);
+				ctx.setXcol(alias);
+			}
+		}
+		
+		
+		KpiDto kpiInfo = kpiJson.get(0);
+		String y = kpiInfo.getAlias();
+		ctx.setYcol(y);
+		
+		//如果是散点图或气泡图,需要 y2col
+		if(kpiJson.size() > 1 && kpiJson.get(1) != null){
+			ctx.setY2col(kpiJson.get(1).getAlias());
+		}
+		if(kpiJson.size() > 2 && kpiJson.get(2) != null){
+			ctx.setY3col(kpiJson.get(2).getAlias());
+		}
+		DimDto scol = chartJson.getScol();
+		if(scol != null){
+			String alias = scol.getAlias();
+			String key = scol.getTableColKey();
+			String txt = scol.getTableColName();
+			if(key != null && key.length() > 0 && txt != null && txt.length() > 0){  //只有在维度关联了维度表后才进行判断
+				ctx.setScol(txt); //用来关联ID,用在钻取中
+			}else{
+				ctx.setScol(alias);
+			}
+		}
+		
+		ctx.setShape(chartJson.getType());
+		if(is3g){
+			//手机页面,宽度设置为100%
+			ctx.setWidth("100%");
+		}else{
+			ctx.setWidth("auto");
+		}
+		ctx.setHeight("240");
+		
+		//设置ID
+		String chartId = ExtConstants.chartIdPrefix + IdCreater.create();
+		ctx.setId(chartId);
+		
+		//设置配置信息
+		List<ChartKeyContext> properties = new ArrayList<ChartKeyContext>();
+		ChartKeyContext val1 = new ChartKeyContext("margin", is3g?"30, 20, 50, 75":"30, 20, 50, 90");  //手机页面减少左边距
+		properties.add(val1);
+		
+		//设置倍率  (在SQL中获取基本单位,运算单位(万、千、百万)等通过倍率获取 )
+		if(kpiInfo.getRate() != null){
+			ctx.setRate(kpiInfo.getRate());
+		}
+		if(kpiJson.size() > 1 && kpiJson.get(1) != null){
+			ctx.setRate2(kpiJson.get(1).getRate());
+		}
+		if(kpiJson.size() > 2 && kpiJson.get(2) != null){
+			ctx.setRate3(kpiJson.get(2).getRate());
+		}
+		
+		properties.add(new ChartKeyContext("ydesc",kpiInfo.getKpi_name()+ "(" + super.writerUnit(kpiInfo.getRate()) +kpiInfo.getUnit()+")"));
+		
+		//格式化配置信息
+		if(kpiInfo.getFmt() != null && kpiInfo.getFmt().length() > 0){
+			properties.add(new ChartKeyContext("formatCol","kpi_fmt"));
+		}
+		
+		if(kpiInfo.getUnit() != null && kpiInfo.getUnit().length() > 0){
+			properties.add(new ChartKeyContext("unitCol","kpi_unit"));
+		}
+		//启用钻取
+		properties.add(new ChartKeyContext("action","drillChart"));
+		
+		if("pie".equals(ctx.getShape())){
+			properties.add(new ChartKeyContext("showLegend","true"));
+			//ctx.setHeight("280"); //重新设置高度,宽度
+			if(!is3g){
+				ctx.setWidth("600");
+			}
+		}
+		if("gauge".equals(ctx.getShape()) && !is3g){
+			ctx.setWidth("210");
+		}
+		if("radar".equals(ctx.getShape()) && !is3g){
+			ctx.setHeight("340"); //重新设置雷达图的高度
+		}
+		if("map".equals(ctx.getShape()) && !is3g){
+			ctx.setWidth("600");
+			ctx.setHeight("350");
+		}
+		if("bubble".equals(ctx.getShape()) || "scatter".equals(ctx.getShape())){
+			KpiDto kpiInfo2 = kpiJson.get(1);
+			//对于散点图和气泡图,需要设置xdesc
+			properties.add(new ChartKeyContext("xdesc", kpiInfo2.getKpi_name() + "(" +  super.writerUnit(kpiInfo2.getRate()) +kpiInfo2.getUnit()+")"));
+			properties.add(new ChartKeyContext("formatCol2", kpiInfo2.getFmt()));
+			properties.add(new ChartKeyContext("unitCol2", kpiInfo2.getUnit()));
+			//设置气泡图
+			if("bubble".equals(ctx.getShape())){
+				KpiDto kpiInfo3 = kpiJson.get(2);
+				properties.add(new ChartKeyContext("formatCol3", kpiInfo3.getFmt()));
+				properties.add(new ChartKeyContext("unitCol3", kpiInfo3.getUnit()));
+			}
+		}
+		//对于曲线图、柱状图设置图例位置
+		if("line".equals(ctx.getShape()) || "column".equals(ctx.getShape())){
+			properties.add(new ChartKeyContext("legendLayout","horizontal"));
+		}
+		//饼图不显示Legend
+		if("pie".equals(ctx.getShape())){
+			properties.add(new ChartKeyContext("showLegend","false"));
+		}
+		
+		//如果是地图,需要设置地图的 mapJson
+		if("map".equals(ctx.getShape())){
+			properties.add(new ChartKeyContext("mapJson",chartJson.getMaparea()));
+		}
+		//手机页面,横轴旋转角度
+		if(is3g){
+			properties.add(new ChartKeyContext("routeXaxisLable","-45"));
+		}
+		//不显示值
+		properties.add(new ChartKeyContext("showLabel", "false"));
+		
+		ctx.setProperties(properties);
+		
+		return ctx;
+	}
+	
+	/**
+	 * 创建sql语句所用函数,图形用这个函数创建SQL
+	 * 其中第二个参数只用在图形中,当用户没选X轴时(xcol)时,用这个做默认xcol
+	 * 其中第三个参数只用在图形中,当用户没选图例(scol)时,用这个做默认图例
+	 * release 表示当前为发布状态, 0 表示不是发布,1表示发布到多维分析,2表示发布到仪表盘
+	 * @param sqlVO
+	 * @param ser
+	 * @return
+	 * @throws ParseException
+	 */
+	public String createSql(ChartQueryDto chart, int release) throws ParseException{
+		Map<String, String> tableAlias = super.createTableAlias(this.cacheService.getDset(chart.getDsetId()));
+		
+		StringBuffer sql = new StringBuffer();
+		
+		sql.append("select ");
+		List<DimDto> dims = chart.getChartJson().getDims();
+		for(int i=0; i<dims.size(); i++){
+			DimDto dim = dims.get(i);
+			String key = dim.getTableColKey();
+			String txt = dim.getTableColName();
+			String tname = dim.getTableName();
+			if(key != null && txt != null && key.length() >0 && txt.length() >0){
+				sql.append(tableAlias.get(tname)+"."+key+", " + tableAlias.get(tname) +"."+ txt + ",");
+			}else{
+				if(dim.getCalc() == 1){ 
+					sql.append(" "+dim.getColname()+" as "+dim.getAlias()+", ");
+				}else{
+					sql.append(" " + tableAlias.get(dim.getTname()) + "."+dim.getColname()+" as "+dim.getAlias()+", ");
+				}
+			}
+			
+		}
+		
+		//判断是否添加 格式化 字段
+		KpiDto info = chart.getKpiJson().get(0);
+		if(info.getFmt() != null && info.getFmt().length() > 0){
+			sql.append("'"+info.getFmt()+"' kpi_fmt,");
+		}
+		//判断是否添加单位字段
+		if(info.getUnit() != null && info.getUnit().length() > 0){
+			//sql.append("'" + ChartService.formatUnits(info)+info.getUnit()+"' kpi_unit,");
+			sql.append("'" + info.getUnit()+"' kpi_unit,");
+		}
+		
+		//第二个指标
+		if(chart.getKpiJson().size() > 1){
+			KpiDto sinfo = chart.getKpiJson().get(1);
+			if(sinfo.getFmt() != null && sinfo.getFmt().length() > 0){
+				sql.append("'"+sinfo.getFmt()+"' kpi_fmt2,");
+			}
+			if(sinfo.getUnit() != null && sinfo.getUnit().length() > 0){
+				sql.append("'" +sinfo.getUnit()+"' kpi_unit2,");
+			}
+		}
+		//第三个指标
+		if(chart.getKpiJson().size() > 2){
+			KpiDto sinfo = chart.getKpiJson().get(2);
+			if(sinfo.getFmt() != null && sinfo.getFmt().length() > 0){
+				sql.append("'"+sinfo.getFmt()+"' kpi_fmt3,");
+			}
+			if(sinfo.getUnit() != null && sinfo.getUnit().length() > 0){
+				sql.append("'" +sinfo.getUnit()+"' kpi_unit3,");
+			}
+		}
+		
+		List<KpiDto> kpis = chart.getKpiJson();
+		if(kpis.size() == 0){
+			sql.append(" 0 kpi_value ");
+		}else{
+			for(int i=0; i<kpis.size(); i++){
+				KpiDto kpi = kpis.get(i);
+				if(kpi.getCalc() != null && kpi.getCalc() == 1){  //表达式,直接取表达式
+					sql.append(kpi.getCol_name() + " ");
+				}else{  //获取字段别名
+					String name = super.convertKpiName(kpi, tableAlias);
+					sql.append( name + " ");
+				}
+				sql.append(kpi.getAlias());
+				if(i != kpis.size() - 1){
+					sql.append(",");
+				}
+			}
+		}
+		
+		JSONObject dset = this.cacheService.getDset(chart.getDsetId());
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		String master = dset.getString("master");
+		sql.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sql.append(" " + jtype);
+			}
+			sql.append(" join " + ref+ " " + tableAlias.get(ref));
+			sql.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sql.append(" ");
+		}
+		sql.append(" where 1=1 ");
+		
+		//数据权限控制筛选
+		if(dataControl != null){
+			String ret = dataControl.process(RSBIUtils.getLoginUserInfo(),  dset.getString("master"));
+			if(ret != null){
+				sql.append(ret + " ");
+			}
+		}
+		for(int i=0; i<dims.size(); i++){
+			DimDto dim = dims.get(i);
+			//处理日期限制
+			if(dim.getType().equals("day")){
+				if(dim.getDay() != null){
+					sql.append(" and " + dim.getColname() + " between '"+dim.getDay().getStartDay()+"' and '" + dim.getDay().getEndDay()+"'");
+				}else
+				if(dim.getVals() != null && dim.getVals().length() > 0){
+					String vls = RSBIUtils.dealStringParam(dim.getVals());
+					sql.append(" and " + dim.getColname() + " in ("+vls+")");
+				}
+			}else
+			if(dim.getType().equals("month")){
+				if(dim.getMonth() != null){
+					sql.append(" and " + dim.getColname() + " between '"+dim.getMonth().getStartMonth()+"' and '" + dim.getMonth().getEndMonth()+"'");
+				}else
+				if(dim.getVals() != null && dim.getVals().length() > 0){
+					String vls = RSBIUtils.dealStringParam(dim.getVals());
+					sql.append(" and " + dim.getColname() + " in ("+vls+")");
+					//isDealDate = true;
+				}
+			}else{
+				//限制维度筛选
+				if(dim.getVals() != null && dim.getVals().length() > 0){
+					String  vls = dim.getVals();
+					if("string".equalsIgnoreCase(dim.getValType())){
+						vls = RSBIUtils.dealStringParam(dim.getVals());
+					}
+					sql.append(" and " + dim.getColname() + " in ("+vls+")");
+				}
+			}
+		
+		}
+		
+		//限制参数的查询条件
+		List<ParamDto> params = chart.getParams();
+		for(int i=0; params!=null&&i<params.size(); i++){
+			ParamDto param = params.get(i);
+			int cubeId = param.getCubeId();
+			String tp = param.getType();
+			String colname = param.getColname();
+			String alias = param.getAlias();
+			String dateformat = param.getDateformat();
+			String tname = param.getTname();
+			//只有参数和组件都来源于同一个表,才能进行参数拼装
+			if((tp.equals("day") || tp.equals("month"))){
+				if(release == 0 && param.getSt() != null && param.getSt().length() > 0 ){
+					sql.append(" and " + colname + " between '"+ param.getSt() + "' and '" +  param.getEnd() + "'");
+				}else if(release == 1){
+					sql.append(" and " + colname + " between '$s_"+alias+"' and '$e_"+alias+"'");
+				}else if(release == 2){
+					sql.append(" #if($"+alias+" != '') and " + tableAlias.get(tname) + "." +colname + " = $"+alias + " #end");   //仪表盘发布,日期,月份只有一个参数
+				}
+			}else{
+				if(release == 0 && param.getVals() != null && param.getVals().length() > 0){
+					//字符串特殊处理
+					String  vls = param.getVals();
+					if("string".equalsIgnoreCase(param.getValType())){
+						vls = RSBIUtils.dealStringParam(param.getVals());
+					}
+					sql.append(" and " + (param.getCalc() == 0 ?(tableAlias.get(tname) + "."):"") + colname + " in ("+vls+")");
+				}else if(release == 1 || release == 2){
+					sql.append(" #if($"+alias+" != '') and " + (param.getCalc() == 0 ?(tableAlias.get(tname) + "."):"") + colname + " in ($extUtils.printVals($"+alias+", '"+param.getValType()+"')) #end");
+				}
+			}
+		}
+		
+		/**
+		Map<String, Object> linkAccept = chart.getChartJson().getLinkAccept();
+		if(linkAccept != null && !linkAccept.isEmpty()){
+			String col = (String)linkAccept.get("col");
+			String valtype = (String)linkAccept.get("valType");
+			String ncol = "$" + col;
+			if("string".equalsIgnoreCase(valtype)){
+				ncol = "'" + ncol + "'";
+			}
+			sql.append(" and  " + col + " = " + ncol);
+		}
+		**/
+		
+		if(dims.size() > 0){
+			sql.append(" group by ");
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				String key = dim.getTableColKey();
+				String txt = dim.getTableColName();
+				String tname = dim.getTableName();
+				if(key != null && txt != null && key.length() >0 && txt.length() >0){
+					sql.append(tableAlias.get(tname)+"."+key+", " + tableAlias.get(tname) + "." + txt);
+				}else{
+					if(dim.getCalc() == 1){
+						sql.append(dim.getColname());
+					}else{
+						sql.append(tableAlias.get(dim.getTname())+"."+dim.getColname());
+					}
+				}
+				if(i != dims.size() - 1){
+					sql.append(",");
+				}
+			}
+		}
+		//处理指标过滤
+		StringBuffer filter = new StringBuffer("");
+		for(KpiDto kpi : chart.getKpiJson()){
+			if(kpi.getFilter() != null){
+				filter.append(" and "+kpi.getCol_name()+" ");
+				String tp = kpi.getFilter().getFilterType();
+				filter.append(tp);
+				filter.append(" ");
+				double val1 = kpi.getFilter().getVal1();
+				if(kpi.getFmt() != null && kpi.getFmt().endsWith("%")){
+					val1 = val1 / 100;
+				}
+				filter.append(val1 * (kpi.getRate() == null ? 1 : kpi.getRate()));
+				if("between".equals(tp)){
+					double val2 = kpi.getFilter().getVal2();
+					if(kpi.getFmt() != null && kpi.getFmt().endsWith("%")){
+						val2 = val2 / 100;
+					}
+					filter.append(" and " + val2 * (kpi.getRate() == null ? 1 : kpi.getRate()));
+				}
+			}
+		}
+		if(filter.length() > 0){
+			sql.append(" having 1=1 " + filter);
+		}
+		if(dims.size() > 0){
+			StringBuffer order = new StringBuffer();
+			order.append(" order by ");
+			KpiDto kpi = chart.getKpiJson().get(0);
+			if(kpi.getSort() != null && kpi.getSort().length() > 0){
+				order.append(kpi.getAlias() + " " + kpi.getSort()) ;
+				order.append(",");
+			}
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				if(dim.getDimord() != null && dim.getDimord().length() > 0){
+					order.append(dim.getTableColKey() != null && dim.getTableColKey().length() > 0 ? dim.getTableColKey() : dim.getColname());
+					order.append(" ");
+					order.append(dim.getDimord());
+					order.append(",");
+				}
+			}
+			if(order.length() <= 11 ){  //判断是否拼接了 order by 字段
+				
+			}else{
+				//返回前先去除最后的逗号
+				 sql.append(order.toString().substring(0, order.length() - 1));
+			}
+		}
+		String ret = sql.toString();
+		//替换 ## 为 函数,##在velocity中为注释意思
+		ret = ret.replaceAll("##", "\\$extUtils.printJH()").replaceAll("@", "'");
+		return ret;
+	}
+	
+	/**
+	 * 创建图形钻取菜单
+	 * @param mv
+	 */
+	public void createChartDrill(MVContext mv, ChartQueryDto chart){
+		StringBuffer txt = new StringBuffer();
+		txt.append("<div class=\"chartdrillmenu\">");
+		
+		int cnt = 0;
+		for(DimDto dim : chart.getChartJson().getParams()){
+			//if(dim.getDimpos().equals("param")){
+				if(cnt == 0){
+					txt.append("钻取维:");
+				}
+				txt.append("<span class=\"chartdrillDim\"><a href=\"javascript:;\" title=\"上卷\" onclick=\"chartGoupDim("+chart.getCompId()+", "+dim.getId()+",'"+dim.getPos()+"',true)\" style=\"opacity:0.5\"></a>"+dim.getDimdesc()+"("+dim.getValDesc()+")</span>");
+				cnt++;
+			//}
+		}
+		if(cnt == 0){
+			txt.append("<span class=\"charttip\">(点击图形节点进行钻取分析)</span>");
+		}
+		txt.append("</div>");
+		
+		TextContext text = new TextContextImpl();
+		text.setText(txt.toString());
+		text.setParent(mv);
+		mv.getChildren().add(text);
+	}
+
+	/**
+	 * 创建图形的dataCenter
+	 * @param sql
+	 * @param sqlVO
+	 * @return
+	 * @throws IOException
+	 */
+	public GridDataCenterContext createDataCenter(ChartJSONDto chartJson, String sql) throws IOException{
+		List<DimDto> dims = chartJson.getDims();
+		GridDataCenterContext ctx = new GridDataCenterContextImpl();
+		GridSetConfContext conf = new GridSetConfContext();
+		ctx.setConf(conf);
+		ctx.setId("DC-" + IdCreater.create());
+		String name = TemplateManager.getInstance().createTemplate(sql);
+		ctx.getConf().setTemplateName(name);
+		String maparea = chartJson.getMaparea();
+		String type = chartJson.getType();
+		if("map".equals(type) && maparea != null && maparea.length() > 0 && !"china".equals(maparea)){  //如果是地图,并且是省份地图。需要忽略其他省份数据
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				if(dim.getType().equals("city")){  //地市
+					GridFilterContext filter = new GridFilterContext();
+					filter.setColumn(dim.getTableColName() != null && dim.getTableColName().length() > 0 ? dim.getTableColName() : dim.getAlias());
+					filter.setFilterType(GridFilter.in);
+					List<Area> ls = areaMapper.listCityByProvCode(maparea);
+					StringBuffer sb = new StringBuffer();
+					for(int j=0; j<ls.size(); j++){
+						Area a = ls.get(j);
+						sb.append(a.getCityName());
+						if(j != ls.size() - 1){
+							sb.append(",");
+						}
+					}
+					filter.setValue(sb.toString());
+					ctx.getProcess().add(filter);  //过滤其他地市
+				}
+			}
+		}
+		return ctx;
+	}
+}

+ 73 - 0
src/main/java/com/ruisitech/bi/service/bireport/ModelCacheService.java

@@ -0,0 +1,73 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisitech.bi.entity.model.DataSource;
+import com.ruisitech.bi.mapper.model.DataSourceMapper;
+import com.ruisitech.bi.mapper.model.DatasetMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 数据建模数据源/数据集缓存对象
+ * @author hy
+ * @date 2017-5-2
+ */
+@Service
+public class ModelCacheService {
+	
+	/**
+	 * 数据源缓存对象
+	 */
+	private Map<String, DataSource> dsources = new HashMap<String, DataSource>();
+	/**
+	 * 数据集缓存对象
+	 */
+	private Map<String, JSONObject> dsets = new HashMap<String, JSONObject>();
+	
+	@Autowired
+	private DataSourceMapper dsMapper;
+	
+	@Autowired
+	private DatasetMapper dsetMapper;
+	
+	
+	public synchronized DataSource getDsource(String id){
+		DataSource ret = dsources.get(id);
+		if(ret == null){
+			DataSource d = dsMapper.getDataSource(id);
+			dsources.put(id, d);
+			ret = d;
+		}
+		return ret;
+	}
+	
+	public synchronized JSONObject getDset(String id){
+		JSONObject ret = dsets.get(id);
+		if(ret == null){
+			String cfg = dsetMapper.getDatasetCfg(id);
+			dsets.put(id, JSON.parseObject(cfg));
+			ret = dsets.get(id);
+		}
+		return ret;
+	}
+	
+	public synchronized void removeDsource(String id){
+		dsources.remove(id);
+	}
+	
+	public synchronized void removeDset(String id){
+		dsets.remove(id);
+	}
+	
+	public synchronized void addDsource(String id, DataSource json){
+		dsources.put(id, json);
+	}
+	
+	public synchronized void addDset(String id, JSONObject json){
+		dsets.put(id, json);
+	}
+}

+ 142 - 0
src/main/java/com/ruisitech/bi/service/bireport/OlapService.java

@@ -0,0 +1,142 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.ruisitech.bi.entity.bireport.OlapInfo;
+import com.ruisitech.bi.entity.model.DataSource;
+import com.ruisitech.bi.entity.model.Dimension;
+import com.ruisitech.bi.mapper.bireport.OlapMapper;
+import com.ruisitech.bi.mapper.model.DataSourceMapper;
+import com.ruisitech.bi.mapper.model.DimensionMapper;
+import com.ruisitech.bi.service.model.DataSourceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class OlapService {
+
+	@Autowired
+	private OlapMapper mapper;
+	
+	@Autowired
+	private DimensionMapper dimMapper;
+	
+	@Autowired
+	private DataSourceMapper dsMapper;
+	
+	@Autowired
+	private DataSourceService dsService;
+	
+	public List<Map<String, Object>> listDims(Integer cubeId){
+		return mapper.listDims(cubeId);
+	}
+	
+	public OlapInfo getOlap(Integer pageId){
+		return mapper.getOlap(pageId);
+	}
+	
+	public List<OlapInfo> listreport(String keyword){
+		return mapper.listreport(keyword);
+	}
+	
+	public void insertOlap(OlapInfo olap){
+		mapper.insertOlap(olap);
+	}
+	
+	public void updateOlap(OlapInfo olap){
+		mapper.updateOlap(olap);
+	}
+	
+	public void deleteOlap(Integer pageId){
+		mapper.deleteOlap(pageId);
+	}
+	
+	public void renameOlap(OlapInfo olap){
+		mapper.renameOlap(olap);
+	}
+	
+	public Integer maxOlapId(){
+		return mapper.maxOlapId();
+	}
+	
+	public Integer olapExist(String pageName){
+		return mapper.olapExist(pageName);
+	}
+	
+	public List<Map<String, Object>> paramFilter(Dimension d, String keyword, String dsid) throws Exception{
+		//查询事实表
+		String col = d.getCol();
+		String key = d.getColkey();
+		String name = d.getColtext();
+		String dimord = d.getDimord();
+		String tname = d.getTname();
+		String coltable = d.getColTable();
+		String sql = "select distinct " +  (key==null||key.length() == 0 ? col : key) + " \"id\", " + (name==null||name.length() == 0 ?col:name) + " \"name\" from ";
+		sql += (coltable == null || coltable.length() == 0 ? tname : coltable);
+		if(keyword != null && keyword.length() > 0){
+			sql += " where "+(name==null||name.length() == 0 ?col:name)+" like '%"+keyword+"%'";
+		}
+		if(dimord != null && dimord.length() > 0){
+			sql += " order by " + (key==null||key.length() == 0 ? col : key)+ " " + dimord;
+		}
+		sql = sql.replaceAll("@", "'");
+		
+		DataSource ds = dsMapper.getDataSource(dsid);
+		List<Map<String, Object>> ret = this.queryTopN(sql, ds, 100);
+		return ret;
+	}
+	
+	public List<Map<String, Object>> queryTopN(String sql, DataSource ds, int n) throws Exception{
+		Connection conn  = null;
+		try {
+			List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
+			if(ds.getUse().equals("jndi")){
+				conn = dsService.getJndi(ds);
+			}else if(ds.getUse().equals("jdbc")){
+				conn = dsService.getJDBC(ds);
+			}
+			
+			PreparedStatement ps = conn.prepareStatement(sql);
+			ps.setMaxRows(n);
+			ResultSet rs = ps.executeQuery();
+			
+			ResultSetMetaData meta = rs.getMetaData();
+			List<String> cols = new ArrayList<String>();
+			for(int i=0; i<meta.getColumnCount(); i++){
+				String name = meta.getColumnLabel(i+1);
+				cols.add(name);
+			}
+			//ret.add(cols);
+			int idx = 0;
+			while(rs.next() && idx <= n){
+				Map<String, Object> m = new HashMap<String, Object>();
+				for(String s : cols){
+					m.put(s, rs.getString(s));
+				}
+				ret.add(m);
+				idx++;
+			}
+			rs.close();
+			ps.close();
+			return ret;
+		} catch (Exception e) {
+			e.printStackTrace();
+			throw e;
+		}finally{
+			if(conn != null){
+				conn.close();
+			}
+		}
+	}
+	
+	public List<Map<String, Object>> listKpiDesc(Integer cubeId){
+		return mapper.listKpiDesc(cubeId);
+	}
+}

+ 296 - 0
src/main/java/com/ruisitech/bi/service/bireport/ReportService.java

@@ -0,0 +1,296 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.bi.engine.view.context.chart.ChartContext;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.cross.CrossReportContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContext;
+import com.ruisi.ext.engine.view.context.form.*;
+import com.ruisi.ext.engine.view.context.html.DivContext;
+import com.ruisi.ext.engine.view.context.html.DivContextImpl;
+import com.ruisi.ext.engine.view.context.html.TextContext;
+import com.ruisi.ext.engine.view.context.html.TextContextImpl;
+import com.ruisitech.bi.entity.bireport.ChartQueryDto;
+import com.ruisitech.bi.entity.bireport.DimDto;
+import com.ruisitech.bi.entity.bireport.ParamDto;
+import com.ruisitech.bi.entity.bireport.TableQueryDto;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.*;
+
+@Service
+@Scope("prototype")
+public class ReportService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.export.tmp";
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	@Autowired
+	private ChartService chartService;
+	@Autowired
+	private TableService tableService;
+
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		
+	}
+	
+	
+	public MVContext json2MV(JSONObject json, int release) throws Exception{
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		JSONArray ps = json.getJSONArray("params");
+		ParamDto[] ls = JSONArray.toJavaObject(ps, ParamDto[].class);
+		List<ParamDto> params = Arrays.asList(ls);
+		//构建参数Text
+		if(!ps.isEmpty()){
+			if(release == 0){
+				StringBuffer sb = new StringBuffer("参数: ");
+				TextContext parStr = new TextContextImpl();
+				for(int i=0; i<params.size(); i++){
+					ParamDto param =params.get(i);
+					String name = param.getName();
+					String type = param.getType();
+					//String colname = param.getString("colname");
+					if("frd".equals(type) || "year".equals(type) || "quarter".equals(type)){
+						sb.append(name + "(" + (param.getValStrs() == null ? "无" : param.getValStrs())+")");
+					}else if("month".equals(type) || "day".equals(type)){
+						sb.append(name + "(" + (param.getSt() == null ? "无" : param.getSt()) + " 至 " + (param.getEnd() == null ? "无" : param.getEnd()) + ")");
+					}
+					sb.append("  ");
+					
+					
+				}
+				parStr.setText(sb.toString());
+				mv.getChildren().add(parStr);
+				parStr.setParent(mv);
+			}else{
+				//把参数变成动态值
+				DivContext div = new DivContextImpl();
+				div.setStyleClass("rpeortParam");
+				div.setChildren(new ArrayList<Element>());
+				mv.getChildren().add(div);
+				div.setParent(mv);
+				for(int i=0; i<params.size(); i++){
+					ParamDto param =params.get(i);
+					String name = param.getName();
+					String type = param.getType();
+					String colname = param.getColname();
+					String values = param.getVals();
+					
+					InputField input = null;
+					InputField input2 = null;
+					if("frd".equalsIgnoreCase(type) || "year".equalsIgnoreCase(type) || "quarter".equalsIgnoreCase(type)){
+						MultiSelectContextImpl target = new MultiSelectContextImpl();
+						String sql = this.createDimSql(param);
+						String template = TemplateManager.getInstance().createTemplate(sql);
+						target.setTemplateName(template);
+						input = target;
+						input.setDefaultValue(values == null ? "" : values);
+						input.setDesc(name);
+						input.setId(colname);
+					}else if("day".equalsIgnoreCase(type)){
+						DateSelectContext target = new DateSelectContextImpl();
+						String val = (String)param.getSt();
+						target.setDefaultValue(val == null ? "" : val.replaceAll("-", ""));
+						target.setDesc("开始" + name);
+						target.setId("s_" + colname);
+						input = target;
+						
+						//创建第二个参数
+						DateSelectContext target2 = new DateSelectContextImpl();
+						String val2 = (String)param.getEnd();
+						target2.setDefaultValue(val2 == null ? "" : val2.replaceAll("-", ""));
+						target2.setDesc("结束" + name);
+						target2.setId("e_" + colname);
+						input2 = target2;
+					}else if("month".equalsIgnoreCase(type)){
+						SelectContextImpl target = new SelectContextImpl();
+						String sql = this.createMonthSql();
+						String template = TemplateManager.getInstance().createTemplate(sql);
+						target.setTemplateName(template);
+						input = target;
+						input.setDefaultValue(param.getSt());
+						input.setDesc("开始" + name);
+						input.setId("s_" +colname);
+						
+						//创建第二个参数
+						SelectContextImpl target2 = new SelectContextImpl();
+						String template2 = TemplateManager.getInstance().createTemplate(sql);
+						target2.setTemplateName(template2);
+						target2.setDefaultValue(param.getEnd());
+						target2.setDesc("结束" + name);
+						target2.setId("e_" + colname);
+						input2 = target2;
+					}
+					div.getChildren().add(input);
+					input.setParent(div);
+					if(input2 != null){
+						div.getChildren().add(input2);
+						input2.setParent(div);
+					}
+				}
+				ButtonContext btn = new ButtonContextImpl();
+				btn.setDesc("查询");
+				btn.setType("button");
+				btn.setMvId(new String[]{ deftMvId });
+				div.getChildren().add(btn);
+				btn.setParent(div);
+			}
+		}
+		JSONArray comps = json.getJSONArray("comps");
+		List<String> dsids = new ArrayList<String>();
+		for(int i=0; i<comps.size(); i++){
+			JSONObject obj = comps.getJSONObject(i);
+			String dsid = (String)obj.get("dsid");
+			if(dsid != null && dsid.length() > 0 && !dsids.contains(dsid)){
+				dsids.add(dsid);
+			}
+			String type = obj.getString("type");
+			if("table".equals(type)){
+				TableQueryDto dto = JSONObject.toJavaObject(obj, TableQueryDto.class);
+				dto.setParams(params);
+				createTable(mv, dto, release);
+			}
+			if("chart".equals(type)){
+				ChartQueryDto dto = JSONObject.toJavaObject(obj, ChartQueryDto.class);
+				dto.setParams(params);
+				createChart(mv, dto, release);
+			}
+		}
+		//生成数据原
+		for(String dsid : dsids){
+			super.createDsource(cacheService.getDsource(dsid), mv);
+		}
+		
+		return mv;
+	}
+	
+	/**
+	 * 
+	 * @param mv
+	 * @param tableJson
+	 * @param kpiJson
+	 * @param params
+	 * @param release  判断当前是否为发布状态, 0 表示不是发布,1表示发布到多维分析,2表示发布到仪表盘
+	 * @return
+	 * @throws IOException
+	 * @throws ParseException
+	 */
+	public void createTable(MVContext mv, TableQueryDto table, int release) throws IOException, ParseException{
+		String dsid = table.getDsid();
+		if(dsid == null || dsid.length() == 0){
+			return;
+		}
+		
+		//添加kpiOther
+		DimDto kpiOther = new DimDto();
+		kpiOther.setType("kpiOther");
+		table.getCols().add(kpiOther);
+		CrossReportContext cr = tableService.json2Table(table);
+		//移除kpiOther
+		table.getCols().remove(table.getCols().size() - 1);
+		String id = ExtConstants.reportIdPrefix + IdCreater.create();
+		cr.setId(id);
+		cr.setOut("html");
+		cr.setShowData(true);
+		
+		String sql = tableService.createSql(table, release);
+		//创建datacenter
+		GridDataCenterContext dc = tableService.createDataCenter(sql, table);
+		cr.setRefDataCetner(dc.getId());
+		dc.getConf().setRefDsource(dsid);
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		
+		Map<String, CrossReportContext> crs = new HashMap<String, CrossReportContext>();
+		crs.put(cr.getId(), cr);
+		mv.setCrossReports(crs);
+	}
+	
+	public void createChart(MVContext mv, ChartQueryDto chart, int release) throws IOException, ParseException{
+		String dsid = chart.getDsid();
+		if(dsid == null || dsid.length() == 0){
+			return;
+		}
+		
+		
+		//创建钻取维度
+		StringBuffer sb = new StringBuffer("");
+		int cnt = 0;
+		for(DimDto dim : chart.getChartJson().getParams()){
+			if(cnt == 0){
+				sb.append("钻取维:");
+			}
+			sb.append(dim.getDimdesc()+"("+dim.getValDesc()+") - ");
+			cnt++;
+		}
+		String drillText = sb.toString();
+		if(drillText.length() > 0){
+			TextContext txt = new TextContextImpl();
+			txt.setText(drillText);
+			mv.getChildren().add(txt);
+			txt.setParent(mv);
+		}
+		ChartContext cr = chartService.json2Chart(chart.getChartJson(), chart.getKpiJson(), false);
+		
+		String sql = chartService.createSql(chart, release);
+		GridDataCenterContext dc = chartService.createDataCenter(chart.getChartJson(), sql);
+		cr.setRefDataCenter(dc.getId());
+		dc.getConf().setRefDsource(dsid);
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		
+		Map<String, ChartContext> crs = new HashMap<String, ChartContext>();
+		crs.put(cr.getId(), cr);
+		mv.setCharts(crs);
+	}
+	
+	public String createDimSql(ParamDto dim){
+		String tname = dim.getTableName();
+		if(tname == null || tname.length() == 0){  //维度未关联码表,直接从数据中查询。
+			String sql = "select distinct "+dim.getColname()+" \"value\", "+dim.getColname()+" \"text\" from " + dim.getTname();
+			sql += " order by "+dim.getColname()+" "  + dim.getDimord();
+			return sql;
+		}else{
+			String sql = "select "+dim.getTableColKey()+" \"value\", "+dim.getTableColName()+" \"text\" from " + tname;
+			sql += " order by "+dim.getTableColKey()+" "  + dim.getDimord();
+			return sql;
+		}
+	}
+	
+	public String createMonthSql(){
+		String sql = "select mid \"value\", mname \"text\" from code_month order by mid desc";
+		return sql;
+	}
+}

+ 223 - 0
src/main/java/com/ruisitech/bi/service/bireport/TableDetailService.java

@@ -0,0 +1,223 @@
+package com.ruisitech.bi.service.bireport;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.view.builder.dsource.DataSourceBuilder;
+import com.ruisi.ext.engine.view.context.dsource.DataSourceContext;
+import com.ruisi.ext.engine.view.context.grid.PageInfo;
+import com.ruisi.ext.engine.wrapper.ExtRequest;
+import com.ruisi.ext.engine.wrapper.TestRequestImpl;
+import com.ruisitech.bi.entity.bireport.TableDetailDto;
+import com.ruisitech.bi.entity.model.DataSource;
+import jxl.Workbook;
+import jxl.write.Label;
+import jxl.write.Number;
+import jxl.write.WritableCell;
+import jxl.write.WritableSheet;
+import jxl.write.WritableWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 提取表格明细Service
+ * @author hq
+ *
+ */
+@Service
+public class TableDetailService extends BaseCompService {
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	/**
+	 * 获取表格的字段
+	 * @param dto
+	 * @return
+	 */
+	public JSONArray getTableHeader(TableDetailDto dto){
+		JSONObject dset = cacheService.getDset(dto.getDsetId());
+		JSONArray cols = dset.getJSONArray("cols");
+		return cols;
+	}
+	
+	/**
+	 * 根据纬度提取明细
+	 * @param dto
+	 * @return
+	 */
+	public List<Map<String, Object>> detailDatas(TableDetailDto dto){
+		JSONObject dset = cacheService.getDset(dto.getDsetId());
+		String sql = this.createSql(dset, dto.getPms());
+		PageInfo page = new PageInfo();
+		if(dto.getPage() != null){
+			page.setCurtpage(dto.getPage() - 1);
+		}
+		if(dto.getRows() != null){
+			page.setPagesize(dto.getRows());
+		}
+		List<Map<String, Object>> ls = this.querySql(sql, page, dto);
+		dto.setTotal((int)page.getAllsize());
+		return ls;
+	}
+	
+	private List<Map<String, Object>> querySql(String sql, PageInfo page, TableDetailDto dto){
+		DataSource ds = this.cacheService.getDsource(dto.getDsid());
+		DataSourceContext dsource = new DataSourceContext();
+		dsource.putProperty("id", ds.getDsid());
+		String use = dsource.getUse();
+		dsource.putProperty("usetype", use);
+		if(use == null || "jdbc".equalsIgnoreCase(use.toString())){
+			String linktype = ds.getLinkType();
+			dsource.putProperty("linktype", linktype);
+			dsource.putProperty("linkname", ds.getLinkName());
+			dsource.putProperty("linkpwd", ds.getLinkPwd());
+			dsource.putProperty("linkurl", ds.getLinkUrl());
+		}else{
+			dsource.putProperty("jndiname", ds.getJndiName());
+		}
+		if(page == null){
+			return new DataSourceBuilder().queryForList(sql, dsource);
+		}else{
+			ExtRequest req =  new TestRequestImpl(null, null);
+			return new DataSourceBuilder().queryForList(sql, dsource, page, req);
+		}
+	}
+	
+	public String createSql(JSONObject dset, Map<String, String> pms){
+		//获取表
+		Map<String, String> tableAlias = super.createTableAlias(dset);
+		
+		StringBuffer sb = new StringBuffer();
+		
+		sb.append("select ");
+		JSONArray cols = dset.getJSONArray("cols");
+		for(int i=0; i<cols.size(); i++){
+			JSONObject col = cols.getJSONObject(i);
+			String tname = col.getString("tname");
+			String name = col.getString("name");
+			sb.append(tableAlias.get(tname));
+			sb.append(".");
+			sb.append(name);
+			sb.append(" as ");
+			sb.append("c" + i);
+			if(i != cols.size() - 1){
+				sb.append(",");
+			}
+		}
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+     		String master = dset.getString("master");
+		sb.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sb.append(" " + jtype);
+			}
+			sb.append(" join " + ref+ " " + tableAlias.get(ref));
+			sb.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sb.append(" ");
+		}
+		sb.append(" where 1=1 ");
+		for(Map.Entry<String, String> p : pms.entrySet()){
+			String name = p.getKey();
+			String val = p.getValue();
+			JSONObject col = findColByAlias(name, dset);
+			String tname = col.getString("tname");
+			String colname = col.getString("name");
+			String expression = col.getString("expression");
+			if(expression != null && expression.length() > 0){
+				colname = expression;
+			}
+			String type = col.getString("type");
+			if("Double".equalsIgnoreCase(type) || "Int".equalsIgnoreCase(type)){
+				sb.append(" and " +  (expression == null || expression.length() == 0 ?tableAlias.get(tname) + ".":"") +colname  + " = " + val);
+			}else{
+				sb.append(" and " + (expression == null || expression.length() == 0 ?tableAlias.get(tname) + ".":"") + colname + " = '" + val+"'");
+			}
+		}
+		return sb.toString().replaceAll("@", "'");
+	}
+	
+	private JSONObject findColByAlias(String alias, JSONObject dset){
+		JSONObject ret = null;
+		JSONArray cols = dset.getJSONArray("cols");
+		for(int i=0; i<cols.size(); i++){
+			JSONObject col = cols.getJSONObject(i);
+			String name = col.getString("name");
+			if(name.equalsIgnoreCase(alias)){
+				ret = col;
+				break;
+			}
+		}
+		if(ret == null){
+			//查找动态字段
+			JSONArray dyans = dset.getJSONArray("dynamic");
+			for(int i=0; i<dyans.size(); i++){
+				JSONObject dyan = dyans.getJSONObject(i);
+				String name = dyan.getString("name");
+				if(name.equals(alias)){
+					ret = dyan;
+					break;
+				}
+			}
+		}
+		return ret;
+	}
+	
+	public void exportDatas(TableDetailDto dto, HttpServletResponse res) throws Exception {
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+		JSONObject dset = cacheService.getDset(dto.getDsetId());
+		String sql = this.createSql(dset, dto.getPms());
+		List<Map<String, Object>> ls = this.querySql(sql, null, dto);
+		OutputStream os =  res.getOutputStream();
+		WritableWorkbook workbook = Workbook.createWorkbook( os );
+		WritableSheet sheet = workbook.createSheet( "页1", 0);
+		//写head
+		JSONArray cols = dset.getJSONArray("cols");
+		for(int i=0; i<cols.size(); i++){
+			JSONObject col = cols.getJSONObject(i);
+			WritableCell cell = new Label( i, 0, col.getString("name") );
+			sheet.addCell(cell);
+		}
+		//写数据
+		for(int i=0; i<ls.size(); i++){
+			Map<String, Object> data = ls.get(i);
+			for(int j=0; j<cols.size(); j++){
+				//JSONObject col = cols.getJSONObject(i);
+				WritableCell cell = null;
+				Object value = data.get("c"+j);
+				if(value == null){
+					cell = new Label( j, i, "" );
+				}else{
+					if(value instanceof Date){
+						Date d = (Date)value;
+						cell = new Label( j, i + 1, sdf.format( d ) );
+					}else if(value instanceof Integer){
+						cell = new Number(j, i + 1, ((Integer) value).intValue());
+					}else if(value instanceof Double){
+						cell = new Number(j, i + 1, ((Double) value).doubleValue());
+					} else if(value instanceof BigDecimal) {
+						cell = new Number(j, i + 1, ((BigDecimal) value).doubleValue());
+					}else{
+						cell = new Label( j, i + 1, value.toString() );
+					}
+				}
+				sheet.addCell( cell );
+			}
+		}
+		workbook.write( );
+		workbook.close( );
+	}
+
+}

Різницю між файлами не показано, бо вона завелика
+ 1247 - 0
src/main/java/com/ruisitech/bi/service/bireport/TableService.java


+ 32 - 0
src/main/java/com/ruisitech/bi/service/frame/DaoHelperConfig.java

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.service.frame;
+
+import com.ruisi.ext.engine.dao.DaoHelper;
+import com.ruisi.ext.engine.dao.DaoHelperImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * 配置 daoHelper
+ * @Author huangqin
+ * @Date 2020/10/19 5:17 下午
+ */
+@Configuration
+public class DaoHelperConfig {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Bean
+    public DaoHelper daoHelper(){
+        DaoHelperImpl dao = new DaoHelperImpl();
+        dao.setJdbcTemplate(jdbcTemplate);
+        return dao;
+    }
+}

+ 157 - 0
src/main/java/com/ruisitech/bi/service/frame/MenuService.java

@@ -0,0 +1,157 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有 
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.service.frame;
+
+import com.ruisi.ext.engine.dao.DaoHelper;
+import com.ruisitech.bi.entity.common.BaseEntity;
+import com.ruisitech.bi.entity.common.Result;
+import com.ruisitech.bi.entity.frame.Menu;
+import com.ruisitech.bi.mapper.frame.MenuMapper;
+import com.ruisitech.bi.util.RSBIUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class MenuService {
+	
+	@Autowired
+	private MenuMapper mapper;
+	
+	@Autowired
+	private DaoHelper daoHelper;
+
+	private String dbName = RSBIUtils.getConstant("dbName");
+
+	/**
+	 * 查询用户PC端菜单
+	 * @param userId
+	 * @return
+	 */
+	public List<Menu> listUserMenus(Integer userId){
+		List<Menu> menuList = mapper.listUserMenus(userId);
+		List<Menu> roots = this.findMenuChildren(0, menuList);
+		//过滤移动端菜单
+		for(int i=0; i<roots.size(); i++){
+			Menu root = roots.get(i);
+			Integer id = root.getMenuId();
+			List<Menu> subList = findMenuChildren(id, menuList);
+			root.setChildren(subList);  //菜单只支持3级
+			//查询第三级
+			for(int j=0; j<subList.size(); j++){
+				Menu sub = subList.get(j);
+				Integer subId = sub.getMenuId();
+				sub.setChildren(findMenuChildren(subId, menuList));
+			}
+		}
+		return roots;
+	}
+
+	private List<Menu> findMenuChildren(Integer pid, List<Menu> menuList){
+		List<Menu> ret = new ArrayList<Menu>();
+		for(int i=0; i<menuList.size(); i++){
+			Menu m = (Menu)menuList.get(i);
+			Integer value = m.getMenuPid();
+			if(value != null && value.equals(pid) ){
+				ret.add(m);
+			}
+		}
+		return ret;
+	}
+	
+	public Menu getById(Integer menuId) {
+		return mapper.getById(menuId);
+	}
+	
+	public List<Map<String, Object>> listMenuByPid(Integer pid){
+		List<Map<String, Object>> ls = mapper.listMenuByPid(pid);
+		for(Map<String, Object> dt : ls) {
+			if("true".equals(dt.get("children"))) {
+				dt.put("children", true);
+				dt.put("icon", "fa fa-folder-o");
+			}else {
+				dt.put("children", false);
+			}
+		}
+		return ls;
+	}
+	
+	public void saveMenu(Menu m) {
+		String idSql = "select max(menu_id) from sc_menu";
+		Integer maxId = (Integer)daoHelper.queryForObject(idSql, Integer.class);
+		final int mid = maxId.intValue() + 1;
+		final Integer pid = m.getMenuPid();
+		String sql="insert into sc_menu(menu_id,menu_pid,menu_name,menu_desc,menu_date,menu_order,menu_url, avatar) values(?,?,?,?,";
+		sql +=  dbName.equals("mysql")?"now()":"strftime('%s','now') * 1000";
+		sql += ",?,?,?)";
+		daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+			@Override
+			public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+				ps.setInt(1, mid);
+				ps.setString(3, m.getMenuName());
+				ps.setString(4, m.getMenuDesc());
+				ps.setInt(2, pid);
+				ps.setInt(5, m.getMenuOrder());
+				ps.setString(6, m.getMenuUrl());
+				ps.setString(7, m.getAvatar());
+				ps.executeUpdate();
+				return null;
+			}
+		});
+		m.setMenuId(mid);
+	}
+
+	public void updateMenu(Menu menu) {
+		String dt = dbName.equals("mysql")?"now()":"strftime('%s','now') * 1000";
+		String sql="update sc_menu set menu_name=?,menu_desc=?,menu_date="+dt+",menu_order=?,menu_url=?,avatar=? where menu_id=?";
+		daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+			@Override
+			public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+				ps.setInt(3, menu.getMenuOrder());
+				ps.setString(2, menu.getMenuDesc());
+				ps.setString(1, menu.getMenuName());
+				ps.setString(4, menu.getMenuUrl());
+				ps.setString(5, menu.getAvatar());
+				ps.setInt(6, menu.getMenuId());	
+				ps.executeUpdate();
+				return null;
+			}
+		});
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public Result deleteMenu(Integer id) {
+		Result r = new Result();
+		String chkSql = "select count(*) from sc_menu where menu_pid = "+id;
+		BigDecimal ct = (BigDecimal)daoHelper.queryForObject(chkSql, BigDecimal.class);
+		if(ct.intValue() > 0){
+			r.setResult(0);
+			r.setMsg("该菜单下可能含有子菜单,不能删除。");
+			return r;
+		}
+		
+		String sql = "delete from sc_menu where menu_id = "+id;
+		daoHelper.execute(sql);
+		
+		//删除菜单角色关系
+		daoHelper.execute("delete from role_menu_rela where menu_id = " + id);
+		//删除菜单用户关系
+		daoHelper.execute("delete from user_menu_rela where menu_id = " + id);
+		r.setResult(1);
+		return r;
+	}
+}

+ 215 - 0
src/main/java/com/ruisitech/bi/service/frame/RoleService.java

@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有 
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.service.frame;
+
+import com.ruisi.ext.engine.dao.DaoHelper;
+import com.ruisitech.bi.entity.frame.Role;
+import com.ruisitech.bi.mapper.frame.RoleMapper;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.bi.util.TreeInterface;
+import com.ruisitech.bi.util.TreeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 权限管理 - 角色管理模块
+ * @author gdp
+ *
+ */
+@Service
+public class RoleService {
+	
+	@Autowired
+	private RoleMapper mapper;
+	
+	@Autowired
+	private DaoHelper daoHelper;
+
+	private String dbName = RSBIUtils.getConstant("dbName");
+
+	public Map<String, Object> listRoleMenus(Integer roleId){
+		List<Map<String, Object>> menus = mapper.listRoleMenus(roleId);
+		TreeService tree = new TreeService();
+		List<Map<String, Object>> ret = tree.createTreeData(menus, new TreeInterface(){
+			@Override
+			public void processMap(Map<String, Object> m) {
+				Object id2 = m.get("id2");
+				if(id2 != null){
+					Map<String, Object> state = new HashMap<String, Object>();
+					state.put("selected", true);
+					m.put("state", state);
+				}
+				
+			}
+
+			@Override
+			public void processEnd(Map<String, Object> m, boolean hasChild) {
+				if(hasChild){
+					m.put("icon", "fa fa-folder-o");
+					m.remove("state");
+				}else {
+					m.put("icon", "fa fa-file-o");
+				}
+			}
+			
+		});
+		Map<String, Object> m = new HashMap<String, Object>();
+		m.put("id", "root");
+		m.put("text", "系统菜单树");
+		m.put("icon", "fa fa-home");
+		m.put("children", ret);
+		return m;
+	}
+	
+	public List<Map<String, Object>> roledata(Integer roleId){
+		List<Map<String, Object>> datas = mapper.roledata(roleId);
+		TreeService tree = new TreeService();
+		List<Map<String, Object>> ret = tree.createTreeData(datas, new TreeInterface(){
+			@Override
+			public void processMap(Map<String, Object> m) {
+				Object seldata = m.get("seldata");
+				if(seldata != null){
+					Map<String, Object> state = new HashMap<String, Object>();
+					state.put("selected", true);
+					m.put("state", state);
+				}
+			}
+
+			@Override
+			public void processEnd(Map<String, Object> m, boolean hasChild) {
+				Map<String, Object> attr = new HashMap<String, Object>();
+				String tp = (String)m.get("tp");
+				attr.put("tp", tp);
+				m.put("li_attr", attr);
+			}
+			
+		});
+		return ret;
+	}
+	
+	public List<Role> list(String keyword){
+		return mapper.list(keyword);
+	}
+	
+	/**
+	 * 查询所有角色及用户所有的角色
+	 * @param userId
+	 * @return
+	 */
+	public List<Role> listUserRole(Integer userId){
+		return mapper.listUserRole(userId);
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public void addUserRole(List<Integer> roleIds, Integer userId) {
+		//删除角色
+		daoHelper.execute("delete from role_user_rela where user_id = " + userId);
+		for(int i=0; roleIds != null && i<roleIds.size(); i++)
+		{
+			Integer roleId = roleIds.get(i);
+			daoHelper.execute("insert into role_user_rela(user_id,role_id) values("+userId+","+roleId+")");
+		}
+	}
+
+	public void saveRole(Role role) {
+		String dt = dbName.equals("mysql")?"now()":"strftime('%s','now') * 1000";
+		String sql = "insert into sc_role(role_name,role_desc,create_date,create_user, ord) values(?,?,"+dt+",?,?)";
+		daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+			public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+				ps.setString(1, role.getRoleName());
+				ps.setString(2, role.getRoleDesc());
+				ps.setString(3, RSBIUtils.getLoginUserInfo().getLoginName());
+				ps.setInt(4, role.getOrd());
+
+				ps.executeUpdate();
+				return null;
+			}
+		});
+	}
+	
+	public void updateRole(Role role) {
+		String sql = "update sc_role set role_name = ?,role_desc = ?, ord=? where role_id = ?";
+		daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+			public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+				ps.setInt(4, role.getRoleId());
+				ps.setString(1, role.getRoleName());
+				ps.setString(2, role.getRoleDesc());
+				ps.setInt(3, role.getOrd());
+				ps.executeUpdate();
+				return null;
+			}
+		});
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public void deleteRole(Integer id) {
+		String sql = "delete from sc_role where role_id = " + id ;
+		daoHelper.execute(sql);
+		//删除角色菜单关系
+		daoHelper.execute("delete from role_menu_rela where role_id = " + id);
+		//删除角色用户关系
+		daoHelper.execute("delete from role_user_rela where role_id = " + id);
+	}
+	
+	public Role getRole(Integer id) {
+		return mapper.getById(id);
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public void roleMenu(String menuIds, Integer roleId) {
+		//删除以前数据
+		String delSql = "delete from role_menu_rela where role_id = " + roleId;
+		daoHelper.execute(delSql);
+		
+		String[] ids = menuIds.split(",");//处理获取的菜单ID格式
+		String sql = "insert into role_menu_rela(role_id, menu_id) values(?,?)";
+		for(final String tmp : ids){//这个循环用于循环插入授权数据
+			if(tmp.length() > 0){
+				daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+					public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+						ps.setInt(1, roleId);
+						ps.setInt(2, new Integer(tmp));
+						ps.executeUpdate();
+						return null;
+					}
+				});
+			}
+		}
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public void roleDataSave(Integer roleId, String dataIds) {
+		//删除以前数据
+		String delsql = "delete from role_data_rela where role_id = " + roleId;
+		this.daoHelper.execute(delsql);
+		if(dataIds == null || dataIds.length() == 0) {
+			return;
+		}
+		String[] datas = dataIds.split(",");
+		for(final String data : datas){
+			String sql = "insert into role_data_rela(role_id, data_id) values(?,?)";
+			this.daoHelper.execute(sql, new PreparedStatementCallback<Object>(){
+				@Override
+				public Object doInPreparedStatement(PreparedStatement ps)
+						throws SQLException, DataAccessException {
+					ps.setInt(1, roleId);
+					ps.setInt(2, Integer.parseInt(data));
+					ps.executeUpdate();
+					return null;
+				}				
+			});
+		}
+	}
+}

+ 58 - 0
src/main/java/com/ruisitech/bi/service/frame/SessionAuthcFilter.java

@@ -0,0 +1,58 @@
+package com.ruisitech.bi.service.frame;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ruisitech.bi.entity.common.RequestStatus;
+import com.ruisitech.bi.entity.common.Result;
+import com.ruisitech.bi.entity.frame.User;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.servlet.AdviceFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * 用户登录验证的拦截器
+ */
+public class SessionAuthcFilter extends AdviceFilter {
+
+	private UserService userService;
+
+	public SessionAuthcFilter(UserService userService){
+		this.userService = userService;
+	}
+
+	@Override
+	protected boolean preHandle(ServletRequest request, ServletResponse response)
+			throws Exception {
+		Subject us = SecurityUtils.getSubject(); 
+		Session session = us.getSession();
+		
+		if(!us.isAuthenticated() && us.isRemembered() && session.getAttribute(ShiroDbRealm.SESSION_USER_KEY) == null){
+			//说明是记住我过来的,恢复SESSION里的值
+			Object staffId = us.getPrincipal();
+			if(staffId != null){
+				User u = userService.getUserByStaffId(staffId.toString());
+				session.setAttribute(ShiroDbRealm.SESSION_USER_KEY, u);
+			}else{
+				response.setContentType("application/json; charset=utf-8");
+				response.setCharacterEncoding("utf-8");
+				Result r = new Result(RequestStatus.FAIL_FIELD.getStatus(), "登录信息已经超时。", null);
+				response.getWriter().print(JSONObject.toJSONString(r));
+				return false;
+			}
+		}
+		if(us.isAuthenticated() || us.isRemembered()){  //不管是认证登陆 还是 记住我登陆, 都放行
+			return true;
+		}else{
+			response.setContentType("application/json; charset=utf-8");
+			response.setCharacterEncoding("utf-8");
+			Result r = new Result(RequestStatus.FAIL_FIELD.getStatus(), "登录信息已经超时。", null);
+			response.getWriter().print(JSONObject.toJSONString(r));
+			return false;
+		}
+	}
+
+}

+ 74 - 0
src/main/java/com/ruisitech/bi/service/frame/ShiroConfig.java

@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.service.frame;
+
+import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
+
+
+import javax.servlet.Filter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @ClassName ShiroConfig
+ * @Description ShiroConfig
+ * @Author gdp
+ * @Date 2020/9/18 10:29 上午
+ */
+@Configuration
+public class ShiroConfig {
+
+    @Autowired
+    private UserService userService;
+
+    @Bean
+    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
+        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
+        shiroFilterFactoryBean.setSecurityManager(securityManager);
+        //拦截器
+        Map<String, Filter> filters = new LinkedHashMap<>();
+        filters.put("authc", new SessionAuthcFilter(userService));
+        shiroFilterFactoryBean.setFilters(filters);
+        //注销
+        shiroFilterFactoryBean.setLoginUrl("/frame/Logout.action");
+        //过滤的URL
+        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
+        filterChainDefinitionMap.put("/doLogin.action", "anon");
+        filterChainDefinitionMap.put("/**", "authc");
+        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
+        return shiroFilterFactoryBean;
+    }
+
+    @Bean
+    public DefaultWebSecurityManager securityManager(ShiroDbRealm customRealm) {
+        DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
+        defaultSecurityManager.setRealm(customRealm);
+        return defaultSecurityManager;
+    }
+
+    @Bean
+    public ShiroDbRealm customRealm() {
+        ShiroDbRealm customRealm = new ShiroDbRealm();
+        return customRealm;
+    }
+
+    /*
+    @Bean
+    public Filter customFilter(){
+        SessionAuthcFilter filter = new SessionAuthcFilter();
+        return filter;
+    }
+
+     */
+
+}

+ 73 - 0
src/main/java/com/ruisitech/bi/service/frame/ShiroDbRealm.java

@@ -0,0 +1,73 @@
+package com.ruisitech.bi.service.frame;
+
+import com.ruisitech.bi.entity.frame.User;
+import com.ruisitech.bi.util.RSBIUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.*;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.realm.AuthorizingRealm;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class ShiroDbRealm extends AuthorizingRealm {
+
+	@Autowired
+	private UserService userService;
+	
+	public static final String SESSION_USER_KEY = "session.user.key";
+
+	/**
+	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用,负责在应用程序中决定用户的访问控制的方法
+	 */
+	@Override
+	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
+		//User user = (User) SecurityUtils.getSubject().getSession().getAttribute(ShiroDbRealm.SESSION_USER_KEY);
+		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+		//info.addRole(user.getRole().trim());
+		return info;
+	}
+
+	/**
+	 * 认证回调函数,登录信息和用户验证信息验证
+	 */
+	@Override
+	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
+		// 把token转换成User对象
+		User userLogin = tokenToUser((UsernamePasswordToken) authcToken);
+		// 验证用户是否可以登录
+		User ui = userService.getUserByStaffId(userLogin.getStaffId());
+		if (ui == null){
+			return null; // 异常处理,找不到数据
+		}
+		if(!ui.getPassword().equals(RSBIUtils.getMD5(userLogin.getPassword().getBytes()))){
+			return null; //密码错误
+		}
+		// 设置session
+		Session session = SecurityUtils.getSubject().getSession();
+		session.setAttribute(ShiroDbRealm.SESSION_USER_KEY, ui);
+		// 当前 Realm 的 name
+		String realmName = this.getName();
+		// 登陆的主要信息: 可以是一个实体类的对象, 但该实体类的对象一定是根据 token 的 username 查询得到的.
+		Object principal = authcToken.getPrincipal();
+		return new SimpleAuthenticationInfo(principal, userLogin.getPassword(),
+				realmName);
+	}
+
+	private User tokenToUser(UsernamePasswordToken authcToken) {
+		User user = new User();
+		user.setStaffId(authcToken.getUsername());
+		user.setPassword(String.valueOf(authcToken.getPassword()));
+		return user;
+	}
+
+	public UserService getUserService() {
+		return userService;
+	}
+
+	public void setUserService(UserService userService) {
+		this.userService = userService;
+	}
+
+}

+ 209 - 0
src/main/java/com/ruisitech/bi/service/frame/UserService.java

@@ -0,0 +1,209 @@
+package com.ruisitech.bi.service.frame;
+
+import com.ruisi.ext.engine.dao.DaoHelper;
+import com.ruisitech.bi.entity.frame.User;
+import com.ruisitech.bi.mapper.frame.UserMapper;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.bi.util.TreeInterface;
+import com.ruisitech.bi.util.TreeService;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class UserService {
+	
+	@Autowired
+	private UserMapper mapper;
+
+	@Autowired
+	private DaoHelper daoHelper;
+
+	public User getUserByStaffId(String staffId){
+		return mapper.getUserByStaffId(staffId);
+	}
+
+	public List<User> listUsers(String keyword){
+		return mapper.listUsers(keyword);
+	}
+
+
+	public User getUserByUserId(Integer userId){
+		return mapper.getUserById(userId);
+	}
+	
+	public void updateLogDateAndCnt(Integer userId){
+		mapper.updateLogDateAndCnt(userId, RSBIUtils.getConstant("dbName"));
+	}
+	
+	public void modPsd(User u){
+		mapper.modPsd(u);
+	}
+	
+	public String checkPsd(Integer userId){
+		return mapper.checkPsd(userId);
+	}
+	
+	public Map<String, Object> appUserinfo(Integer userId){
+		return mapper.appUserinfo(userId);
+	}
+	
+	public String shiroLogin(String userName, String password){
+		UsernamePasswordToken token = new UsernamePasswordToken(userName, password, null);   
+	    token.setRememberMe(true);
+	    // shiro登陆验证  
+	    try {  
+	        SecurityUtils.getSubject().login(token);  
+	    } catch (UnknownAccountException ex) {  
+	        return "账号不存在或者密码错误!";  
+	    } catch (IncorrectCredentialsException ex) {  
+	        return "账号不存在或者密码错误!";  
+	    } catch (AuthenticationException ex) {
+	    	String ret = null;
+	    	Throwable t = ex;
+	    	while(true){
+	    		t = t.getCause();
+	    		if(t == null || t.getCause() == null){
+	    			ret = t.getMessage();
+	    			break;
+	    		}
+	    	}
+	    	return "系统错误:" + ret;
+	    } catch (Exception ex) {  
+	        ex.printStackTrace();  
+	        return "内部错误,请重试!";  
+	    }
+	    return "SUC";
+	}
+
+	public String saveUser(User u) {
+		int cnt = mapper.userExist(u.getStaffId());
+		if(cnt > 0){
+			return "账号已经存在。";
+		}
+		u.setUserId(mapper.maxUserId());
+		u.setPassword(RSBIUtils.getMD5(u.getPassword().getBytes()));
+		mapper.insertuser(u);
+		return null;
+	}
+
+	@Transactional(rollbackFor = Exception.class)
+	public void deleteUser(Integer userId) {
+		//删除用户
+		daoHelper.execute("delete from sc_login_user where user_id = " + userId);
+		//删除用户菜单关系
+		daoHelper.execute("delete from user_menu_rela where user_id = " + userId);
+		//删除用户角色关系
+		daoHelper.execute("delete from role_user_rela where user_id = " + userId);
+	}
+
+	public User getUserById(Integer userId) {
+		return mapper.getUserById(userId);
+	}
+
+	public void updateUser(User u) {
+		mapper.updateuser(u);
+		if(u.getPassword() != null && u.getPassword().length() > 0) {
+			//修改密码
+			u.setPassword(RSBIUtils.getMD5(u.getPassword().getBytes()));
+			mapper.modPsd(u);
+		}
+	}
+
+	public Map<String, Object> listUserMenus(Integer userId){
+		List<Map<String, Object>> ls = mapper.listUserMenus(userId);
+		TreeService ser = new TreeService();
+		List<Map<String, Object>> ret = ser.createTreeData(ls, new TreeInterface(){
+
+			@Override
+			public void processMap(Map<String, Object> m) {
+				Map<String, Object> state = new HashMap<String, Object>();
+				String chk2 = m.get("id2") == null ? "" : m.get("id2").toString();
+				if(chk2 == null || chk2.length() == 0){
+					//id3为用户所拥有的菜单,需要判断是否checked
+					String chk3 = m.get("id3") == null ? "" : m.get("id3").toString();
+					if(chk3 == null || chk3.length() == 0){
+						state.put("selected", false);
+					}else{
+						state.put("selected", true);
+					}
+					state.put("disabled", false);
+				}else{
+					state.put("disabled", true);
+					state.put("selected", true);
+				}
+				m.put("state", state);
+				//设置属性
+				Map<String, Object> attributes = new HashMap<String, Object>();
+				m.put("li_attr", attributes);
+				attributes.put("id2", m.get("id2"));
+				attributes.put("id3", m.get("id3"));
+				attributes.put("disabled", m.get("disabled"));
+			}
+
+			@Override
+			public void processEnd(Map<String, Object> m, boolean hasChild) {
+				String chk3 = m.get("id3") == null ? "" : m.get("id3").toString();
+				if(hasChild && chk3 != null && chk3.length() > 0){
+					m.remove("checked");
+				}
+				if(hasChild) {
+					m.put("icon", "fa fa-folder-o");
+				}else {
+					m.put("icon", "fa fa-file-o");
+				}
+			}
+
+		});
+		Map<String, Object> m = new HashMap<String, Object>();
+		m.put("id", "root");
+		m.put("text", "系统菜单树");
+		m.put("icon", " fa fa-home");
+		Map<String, Object> state = new HashMap<String, Object>();
+		state.put("disabled", true);
+		m.put("state", state);
+		m.put("children", ret);
+
+		return m;
+	}
+
+	/**
+	 * 给用户授权菜单
+	 * @param userId
+	 * @param menuIds
+	 */
+	@Transactional(rollbackFor = Exception.class)
+	public void saveUserMenu(Integer userId, String menuIds) {
+		//删除以前数据
+		String delSql = "delete from user_menu_rela where user_id = " + userId ;
+		daoHelper.execute(delSql);
+
+		String[] ids = menuIds.split(",");
+		String sql = "insert into user_menu_rela(user_id, menu_id) values(?,?)";
+		for(final String tmp : ids){
+			if(tmp.length() > 0){
+				daoHelper.execute(sql, ps -> {
+					ps.setInt(1, userId);
+					ps.setInt(2, new Integer(tmp));
+					ps.executeUpdate();
+					return null;
+				});
+			}
+		}
+	}
+}

+ 418 - 0
src/main/java/com/ruisitech/bi/service/model/CubeService.java

@@ -0,0 +1,418 @@
+package com.ruisitech.bi.service.model;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisitech.bi.entity.common.RequestStatus;
+import com.ruisitech.bi.entity.common.Result;
+import com.ruisitech.bi.entity.model.Cube;
+import com.ruisitech.bi.entity.model.Dimension;
+import com.ruisitech.bi.entity.model.Measure;
+import com.ruisitech.bi.mapper.model.*;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class CubeService {
+	
+	private Logger log = Logger.getLogger(CubeService.class);
+	
+	@Autowired
+	private CubeMapper mapper;
+	
+	@Autowired
+	private DimensionMapper dimMapper;
+	
+	@Autowired
+	private MeasureMapper kpiMapper;
+	
+	@Autowired
+	private CubeColMetaMapper metaMapper;
+	
+	@Autowired
+	private DatasetMapper dsetMapper;
+
+	public List<Cube> listCube(String keyword){
+		return mapper.listCube(keyword);
+	}
+	
+	public Integer getMaxCubeId(){
+		return mapper.getMaxCubeId();
+	}
+	
+	public JSONObject getCubeById(Integer cubeId){
+		Cube cube = mapper.getCubeById(cubeId);
+		JSONObject ret = (JSONObject) JSONObject.toJSON(cube);
+		//查询字段
+		String cfg = dsetMapper.getDatasetCfg(cube.getDsetId());
+		JSONObject dset = JSONObject.parseObject(cfg);
+		ret.put("cols", dset.get("cols"));
+		ret.put("dynamic", dset.get("dynamic"));
+		//查询维度
+		ret.put("dims", mapper.getCubeDims(cubeId));
+		//查询度量
+		ret.put("kpis", mapper.getCubeKpis(cubeId));
+		return ret;
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public Result insertCube(Cube cube){
+		Result ret = new Result();
+		try{
+			Integer cubeId = mapper.getMaxCubeId();
+			cube.setCubeId(cubeId);
+			mapper.insertCube(cube);
+		
+			this.insertDim(cube);
+			this.insertDimRela(cube);
+			this.insertKpi(cube);
+			this.insertKpiRela(cube);
+			ret.setResult(RequestStatus.SUCCESS.getStatus());
+		}catch(Exception ex){
+			ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			ret.setMsg(ex.getMessage());
+			log.error("立方体保存出错。", ex);
+		}
+		return ret;
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public Result deleteCube(Integer cubeId){
+		Result ret = new Result();
+		try{
+			//删除表
+			mapper.deleteCube(cubeId);
+			metaMapper.deleteByCubeId(cubeId);
+			//删除指标
+			Measure kpi = new Measure();
+			kpi.setCubeId(cubeId);
+			kpiMapper.deleteKpi(kpi);
+			//删除维度
+			Dimension dim = new Dimension();
+			dim.setCubeId(cubeId);
+			dimMapper.deleteDim(dim);
+			//删除分组
+			dimMapper.deleteGroupByCubeId(cubeId);
+			ret.setResult(RequestStatus.SUCCESS.getStatus());
+		}catch(Exception ex){
+			ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			ret.setMsg(ex.getMessage());
+			log.error("立方体保存出错。", ex);
+		}
+		return ret; 
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public Result updateCube(Cube cube){
+		Result ret = new Result();
+		try{
+			mapper.updateCube(cube);
+			//在编辑立方体时,通过delObj 来描述哪些维度,度量、分组被删除掉了。先第一步删除这些
+			List<Map<String, Object>> dels = cube.getDelObj();
+			for(int i=0; dels!=null&&i<dels.size(); i++){
+				Map<String, Object> obj = dels.get(i);
+				Object tp = obj.get("type");
+				Object id = obj.get("id");
+				if(id == null || id.toString().length() == 0){
+					continue;
+				}
+				
+				if("dim".equals(tp)){
+					Dimension dim = new Dimension();
+					dim.setCubeId(cube.getCubeId());
+					dim.setDimId((Integer)id);
+					dimMapper.deleteDim(dim);
+				}else if("kpi".equals(tp)){
+					Measure kpi = new Measure();
+					kpi.setCubeId(cube.getCubeId());
+					kpi.setKpiId((Integer)id);
+					kpiMapper.deleteKpi(kpi);
+				}else if("group".equals(tp)){
+					dimMapper.deleteGroupById((String)id);
+				}
+			}
+			
+			//删除关系表数据,再从建
+			//处理维度
+			this.updateDim(cube);
+			this.insertDimRela(cube);
+			//处理指标
+			this.updateKpi(cube);
+			this.insertKpiRela(cube);
+			ret.setResult(RequestStatus.SUCCESS.getStatus());
+		}catch(Exception ex){
+			ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			ret.setMsg(ex.getMessage());
+			log.error("立方体保存出错。", ex);
+		}
+		return ret;
+	}
+	
+	private void updateDim(Cube cube){
+		List<String> groupkeys = dimMapper.listGroup(cube.getCubeId());
+		List<Dimension> dims = cube.getDims();
+		for(int i=0; i<dims.size(); i++){
+			Dimension dim = dims.get(i);
+			dim.setCubeId(cube.getCubeId());
+			dim.setOrd(i);
+			String type = dim.getType();
+			if(type == null || type.length() == 0){
+				dim.setType("frd");
+			}
+			//判断是否有分组,如果有分组插入分组
+			String groupId = dim.getGroupId();
+			if(groupId != null && groupId.length() > 0 && !groupkeys.contains(groupId)){
+				dimMapper.insertGroup(dim);
+				groupkeys.add(groupId);
+			}
+			Integer targetId = dim.getTargetId();
+			if(targetId == null){  //新增维度
+				dimMapper.insertDim(dim);
+				targetId = dimMapper.getMaxDimId();
+			}else{ //修改维度
+				String isupdate = dim.getIsupdate();
+				if("y".equals(isupdate)){  //只有修改过的维度才更新
+					dimMapper.updatedim(dim);
+				}
+			}
+			dim.setDimId(targetId);
+		}
+	}
+	
+	private void updateKpi(Cube cube){
+		List<Measure> kpis = cube.getKpis();
+		for(int i=0; i<kpis.size(); i++){
+			Measure kpi = kpis.get(i);
+			kpi.setCubeId(cube.getCubeId());
+			Integer targetId = kpi.getTargetId();
+			if(targetId == null){ //新增
+				kpiMapper.insertKpi(kpi);
+				targetId = kpiMapper.getMaxKpiId();
+			}else{ //修改
+				String isupdate = kpi.getIsupdate();
+				if("y".equals(isupdate)){
+					kpiMapper.updateKpi(kpi);
+				}
+			}
+			kpi.setKpiId(targetId);
+		}
+	}
+	
+	private void insertDim(Cube cube){
+		List<String> groupkeys = new ArrayList<String>();
+		List<Dimension> dims = cube.getDims();
+		int dimId = 0;
+		for(int i=0; i<dims.size(); i++){
+			Dimension dim = dims.get(i);
+			dim.setOrd(i);
+			String type = dim.getType();
+			if(type == null || type.length() == 0){
+				dim.setType("frd");
+			}
+			dim.setCubeId(cube.getCubeId());
+			dimMapper.insertDim(dim);
+			if(i == 0){
+				dimId = dimMapper.getMaxDimId();
+			}else{
+				dimId++;
+			}
+		
+			//判断是否有分组,如果有分组插入分组
+			String groupId = dim.getGroupId();
+			if(groupId != null && groupId.length() > 0 && !groupkeys.contains(groupId)){
+				dimMapper.insertGroup(dim);
+				groupkeys.add(groupId);
+			}
+			
+			dim.setDimId(dimId);
+		}
+	}
+	
+	private void insertDimRela(Cube cube){
+		metaMapper.deleteDimMeta(cube.getCubeId());
+		List<Dimension> dims = cube.getDims();
+		for(int i=0; i<dims.size(); i++){
+			Dimension dim = dims.get(i);
+			dim.setColId(dim.getDimId());
+			dim.setOrd(i);
+			dim.setColType(1);
+			metaMapper.insertMeta(dim);
+		}
+	}
+	
+	private void insertKpi(Cube cube){
+		int kpiId = 0;
+		List<Measure> kpis = cube.getKpis();
+		for(int i=0; i<kpis.size(); i++){
+			Measure kpi = kpis.get(i);
+			kpi.setCubeId(cube.getCubeId());
+			kpiMapper.insertKpi(kpi);
+			if(i == 0){
+				kpiId = kpiMapper.getMaxKpiId();
+			}else{
+				kpiId++;
+			}
+			kpi.setKpiId(kpiId);
+		}
+	}
+	
+	private void insertKpiRela(Cube cube){
+		//先删除指标数据
+		metaMapper.deleteKpiMeta(cube.getCubeId());
+		List<Measure> kpis = cube.getKpis();
+		for(int i=0; i<kpis.size(); i++){
+			Measure kpi = kpis.get(i);
+			kpi.setColId(kpi.getKpiId());
+			kpi.setOrd(i);
+			//如果指标不是计算指标,直接拼接,计算指标直接取公式
+			int calcKpi = kpi.getCalcKpi();  //新增度量那创建的计算指标
+			//int calc = kpi.getCalc();  //数据集创建的动态字段
+			if(calcKpi == 0){
+				kpi.setCol(kpi.getAggreCol());
+			}else{
+				kpi.setCol(kpi.getCol());
+			}
+			kpi.setColType(2);
+			metaMapper.insertMeta(kpi);
+		}
+	}
+	
+	public Object treeCube(Integer cubeId){
+		Map<String, Object> curGroup = null; //当前分组对象.
+		List<Map<String, Object>> ls = mapper.listDs(String.valueOf(cubeId));
+		for(int i=0; i<ls.size(); i++){
+			Map<String, Object> m = (Map<String, Object>)ls.get(i);
+			m.put("iconCls", "icon-cube");
+			//给数据集节点添加维度、指标节点
+			List<Map<String, Object>> cubeChild = new ArrayList<Map<String, Object>>();
+			m.put("children", cubeChild);
+			Map<String, Object> wdnode = new HashMap<String, Object>();
+			wdnode.put("id", "wd");
+			wdnode.put("text", "维度");
+			wdnode.put("state", "open");
+			wdnode.put("iconCls", "icon-dim2");
+			List<Map<String, Object>> wdnodeChild = new ArrayList<Map<String, Object>>();
+			wdnode.put("children", wdnodeChild);
+			cubeChild.add(wdnode);
+			Map<String, Object> zbnode = new HashMap<String, Object>();
+			zbnode.put("id", "zb");
+			zbnode.put("text", "度量");
+			zbnode.put("state", "open");
+			zbnode.put("iconCls", "icon-kpigroup");
+			List<Map<String, Object>> zbnodeChild = new ArrayList<Map<String, Object>>();
+			zbnode.put("children", zbnodeChild);
+			cubeChild.add(zbnode);
+			
+			List<Map<String, Object>> children = mapper.listCubeMeta(cubeId);
+			
+			//设置attributes;
+			for(int j=0; j<children.size(); j++){
+				Map<String, Object> child = (Map<String, Object>)children.get(j);
+				Integer col_type = new Integer(child.get("col_type").toString());
+				String grouptype = (String)child.get("grouptype");
+				if(grouptype == null || grouptype.length() == 0){
+					grouptype = null;
+				}
+				String groupname = (String)child.get("groupname");
+				if(grouptype != null && grouptype.length() > 0){
+					if(curGroup == null || !curGroup.get("id").equals(grouptype)){
+						//添加分组节点
+						Map<String, Object> fz = new HashMap<String, Object>();
+						fz.put("id", grouptype);
+						fz.put("text", groupname);
+						fz.put("state", "open");
+						fz.put("iconCls", "icon-dim");
+						fz.put("children", new ArrayList());
+						//给分组添加attributes (把分组的第一个节点信息传递给他,拖拽分组时就当拖拽第一个节点)
+						Map<String, Object> attr = new HashMap<String, Object>();
+						fz.put("attributes", attr);
+						attr.put("col_type", col_type);
+						attr.put("col_id", child.get("col_id"));
+						attr.put("col_name", child.get("col_name"));
+						attr.put("cubeId", child.get("cubeId"));
+						attr.put("dsetId", child.get("dsetId"));
+						attr.put("dsid", child.get("dsid"));
+						attr.put("alias", child.get("alias"));
+						attr.put("dim_type", child.get("dim_type"));
+						attr.put("tableName", child.get("tableName") == null ? "" : child.get("tableName"));
+						attr.put("tableColKey", child.get("tableColKey") == null ? "" : child.get("tableColKey"));
+						attr.put("tableColName", child.get("tableColName") == null ? "" : child.get("tableColName"));
+						attr.put("ordcol", child.get("ordcol") == null ? "" : child.get("ordcol"));
+						attr.put("dateformat", child.get("dateformat") == null ? "" : child.get("dateformat"));
+						attr.put("tname", child.get("tname"));
+						attr.put("calc", child.get("calc"));
+						if(curGroup == null){
+							attr.put("iscas", "");
+						}else{
+							attr.put("iscas", "y");
+						}
+						attr.put("dimord", child.get("dimord") == null ? "" : child.get("dimord"));
+						attr.put("grouptype", grouptype);
+						attr.put("valType", child.get("valType"));
+						wdnodeChild.add(fz);
+						curGroup = fz;
+					}
+				}else{
+					curGroup = null;
+				}
+				Map<String, Object> attr = new HashMap<String, Object>();
+				child.put("attributes", attr);
+				//添加立方体所使用的数据源到Tree
+				attr.put("col_type", col_type);
+				attr.put("col_id", child.get("col_id"));
+				attr.put("col_name", child.get("col_name"));
+				attr.put("cubeId", child.get("cubeId"));
+				attr.put("dsetId", child.get("dsetId"));
+				attr.put("dsid", child.get("dsid"));
+				attr.put("alias", child.get("alias"));
+				attr.put("fmt", child.get("fmt") == null ? "" : child.get("fmt"));
+				attr.put("aggre", child.get("aggre"));
+				attr.put("dim_type", child.get("dim_type"));
+				attr.put("tableName", child.get("tableName") == null ? "" : child.get("tableName"));
+				attr.put("tableColKey", child.get("tableColKey") == null ? "" : child.get("tableColKey"));
+				attr.put("tableColName", child.get("tableColName") == null ? "" : child.get("tableColName"));
+				attr.put("dateformat", child.get("dateformat") == null ? "" : child.get("dateformat"));
+				attr.put("tname", child.get("tname"));
+				attr.put("calc", child.get("calc"));
+				if(curGroup == null){
+					attr.put("iscas", "");
+				}else{
+					attr.put("iscas", "y");
+				}
+				attr.put("dimord", child.get("dimord") == null ? "" : child.get("dimord"));
+				attr.put("rate", child.get("rate"));
+				attr.put("unit", child.get("unit") == null ? "" : child.get("unit"));
+				attr.put("grouptype", grouptype);
+				attr.put("calc_kpi", child.get("calc_kpi"));
+				attr.put("valType", child.get("valType"));
+				attr.put("ordcol", child.get("ordcol") == null ? "" : child.get("ordcol"));
+				//设置节点图标
+				if(col_type == 1){
+					if(grouptype == null || grouptype.length() == 0){
+						child.put("iconCls", "icon-dim");
+					}else{
+						child.put("iconCls", "icon-dimlevel");
+					}
+				}else{
+					child.put("iconCls", "icon-kpi");
+				}
+				if(col_type == 1){
+					if(curGroup == null){
+						wdnodeChild.add(child);
+					}else{
+						((List)curGroup.get("children")).add(child);
+					}
+				}else{
+					zbnodeChild.add(child);
+				}
+			}
+		}
+		return ls;
+	}
+}

+ 255 - 0
src/main/java/com/ruisitech/bi/service/model/DataSourceService.java

@@ -0,0 +1,255 @@
+package com.ruisitech.bi.service.model;
+
+import com.ruisi.ext.engine.view.exception.ExtConfigException;
+import com.ruisitech.bi.entity.common.RequestStatus;
+import com.ruisitech.bi.entity.common.Result;
+import com.ruisitech.bi.entity.model.DataSource;
+import com.ruisitech.bi.mapper.model.DataSourceMapper;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+@Service
+public class DataSourceService {
+	/**
+	public static final String mysql = "com.mysql.jdbc.Driver";
+	public static final String oracle = "oracle.jdbc.driver.OracleDriver";
+	public static final String sqlserver = "net.sourceforge.jtds.jdbc.Driver";
+	public static final String db2 = "com.ibm.db2.jcc.DB2Driver";
+	public static final String psql = "org.postgresql.Driver";
+	public static final String hive = "org.apache.hive.jdbc.HiveDriver";
+	public static final String kylin = "org.apache.kylin.jdbc.Driver";
+	**/
+	/**
+	public static final String showTables_mysql = "show tables";
+	public static final String showTables_oracle = "select table_name from tabs";
+	public static final String showTables_sqlser = "select name from sysobjects where xtype='U' order by name";
+	public static final String showTables_db2 = "select name from sysibm.systables where type='T' and creator='$0'";
+	public static final String showTables_psql = "select tablename from pg_tables where tableowner='$0'";
+	public static final String showTables_hive = "show tables";
+	public static final String showTables_kylin = "show tables";
+	**/
+	
+	private Logger log = Logger.getLogger(DataSourceService.class);
+	
+	@Autowired
+	private DataSourceMapper mapper;
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	public List<DataSource> listDataSource(){
+		return mapper.listDataSource();
+	}
+	
+	public void insertDataSource(DataSource ds){
+		ds.setDsid(UUID.randomUUID().toString().replaceAll("-", ""));
+		if("jndi".equals(ds.getUse())){
+			ds.setDsname(ds.getJndiName());
+		}
+		mapper.insertDataSource(ds);
+	}
+	
+	public void updateDataSource(DataSource ds){
+		if("jndi".equals(ds.getUse())){
+			ds.setDsname(ds.getJndiName());
+		}
+		mapper.updateDataSource(ds);
+		//清除缓存
+		this.cacheService.removeDsource(ds.getDsid());
+	}
+	
+	public void deleteDataSource(String dsid){
+		mapper.deleteDataSource(dsid);
+		//清除缓存
+		this.cacheService.removeDsource(dsid);
+	}
+	
+	public DataSource getDataSource(String dsid){
+		return mapper.getDataSource(dsid);
+	}
+	
+	public Result testJNDI(DataSource ds){
+		Result ret = new Result();
+		Connection con = null;
+		try{
+		  	Context ctx = new InitialContext();      
+		    String strLookup = "java:comp/env/"+ds.getJndiName(); 
+		    javax.sql.DataSource sds = (javax.sql.DataSource) ctx.lookup(strLookup);
+		    con = sds.getConnection();
+		    if (con != null){
+		    	ret.setResult(RequestStatus.SUCCESS.getStatus());
+		    }else{
+		    	ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+		    }
+		}catch (Exception e) {
+			log.error("JNDI测试出错", e);
+			ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			ret.setMsg(e.getMessage());
+		}finally{
+			if(con != null){
+				try {
+					con.close();
+				} catch (SQLException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return ret;
+	}
+	
+	public Connection getJDBC(DataSource ds) throws Exception{
+		try {
+			Connection conn = null;
+			Class.forName(ds.getClazz()).newInstance();
+			conn= DriverManager.getConnection(ds.getLinkUrl(), ds.getLinkName(), ds.getLinkPwd());
+			return conn;
+		} catch (Exception e) {
+			throw e;
+		}
+	}
+	
+	public Connection getJndi(DataSource ds) throws Exception {
+		Connection con = null;
+		try {
+			Context ctx = new InitialContext();      
+		    String strLookup = "java:comp/env/"+ds.getJndiName(); 
+		    javax.sql.DataSource sds =(javax.sql.DataSource) ctx.lookup(strLookup);
+		    con = sds.getConnection();
+		}catch(Exception ex){
+			ex.printStackTrace();
+			throw ex;
+		}
+	    return con;
+	}
+	
+	public Result testDataSource(DataSource ds) throws ExtConfigException {
+		Result ret = new Result();
+		String clazz = ds.getClazz();
+		Connection conn = null;
+		try {
+			Class.forName(clazz).newInstance();
+			conn= DriverManager.getConnection(ds.getLinkUrl(), ds.getLinkName(),  ds.getLinkPwd());
+			if(conn != null){
+				ret.setResult(RequestStatus.SUCCESS.getStatus());
+			}else{
+				ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			}
+		} catch (Exception e) {
+			log.error("JDBC测试出错。", e);
+			ret.setResult(RequestStatus.FAIL_FIELD.getStatus());
+			ret.setMsg(e.getMessage());
+		}finally{
+			if(conn != null){
+				try {
+					conn.close();
+				} catch (SQLException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return ret;
+	}
+	
+	public List<Map<String, Object>> listTables(String dsid, String searchTname) throws Exception{
+		DataSource ds = mapper.getDataSource(dsid);
+		final List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
+		Connection conn = null;
+		try {
+			if(ds.getUse().equals("jndi")){
+				conn = this.getJndi(ds);
+			}else if(ds.getUse().equals("jdbc")){
+				conn = this.getJDBC(ds);
+			}
+			String schem = null;
+			if("oracle".equals(ds.getLinkType())){
+				schem = ds.getLinkName().toUpperCase();
+			}
+			if("postgresql".equals(ds.getLinkType())) {
+				if (ds.getLinkUrl().toLowerCase().indexOf("schema") > 0) {
+					String currentSchema = ds.getLinkUrl().toLowerCase().substring(ds.getLinkUrl().toLowerCase().lastIndexOf("schema"));
+					int start = currentSchema.indexOf("=");
+					int end = currentSchema.indexOf("&");
+					schem = currentSchema.substring(start + 1,end > 0 ? end : currentSchema.length());
+				}
+			}
+			String catalog = null;
+			if("mysql".equals(ds.getLinkType())) {
+				catalog = conn.getCatalog();
+			}
+			ResultSet tbs = conn.getMetaData().getTables(catalog, schem, (searchTname!=null&&searchTname.length() > 0) ?("%"+searchTname+"%"):"%", new String[]{"TABLE","VIEW"});
+			while(tbs.next()){
+				Map<String, Object> m = new HashMap<String, Object>();
+				String tname = tbs.getString("TABLE_NAME");
+				if (StringUtils.isNotBlank(schem)) {
+					tname = schem + "." + tname;
+				}
+				m.put("id", tname);
+				m.put("text", tname);
+				m.put("icon", "fa fa-table");
+				ret.add(m);
+			}
+			tbs.close();
+			
+			/**
+			String qsql = null;
+			if("mysql".equals(ds.getLinkType())){
+				qsql = showTables_mysql;
+			}else if("oracle".equals(ds.getLinkType())){
+				qsql = showTables_oracle;
+			}else if("sqlserver".equals(ds.getLinkType())){
+				qsql = showTables_sqlser;
+			}else if("db2".equals(ds.getLinkType())){
+				qsql = ConstantsEngine.replace(showTables_db2, ds.getLinkName());
+			}else if("postgresql".equals(ds.getLinkType())){
+				qsql = ConstantsEngine.replace(showTables_psql, ds.getLinkName());
+			}else if("hive".equals(ds.getLinkType())){
+				qsql = showTables_hive;
+			}else if("kylin".equals(ds.getLinkType())){
+				qsql = showTables_kylin;
+			}
+			ResultSet tbs = conn.getMetaData().getTables(null, null, "%", new String[]{"TABLE"});
+			
+		
+			while(tbs.next()){
+				for(int i=0; i<tbs.getMetaData().getColumnCount(); i++){
+					String col = tbs.getMetaData().getColumnLabel(i + 1);
+					System.out.println( col + " === " + tbs.getString(col));
+				}
+			}
+			tbs.close();
+			PreparedStatement ps = conn.prepareStatement(qsql);
+			ResultSet rs = ps.executeQuery();
+			while(rs.next()){
+				Map<String, Object> m = new HashMap<String, Object>();
+				copyData(rs, m);
+				ret.add(m);
+			}
+			rs.close();
+			ps.close();
+			**/
+		}catch (SQLException e) {
+			e.printStackTrace();
+			throw new RuntimeException("sql 执行报错.");
+		}finally{
+			if(conn != null){
+				try {
+					conn.close();
+				} catch (SQLException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return ret;
+	}
+}

+ 309 - 0
src/main/java/com/ruisitech/bi/service/model/DatasetService.java

@@ -0,0 +1,309 @@
+package com.ruisitech.bi.service.model;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisitech.bi.entity.common.DSColumn;
+import com.ruisitech.bi.entity.model.DataSource;
+import com.ruisitech.bi.entity.model.Dataset;
+import com.ruisitech.bi.mapper.model.DatasetMapper;
+import com.ruisitech.bi.mapper.model.DimensionMapper;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class DatasetService {
+
+	@Autowired
+	private DatasetMapper mapper;
+	
+	@Autowired
+	private DataSourceService dsService;
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	@Autowired
+	private DimensionMapper dimMapper;
+	
+	public List<Dataset> listDataset(){
+		return mapper.listDataset();
+	}
+	
+	@Transactional(rollbackFor = Exception.class)
+	public void updateDset(Dataset ds){
+		mapper.updateDset(ds);
+		//同步立方体表的字段类型
+		JSONObject obj = (JSONObject)JSON.parse(ds.getCfg());
+		JSONArray cols = obj.getJSONArray("cols");
+		for(int i=0; i<cols.size(); i++){
+			JSONObject col = cols.getJSONObject(i);
+			String isupdate = (String)col.get("isupdate");
+			if("y".equals(isupdate)){
+				String type = col.getString("type");
+				Map<String,Object> param = new HashMap<String, Object>();
+				param.put("vtype", type);
+				param.put("tname", col.getString("tname"));
+				param.put("col", col.getString("name"));
+				param.put("dset", obj.get("dsetId"));
+				dimMapper.updateColType(param);
+			}
+		}
+		
+		//删除缓存
+		cacheService.removeDset(ds.getDsid());
+	}
+	
+	/**
+	 * 重新加载数据集的字段
+	 * @param dsetId
+	 * @throws Exception 
+	 */
+	public void reloadDset(String dsetId, String dsid) throws Exception{
+		String cfg = mapper.getDatasetCfg(dsetId);
+		JSONObject json = JSON.parseObject(cfg);
+		JSONArray oldCols = json.getJSONArray("cols");
+		List<DSColumn> cols = this.queryMetaAndIncome(json, dsid);
+		//添加新的字段到原数据集中
+		List<DSColumn> addList = new ArrayList<DSColumn>();
+		for(DSColumn col : cols){
+			if(!existCol(col.getName(), oldCols)){
+				addList.add(col);
+			}
+		}
+		if(addList.size() == 0){
+			return;
+		}
+		for(DSColumn col : addList){
+			oldCols.add(JSON.toJSON(col));
+		}
+		String newCfg = json.toJSONString();
+		Dataset ds = new Dataset();
+		ds.setDsetId(dsetId);
+		ds.setCfg(newCfg);
+		mapper.updateDsetCfg(ds);
+	}
+	
+	private boolean existCol(String colName, JSONArray cols){
+		boolean ext = false;
+		for(int i=0; i<cols.size(); i++){
+			JSONObject col = cols.getJSONObject(i);
+			String name = col.getString("name");
+			if(name.equals(colName)){
+				ext = true;
+				break;
+			}
+		}
+		return ext;
+	}
+	
+	public void insertDset(Dataset ds){
+		mapper.insertDset(ds);
+	}
+	
+	public void deleteDset(String dsetId){
+		mapper.deleteDset(dsetId);
+		//删除缓存
+		cacheService.removeDset(dsetId);
+	}
+	
+	public String getDatasetCfg(String dsetId){
+		return mapper.getDatasetCfg(dsetId);
+	}
+	
+	public List<DSColumn> listTableColumns(String dsid, String tname) throws Exception{
+		DataSource ds = dsService.getDataSource(dsid);
+		Connection conn = null;
+		try {
+			if(ds.getUse().equals("jndi")){
+				conn = dsService.getJndi(ds);
+			}else if(ds.getUse().equals("jdbc")){
+				conn = dsService.getJDBC(ds);
+			}
+			String sql = "select * from "+ tname;
+			PreparedStatement ps = conn.prepareStatement(sql);
+			ps.setMaxRows(1);
+			ResultSet rs = ps.executeQuery();
+			List<DSColumn> cols = copyValue(rs);
+			rs.close();
+			ps.close();
+			return cols;
+		}catch (SQLException e) {
+			e.printStackTrace();
+			throw new RuntimeException("sql 执行报错.");
+		}finally{
+			if(conn != null){
+				conn.close();
+			}
+		}
+	}
+	
+	public List<DSColumn> copyValue(ResultSet rs) throws SQLException{
+		ResultSetMetaData meta = rs.getMetaData();
+		List<DSColumn> cols = new ArrayList<DSColumn>();
+		for(int i=0; i<meta.getColumnCount(); i++){
+			String name = meta.getColumnName(i+1);
+			if(name.indexOf(".") >= 0){
+				name = name.substring(name.indexOf(".") + 1, name.length());
+			}
+			String tp = meta.getColumnTypeName(i+1);
+			//meta.get
+			//tp转换
+			tp = columnType2java(tp);
+			DSColumn col = new DSColumn();
+			col.setName(name);
+			col.setType(tp);
+			col.setIsshow(true);
+			col.setIdx(i+1);
+			if("Date".equals(tp)){
+				//日期不设置长度
+			}else{
+				col.setLength(meta.getColumnDisplaySize(i + 1));
+			}
+			cols.add(col);
+		}
+		return cols;
+	}
+	
+	public String columnType2java(String tp){
+		tp = tp.replaceAll(" UNSIGNED", ""); //mysql 存在 UNSIGNED 类型, 比如: INT UNSIGNED
+		String ret = null;
+		if("varchar".equalsIgnoreCase(tp) || "varchar2".equalsIgnoreCase(tp) || "nvarchar".equalsIgnoreCase(tp) || "char".equalsIgnoreCase(tp)){
+			ret = "String";
+		}else if("int".equalsIgnoreCase(tp) || "MEDIUMINT".equalsIgnoreCase(tp) || "BIGINT".equalsIgnoreCase(tp) || "smallint".equalsIgnoreCase(tp) || "TINYINT".equalsIgnoreCase(tp)){
+			ret = "Int";
+		}else if("number".equalsIgnoreCase(tp) || "DECIMAL".equalsIgnoreCase(tp) || "Float".equalsIgnoreCase(tp) || "Double".equalsIgnoreCase(tp)){
+			ret = "Double";
+		}else if("DATETIME".equalsIgnoreCase(tp) || "DATE".equalsIgnoreCase(tp) || "Timestamp".equalsIgnoreCase(tp)){
+			ret = "Date";
+		}
+		return ret;
+	}
+	
+	/**
+	 * 查询数据集的字段
+	 * @param dataset
+	 * @param dsid
+	 * @return
+	 * @throws Exception 
+	 */
+	public List<DSColumn> queryMetaAndIncome(JSONObject dataset, String dsid) throws Exception{
+		DataSource ds = this.dsService.getDataSource(dsid);
+		List<String> tables = new ArrayList<String>();
+		//需要进行关联的表
+		JSONArray joinTabs = (JSONArray)dataset.get("joininfo");
+		//生成sql
+		StringBuffer sb = new StringBuffer("select a0.* ");
+		//添加 列的分隔符,方便识别列是从哪个表来
+		if(joinTabs!=null&&joinTabs.size() != 0){ //无关联表,不需要该字段
+			sb.append(",'' a$idx ");
+		}
+		
+		List<String> tabs = new ArrayList<String>(); //需要进行关联的表,从joininfo中获取,剔除重复的表
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){
+			JSONObject join = joinTabs.getJSONObject(i);
+			String ref = join.getString("ref");
+			if(!tabs.contains(ref)){
+				tabs.add(ref);
+			}
+		}
+		
+		for(int i=0; i<tabs.size(); i++){
+			sb.append(", a"+(i+1)+".* ");
+			if(i != tabs.size() - 1){
+				//添加 列的分隔符,方便识别列是从哪个表来
+				sb.append(",'' a$idx");
+			}
+		}
+		sb.append("from ");
+		String master = dataset.getString("master");
+		sb.append( master + " a0 ");
+		tables.add(dataset.getString("master"));
+		for(int i=0; i<tabs.size(); i++){
+			String tab = tabs.get(i);
+			sb.append(", " +tab);
+			sb.append(" a"+(i+1)+" ");
+			tables.add(tab);
+		}
+		sb.append("where 1=2 ");
+		for(int i=0; i<tabs.size(); i++){
+			String tab = tabs.get(i);
+			List<JSONObject> refs = getJoinInfoByTname(tab, joinTabs);
+			for(int k=0; k<refs.size(); k++){
+				JSONObject t = refs.get(k);
+				sb.append("and a0."+t.getString("col")+"=a"+(i+1)+"."+t.getString("refKey"));
+				sb.append(" ");
+			}
+		}
+		
+		Connection conn  = null;
+		try {
+			if(ds.getUse().equals("jndi")){
+				conn = this.dsService.getJndi(ds);
+			}else if(ds.getUse().equals("jdbc")){
+				conn = this.dsService.getJDBC(ds);
+			}
+			PreparedStatement ps = conn.prepareStatement(sb.toString());
+			ps.setMaxRows(1);
+			ResultSet rs = ps.executeQuery();
+			
+			ResultSetMetaData meta = rs.getMetaData();
+			List<DSColumn> cols = new ArrayList<DSColumn>();
+			String tname = tables.get(0);
+			int idx = 1;
+			for(int i=0; i<meta.getColumnCount(); i++){
+				String name = meta.getColumnName(i+1);
+				if(name.indexOf(".") >= 0){
+					name = name.substring(name.indexOf(".") + 1, name.length());
+				}
+				String tp = meta.getColumnTypeName(i+1);
+				//遇到a$idx 表示字段做分割, 需要变换字段所属表信息
+				if("a$idx".equalsIgnoreCase(name)){
+					tname = tables.get(idx);
+					idx++;
+					continue;
+				}
+				tp = columnType2java(tp);
+				DSColumn col = new DSColumn();
+				col.setIdx(idx);
+				col.setDispName("");
+				col.setExpression("");
+				col.setName(name);
+				col.setType(tp);
+				col.setTname(tname);
+				col.setIsshow(true);
+				cols.add(col);
+			}
+			rs.close();
+			ps.close();
+			return cols;
+		} catch (SQLException e) {
+			e.printStackTrace();
+			throw new RuntimeException("sql 执行报错.");
+		}finally{
+			if(conn != null){
+				conn.close();
+			}
+		}
+	}
+	
+	private List<JSONObject> getJoinInfoByTname(String tname, JSONArray joins){
+		List<JSONObject> ret = new ArrayList<JSONObject>();
+		for(int i=0; joins!=null&&i<joins.size(); i++){
+			JSONObject join = joins.getJSONObject(i);
+			String ref = join.getString("ref");
+			if(ref.equals(tname)){
+				ret.add(join);
+			}
+		}
+		return ret;
+	}
+}

+ 17 - 0
src/main/java/com/ruisitech/bi/service/model/DimensionService.java

@@ -0,0 +1,17 @@
+package com.ruisitech.bi.service.model;
+
+import com.ruisitech.bi.entity.model.Dimension;
+import com.ruisitech.bi.mapper.model.DimensionMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DimensionService {
+
+	@Autowired
+	private DimensionMapper mapper;
+	
+	public Dimension getDimInfo(Integer dimId, Integer cubeId){
+		return mapper.getDimInfo(dimId, cubeId);
+	}
+}

+ 191 - 0
src/main/java/com/ruisitech/bi/service/portal/BoxService.java

@@ -0,0 +1,191 @@
+package com.ruisitech.bi.service.portal;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisi.ext.engine.view.context.html.*;
+import com.ruisi.ext.engine.view.emitter.highcharts.util.ChartUtils;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.portal.BoxQuery;
+import com.ruisitech.bi.service.bireport.BaseCompService;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.ext.service.DataControlInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@Scope("prototype")
+public class BoxService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.portal.box";
+	
+	private Map<String, InputField> mvParams = new HashMap<String, InputField>(); //mv的参数
+
+	@Autowired
+	private DataControlInterface dataControl; //数据权限控制
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		mvParams.clear();
+	}
+	
+	public MVContext json2MV(BoxQuery box) throws Exception{
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		
+		//处理参数,把参数设为hidden
+		super.parserHiddenParam(box.getPortalParams(), mv, mvParams);	
+		
+		this.json2Box(box, mv, false);
+		
+		super.createDsource(this.cacheService.getDsource(box.getDsid()), mv);
+		
+		
+		return mv;
+	}
+	
+	/**
+	 * 通过数据生成 box 块
+	 * @param mv
+	 * @throws IOException 
+	 */
+	public void json2Box(BoxQuery box, Element mv, boolean crtTitle) throws IOException{
+		if(box.getKpiJson()== null){
+			return;
+		}
+		//创建标题
+		if(crtTitle){
+			TextContext text = new TextContextImpl();
+			TextProperty tp = new TextProperty();
+			tp.setAlign("center");
+			tp.setColor(box.getKpiJson().getTfontcolor());
+			tp.setStyleClass("ibox-title-view");
+			text.setText(box.getName());
+			text.setTextProperty(tp);
+			mv.getChildren().add(text);
+			text.setParent(mv);
+		}
+		//创建box 的 data 标签
+		String sql = createSql(box);
+		DataContext data = new DataContextImpl();
+		data.setKey("k" + box.getKpiJson().getKpi_id());
+		data.setRefDsource(box.getDsid());
+		String name = TemplateManager.getInstance().createTemplate(sql);
+		data.setTemplateName(name);
+		mv.getChildren().add(data);
+		data.setParent(mv);
+		
+		//创建box 显示 text 标签
+		KpiDto kpi = box.getKpiJson();
+		TextContext text = new TextContextImpl();
+		String str = "#if($!k"+kpi.getKpi_id()+"."+kpi.getAlias()+") $extUtils.numberFmt($!k"+kpi.getKpi_id()+"."+kpi.getAlias()+", '"+kpi.getFmt()+"') <font size='2'>" ;
+		Object rate = kpi.getRate();
+		if(rate != null){
+			str += ChartUtils.writerUnit(new Integer(rate.toString()));
+		}
+		str += kpi.getUnit()+"</font>";
+		str += "#else - #end";
+		String word = TemplateManager.getInstance().createTemplate(str);
+		text.setTemplateName(word);
+		text.setFormatHtml(true);
+		TextProperty tp = new TextProperty();
+		tp.setAlign("center");
+		tp.setWeight("normal");
+		if(box.getHeight() != null){
+			tp.setLineHeight(box.getHeight());
+			tp.setHeight(String.valueOf(box.getHeight()));
+		}
+		Integer tfontsize = box.getKpiJson().getTfontsize();
+		if(tfontsize != null){
+			tp.setSize(String.valueOf(tfontsize));
+		}else{
+			tp.setSize("32");
+		}
+		String tfontcolor = box.getKpiJson().getTfontcolor();
+		if(tfontcolor != null && tfontcolor.length() > 0){
+			tp.setColor(tfontcolor);
+		}else{
+			tp.setColor("#000000");
+		}
+		tp.setStyleClass("boxcls");
+		text.setTextProperty(tp);
+		mv.getChildren().add(text);
+		text.setParent(mv);
+	}
+	
+	public String createSql(BoxQuery box){
+		JSONObject dset = this.cacheService.getDset(box.getDsetId());
+		Map<String, String> tableAlias = createTableAlias(dset);
+		KpiDto kpi = box.getKpiJson();
+		StringBuffer sql = new StringBuffer();
+		sql.append("select ");
+		Integer rate = kpi.getRate();
+		if(kpi.getCalc() != null && kpi.getCalc() == 1){  //表达式,直接取表达式
+			sql.append(kpi.getCol_name());
+		}else{  //获取字段别名
+			String name = super.convertKpiName(kpi, tableAlias);
+			sql.append( name);
+		}
+		if(rate != null){
+			sql.append("/" + rate);
+		}
+		sql.append(" as ");
+		sql.append(kpi.getAlias());
+		
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		String master = dset.getString("master");
+		sql.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sql.append(" " + jtype);
+			}
+			sql.append(" join " + ref+ " " + tableAlias.get(ref));
+			sql.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sql.append(" ");
+		}
+		sql.append(" where 1=1 ");
+		
+		if(dataControl != null){
+			String ret = dataControl.process(RSBIUtils.getLoginUserInfo(), (String)dset.get("master"));
+			if(ret != null){
+				sql.append(ret + " ");
+			}
+		}
+		sql.append(" " + dealCubeParams(box.getParams(), tableAlias));
+		return sql.toString().replaceAll("@", "'");
+	}
+
+	public Map<String, InputField> getMvParams() {
+		return mvParams;
+	}
+}

+ 293 - 0
src/main/java/com/ruisitech/bi/service/portal/GridService.java

@@ -0,0 +1,293 @@
+package com.ruisitech.bi.service.portal;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisi.ext.engine.view.context.grid.PageInfo;
+import com.ruisi.ext.engine.view.context.gridreport.GridCell;
+import com.ruisi.ext.engine.view.context.gridreport.GridReportContext;
+import com.ruisi.ext.engine.view.context.gridreport.GridReportContextImpl;
+import com.ruisitech.bi.entity.portal.CompParamDto;
+import com.ruisitech.bi.entity.portal.GridColDto;
+import com.ruisitech.bi.entity.portal.GridQuery;
+import com.ruisitech.bi.service.bireport.BaseCompService;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.ext.service.DataControlInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Scope("prototype")
+public class GridService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.portal.gridReport";
+	
+	private Map<String, InputField> mvParams = new HashMap<String, InputField>(); //mv的参数
+	
+	@Autowired
+	private DataControlInterface dataControl; //数据权限控制
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		mvParams.clear();
+	}
+	
+	public MVContext json2MV(GridQuery grid) throws Exception{
+		
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		
+		//处理参数,把参数设为hidden
+		parserHiddenParam(grid.getPortalParams(), mv, this.mvParams);
+		
+		//创建corssReport
+		GridReportContext cr = json2Grid(grid);
+		//设置ID
+		String id = ExtConstants.reportIdPrefix + IdCreater.create();
+		cr.setId(id);
+		
+		//创建数据sql
+		String sql = this.createSql(grid);
+		String name = TemplateManager.getInstance().createTemplate(sql);
+		cr.setTemplateName(name);
+		
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		
+		Map<String, GridReportContext> crs = new HashMap<String, GridReportContext>();
+		crs.put(cr.getId(), cr);
+		mv.setGridReports(crs);
+		
+		//设置数据集
+		String dsid = super.createDsource(this.cacheService.getDsource(grid.getDsid()), mv);
+		cr.setRefDsource(dsid);
+		
+		return mv;
+	}
+
+	public GridReportContext json2Grid(GridQuery gridJson){
+		GridReportContext grid = new GridReportContextImpl();
+		Integer height = gridJson.getHeight();
+		grid.setOut("lockUI");
+		if(height != null){
+			grid.setHeight(String.valueOf(height));
+		}
+		List<GridColDto> cols = gridJson.getCols();
+		//生成head
+		GridCell[][] headers = new GridCell[1][cols.size()];
+		for(int i=0; i<cols.size(); i++){
+			GridColDto col = cols.get(i);
+			GridCell cell = new GridCell();
+			cell.setColSpan(1);
+			cell.setRowSpan(1);
+			String name = col.getName();
+			String id = col.getId();
+			String dispName = col.getDispName();
+			cell.setDesc(dispName == null || dispName.length() == 0 ? name : dispName);
+			cell.setAlias(id);
+			headers[0][i] = cell;
+		}
+		grid.setHeaders(headers);
+		
+		//生成Detail
+		GridCell[][] detail = new GridCell[1][cols.size()];
+		for(int i=0; i<cols.size(); i++){
+			GridColDto col = cols.get(i);
+			GridCell cell = new GridCell();
+			String id = col.getId();
+			String type = col.getType();
+			cell.setAlias(id);
+			String fmt = col.getFmt();
+			String align = col.getAlign();
+			if(fmt != null && fmt.length() > 0){
+				cell.setFormatPattern(fmt);
+			}
+			if(align != null && align.length() > 0){
+				cell.setAlign(align);
+			}
+			detail[0][i] = cell;
+		}
+		grid.setDetails(detail);
+		
+		//设置分页
+		Integer pageSize = gridJson.getPageSize();
+		if(pageSize == null){
+			pageSize = 10;
+		}
+		PageInfo page = new PageInfo();
+		page.setPagesize(pageSize);
+		//是否禁用分页
+		String isnotfy = gridJson.getIsnotfy();
+		if("true".equals(isnotfy)){
+			
+		}else{
+			grid.setPageInfo(page);
+		}
+		return grid;
+	}
+	
+	public String createSql(GridQuery grid){
+		JSONObject dset = this.cacheService.getDset(grid.getDsetId());
+		Map<String, String> tableAlias = createTableAlias(dset);
+		StringBuffer sb = new StringBuffer("select ");
+		List<GridColDto> cols = grid.getCols();
+		for(int i=0; i<cols.size(); i++){
+			GridColDto col = cols.get(i);
+			String tname = col.getTname();
+			String name = col.getName();
+			String expression = col.getExpression();  //表达式字段
+			if(expression != null && expression.length() > 0){
+				sb.append(" "+ expression + " as " + name);
+			}else{
+				sb.append(" "+tableAlias.get(tname)+"."+name + " as " + name);
+			}
+			if(i != cols.size() - 1){
+				sb.append(",");
+			}
+		}
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		String master = dset.getString("master");
+		sb.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sb.append(" " + jtype);
+			}
+			sb.append(" join " + ref+ " " + tableAlias.get(ref));
+			sb.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sb.append(" ");
+			
+		}
+		sb.append(" where 1=1 ");
+		//数据权限
+		if(dataControl != null){
+			String ret = dataControl.process(RSBIUtils.getLoginUserInfo(), master);
+			if(ret != null){
+				sb.append(ret + " ");
+			}
+		}
+		
+		//添加参数筛选
+		List<CompParamDto> compParams = grid.getParams();
+		for(int i=0; compParams!=null&&i<compParams.size(); i++){
+			CompParamDto param = compParams.get(i);
+			String col = param.getCol();
+			String tname = param.getTname();
+			String expression = param.getExpression();  //如果有表达式,用表达式替换 字段
+			if(expression != null && expression.length() > 0) {
+				col = expression;
+			}else{
+				col = tableAlias.get(tname)+"." + col;
+			}
+			String type = param.getType();
+			String val = param.getVal();
+			String val2 = param.getVal2();
+			String valuetype = param.getValuetype();
+			String usetype = param.getUsetype();
+			String linkparam = param.getLinkparam();
+			String linkparam2 = param.getLinkparam2();
+			
+			
+			if(type.equals("like")){
+				if(val != null){
+					val = "%"+val+"%";
+				}
+				if(val2 != null){
+					val2 = "%"+val2+"%";
+				}
+			}
+			if("string".equals(valuetype)){
+				if(val != null){
+					if("in".equals(type)){  //in需要把数据用逗号分隔的重新生成
+						String[] vls = val.split(",");
+						val = "";
+						for(int j=0; j<vls.length; j++){
+							val = val + "'" + vls[j] + "'";
+							if(j != vls.length - 1){
+								val = val + ",";
+							}
+						}
+					}else{
+						val = "'" + val + "'";
+					}
+				}
+				if(val2 != null){
+					val2 = "'" + val2 + "'";
+				}
+			}
+			if(type.equals("between")){
+				if(usetype.equals("gdz")){
+					sb.append(" and " +  col + " " + type + " " + val + " and " + val2);
+				}else{
+					sb.append("#if([x]"+linkparam+" != '' && [x]"+linkparam2+" != '') ");
+					sb.append(" and "  + col + " " + type + " " + ("string".equals(valuetype)?"'":"") + "[x]"+linkparam +("string".equals(valuetype)?"'":"") + " and " + ("string".equals(valuetype)?"'":"")+ "[x]"+linkparam2 + ("string".equals(valuetype)?"'":"") + " #end");
+				}
+			}else if(type.equals("in")){
+				if(usetype.equals("gdz")){
+					sb.append(" and " + col + " in (" + val + ")");
+				}else{
+					sb.append("#if([x]"+linkparam+" != '') ");
+					sb.append(" and " + col + " in (" + "$extUtils.printVals([x]"+linkparam + ", '"+valuetype+"'))");
+					sb.append("  #end");
+				}
+			}else{
+				if(usetype.equals("gdz")){
+					sb.append(" and " + col + " " + type + " " + val);
+				}else{
+					sb.append("#if([x]"+linkparam+" != '') ");
+					sb.append(" and " + col + " "+type+" " + ("string".equals(valuetype) ? "'"+("like".equals(type)?"%":"")+""+"[x]"+linkparam+""+("like".equals(type)?"%":"")+"'":"[x]"+linkparam) + "");
+					sb.append("  #end");
+				}
+			}
+		}
+		//排序字段
+		for(int i=0; i<cols.size(); i++){
+			GridColDto col = cols.get(i);
+			String id = col.getId();
+			String sort = col.getSort();
+			String tname = col.getTname();
+			String expression = col.getExpression();
+			if(sort != null && sort.length() > 0){
+				sb.append(" order by "+(expression != null && expression.length() > 0 ? "" :tableAlias.get(tname)+".") + id + " ");
+				sb.append(sort);
+				break;
+			}
+		}
+		return sb.toString().replaceAll("@", "'").replaceAll("\\[x\\]", "\\$");
+	}
+
+	public Map<String, InputField> getMvParams() {
+		return mvParams;
+	}
+	
+}

+ 43 - 0
src/main/java/com/ruisitech/bi/service/portal/MobReportTypeService.java

@@ -0,0 +1,43 @@
+package com.ruisitech.bi.service.portal;
+
+import com.ruisitech.bi.entity.portal.MobReportType;
+import com.ruisitech.bi.mapper.portal.MobReportTypeMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class MobReportTypeService {
+	
+	@Autowired
+	private MobReportTypeMapper mapper;
+
+	public List<MobReportType> listcataTree(){
+		return mapper.listcataTree();
+	}
+	
+	public void insertType(MobReportType type){
+		mapper.insertType(type);
+	}
+	
+	public void updateType(MobReportType type){
+		mapper.updateType(type);
+	}
+	
+	public void deleleType(Integer id){
+		mapper.deleleType(id);
+	}
+	
+	public MobReportType getType(Integer id){
+		return mapper.getType(id);
+	}
+	
+	public Integer cntReport(Integer id){
+		return mapper.cntReport(id);
+	}
+	
+	public Integer maxTypeId(){
+		return mapper.maxTypeId();
+	}
+}

+ 563 - 0
src/main/java/com/ruisitech/bi/service/portal/PortalChartService.java

@@ -0,0 +1,563 @@
+package com.ruisitech.bi.service.portal;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.bi.engine.view.context.chart.ChartContext;
+import com.ruisi.bi.engine.view.context.chart.ChartContextImpl;
+import com.ruisi.bi.engine.view.context.chart.ChartKeyContext;
+import com.ruisi.bi.engine.view.context.chart.ChartLinkContext;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContext;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisi.ext.engine.view.emitter.chart.AbstractChartEmitter;
+import com.ruisitech.bi.entity.bireport.ChartJSONDto;
+import com.ruisitech.bi.entity.bireport.DimDto;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.portal.LinkAcceptDto;
+import com.ruisitech.bi.entity.portal.PortalChartQuery;
+import com.ruisitech.bi.service.bireport.BaseCompService;
+import com.ruisitech.bi.service.bireport.ChartService;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.ext.service.DataControlInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Scope("prototype")
+public class PortalChartService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.portal.chart";
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	@Autowired
+	private ChartService chartService;
+	
+	private Map<String, InputField> mvParams = new HashMap<String, InputField>(); //mv的参数
+	
+	@Autowired
+	private DataControlInterface dataControl; //数据权限控制
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		mvParams.clear();
+	}
+	
+	public MVContext json2MV(PortalChartQuery chart) throws Exception{
+		
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		
+		//处理参数,把参数设为hidden
+		super.parserHiddenParam(chart.getPortalParams(), mv, mvParams);	
+		
+		//创建chart
+		ChartContext cr = this.json2Chart(chart, chart.getId(), false);
+		
+		//重新设置chartId
+		cr.setId("C"+chart.getId());
+		
+		String sql = createSql(chart, 0);
+		GridDataCenterContext dc = chartService.createDataCenter(chart.getChartJson(), sql);
+		cr.setRefDataCenter(dc.getId());
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		//判断是否有事件,是否需要添加参数
+		/**
+		Map<String, Object> linkAccept = chart.getChartJson().getLinkAccept();
+		if(linkAccept != null && !linkAccept.isEmpty()){
+			//创建参数
+			TextFieldContext linkText = new TextFieldContextImpl();
+			linkText.setType("hidden");
+			linkText.setDefaultValue((String)linkAccept.get("dftval"));
+			linkText.setId((String)linkAccept.get("alias"));
+			mv.getChildren().add(0, linkText);
+			linkText.setParent(mv);
+			this.mvParams.put(linkText.getId(), linkText);
+			ExtContext.getInstance().putServiceParam(mv.getMvid(), linkText.getId(), linkText);
+			mv.setShowForm(true);
+		}
+		**/
+		Map<String, ChartContext> crs = new HashMap<String, ChartContext>();
+		crs.put(cr.getId(), cr);
+		mv.setCharts(crs);
+		
+		//设置数据集
+		String dsid = super.createDsource(this.cacheService.getDsource(chart.getDsid()), mv);
+		dc.getConf().setRefDsource(dsid);
+		
+		return mv;
+	}
+	
+	public ChartContext json2Chart(PortalChartQuery chart, String compId, boolean is3g){
+		ChartContext ctx = new ChartContextImpl();
+		ChartJSONDto chartJson = chart.getChartJson();
+		//设置x
+		DimDto obj = chartJson.getXcol();
+		if(obj != null){
+			String alias = obj.getAlias();
+			String key = obj.getTableColKey();
+			String txt = obj.getTableColName();
+			if(key != null && key.length() > 0 && txt != null && txt.length() > 0){  //只有在维度关联了维度表后才进行判断
+				ctx.setXcolDesc(key); //用来关联ID,用在钻取中
+				ctx.setXcol(txt);
+			}else{
+				ctx.setXcol(alias);
+				ctx.setXcolDesc(alias);
+			}
+		}
+		List<KpiDto> kpiJson = chart.getKpiJson();
+		KpiDto kpiInfo = kpiJson.get(0);
+		String y = kpiInfo.getAlias();
+		ctx.setYcol(y);
+		
+		//如果是散点图或气泡图,需要 y2col
+		String chartType = chartJson.getType();
+		if(chartType.equals("scatter")){
+			ctx.setY2col(kpiJson.get(1).getAlias());
+		}
+		if(chartType.equals("bubble")){
+			ctx.setY2col(kpiJson.get(1).getAlias());
+			ctx.setY3col(kpiJson.get(2).getAlias());
+		}
+		
+		//设置倍率
+		if(kpiInfo.getRate() != null){
+			ctx.setRate(kpiInfo.getRate());
+		}
+		if(kpiJson.size() > 1){
+			ctx.setRate2(kpiJson.get(1).getRate());
+		}
+		if(kpiJson.size() > 2){
+			ctx.setRate3(kpiJson.get(2).getRate());
+		}
+		
+		
+		DimDto scol = chartJson.getScol();
+		if(scol != null){
+			ctx.setScol(scol.getAlias());
+		}
+		
+		ctx.setShape(chartJson.getType());
+		if("pie".equals(ctx.getShape()) || "gauge".equals(ctx.getShape())){
+			ctx.setWidth("100%");
+			ctx.setHeight(chartJson.getHeight() == null ? "250" : String.valueOf(chartJson.getHeight()));
+		}else{
+			ctx.setWidth("100%");
+			ctx.setHeight(chartJson.getHeight() == null ? "250" : String.valueOf(chartJson.getHeight()));
+		}
+		//默认图形为居中
+		ctx.setAlign("center");
+		
+		
+		//设置配置信息
+		List<ChartKeyContext> properties = new ArrayList<ChartKeyContext>();
+		String unitStr = super.writerUnit(kpiInfo.getRate()) + (kpiInfo.getUnit() == null ? "" : kpiInfo.getUnit());
+		
+		properties.add(new ChartKeyContext("ydesc",kpiInfo.getYdispName()+(unitStr.length() == 0 ? "" : "("+unitStr+")")));
+		if("bubble".equals(ctx.getShape()) || "scatter".equals(ctx.getShape())){
+			KpiDto kpiInfo2 = kpiJson.get(1);
+			//对于散点图和气泡图,需要设置xdesc
+			String unit2Str = super.writerUnit(kpiInfo2.getRate()) + (kpiInfo2.getUnit() == null ? "" : kpiInfo2.getUnit());
+			properties.add(new ChartKeyContext("xdesc", kpiInfo2.getKpi_name() + (unit2Str.length() == 0 ? "": "("+unit2Str+")")));
+			properties.add(new ChartKeyContext("formatCol2", kpiInfo2.getFmt()));
+		}else
+		if(chartJson.getXcol() != null){
+			properties.add(new ChartKeyContext("xdesc", chartJson.getXcol().getXdispName()));
+		}
+		//title
+		/**
+		String tit = (String)chartJson.get("title");
+		if(tit != null && tit.length() > 0){
+			properties.add(new ChartKeyContext("title", tit));
+		}
+		**/
+		
+		
+		//格式化配置信息
+		if(kpiInfo.getFmt() != null && kpiInfo.getFmt().length() > 0){
+			properties.add(new ChartKeyContext("formatCol", "kpi_fmt"));
+		}
+		
+		if(kpiInfo.getUnit() != null && kpiInfo.getUnit().length() > 0){
+			properties.add(new ChartKeyContext("unitCol", "kpi_unit"));
+		}
+		if(kpiInfo.getMin() != null){
+			properties.add(new ChartKeyContext("ymin", String.valueOf(kpiInfo.getMin())));
+		}
+		if(kpiInfo.getMax() != null){
+			properties.add(new ChartKeyContext("ymax", String.valueOf(kpiInfo.getMax())));
+		}
+		//lengend
+		if(chartJson.getShowLegend() != null && chartJson.getShowLegend().equals("true")){
+			ChartKeyContext val1 = new ChartKeyContext("showLegend", "false");
+			properties.add(val1);
+		}else{
+			ChartKeyContext val1 = new ChartKeyContext("showLegend", "true");
+			properties.add(val1);
+		}
+		//legendLayout
+		String legendLayout = chartJson.getLegendLayout();
+		if(legendLayout != null){
+			ChartKeyContext val1 = new ChartKeyContext("legendLayout", legendLayout);
+			properties.add(val1);
+		}
+		//legendLayout
+		String legendpos = chartJson.getLegendpos();
+		if(legendpos != null){
+			ChartKeyContext val1 = new ChartKeyContext("legendPosition", legendpos);
+			properties.add(val1);
+		}
+		
+		if(obj != null){
+			//取得top
+			Integer top = obj.getTop();
+			if(top != null){
+				ChartKeyContext val1 = new ChartKeyContext("xcnt", String.valueOf(top));
+				properties.add(val1);
+			}
+			if(obj.getTickInterval() != null){
+				ChartKeyContext val1 = new ChartKeyContext("tickInterval", obj.getTickInterval());
+				properties.add(val1);
+			}
+			if(obj.getRouteXaxisLable() != null){
+				ChartKeyContext val1 = new ChartKeyContext("routeXaxisLable", obj.getRouteXaxisLable());
+				properties.add(val1);
+			}
+		}
+		properties.add(new ChartKeyContext("action","setSeriesColor"));
+		
+		//设置饼图是否显示标签
+		String dataLabel = chartJson.getDataLabel();
+		if(dataLabel == null || "false".equals(dataLabel)){
+			ChartKeyContext val3 = new ChartKeyContext("showLabel", "false");
+			properties.add(val3);
+		}else{
+			ChartKeyContext val3 = new ChartKeyContext("showLabel", "true");
+			properties.add(val3);
+		}
+		
+		//设置仪表盘数量
+		ChartKeyContext val1 = new ChartKeyContext("gaugeCnt", "1");
+		properties.add(val1);
+		
+		//marginLeft,marginRight
+		String marginLeft = chartJson.getMarginLeft();
+		if(marginLeft != null && marginLeft.length() > 0){
+			ChartKeyContext tmp = new ChartKeyContext("marginLeft", marginLeft);
+			properties.add(tmp);
+		}
+		String marginRight = chartJson.getMarginRight();
+		if(marginRight != null && marginRight.length() > 0){
+			ChartKeyContext tmp = new ChartKeyContext("marginRight", marginRight);
+			properties.add(tmp);
+		}
+		
+		String markerEnabled = chartJson.getMarkerEnabled();
+		if(markerEnabled != null && "true".equals(markerEnabled)){
+			ChartKeyContext md = new ChartKeyContext("markerEnabled", "false");
+			properties.add(md);
+		}
+		//如果是地图,需要设置地图的 mapJson
+		if("map".equals(ctx.getShape())){
+			properties.add(new ChartKeyContext("mapJson",chartJson.getMaparea()));
+		}
+		
+		ctx.setProperties(properties);
+		
+		//判断是否有事件
+		Map<String, Object> link = chartJson.getLink();
+		if(link != null && !link.isEmpty()){
+			ctx.setLink(createChartLink(link));
+		}
+	
+		ctx.setLabel(compId);  //都加上label
+		
+		//判断曲线图、柱状图是否双坐标轴
+		Integer typeIndex = chartJson.getTypeIndex();
+		if((chartType.equals("column")||chartType.equals("line")) && (typeIndex == 2 || 4 == typeIndex) && kpiJson.size() > 1 && kpiJson.get(1) != null){
+			List<KpiDto> kpis = kpiJson;
+			ctx.setY2col(kpis.get(1).getAlias());
+			ctx.setMergeData(kpis.get(1).getMergeData());
+			ctx.setY2Aggre(kpis.get(1).getAggre());
+			String y2unit = super.writerUnit(kpis.get(1).getRate()) + (kpis.get(1).getUnit() == null ? "" : kpis.get(1).getUnit()) ;
+			ChartKeyContext y2desc = new ChartKeyContext("y2desc", kpis.get(1).getYdispName() + (y2unit.length() ==0 ? "" : "("+y2unit+")"));
+			properties.add(y2desc);
+			ChartKeyContext y2fmtcol = new ChartKeyContext("formatCol2", kpis.get(1).getFmt());
+			properties.add(y2fmtcol);
+		}
+		//判断柱状图是否显示为堆积图
+		if("column".equals(chartType) && (3 == typeIndex || 4 == typeIndex)){
+			ChartKeyContext stack = new ChartKeyContext("stack", "true");
+			properties.add(stack);
+		}
+		//饼图
+		if("pie".equals(chartType) && 2 == typeIndex){
+			ChartKeyContext ring = new ChartKeyContext("ring", "true");
+			properties.add(ring);
+		}
+		if("pie".equals(chartType) && 3 == typeIndex){
+			ctx.setShape("nestingPie");  //嵌套圆环图
+		}
+		if("map".equals(chartType) && 2 == typeIndex){
+			ctx.setShape("scatterMap");  //地图散点图嵌套
+		}
+		ctx.setSeriesColor(chart.getColors());
+		return ctx;
+	}
+	
+	public ChartLinkContext createChartLink(Map<String, Object> link){
+		String type = (String)link.get("type");
+		String target = (String)link.get("target");
+		String url = (String)link.get("url");
+		String paramName = (String)link.get("paramName");
+		
+		ChartLinkContext clink = new ChartLinkContext();
+		if(url != null && url.length() > 0){
+			clink.setLinkUrl(url);
+		}else{
+			clink.setTarget(target.split(","));
+			clink.setType(type.split(","));
+		}
+		clink.setParamName(paramName);
+		return clink;
+	}
+	
+	/**
+	 * 创建sql语句所用函数,图形用这个函数创建SQL
+	 * 其中第二个参数只用在图形中,当用户没选X轴时(xcol)时,用这个做默认xcol
+	 * 其中第三个参数只用在图形中,当用户没选图例(scol)时,用这个做默认图例
+	 * release 表示当前为发布状态, 0 表示不是发布,1表示发布到多维分析,2表示发布到仪表盘
+	 * @param sqlVO
+	 * @param ser
+	 * @return
+	 * @throws ParseException
+	 */
+	public String createSql(PortalChartQuery chart, int release) throws ParseException {
+		JSONObject dset = cacheService.getDset(chart.getDsetId());
+		Map<String, String> tableAlias = createTableAlias(dset);
+		
+		StringBuffer sql = new StringBuffer();
+		
+		sql.append("select ");
+		List<DimDto> dims = chart.getChartJson().getDims();
+		for(int i=0; i<dims.size(); i++){
+			DimDto dim = dims.get(i);
+			String tname = dim.getTname();
+			String tableName = dim.getTableName();
+			String key = dim.getTableColKey();
+			String txt = dim.getTableColName();
+			if(key != null && txt != null && key.length() >0 && txt.length() >0){
+				sql.append(tableAlias.get(tableName)+"."+key+", " + tableAlias.get(tableName) + "." + txt + ",");
+			}else{
+				if(dim.getCalc() == 0){
+					sql.append(" "+tableAlias.get(tname)+"."+dim.getColname()+" as "+dim.getAlias()+", ");
+				}else{
+					sql.append(" " + dim.getColname() + " as "+dim.getAlias()+", ");
+				}
+			}
+			
+		}
+		
+		//判断是否添加 格式化 字段
+		KpiDto info = chart.getKpiJson().get(0);
+		if(info.getFmt() != null && info.getFmt().length() > 0){
+			sql.append("'"+info.getFmt()+"' kpi_fmt,");
+		}
+		//判断是否添加单位字段
+		if(info.getUnit() != null && info.getUnit().length() > 0){
+			//sql.append("'" + ChartService.formatUnits(info)+info.getUnit()+"' kpi_unit,");
+			sql.append("'" + info.getUnit()+"' kpi_unit,");
+		}
+		
+		//第二个指标
+		if(chart.getKpiJson().size() > 1 && chart.getKpiJson().get(1) != null){
+			KpiDto sinfo = chart.getKpiJson().get(1);
+			if(sinfo.getFmt() != null && sinfo.getFmt().length() > 0){
+				sql.append("'"+sinfo.getFmt()+"' kpi_fmt2,");
+			}
+			if(sinfo.getUnit() != null && sinfo.getUnit().length() > 0){
+				sql.append("'" +sinfo.getUnit()+"' kpi_unit2,");
+			}
+		}
+		//第三个指标
+		if(chart.getKpiJson().size() > 2 && chart.getKpiJson().get(2) != null){
+			KpiDto sinfo = chart.getKpiJson().get(2);
+			if(sinfo.getFmt() != null && sinfo.getFmt().length() > 0){
+				sql.append("'"+sinfo.getFmt()+"' kpi_fmt3,");
+			}
+			if(sinfo.getUnit() != null && sinfo.getUnit().length() > 0){
+				sql.append("'" +sinfo.getUnit()+"' kpi_unit3,");
+			}
+		}
+		
+		List<KpiDto> kpis = chart.getKpiJson();
+		if(kpis.size() == 0){
+			sql.append(" 0 kpi_value ");
+		}else{
+			for(int i=0; i<kpis.size(); i++){
+				KpiDto kpi = kpis.get(i);
+				if(kpi.getCalc() != null && kpi.getCalc() == 1){  //表达式,直接取表达式
+					sql.append(kpi.getCol_name() + " ");
+				}else{  //获取字段别名
+					String name = super.convertKpiName(kpi, tableAlias);
+					sql.append( name + " ");
+				}
+				sql.append(kpi.getAlias());
+				if(i != kpis.size() - 1){
+					sql.append(",");
+				}
+			}
+		}
+		
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		String master = dset.getString("master");
+		sql.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sql.append(" " + jtype);
+			}
+			sql.append(" join " + ref+ " " + tableAlias.get(ref));
+			sql.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sql.append(" ");
+		}
+		sql.append(" where 1=1 ");
+		//数据权限
+		if(dataControl != null){
+			String ret = dataControl.process(RSBIUtils.getLoginUserInfo(), dset.getString("master"));
+			if(ret != null){
+				sql.append(ret + " ");
+			}
+		}
+		
+		//限制参数的查询条件
+		sql.append(dealCubeParams(chart.getParams(), tableAlias));
+		
+		//
+		LinkAcceptDto linkAccept = chart.getChartJson().getLinkAccept();
+		if(linkAccept != null && release == 1){
+			String col = linkAccept.getCol();
+			String compId = chart.getId();
+			String alias = super.findEventParamName(compId);
+			if(alias == null){
+				alias = linkAccept.getAlias();
+			}
+			String valtype = linkAccept.getValType();
+			String tname = linkAccept.getTname();
+			String dimTname = linkAccept.getDimTname();
+			String ncol = "$" + alias;
+			Integer calc = linkAccept.getCalc();
+			if("string".equalsIgnoreCase(valtype)){
+				ncol = "'" + ncol + "'";
+			}
+			sql.append("#if( $"+alias+" && $"+alias+" != '') and  ");
+			if(calc == null || calc == 0){  //表达式不增加别名
+				sql.append(tableAlias.get(dimTname == null || dimTname.length() == 0 ? tname:dimTname)+".");
+			}
+			sql.append(col + " = " + ncol + " #end");
+		}
+		
+		if(dims.size() > 0){
+			sql.append(" group by ");
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				String tname = dim.getTname();
+				String tableName = dim.getTableName();
+				String key = dim.getTableColKey();
+				String txt = dim.getTableColName();
+				if(key != null && txt != null && key.length() >0 && txt.length() >0){
+					sql.append(tableAlias.get(tableName)  + "." + key+", " + tableAlias.get(tableName) + "." + txt);
+				}else{
+					if(dim.getCalc() != null && dim.getCalc() == 1){
+						sql.append(dim.getColname());
+					}else{
+						sql.append(tableAlias.get(tname)+"."+dim.getColname());
+					}
+				}
+				
+				if(i != dims.size() - 1){
+					sql.append(",");
+				}
+			}
+		}
+		if(dims.size() > 0){
+			StringBuffer order = new StringBuffer();
+			order.append(" order by ");
+			KpiDto kpi = chart.getKpiJson().get(0);
+			if(kpi.getSort() != null && kpi.getSort().length() > 0){
+				order.append(kpi.getAlias() + " " + kpi.getSort()) ;
+				order.append(",");
+			}
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				if(dim.getDimord() != null && dim.getDimord().length() > 0){
+					order.append(dim.getTableColKey() != null && dim.getTableColKey().length() > 0 ? dim.getTableColKey() : dim.getColname());
+					order.append(" ");
+					order.append(dim.getDimord());
+					order.append(",");
+				}
+			}
+			if(order.length() <= 11 ){  //判断是否拼接了 order by 字段
+				
+			}else{
+				//返回前先去除最后的逗号
+				 sql.append(order.toString().substring(0, order.length() - 1));
+			}
+		}
+		String ret = sql.toString();
+		//替换 ## 为 函数,##在velocity中为注释意思
+		ret = ret.replaceAll("##", "\\$extUtils.printJH()").replaceAll("@", "'");
+		return ret;
+	}
+	
+	public Object queryChartColors(){
+		AbstractChartEmitter.ColorVO[] vls = AbstractChartEmitter.ColorVO.values();
+		String[] v = new String[vls.length];
+		for(int i=0; i<vls.length; i++){
+			AbstractChartEmitter.ColorVO c = vls[i];
+			v[i] = c.toString();
+		}
+		return v;
+	}
+
+	public Map<String, InputField> getMvParams() {
+		return mvParams;
+	}
+
+	public ChartService getChartService() {
+		return chartService;
+	}
+
+}

+ 759 - 0
src/main/java/com/ruisitech/bi/service/portal/PortalPageService.java

@@ -0,0 +1,759 @@
+package com.ruisitech.bi.service.portal;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.bi.engine.view.context.chart.ChartContext;
+import com.ruisi.bi.engine.view.context.chart.ChartKeyContext;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.cross.BaseKpiField;
+import com.ruisi.ext.engine.view.context.cross.CrossKpi;
+import com.ruisi.ext.engine.view.context.cross.CrossReportContext;
+import com.ruisi.ext.engine.view.context.cross.RowDimContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContext;
+import com.ruisi.ext.engine.view.context.face.OptionsLoader;
+import com.ruisi.ext.engine.view.context.form.*;
+import com.ruisi.ext.engine.view.context.gridreport.GridReportContext;
+import com.ruisi.ext.engine.view.context.html.*;
+import com.ruisi.ext.engine.view.context.html.table.*;
+import com.ruisi.ext.engine.view.exception.ExtConfigException;
+import com.ruisitech.bi.entity.bireport.DimDto;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.bireport.TableQueryDto;
+import com.ruisitech.bi.entity.model.Dimension;
+import com.ruisitech.bi.entity.portal.*;
+import com.ruisitech.bi.service.bireport.BaseCompService;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import com.ruisitech.bi.service.model.DimensionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Service
+@Scope("prototype")
+public class PortalPageService extends BaseCompService {
+	
+	public final static String deftMvId = "mv.portal.tmp";
+	
+	private Map<String, InputField> mvParams = new HashMap<String, InputField>(); //mv的参数
+	private StringBuffer css = new StringBuffer(); //在创建页面过程中生成所需要的组件样式文件
+	private StringBuffer scripts = new StringBuffer();
+	private List<String> dsids = new ArrayList<String>(); //用到的数据原
+	
+	@Autowired
+	private DimensionService dimService;
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	@Autowired
+	private PortalChartService chartService;
+	
+	@Autowired
+	private GridService gridSerivce;
+	
+	@Autowired
+	private PortalTableService tableService;
+	
+	@Autowired
+	private BoxService boxSerivce;
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		mvParams.clear();
+		dsids.clear();
+	}
+	
+	public MVContext json2MV(JSONObject pageJson, boolean release, boolean export) throws Exception{
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		String mvId = pageJson.getString("id");  //用报表ID做MV得ID,防止报表串表
+		mv.setMvid("mv_" + mvId);
+		
+		IncludeContext inc = new IncludeContextImpl();
+		String stylename = (String)pageJson.get("stylename");
+		if(stylename != null && stylename.length() > 0 && !"def".equals(stylename)){
+			inc.setPage("/resource/css/portal-inc-"+stylename+".css");
+		}else{
+			inc.setPage("/resource/css/portal-inc.css");
+		}
+		mv.getChildren().add(inc);
+		inc.setParent(mv);
+		
+		//解析参数
+		Object param = pageJson.get("params");
+		if(param != null && ((JSONArray)param).size()>0){
+			DivContext outdiv = new DivContextImpl();
+			outdiv.setStyleClass("ibox reportParams");
+			outdiv.setStyle("margin:5px;");
+			outdiv.setChildren(new ArrayList<Element>());
+			outdiv.setParent(mv);
+			mv.getChildren().add(outdiv);
+			
+			//row div
+			DivContext rows = new DivContextImpl();
+			rows.setStyleClass("row");
+			rows.setChildren(new ArrayList<Element>());
+			outdiv.getChildren().add(rows);
+			rows.setParent(outdiv);
+			
+			
+			DivContext div = new DivContextImpl();
+			div.setStyleClass("ibox-content");
+			div.setStyle("padding:5px;border:none;");
+			div.setParent(rows);
+			div.setChildren(new ArrayList<Element>());
+			rows.getChildren().add(div);
+			
+			JSONArray pp = (JSONArray)param;
+			for(int i=0; i<pp.size(); i++){
+				this.parserParam(pp.getJSONObject(i), div, mv, release?false:true);
+			}
+
+			//创建提交按钮
+			DivContext btndiv = new DivContextImpl();
+			btndiv.setStyleClass("col-sm-3");
+			btndiv.setChildren(new ArrayList<Element>());
+			div.getChildren().add(btndiv);
+			btndiv.setParent(div);
+			
+			ButtonContext btn = new ButtonContextImpl();
+			btn.setDesc("查询");
+			btn.setType("button");
+			btn.setMvId(new String[]{mv.getMvid()});
+			btndiv.getChildren().add(btn);
+			btn.setParent(btndiv);
+			//清除按钮
+			ButtonContext clearBtn = new ButtonContextImpl();
+			clearBtn.setDesc("清除");
+			clearBtn.setType("button");
+			clearBtn.setOnClick("clear_params");
+			clearBtn.setStyleClass("btn btn-success btn-sm");
+			btndiv.getChildren().add(clearBtn);
+			clearBtn.setParent(btndiv);
+		}
+		
+		JSONObject body = pageJson.getJSONObject("body");
+		super.setPageBody(body);
+		chartService.setPageBody(body);
+		tableService.setPageBody(body);
+		parserBody(body, mv, param, release);
+		//生成样式
+		TextContext csstext = new TextContextImpl();
+		csstext.setText("<style>" + this.css.toString() + "</style>");
+		mv.getChildren().add(csstext);
+		csstext.setParent(mv);
+		//生成数据原
+		for(String dsid : dsids){
+			createDsource(this.cacheService.getDsource(dsid), mv);
+		}
+		return mv;
+	}
+	
+	//解析布局器
+	public void parserBody(JSONObject body, MVContext mv, Object param, boolean release) throws Exception{
+		TableContext tab = new TableContextImpl();
+		tab.setStyleClass("r_layout");
+		tab.setChildren(new ArrayList<Element>());
+		mv.getChildren().add(tab);
+		tab.setParent(mv);
+		for(int i=1; true; i++){
+			Object tmp = body.get("tr" + i);
+			if(tmp == null){
+				break;
+			}
+			JSONArray trs = (JSONArray)tmp;
+			TrContext tabTr = new TrContextImpl();
+			tabTr.setChildren(new ArrayList<Element>());
+			tab.getChildren().add(tabTr);
+			tabTr.setParent(tab);
+			for(int j=0; j<trs.size(); j++){
+				JSONObject td = trs.getJSONObject(j);
+				TdContext tabTd = new TdContextImpl();
+				tabTd.setStyleClass("layouttd");
+				tabTd.setChildren(new ArrayList<Element>());
+				tabTd.setParent(tabTr);
+				tabTr.getChildren().add(tabTd);
+				tabTd.setColspan(String.valueOf(td.getIntValue("colspan")));
+				tabTd.setRowspan(String.valueOf(td.getIntValue("rowspan")));
+				tabTd.setWidth(td.getIntValue("width") + "%");
+				
+				Object cldTmp = td.get("children");
+				
+				if(cldTmp != null){
+					JSONArray children = (JSONArray)cldTmp;
+					for(int k=0; k<children.size(); k++){
+						JSONObject comp = children.getJSONObject(k);
+						String tp = comp.getString("type");
+						
+						//生成外层div
+						DivContext div = new DivContextImpl(); //外层div
+						div.setStyleClass("ibox");
+						div.setChildren(new ArrayList<Element>());
+						tabTd.getChildren().add(div);
+						div.setParent(tabTd);
+						
+						//判断组件是否是TD中最后一个,如果是,不要 margin-bottom 样式
+						if(k == children.size() - 1){
+							div.setStyle("margin-bottom:auto;");
+						}
+						div.setStyle((div.getStyle() == null ? "" : div.getStyle()) + "border:none;margin-bottom:10px;");  //去除div边框
+						
+						//判断是否生成title
+						String showtitle = (String)comp.get("showtitle");
+						if((showtitle != null && "false".equalsIgnoreCase(showtitle))
+								//数据框默认不生成title
+								|| tp.equals("box") ){   //不生成head
+							
+						}else{   //生成head
+							DivContext head = new DivContextImpl(); //内层head Div
+							head.setChildren(new ArrayList<Element>());
+							head.setStyleClass("ibox-title-view");
+							div.getChildren().add(head);
+							head.setParent(div);
+							
+							TextContext text = new TextContextImpl(); //head Div 的文字
+							text.setText(comp.getString("name"));
+							TextProperty ctp = new TextProperty();
+							ctp.setAlign("center");
+							ctp.setWeight("bold");
+							text.setTextProperty(ctp);
+							head.getChildren().add(text);
+							text.setParent(head);
+						}
+						
+						DivContext content = new DivContextImpl(); //内层content Div
+						content.setStyleClass("ibox-content");
+						content.setStyle("border-top:none; padding:3px;");
+						
+						//组件背景色 
+						String bgcolor = (String)comp.get("bgcolor");
+						if(bgcolor != null && bgcolor.length() > 0){
+							content.setStyle((content.getStyle() == null ? "" : content.getStyle())  + "background-color:"+bgcolor+";");
+						}
+						
+						content.setChildren(new ArrayList<Element>());
+						div.getChildren().add(content);
+						content.setParent(div);
+						
+						if(tp.equals("text")){
+							this.createText(content, comp);
+						}else if(tp.equals("chart")){
+							PortalChartQuery chart = JSONObject.toJavaObject(comp, PortalChartQuery.class);
+							this.createChart(mv, content, chart, release);
+						}else if(tp.equals("table")){
+							PortalTableQuery table = JSONObject.toJavaObject(comp, PortalTableQuery.class);
+							this.crtTable(mv, content, table, release);
+						}else if(tp.equals("grid")){
+							GridQuery grid = JSONObject.toJavaObject(comp, GridQuery.class);
+							this.crtGrid(mv, content, grid, release);
+						}else if(tp.equals("box")){
+							BoxQuery ncomp = JSONObject.toJavaObject(comp, BoxQuery.class);
+							this.createBox(mv, content, ncomp);
+						}
+					}
+				}
+			}
+		}
+		//生成scripts
+		String s = scripts.toString();
+		if(s.length() > 0){
+			mv.setScripts(s);
+		}
+	}
+	
+	/**
+	 * 生成动态参数
+	 * @param params
+	 * @param mv
+	 * @param isput 是否把参数放入MV对象,在发布的时候不用
+	 * @throws ExtConfigException
+	 * @throws IOException
+	 */
+	public void parserParam(JSONObject param, DivContext div, MVContext mv, boolean isput) throws ExtConfigException, IOException {
+	
+			String type = param.getString("type");
+			String id = param.getString("paramid");
+			String desc = param.getString("name");
+			String def = (String)param.get("defvalue");
+			String vtp = (String)param.get("valtype");
+			String dtformat = (String)param.get("dtformat");
+			String hiddenprm = (String)param.get("hiddenprm");
+			//String refds = (String)param.get("dsource");
+			
+			InputField input = null;
+			if("y".equals(hiddenprm)){
+				TextFieldContext txt = new TextFieldContextImpl();
+				txt.setType("hidden");
+				txt.setShow(true);
+				input = txt;
+			}else{
+				if("radio".equals(type)){
+					SelectContextImpl target = new SelectContextImpl();
+					if("static".equals(vtp)){
+						this.paramOptions(param, target);
+					}else if("dynamic".equals(vtp)){
+						String sql = this.createDimSql(param);
+						String template = TemplateManager.getInstance().createTemplate(sql);
+						target.setTemplateName(template);
+						String dsid = param.getJSONObject("option").getString("dsource");
+						target.setRefDsource(dsid);  //获取数据源
+						if(!dsids.contains(dsid)){
+							dsids.add(dsid);
+						}
+					}
+					target.setAddEmptyValue(true);
+					input = target;
+				}else if("checkbox".equals(type)){
+					SelectContext target = new MultiSelectContextImpl();
+					if("static".equals(vtp)){
+						this.paramOptions(param, target);
+					}else if("dynamic".equals(vtp)){
+						String sql = this.createDimSql(param);
+						String template = TemplateManager.getInstance().createTemplate(sql);
+						target.setTemplateName(template);
+						String dsid = param.getJSONObject("option").getString("dsource");
+						target.setRefDsource(dsid);  //获取数据源
+						if(!dsids.contains(dsid)){
+							dsids.add(dsid);
+						}
+					}
+					input = target;
+				}else if("dateselect".equals(type) || "monthselect".equals(type) || "yearselect".equals(type)){  //日历框
+					DateSelectContextImpl target = new DateSelectContextImpl();
+					//target.setShowCalendar(true);
+					String max =  (String)param.get("maxval");
+					if(max != null && max.length() > 0){
+						target.setMaxDate(max);
+					}
+					String min = (String)param.get("minval");
+					if(min != null && min.length() > 0){
+						target.setMinDate(min);
+					}
+					if(dtformat != null && dtformat.length() > 0){
+						target.setDateFormat(dtformat);
+					}
+					if("monthselect".equals(type)){
+						target.setDateType("month");
+					}else if("yearselect".equals(type)){
+						target.setDateType("year");
+					}
+					input = target;
+				}else if("text".equals(type)){
+					TextFieldContext target = new TextFieldContextImpl();
+					input = target;
+				}
+			}
+			input.setId(id);
+			input.setDesc(desc);
+			String size = (String)param.get("size");
+			if(size != null && size.length() > 0){
+				if("radio".equals(type)){
+					//select 框就是 radio,他的size表示像素,转换成实际size
+					input.setSize(String.valueOf(Integer.parseInt(size) * 8));
+				}else{
+					input.setSize(size);
+				}
+			}
+			if(def != null && def.length() > 0){
+				if(("dateselect".equals(type) || "monthselect".equals(type) || "yearselect".equals(type) )&& "now".equals(def)){
+					def = new SimpleDateFormat(dtformat).format(new Date());
+				}
+				input.setDefaultValue(def);
+			}
+			input.setOutBox(true);
+			div.getChildren().add(input);
+			input.setParent(div);
+			
+			//把参数放入对象
+			if(isput){
+				this.mvParams.put(input.getId(), input);
+				ExtContext.getInstance().putServiceParam(mv.getMvid(), input.getId(), input);
+			}
+						
+			//处理样式
+			JSONObject style = (JSONObject)param.get("style");
+			if(style != null && !style.isEmpty()){
+				StringBuffer sb = new StringBuffer();
+				String talign = (String)style.get("talign"); //排列方式
+				if(talign != null && "horizontal".equals(talign) && ("radio".equals(type) || "checkbox".equals(type))){
+					((RadioContextImpl)input).setRadioStyle("display:inline;");
+				}
+				String theight = (String)style.get("theight");
+				String fontweight = (String)style.get("tfontweight");
+				String tfontcolor = (String)style.get("tfontcolor");
+				String tfontsize = (String)style.get("tfontsize");
+				if(tfontsize != null && tfontsize.length() > 0){
+					sb.append("font-size:"+tfontsize+"px;");
+				}
+				if(theight != null && theight.length() > 0){
+					sb.append("height:"+theight+"px;");
+				}
+				if(fontweight != null && "true".equals(fontweight)){
+					sb.append("font-weight:bold;");
+				}
+				if(tfontcolor != null && tfontcolor.length() > 0){
+					sb.append("color:" + tfontcolor+";");
+				}
+				
+				String italic = (String)style.get("titalic");
+				String underscore = (String)style.get("tunderscore");
+				String lineheight = (String)style.get("tlineheight");
+				String tbgcolor = (String)style.get("tbgcolor");
+				if("true".equals(italic)){
+					sb.append("font-style:italic;");
+				}
+				if("true".equals(underscore)){
+					sb.append("text-decoration: underline;");
+				}
+				if(lineheight != null && lineheight.length() > 0){
+					sb.append("line-height:"+lineheight+"px;");
+				}
+				if(tbgcolor != null && tbgcolor.length() > 0){
+					sb.append("background-color:"+tbgcolor+";");
+				}
+				div.setStyle(sb.toString());
+			}
+		
+	}
+	
+	private void paramOptions(JSONObject param, OptionsLoader option){
+		List ls = option.loadOptions();
+		if(ls == null){
+			ls = new ArrayList();
+			option.setOptions(ls);
+		}
+		Object vals = param.get("values");
+		if(vals != null){
+			JSONArray values = (JSONArray)vals;
+			for(int i=0; i<values.size(); i++){
+				JSONObject opt = values.getJSONObject(i);
+				Map<String, String> nOption = new HashMap<String, String>();
+				nOption.put("text", opt.getString("text"));
+				nOption.put("value", opt.getString("value"));
+				ls.add(nOption);
+			}
+		}
+	}
+	
+	public String createDimSql(JSONObject dim){
+		JSONObject opt = dim.getJSONObject("option");
+		//查询事实表
+		Dimension d = dimService.getDimInfo(new Integer(opt.get("dimId").toString()), new Integer(opt.get("tableId").toString()));
+		String col = d.getCol();
+		String key = d.getColkey();
+		String name = d.getColtext();
+		String dimord = d.getDimord();
+		String sql =  "select distinct " +  (key==null||key.length() == 0 ? col : key) + " \"value\", " + (name==null||name.length() == 0 ?col:name) + " \"text\" from ";
+		sql += (d.getColTable() == null || d.getColTable().length() == 0 ? d.getTname() : d.getColTable());
+		if(dimord != null && dimord.length() > 0){
+			sql += " order by " + (key==null||key.length() == 0 ? col : key) + " " + dimord;
+		}
+		 //直接从数据中查询。
+		return sql;
+	}
+	
+	public String createMonthSql(){
+		String sql = "select mid \"value\", mname \"text\" from code_month order by mid desc";
+		return sql;
+	}
+	
+	public void createBox(MVContext mv, Element td, BoxQuery compJson) throws IOException{
+		String dsetId = compJson.getDsetId();
+		String dsid = compJson.getDsid();
+		if(dsetId == null || dsid == null){
+			return;
+		}
+		if(!this.dsids.contains(dsid)){
+			dsids.add(dsid);
+		}
+		boxSerivce.json2Box(compJson, td, true);
+		if(!this.dsids.contains(compJson.getDsid())){
+			this.dsids.add(compJson.getDsid());
+		}
+	}
+	
+	public void createText(Element td, JSONObject compJson){
+		TextContext text = new TextContextImpl();
+		JSONObject style = (JSONObject)compJson.get("style");
+		TextProperty tp = new TextProperty();
+		Integer height = compJson.getInteger("height");
+		if(height != null){
+			tp.setHeight(String.valueOf(height));
+		}
+		if(style != null && !style.isEmpty()){
+			tp.setAlign((String)style.get("talign"));
+			tp.setSize((String)style.get("tfontsize"));
+			String fontweight = (String)style.get("tfontweight");
+			tp.setWeight("true".equals(fontweight)?"bold":"normal");
+			tp.setColor((String)style.get("tfontcolor"));
+			tp.setId("C"+ IdCreater.create());
+			
+			
+			css.append("#"+tp.getId()+"{");
+			String italic = (String)style.get("titalic");
+			String underscore = (String)style.get("tunderscore");
+			String lineheight = (String)style.get("tlineheight");
+			String tbgcolor = (String)style.get("tbgcolor");
+			if("true".equals(italic)){
+				css.append("font-style:italic;");
+			}
+			if("true".equals(underscore)){
+				css.append("text-decoration: underline;");
+			}
+			if(lineheight != null && lineheight.length() > 0){
+				css.append("line-height:"+lineheight+"px;");
+			}
+			if(tbgcolor != null && tbgcolor.length() > 0){
+				css.append("background-color:"+tbgcolor+";");
+			}
+			css.append("}");
+		}
+		text.setTextProperty(tp);
+		String desc = compJson.getString("desc");
+		text.setText(desc);
+		text.setParent(td);
+		text.setFormatEnter(true);
+		td.getChildren().add(text);
+	}
+	
+	public void createChart(MVContext mv, Element tabTd, PortalChartQuery chart, boolean release) throws Exception{
+		if(chart.getChartJson() == null){
+			return;
+		}
+		if(chart.getKpiJson() == null || chart.getKpiJson().size() == 0){
+			return;
+		}
+		KpiDto firstKpi = chart.getKpiJson().get(0);
+		if(firstKpi == null){
+			return; //未选指标
+		}
+
+		ChartContext cr = chartService.json2Chart(chart, chart.getId(), false);
+		cr.setId("C" + IdCreater.create());
+		//删除action (设置系列颜色事件)
+		for(int i=0; i<cr.getProperties().size(); i++){
+			ChartKeyContext p = cr.getProperties().get(i);
+			if(p.getName().equals("action")){
+				p.setValue(null);
+			}
+		}
+		
+		
+		String sql = chartService.createSql(chart, 1);
+		GridDataCenterContext dc = chartService.getChartService().createDataCenter(chart.getChartJson(), sql);
+		cr.setRefDataCenter(dc.getId());
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		tabTd.getChildren().add(cr);
+		cr.setParent(tabTd);
+		if(mv.getCharts() == null){
+			Map crs = new HashMap();
+			mv.setCharts(crs);
+		}
+		mv.getCharts().put(cr.getId(), cr);
+		
+		//判断是否有事件,是否需要添加参数
+		LinkAcceptDto linkAccept = chart.getChartJson().getLinkAccept();
+		if(linkAccept != null){
+			String alias = super.findEventParamName(chart.getId());
+			if(alias == null){
+				alias = linkAccept.getAlias();
+			}
+			String tableColKey = linkAccept.getTableColKey();
+			if(tableColKey != null && tableColKey.length() > 0){  //如果有tableColKey,把tableColKey作为参数ID
+				alias = tableColKey;
+			}
+			//如果参数重复,不放置
+			if(!mvParams.containsKey(alias)){
+				//创建参数
+				TextFieldContext linkText = new TextFieldContextImpl();
+				linkText.setType("hidden");
+				linkText.setDefaultValue(linkAccept.getDftval());
+				linkText.setId(alias);
+				linkText.setShow(true);
+				mv.getChildren().add(0, linkText);
+				linkText.setParent(mv);
+				if(!release){
+					this.mvParams.put(linkText.getId(), linkText);
+					ExtContext.getInstance().putServiceParam(mv.getMvid(), linkText.getId(), linkText);
+					mv.setShowForm(true);
+				}
+			}
+		}
+		//设置ds
+		dc.getConf().setRefDsource(chart.getDsid());
+		if(!this.dsids.contains(chart.getDsid())){
+			this.dsids.add(chart.getDsid());
+		}
+	}
+	
+	public void crtGrid(MVContext mv, Element tabTd, GridQuery grid, boolean release) throws IOException{
+		List<GridColDto> cols = grid.getCols();
+		if(cols == null || cols.size() == 0){
+			return;
+		}
+		
+		if(!this.dsids.contains(grid.getDsid())){
+			this.dsids.add(grid.getDsid());
+		}
+		
+		//创建corssReport
+		GridReportContext cr = gridSerivce.json2Grid(grid);
+		//设置ID
+		cr.setId("g_" + grid.getId());
+		cr.setRefDsource(grid.getDsid());
+		
+		//创建数据sql
+		String sql = gridSerivce.createSql(grid);
+		String name = TemplateManager.getInstance().createTemplate(sql);
+		cr.setTemplateName(name);
+		
+		tabTd.getChildren().add(cr);
+		cr.setParent(tabTd);
+		
+		if(mv.getGridReports() == null){
+			Map<String, GridReportContext> crs = new HashMap<String, GridReportContext>();
+			mv.setGridReports(crs);
+		}
+		Map<String, GridReportContext> crs = mv.getGridReports();
+		crs.put(cr.getId(), cr);
+		
+		mv.setGridReports(crs);
+	}
+	
+	public void crtTable(MVContext mv, Element tabTd, PortalTableQuery table, boolean release) throws Exception {
+		if(table.getCols() == null && table.getRows() == null) {
+			return;
+		}
+		if(!this.dsids.contains(table.getDsid())){
+			dsids.add(table.getDsid());
+		}
+		//创建corssReport
+		TableQueryDto dto = new TableQueryDto();
+		dto.setCompId(table.getId());
+		dto.setLink(table.getLink());
+		dto.setDrillDim(table.getDrillDim());
+		dto.setCols(table.getCols());
+		dto.setRows(table.getRows());
+		dto.setKpiJson(table.getKpiJson());
+		CrossReportContext cr = null;
+		//处理kpiOther
+		CrossKpi mybaseKpi = null;
+		List<DimDto> cols = table.getCols();
+		if(cols.size() > 0 && table.getKpiJson().size() == 1){
+			//如果只有一个指标,并且具有列维度,放入baseKpi
+			KpiDto kpi = table.getKpiJson().get(0);
+			CrossKpi baseKpi = new BaseKpiField();
+			baseKpi.setAggregation(kpi.getAggre());
+			baseKpi.setAlias(kpi.getAlias());
+			baseKpi.setFormatPattern(kpi.getFmt());
+			baseKpi.setKpiRate(kpi.getRate() == null ? null : new BigDecimal(kpi.getRate()));
+			mybaseKpi = baseKpi;
+			cr = tableService.getTableService().json2Table(dto);
+			cr.setBaseKpi(mybaseKpi);
+		}else{
+			DimDto kpiOther = new DimDto();
+			kpiOther.setType("kpiOther");
+			cols.add(kpiOther);
+			cr = tableService.getTableService().json2Table(dto);
+			cols.remove(cols.size() - 1);
+		}
+	
+		String id = ExtConstants.reportIdPrefix + IdCreater.create();
+		cr.setId(id);
+		cr.setOut("lockUI");
+		String height = table.getHeight();
+		if(height != null && height.length() > 0){
+			cr.setHeight(height);
+		}
+		cr.setShowData(true);
+		if(mybaseKpi != null){
+			cr.setBaseKpi(mybaseKpi);
+		}
+		
+		String sql = tableService.createSql(table, 1, 0);
+		GridDataCenterContext dc = tableService.createDataCenter(sql, table);
+		cr.setRefDataCetner(dc.getId());
+		dc.getConf().setRefDsource(table.getDsid());
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		//判断是否有钻取维
+		List<RowDimContext> drillDims = cr.getDims();
+		for(int i=0; drillDims!=null&&i<drillDims.size(); i++){
+			RowDimContext drillDim = drillDims.get(i);
+			//生成钻取维的DataCenter
+			sql = tableService.createSql(table, 0, i+1);
+			GridDataCenterContext drillDc = tableService.createDataCenter(sql, table);
+			drillDim.setRefDataCenter(drillDc.getId());
+			mv.getGridDataCenters().put(drillDc.getId(), drillDc);
+		}
+		
+		tabTd.getChildren().add(cr);
+		cr.setParent(tabTd);
+		
+		//判断是否有事件,是否需要添加参数
+		LinkAcceptDto linkAccept = table.getLinkAccept();
+		if(linkAccept != null){
+			String alias = super.findEventParamName(table.getId());
+			if(alias == null){
+				alias = linkAccept.getAlias();
+			}
+			String tableColKey = linkAccept.getTableColKey();
+			if(tableColKey != null && tableColKey.length() > 0){  //如果有tableColKey,把tableColKey作为参数ID
+				alias = tableColKey;
+			}
+			//如果参数重复,不放置
+			if(!mvParams.containsKey(alias)){
+				//创建参数
+				TextFieldContext linkText = new TextFieldContextImpl();
+				linkText.setType("hidden");
+				linkText.setDefaultValue(linkAccept.getDftval());
+				linkText.setId(alias);
+				linkText.setShow(true);
+				mv.getChildren().add(0, linkText);
+				linkText.setParent(mv);
+				if(!release){
+					this.mvParams.put(linkText.getId(), linkText);
+					ExtContext.getInstance().putServiceParam(mv.getMvid(), linkText.getId(), linkText);
+					mv.setShowForm(true);
+				}
+			}
+			
+		}
+		if(mv.getCrossReports() == null){
+			Map crs = new HashMap();
+			mv.setCrossReports(crs);
+		}
+		mv.getCrossReports().put(cr.getId(), cr);
+		scripts.append(tableService.getTableService().getScripts());
+	}
+
+	public Map<String, InputField> getMvParams() {
+		return mvParams;
+	}
+
+}

+ 52 - 0
src/main/java/com/ruisitech/bi/service/portal/PortalService.java

@@ -0,0 +1,52 @@
+package com.ruisitech.bi.service.portal;
+
+import com.ruisitech.bi.entity.portal.Portal;
+import com.ruisitech.bi.mapper.portal.PortalMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class PortalService {
+	
+	@Autowired
+	private PortalMapper mapper;
+	
+	public List<Portal> listPortal(){
+		return mapper.listPortal();
+	}
+	
+	public String getPortalCfg(String pageId){
+		return mapper.getPortalCfg(pageId);
+	}
+	
+	public List<Portal> list3g(Integer cataId){
+		return mapper.list3g(cataId);
+	}
+	
+	public void insertPortal(Portal portal){
+		mapper.insertPortal(portal);
+	}
+	
+	public void deletePortal(String pageId){
+		mapper.deletePortal(pageId);
+	}
+	
+	public void updatePortal(Portal portal){
+		mapper.updatePortal(portal);
+	}
+	
+	public Portal getPortal(String pageId){
+		return mapper.getPortal(pageId);
+	}
+	
+	public void renamePortal(Portal portal){
+		mapper.renamePortal(portal);
+	}
+	
+	public List<Map<String, Object>> listAppReport(Integer userId, Integer cataId){
+		return mapper.listAppReport(userId, cataId);
+	}
+}

+ 459 - 0
src/main/java/com/ruisitech/bi/service/portal/PortalTableService.java

@@ -0,0 +1,459 @@
+package com.ruisitech.bi.service.portal;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.init.TemplateManager;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.MVContextImpl;
+import com.ruisi.ext.engine.view.context.cross.BaseKpiField;
+import com.ruisi.ext.engine.view.context.cross.CrossKpi;
+import com.ruisi.ext.engine.view.context.cross.CrossReportContext;
+import com.ruisi.ext.engine.view.context.cross.RowDimContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContext;
+import com.ruisi.ext.engine.view.context.dc.grid.GridDataCenterContextImpl;
+import com.ruisi.ext.engine.view.context.dc.grid.GridSetConfContext;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisitech.bi.entity.bireport.DimDto;
+import com.ruisitech.bi.entity.bireport.KpiDto;
+import com.ruisitech.bi.entity.bireport.TableQueryDto;
+import com.ruisitech.bi.entity.portal.LinkAcceptDto;
+import com.ruisitech.bi.entity.portal.PortalTableQuery;
+import com.ruisitech.bi.service.bireport.BaseCompService;
+import com.ruisitech.bi.service.bireport.ModelCacheService;
+import com.ruisitech.bi.service.bireport.TableService;
+import com.ruisitech.bi.util.RSBIUtils;
+import com.ruisitech.ext.service.DataControlInterface;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Scope("prototype")
+public class PortalTableService  extends BaseCompService {
+
+	public final static String deftMvId = "mv.portal.table";
+	
+	private Map<String, InputField> mvParams = new HashMap<String, InputField>(); //mv的参数
+	
+	@Autowired
+	private DataControlInterface dataControl; //数据权限控制
+	
+	@Autowired
+	private ModelCacheService cacheService;
+	
+	@Autowired
+	private TableService tableService;
+	
+	public @PostConstruct void init() {
+		
+	}  
+	
+	public @PreDestroy void destory() {
+		mvParams.clear();
+	}
+	
+	/**
+	 * 生成表格SQL
+	 * @param sqlVO
+	 * @param tinfo
+	 * @param params
+	 * @param release  判断当前是否为发布状态, 0 表示不是发布,1表示发布到多维分析,2表示发布到仪表盘
+	 * @param drillLevel 是否有钻取,从0开始, 0表示不钻取,1表示钻取一层,以此类推
+	 * @return
+	 * @throws ParseException
+	 */
+	public String createSql(PortalTableQuery table, int release, int drillLevel) throws ParseException{
+		JSONObject dset = cacheService.getDset(table.getDsetId());
+		Map<String, String> tableAlias = super.createTableAlias(dset);
+		StringBuffer sql = new StringBuffer();
+		sql.append("select ");
+		List<DimDto> dims = table.getDims();
+		for(int i=0; i<dims.size(); i++){
+			DimDto dim = dims.get(i);
+			String t = dim.getTname();
+			String key = dim.getTableColKey();
+			String txt = dim.getTableColName();
+			String tname = dim.getTableName();
+			int iscalc = dim.getCalc();
+			if(key != null && txt != null && key.length() >0 && txt.length() >0){
+				sql.append(tableAlias.get(tname)+"."+key+", "+tableAlias.get(tname)+"." + txt + ",");
+			}else{
+				if(iscalc == 1){
+					sql.append(dim.getColname()+" as "+dim.getAlias()+", ");
+				}else{
+					sql.append(tableAlias.get(t)+"."+dim.getColname()+" as "+dim.getAlias()+", ");
+				}
+			}
+			
+		}
+		
+		//处理钻取维
+		List<Map<String, Object>> drillDim = table.getDrillDim();
+		if(drillDim != null && drillDim.size() >= drillLevel){
+			for(int i=0; i<drillLevel; i++){
+				Map<String, Object> dim = drillDim.get(i);
+				String key = (String)dim.get("tableColKey");
+				String txt = (String)dim.get("tableColName");
+				String tname = (String)dim.get("tableName");
+				String t = (String)dim.get("tname");
+				int iscalc = (Integer)dim.get("calc");
+				if(key != null && txt != null && key.length() >0 && txt.length() >0){
+					sql.append(tableAlias.get(tname)+"."+key+", "+ tableAlias.get(tname) +"." + txt + ",");
+				}else{
+					if(iscalc == 1){
+						sql.append(dim.get("colname")+" as "+dim.get("code")+", ");
+					}else{
+						sql.append(tableAlias.get(t)+"."+dim.get("colname")+" as "+dim.get("code")+", ");
+					}
+				}
+			}
+			
+		}
+		
+		List<KpiDto> kpis = table.getKpiJson();
+		if(kpis.size() == 0){
+			sql.append(" 0 kpi_value ");
+		}else{
+			for(int i=0; i<kpis.size(); i++){
+				KpiDto kpi = kpis.get(i);
+				if(kpi.getCalc() != null && kpi.getCalc() == 1){  //表达式,直接取表达式
+					sql.append(kpi.getCol_name() + " ");
+				}else{  //获取字段别名
+					String name = super.convertKpiName(kpi, tableAlias);
+					sql.append( name + " ");
+				}
+				sql.append(kpi.getAlias());
+				if(i != kpis.size() - 1){
+					sql.append(",");
+				}
+			}
+		}
+		
+		//如果名字是SQL,加括号,是表名不加括号
+		JSONArray joinTabs = (JSONArray)dset.get("joininfo");
+		String master = dset.getString("master");
+		sql.append(" from " + master + " a0");
+		
+		for(int i=0; joinTabs!=null&&i<joinTabs.size(); i++){  //通过主表关联
+			JSONObject tab = joinTabs.getJSONObject(i);
+			String ref = tab.getString("ref");
+			String refKey = tab.getString("refKey");
+			String jtype = (String)tab.get("jtype");
+			if("left".equals(jtype) || "right".equals(jtype)){
+				sql.append(" " + jtype);
+			}
+			sql.append(" join " + ref+ " " + tableAlias.get(ref));
+			sql.append(" on a0."+tab.getString("col")+"="+tableAlias.get(ref)+"."+refKey);
+			sql.append(" ");
+			
+		}
+		sql.append(" where 1=1 ");
+		
+		//数据权限
+		if(dataControl != null){
+			String ret = dataControl.process(RSBIUtils.getLoginUserInfo(), dset.getString("master"));
+			if(ret != null){
+				sql.append(ret + " ");
+			}
+		}
+		
+		//限制参数的查询条件
+		sql.append(dealCubeParams(table.getParams(), tableAlias));
+		
+		//在钻取的时候设置过滤
+		if(drillLevel == 1 && table.getRows().size() == 1) {
+			DimDto row = table.getRows().get(0);
+			String valType = row.getValType();
+			String tname = row.getTname();
+			if("String".equalsIgnoreCase(valType)){
+				sql.append(" and "+ (row.getCalc() == 1 ?"":tableAlias.get(tname)+".") + row.getColname()+" = '$"+row.getAlias()+"'");
+			}else{
+				sql.append(" and " + (row.getCalc() == 1 ?"":tableAlias.get(tname)+".") + row.getColname()+" = $"+row.getAlias());
+			}
+		}
+		
+		//处理事件接受的参数限制条件
+		LinkAcceptDto linkAccept = table.getLinkAccept();
+		if(linkAccept != null && release == 1 ){  //预览状态
+			String col = linkAccept.getCol();
+			String alias = super.findEventParamName(table.getId());
+			if(alias == null){
+				alias = linkAccept.getAlias();
+			}
+			String valtype = linkAccept.getValType();
+			String tname = linkAccept.getTname();  //维度来源表
+			String dimTname = linkAccept.getDimTname();  //维度映射的表
+			Integer calc = linkAccept.getCalc();
+			String ncol = "$" + alias;
+			if("string".equalsIgnoreCase(valtype)){
+				ncol = "'" + ncol + "'";
+			}
+			sql.append("#if( $"+alias+" && $"+alias+" != '') and  ");
+			if(calc == null || calc == 0){  //表达式不增加别名
+				sql.append(tableAlias.get(dimTname == null || dimTname.length() == 0 ? tname:dimTname)+".");
+			}
+			sql.append(col + " = " + ncol + " #end");
+		}
+		
+		if(dims.size() > 0){
+			sql.append(" group by ");
+			for(int i=0; i<dims.size(); i++){
+				DimDto dim = dims.get(i);
+				String key = dim.getTableColKey();
+				String txt = dim.getTableColName();
+				String tname = dim.getTableName();
+				String t = dim.getTname();
+				int calc = dim.getCalc();
+				if(key != null && txt != null && key.length() >0 && txt.length() >0){
+					sql.append(tableAlias.get(tname) + "." + key+", "+ tableAlias.get(tname) +"." + txt);
+				}else{
+					if(calc == 1){
+						sql.append(dim.getColname());
+					}else{
+						sql.append(tableAlias.get(t) + "."+ dim.getColname());
+					}
+				}
+				if(i != dims.size() - 1){
+					sql.append(",");
+				}
+			}
+			//钻取的group by
+			if(drillDim != null && drillDim.size() >= drillLevel){
+				for(int i=0; i<drillLevel; i++){
+					Map<String, Object> dim = drillDim.get(i);
+					String key = (String)dim.get("tableColKey");
+					String txt = (String)dim.get("tableColName");
+					String tname = (String)dim.get("tableName");
+					String t = (String)dim.get("tname");
+					int iscalc = (Integer)dim.get("calc");
+					if(key != null && txt != null && key.length() >0 && txt.length() >0){
+						sql.append("," + (iscalc == 1 ? "":tableAlias.get(tname) + ".") + key);
+					}else{
+						sql.append("," + (iscalc == 1 ?"":tableAlias.get(t) + ".") + dim.get("code"));
+					}
+				}
+			}
+		}
+		//处理指标过滤
+		/**
+		StringBuffer filter = new StringBuffer("");
+		for(KpiInfo kpi : sqlVO.getKpis()){
+			if(kpi.getFilter() != null){
+				filter.append(" and "+kpi.getColName()+" ");
+				String tp = kpi.getFilter().getFilterType();
+				filter.append(tp);
+				filter.append(" ");
+				double val1 = kpi.getFilter().getVal1();
+				if(kpi.getFmt() != null && kpi.getFmt().endsWith("%")){
+					val1 = val1 / 100;
+				}
+				filter.append(val1 * (kpi.getRate() == null ? 1 : kpi.getRate()));
+				if("between".equals(tp)){
+					double val2 = kpi.getFilter().getVal2();
+					if(kpi.getFmt() != null && kpi.getFmt().endsWith("%")){
+						val2 = val2 / 100;
+					}
+					filter.append(" and " + val2 * (kpi.getRate() == null ? 1 : kpi.getRate()));
+				}
+			}
+		}
+		**/
+		String retSql = null;
+		
+		if(dims.size() > 0){
+			StringBuffer order = new StringBuffer();
+			order.append(" order by ");
+			//先按col排序
+			for(int i=0; i<table.getCols().size(); i++){
+				DimDto dim = table.getCols().get(i);
+				if(dim.getDimord() != null && dim.getDimord().length() > 0){
+					order.append(dim.getTableColKey() != null && dim.getTableColKey().length() > 0 ? dim.getTableColKey() : dim.getColname());
+					order.append(" ");
+					order.append(dim.getDimord());
+					order.append(",");
+				}
+			}
+			//判断是否按指标排序
+			for(int i=0; i<kpis.size(); i++){
+				KpiDto kpi = kpis.get(i);
+				if(kpi.getSort() != null && kpi.getSort().length() > 0){
+					order.append(kpi.getAlias() + " " + kpi.getSort());
+					order.append(",");
+				}
+			}
+			
+			//再按row排序
+			for(int i=0; i<table.getRows().size(); i++){
+				DimDto dim = table.getRows().get(i);
+				if(dim.getDimord() != null && dim.getDimord().length() > 0){
+					order.append(dim.getTableColKey() != null && dim.getTableColKey().length() > 0 ? dim.getTableColKey() : dim.getColname());
+					order.append(" ");
+					order.append(dim.getDimord());
+					order.append(",");
+				}
+			}
+			
+			
+			if(order.length() <= 11 ){  //判断是否拼接了 order by 字段
+				retSql = sql.toString();
+			}else{
+				//返回前先去除最后的逗号
+				retSql = sql + order.toString().substring(0, order.length() - 1);
+			}
+		}else{
+			retSql =  sql.toString();
+		}
+		return retSql.replaceAll("@", "'");
+	}
+	
+	/**
+	 * 门户使用的JSON2MV对象
+	 */
+	public MVContext json2MV(PortalTableQuery table) throws Exception{
+		
+		//创建MV
+		MVContext mv = new MVContextImpl();
+		mv.setChildren(new ArrayList<Element>());
+		String formId = ExtConstants.formIdPrefix + IdCreater.create();
+		mv.setFormId(formId);
+		mv.setMvid(deftMvId);
+		
+		//处理参数,把参数设为hidden
+		parserHiddenParam(table.getPortalParams(), mv, this.mvParams);
+		
+		//创建corssReport
+		TableQueryDto dto = new TableQueryDto();
+		dto.setCompId(table.getId());
+		dto.setLink(table.getLink());
+		dto.setDrillDim(table.getDrillDim());
+		dto.setCols(table.getCols());
+		dto.setRows(table.getRows());
+		dto.setKpiJson(table.getKpiJson());
+		CrossReportContext cr = null;
+		//处理kpiOther
+		CrossKpi mybaseKpi = null;
+		List<DimDto> cols = table.getCols();
+		if(cols.size() > 0 && table.getKpiJson().size() == 1){
+			//如果只有一个指标,并且具有列维度,放入baseKpi
+			KpiDto kpi = table.getKpiJson().get(0);
+			CrossKpi baseKpi = new BaseKpiField();
+			baseKpi.setAggregation(kpi.getAggre());
+			baseKpi.setAlias(kpi.getAlias());
+			baseKpi.setFormatPattern(kpi.getFmt());
+			baseKpi.setKpiRate(kpi.getRate() == null ? null : new BigDecimal(kpi.getRate()));
+			mybaseKpi = baseKpi;
+			cr = tableService.json2Table(dto);
+			cr.setBaseKpi(mybaseKpi);
+		}else{
+			DimDto kpiOther = new DimDto();
+			kpiOther.setType("kpiOther");
+			cols.add(kpiOther);
+			cr = tableService.json2Table(dto);
+			cols.remove(cols.size() - 1);
+		}
+		//设置ID
+		String id = ExtConstants.reportIdPrefix + IdCreater.create();
+		cr.setId(id);
+		cr.setOut("lockUI");
+		String height =  table.getHeight();
+		if(height != null && height.length() > 0){
+			cr.setHeight(height);
+		}
+		cr.setShowData(true);
+		
+		//创建datacenter
+		String sql = this.createSql(table, 0, 0);
+		GridDataCenterContext dc = this.createDataCenter(sql, table);
+		cr.setRefDataCetner(dc.getId());
+		if(mv.getGridDataCenters() == null){
+			mv.setGridDataCenters(new HashMap<String, GridDataCenterContext>());
+		}
+		mv.getGridDataCenters().put(dc.getId(), dc);
+		
+		//判断是否有钻取维
+		List<RowDimContext> drillDims = cr.getDims();
+		for(int i=0; drillDims!=null&&i<drillDims.size(); i++){ 
+			RowDimContext drillDim = drillDims.get(i);
+			//生成钻取维的DataCenter
+			sql = this.createSql(table, 0, i+1);
+			GridDataCenterContext drillDc = this.createDataCenter(sql, table);
+			drillDim.setRefDataCenter(drillDc.getId());
+			mv.getGridDataCenters().put(drillDc.getId(), drillDc);
+		}
+		
+		mv.getChildren().add(cr);
+		cr.setParent(mv);
+		
+		//判断是否有事件,是否需要添加参数
+		/**
+		Map<String, Object> linkAccept = table.getLinkAccept();
+		if(linkAccept != null && !linkAccept.isEmpty()){
+			//创建参数
+			TextFieldContext linkText = new TextFieldContextImpl();
+			linkText.setType("hidden");
+			linkText.setDefaultValue((String)linkAccept.get("dftval"));
+			linkText.setId((String)linkAccept.get("col"));
+			linkText.setShow(true);
+			mv.getChildren().add(0, linkText);
+			linkText.setParent(mv);
+			this.mvParams.put(linkText.getId(), linkText);
+			ExtContext.getInstance().putServiceParam(mv.getMvid(), linkText.getId(), linkText);
+			mv.setShowForm(true);
+		}
+		**/
+		
+		Map<String, CrossReportContext> crs = new HashMap<String, CrossReportContext>();
+		crs.put(cr.getId(), cr);
+		mv.setCrossReports(crs);
+		
+		//处理scripts
+		String scripts = tableService.getScripts().toString();
+		if(scripts.length() > 0){
+			mv.setScripts(scripts);
+		}
+		//数据源
+		String dsid = createDsource(this.cacheService.getDsource(table.getDsid()), mv);
+		dc.getConf().setRefDsource(dsid);
+		return mv;
+	}
+	
+	/**
+	 * 创建表格datacenter
+	 * @param sql
+	 * @return
+	 * @throws IOException
+	 */
+	public GridDataCenterContext createDataCenter(String sql, PortalTableQuery table) throws IOException{
+		GridDataCenterContext ctx = new GridDataCenterContextImpl();
+		GridSetConfContext conf = new GridSetConfContext();
+		conf.setRefDsource(table.getDsid());
+		ctx.setConf(conf);
+		ctx.setId("DC-" + IdCreater.create());
+		String name = TemplateManager.getInstance().createTemplate(sql);
+		ctx.getConf().setTemplateName(name);
+		
+		return ctx;
+	}
+
+	public Map<String, InputField> getMvParams() {
+		return mvParams;
+	}
+
+	public TableService getTableService() {
+		return tableService;
+	}
+	
+}

+ 27 - 0
src/main/java/com/ruisitech/bi/util/BaseController.java

@@ -0,0 +1,27 @@
+package com.ruisitech.bi.util;
+
+import com.ruisitech.bi.entity.common.RequestStatus;
+import com.ruisitech.bi.entity.common.Result;
+
+public class BaseController {
+
+	public Object buildSucces(){
+		return new Result(RequestStatus.SUCCESS.getStatus(), "操作成功", null);
+	}
+	
+	public Object buildSucces(Object datas){
+		return new Result(RequestStatus.SUCCESS.getStatus(), "操作成功", datas);
+	}
+	
+	public Object buildSucces(com.github.pagehelper.PageInfo<?> page){
+		Long total = page.getTotal();
+	   // Integer pageIndex = page.getPageNum();
+	   // Integer pageSize = page.getPageSize();
+	    Object datas = (Object) page.getList();
+		return new Result(RequestStatus.SUCCESS.getStatus(), "操作成功", datas, total);
+	}
+	
+	public Object buildError(String msg){
+		return new Result(RequestStatus.FAIL_FIELD.getStatus(), msg, null);
+	}
+}

+ 167 - 0
src/main/java/com/ruisitech/bi/util/CompPreviewService.java

@@ -0,0 +1,167 @@
+package com.ruisitech.bi.util;
+
+import com.ruisi.bi.engine.cross.CrossFieldLoader;
+import com.ruisi.bi.engine.view.emitter.ContextEmitter;
+import com.ruisi.bi.engine.view.emitter.html.HTMLEmitter;
+import com.ruisi.ext.engine.ConstantsEngine;
+import com.ruisi.ext.engine.ExtConfigConstants;
+import com.ruisi.ext.engine.ExtConstants;
+import com.ruisi.ext.engine.control.InputOption;
+import com.ruisi.ext.engine.control.InputOptionFactory;
+import com.ruisi.ext.engine.dao.DaoHelper;
+import com.ruisi.ext.engine.init.ExtEnvirContext;
+import com.ruisi.ext.engine.init.ExtEnvirContextImpl;
+import com.ruisi.ext.engine.service.loginuser.LoginUserFactory;
+import com.ruisi.ext.engine.service.loginuser.LoginUserInfoLoader;
+import com.ruisi.ext.engine.util.DaoUtils;
+import com.ruisi.ext.engine.util.IdCreater;
+import com.ruisi.ext.engine.view.builder.BuilderManager;
+import com.ruisi.ext.engine.view.context.Element;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.engine.view.context.MVContext;
+import com.ruisi.ext.engine.view.context.form.InputField;
+import com.ruisi.ext.engine.view.exception.ExtRuntimeException;
+import com.ruisi.ext.engine.wrapper.ExtRequest;
+import com.ruisi.ext.engine.wrapper.ExtRequestImpl;
+import com.ruisi.ext.engine.wrapper.ExtResponse;
+import com.ruisi.ext.engine.wrapper.ExtResponseImpl;
+import com.ruisitech.bi.service.bireport.TableService;
+import com.ruisitech.ext.service.ExtLoginInfoLoader;
+import org.apache.commons.fileupload.FileUploadException;
+
+import javax.script.*;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 组件预览类.创建必要的组件预览对象
+ * @author hq
+ * @date Aug 18, 2010
+ */
+public class CompPreviewService {
+	
+	private ExtRequest request;
+	private ExtResponse response;
+	private ServletContext context;
+	private DaoHelper dao;
+	public DaoHelper getDao() {
+		return dao;
+	}
+
+	private ExtEnvirContext envirCtx;
+	public ExtEnvirContext getEnvirCtx() {
+		return envirCtx;
+	}
+
+	Map<String, InputField> params = null; //请求的参数
+	
+	public Map<String, InputField> getParams() {
+		return params;
+	}
+
+	public void setParams(Map<String, InputField> params) {
+		this.params = params;
+	}
+	
+	public CompPreviewService(ExtRequest request, ExtResponse response, ServletContext context, DaoHelper dao){
+		this.request = request;
+		this.response = response;
+		this.context = context;
+		this.dao = dao;
+	}
+
+	public CompPreviewService(HttpServletRequest req, HttpServletResponse resp, ServletContext sctx) throws IOException{
+		request = new ExtRequestImpl(req);
+		response = new ExtResponseImpl(resp);
+		context = sctx;
+		dao = DaoUtils.getDaoHelper(context);
+		//out = new ExtWriterImpl(response.getWriter());
+	}
+	
+	public void initPreview() throws FileUploadException {
+		
+		LoginUserFactory loginUserFactory = LoginUserFactory.getInstance();
+		LoginUserInfoLoader loginUserInfoLoader = new ExtLoginInfoLoader();
+		loginUserFactory.createLoginUser(request, response, dao, loginUserInfoLoader);
+		
+		//servletContext放入request, 显示图形时需要调用
+		InputOption option = InputOptionFactory.createInputOption(request, response, params);
+		request.setAttribute(ExtConstants.optionIdKey, option);
+		ExtEnvirContext ec = new ExtEnvirContextImpl(option);
+		this.envirCtx = ec;
+		//request.setAttribute(ExtConstants.contextSessionKey, ec);
+		
+		//请求为post,设置fromId
+		request.setAttribute(ExtConstants.fromIdKey, TableService.deftMvId);
+		
+		//创建crossReport需要用到的loader
+		CrossFieldLoader loader = null;
+		String fieldLoader = ExtContext.getInstance().getConstant("fieldLoader");
+		if(fieldLoader == null){
+			throw new ExtRuntimeException("未配置 fieldLoader.");
+		}
+		try {
+			loader = (CrossFieldLoader)Class.forName(fieldLoader).newInstance();
+			loader.setRequest(this.request);
+		} catch (Exception e) {
+			String err = ConstantsEngine.replace(ExtConfigConstants.crossColNotExist, fieldLoader);
+			throw new ExtRuntimeException(err);
+		}
+		request.setAttribute(ExtConstants.fieldLoader, loader);
+	}
+	
+	public String buildMV(Element mv, ServletContext sctx) throws Exception{
+		ContextEmitter emitter = new HTMLEmitter();
+		return buildMV(mv, emitter, sctx);
+	}
+	
+	public String buildMV(Element mv, ContextEmitter emitter, ServletContext sctx) throws Exception{
+		//把MV放入内存对象
+		if(mv instanceof MVContext){
+			MVContext mvo = (MVContext)mv;
+			String formId = ExtConstants.formIdPrefix + IdCreater.create();
+			mvo.setFormId(formId);
+			mvo.setCreateDate(new Date());
+			ExtContext.getInstance().putMVContext(mvo , false);
+		}
+		Map<String, InputField> params =  this.params;
+		InputOption option = InputOptionFactory.createInputOption(request, response, params);
+		String ret = BuilderManager.buildContext2String(mv, request, this.envirCtx,  response, dao, emitter, option, sctx);
+		return ret;
+	}
+	
+	/**
+	 * 预先编译js运算公式
+	 * @throws ScriptException 
+	 */
+	public void initJSFunc(String scripts) throws ScriptException{
+		ScriptEngineManager factory = new ScriptEngineManager();
+		ScriptEngine engine = factory.getEngineByName("JavaScript");
+
+		//把一些常用的对象放入其中
+		//engine.put("out", out);
+		engine.put("request", this.request);
+		Compilable compilable = (Compilable) engine;
+		CompiledScript compiled = compilable.compile(scripts);
+		compiled.eval();
+		
+		//把engine放入request,方便调用
+		request.setAttribute(ExtConstants.scriptEngineKey, engine);
+	}
+
+	public ExtRequest getRequest() {
+		return request;
+	}
+
+	public ExtResponse getResponse() {
+		return response;
+	}
+
+	public ServletContext getContext() {
+		return context;
+	}
+}

+ 48 - 0
src/main/java/com/ruisitech/bi/util/HeadFilter.java

@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.util;
+
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 跨域请求设置Filter
+ * @author gdp
+ * @Date 2020/9/18 9:38 上午
+ */
+@Component
+public class HeadFilter implements Filter  {
+
+    @Override
+    public void destroy() {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse resp, FilterChain chain)
+            throws IOException, ServletException {
+        HttpServletResponse response=(HttpServletResponse)resp;
+        HttpServletRequest req = (HttpServletRequest)request;
+        String origin = req.getHeader("Origin");
+        if(origin == null) {
+            origin = req.getHeader("Referer");
+        }
+        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild");
+        response.setHeader("Access-Control-Allow-Origin", origin);//这里不能写*,*代表接受所有域名访问,如写*则下面一行代码无效。谨记
+        response.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许携带cookie
+        chain.doFilter(req, response);
+    }
+
+    @Override
+    public void init(FilterConfig arg0)
+            throws ServletException {
+    }
+
+}

+ 63 - 0
src/main/java/com/ruisitech/bi/util/MVCleanListener.java

@@ -0,0 +1,63 @@
+package com.ruisitech.bi.util;
+
+import com.ruisi.ext.engine.control.ContextListener;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.engine.view.context.MVContext;
+
+import javax.servlet.ServletContextEvent;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 清除 MV 缓存得 listerner
+ * @author hq
+ *
+ */
+public class MVCleanListener implements ContextListener {
+	
+	private boolean isgo = true;
+
+	@Override
+	public void contextInit(ServletContextEvent arg0) {
+		
+		Thread t = new Thread(new Runnable() {
+
+			@Override
+			public void run() {
+				while(isgo) {
+					try {
+						//移除超过1小时得mv缓存
+						long now = new Date().getTime();
+						List<String> removeIds = new ArrayList<String>();
+						Map<String, MVContext> mvs = ExtContext.getInstance().getAllMV();
+						for(Map.Entry<String, MVContext> mv : mvs.entrySet()) {
+							Date crtdate = mv.getValue().getCreateDate();
+							if(crtdate != null && now - crtdate.getTime() >= 1000 * 60  * 60 ) {
+								removeIds.add(mv.getKey());
+							}
+						}
+						for(String mvId : removeIds) {
+							ExtContext.getInstance().removeMV(mvId);
+						}
+						
+						Thread.sleep(60 * 1000);
+					}catch(Exception ex) {
+						ex.printStackTrace();
+					}
+					
+				}
+			}
+			
+		});
+		t.start();
+		
+	}
+
+	@Override
+	public void contextDest(ServletContextEvent arg0) {
+		isgo = false;
+	}
+
+}

+ 260 - 0
src/main/java/com/ruisitech/bi/util/RSBIUtils.java

@@ -0,0 +1,260 @@
+package com.ruisitech.bi.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.ruisi.ext.engine.view.context.ExtContext;
+import com.ruisi.ext.runtime.tag.CalendarTag;
+import com.ruisitech.bi.entity.frame.User;
+import com.ruisitech.bi.service.frame.ShiroDbRealm;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public final class RSBIUtils {
+	
+	
+	/**
+	 * 给str加密md5。
+	 * @return
+	 */
+	public static String getEncodedStr(String str){
+		if(str==null)return null;
+		return getMD5(str.getBytes());
+	}
+
+	/**
+	 * 获取字符串MD5
+	 * @param source
+	 * @return
+	 */
+	public static String getMD5(byte[] source) {  
+	    String s = null;  
+	    char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',  
+	            'a', 'b', 'c', 'd', 'e', 'f' };// 用来将字节转换成16进制表示的字符  
+	    try {  
+	        java.security.MessageDigest md = java.security.MessageDigest  
+	                .getInstance("MD5");  
+	        md.update(source);  
+	        byte tmp[] = md.digest();// MD5 的计算结果是一个 128 位的长整数,  
+	        // 用字节表示就是 16 个字节  
+	        char str[] = new char[16 * 2];// 每个字节用 16 进制表示的话,使用两个字符, 所以表示成 16  
+	        // 进制需要 32 个字符  
+	        int k = 0;// 表示转换结果中对应的字符位置  
+	        for (int i = 0; i < 16; i++) {// 从第一个字节开始,对 MD5 的每一个字节// 转换成 16  
+	            // 进制字符的转换  
+	            byte byte0 = tmp[i];// 取第 i 个字节  
+	            str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换,// >>>  
+	            // 为逻辑右移,将符号位一起右移  
+	            str[k++] = hexDigits[byte0 & 0xf];// 取字节中低 4 位的数字转换  
+
+	        }  
+	        s = new String(str);// 换后的结果转换为字符串  
+
+	    } catch (NoSuchAlgorithmException e) {  
+	        // TODO Auto-generated catch block  
+	        e.printStackTrace();  
+	    }  
+	    return s;  
+	}
+	
+	/**
+	 * 获取ext-config中配置的变量。
+	 * @return
+	 */
+	public static String getConstant(String name){
+		return ExtContext.getInstance().getConstant(name);
+	}
+	public static String getUUIDStr(){
+		return UUID.randomUUID().toString().replace("-","");
+	}
+	
+	public static String dealStringParam(String vals){
+		String[] vls = vals.split(",");
+		StringBuffer sb = new StringBuffer();
+		for(int i=0; i<vls.length; i++){
+			String v = vls[i];
+			sb.append("'" + v + "'");
+			if(i != vls.length - 1){
+				sb.append(",");
+			}
+		}
+		return sb.toString();
+	}
+	
+	public static Map<String, String> getAllParams(HttpServletRequest req){
+		Map<String, String> dt = new HashMap<String, String>();
+		Enumeration<String> enu = req.getParameterNames();
+		while(enu.hasMoreElements()){
+			String key = (String)enu.nextElement();
+			dt.put(key, req.getParameter(key));
+		}
+		return dt;
+	}
+	
+	public static boolean isShowMenu(String name, HttpServletRequest req){
+		JSONObject obj = (JSONObject)req.getAttribute("menuDisp");
+		if(obj == null){
+			return true;
+		}
+		Object r = obj.get(name);
+		if(r == null){
+			return true;
+		}
+		if(r instanceof Integer && (Integer)r == 0){
+			return false;
+		}else{
+			return true;
+		}
+	}
+	
+	public static String getAppUserId(){
+		String uid = "";
+		return uid;
+	}
+	
+	public static SqlSession getSqlSession(ServletContext sctx){
+		SqlSession sqlSession=null;
+		WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sctx);
+		SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)ctx.getBean("sqlSessionFactory");
+		sqlSession = sqlSessionFactory.openSession();
+		return sqlSession;
+	}
+	
+	public static void closeSqlSession(SqlSession sqlSession){
+		 if(sqlSession!=null){
+             sqlSession.close();
+         }
+	}
+	
+	public static User getLoginUserInfo(){
+		Subject us = SecurityUtils.getSubject();
+		User u = (User)us.getSession().getAttribute(ShiroDbRealm.SESSION_USER_KEY);
+		return u;
+	}
+	
+	/**
+	 * 生成导出html
+	 * @param body
+	 * @param host
+	 * @param type 表示使用的类型,是 olap表示多维分析的导出, report 表示报表的导出
+	 * @return
+	 */
+	public static String htmlPage(String body, String host, String type){
+		StringBuffer sb = new StringBuffer();
+		
+		sb.append("<!DOCTYPE html>");
+		sb.append("<html lang=\"en\">");
+		sb.append("<head>");
+		sb.append("<title>睿思BI</title>");
+		sb.append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\">");
+		sb.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
+		sb.append("<script type=\"text/javascript\" src=\""+host+"/ext-res/js/jquery.min.js\"></script>");
+		sb.append("<script type=\"text/javascript\" src=\""+host+"/ext-res/js/ext-base.js\"></script>");
+		sb.append("<script type=\"text/javascript\" src=\""+host+"/ext-res/js/echarts.min.js\"></script>");
+		sb.append("<script type=\"text/javascript\" src=\""+host+"/ext-res/js/sortabletable.js\"></script>");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/ext-res/css/bootstrap.min.css\" />");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/resource/css/animate.css\" />");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/resource/css/style.css\" />");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/resource/css/font-awesome.css?v=4.4.0\" />");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/resource/jquery-easyui-1.4.4/themes/gray/easyui.css\">");
+		sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\""+host+"/resource/jquery-easyui-1.4.4/themes/icon.css\">");
+		sb.append("<script type=\"text/javascript\" src=\""+host+"/resource/jquery-easyui-1.4.4/jquery.easyui.min.js\"></script>");
+		sb.append("</head>");
+		sb.append("<style>");
+		sb.append("table.r_layout {table-layout:fixed;width:100%;}");
+		sb.append("table.r_layout td.layouttd {padding:10px;}");
+		sb.append(".inputform2 {width:120px;}");
+		sb.append(".inputtext {width:90px;}");
+		sb.append("</style>");
+		sb.append("<body class=\"gray-bg\">");
+	
+		sb.append(body);
+		
+		sb.append("</body>");
+		sb.append("</html>");
+		
+		return sb.toString();
+	}
+	
+	public static boolean exist(String id, String[] ids){
+		boolean exist = false;
+		for(String tid : ids){
+			if(tid.equals(id)){
+				exist = true;
+				break;
+			}
+		}
+		return exist;
+	}
+	
+	public static String getFestival(Object key, HttpServletRequest req){
+		String df = (String)req.getAttribute("dateformat");
+		String ret = CalendarTag.getFestival((String)key, df);
+		return ret;
+	}
+	
+	/**
+	 * 将容易引起xss漏洞的半角字符直接替换成全角字符 在保证不删除数据的情况下保存 
+	 * @param value
+	 * @return
+	 */
+	public static String htmlEscape(String value){
+		if(value == null || value.length() == 0){
+			return value;
+		}
+		value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+        value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
+        value = value.replaceAll("'", "&#39;");
+        value = value.replaceAll("eval\\((.*)\\)", "");
+        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
+        value = value.replaceAll("script", "");
+        return value;
+	}
+	
+	 /**
+     * Escape解码
+     * @param src 加盐字符串
+     * @return 明文
+     */
+    public static String unescape(String src) {
+        StringBuffer tmp = new StringBuffer();
+        tmp.ensureCapacity(src.length());
+        int lastPos = 0, pos = 0;
+        char ch;
+        while (lastPos < src.length()) {
+            pos = src.indexOf("%", lastPos);
+            if (pos == lastPos) {
+                if (src.charAt(pos + 1) == 'u') {
+                    ch = (char) Integer.parseInt(src
+                            .substring(pos + 2, pos + 6), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 6;
+                } else {
+                    ch = (char) Integer.parseInt(src
+                            .substring(pos + 1, pos + 3), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 3;
+                }
+            } else {
+                if (pos == -1) {
+                    tmp.append(src.substring(lastPos));
+                    lastPos = src.length();
+                } else {
+                    tmp.append(src.substring(lastPos, pos));
+                    lastPos = pos;
+                }
+            }
+        }
+        return tmp.toString();
+    }
+}

+ 34 - 0
src/main/java/com/ruisitech/bi/util/SqliteHelperImpl.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 本系统版权归成都睿思商智科技有限公司所有
+ * 用户不能删除系统源码上的版权信息, 使用许可证地址:
+ * https://www.ruisitech.com/licenses/index.html
+ */
+package com.ruisitech.bi.util;
+
+import com.ruisi.ext.engine.dao.DatabaseHelper;
+import com.ruisi.ext.engine.view.context.grid.PageInfo;
+
+/**
+ * bi系统的 sqlite 实现
+ * @ClassName SqliteHelperImpl
+ * @Description SqliteHelperImpl
+ * @Author gdp
+ * @Date 2020/6/2 1:17 下午
+ */
+public class SqliteHelperImpl implements DatabaseHelper {
+
+    @Override
+    public String getDatabaseType() {
+        return "sqlite";
+    }
+
+    @Override
+    public String getClazz() {
+        return "org.sqlite.JDBC";
+    }
+
+    @Override
+    public String getQueryPageSql(String sql, PageInfo page) {
+        return "select * from ("+sql+") bb Limit "+ page.getPagesize()+" Offset " + (page.getCurtpage() * page.getPagesize());
+    }
+}

+ 10 - 0
src/main/java/com/ruisitech/bi/util/TreeInterface.java

@@ -0,0 +1,10 @@
+package com.ruisitech.bi.util;
+
+import java.util.Map;
+
+public interface TreeInterface {
+	
+	public void processMap(Map<String, Object> m);
+	
+	public void processEnd(Map<String, Object> m, boolean hasChild);
+}

+ 150 - 0
src/main/java/com/ruisitech/bi/util/TreeService.java

@@ -0,0 +1,150 @@
+package com.ruisitech.bi.util;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 递归调用,生成Tree 数据
+ * @author hq
+ * @date 2014-7-30
+ */
+public class TreeService {
+	
+	public List<Map<String, Object>> createTreeData(List<Map<String, Object>> datas, com.ruisitech.bi.util.TreeInterface treeface){
+		List<Map<String, Object>> roots = this.getChildren(datas, 0);
+		this.loopChildren(roots, datas, treeface);
+		return roots;
+	}
+	
+	public List<Map<String, Object>> createTreeDataById(List<Map<String, Object>> datas, com.ruisitech.bi.util.TreeInterface treeface, int id){
+		List<Map<String, Object>> roots = this.getChildren(datas, id);
+		this.loopChildren(roots, datas, treeface);
+		return roots;
+	}
+	
+	private void loopChildren(List<Map<String, Object>> nodes, List<Map<String, Object>> datas, com.ruisitech.bi.util.TreeInterface treeface){
+		for(int i=0; i<nodes.size(); i++){
+			Map<String, Object> root = (Map<String, Object>)nodes.get(i);
+			treeface.processMap(root);
+			int id;
+			Object ret = root.get("id");
+			if(ret instanceof Integer){
+				id = (Integer)ret;
+			}else if(ret instanceof BigDecimal){
+				id = ((BigDecimal)ret).intValue();
+			}else{
+				id = ((Long)ret).intValue();
+			}
+			List<Map<String, Object>> child = this.getChildren(datas, id);
+			if(child.size() > 0){
+				this.loopChildren(child, datas, treeface);
+			}
+			/**
+			if(child.size() > 0){
+				root.put("state", "closed");
+			}
+			 **/
+			treeface.processEnd(root, child.size() > 0 ? true : false);
+			root.put("children", child);
+		}
+	}
+	
+	private List<Map<String, Object>> getChildren(List<Map<String, Object>> datas, int id){
+		List<Map<String, Object>> roots = new ArrayList<Map<String, Object>>();
+		for(int i=0; i<datas.size(); i++){
+			Map<String, Object> m = (Map<String, Object>)datas.get(i);
+			int pid;
+			Object pobj = m.get("pid");
+			if(pobj instanceof Integer){
+				pid = (Integer)pobj;
+			}else if(pobj instanceof Long){
+				pid = ((Long)pobj).intValue();
+			}else if(pobj instanceof BigDecimal){
+				pid = ((BigDecimal)pobj).intValue();
+			}else{
+				throw new RuntimeException("类型不支持。");
+			}
+			if(pid == id){
+				roots.add(m);
+			}
+		}
+		return roots;
+	}
+	
+	/**
+	 * 给目录上添加报表
+	 */
+	public void addReport2Cata(List<Map<String, Object>> catas, List<Map<String, Object>> reports){
+		for(int i=0; i<catas.size(); i++){
+			Map<String, Object> cata = (Map<String, Object>)catas.get(i);
+			cata.put("state", "closed");
+			List<Map<String, Object>> rpt = this.findReports(cata, reports);
+			List<Map<String, Object>> children = (List<Map<String, Object>>)cata.get("children");
+			if(children != null && children.size() > 0){
+				addReport2Cata(children, reports);
+			}
+			//给目录的 children 添加报
+			//设置图标
+			for(int j=0; j<rpt.size(); j++){
+				Map<String, Object> rp = (Map<String, Object>)rpt.get(j);
+				rp.put("iconCls", "icon-gears");
+				//添加attributes
+				Map<String, Object> att = new HashMap<String, Object>();
+				att.put("rfile", rp.get("rfile"));
+				rp.put("attributes", att);
+				rp.remove("crtdate");
+			}
+			children.addAll(rpt);
+		}
+		return;
+	}
+	/**
+	private Map<String, Object> copyMap(Map<String, Object> map){
+		Map<String, Object> ret = new HashMap<String, Object>();
+		Iterator<String> it = map.keySet().iterator();
+		while(it.hasNext()){
+			String key = it.next();
+			if("children".equals(key)){
+				continue;
+			}
+			ret.put(key, map.get(key));
+		}
+		return ret;
+	}
+	**/
+	private List<Map<String, Object>> findReports(Map<String, Object> cata, List<Map<String, Object>> reports){
+		List<Map<String, Object>> ret = new ArrayList<Map<String, Object>>();
+		int id;
+		Object pobj = cata.get("id");
+		if(pobj instanceof Integer){
+			id = (Integer)pobj;
+		}else if(pobj instanceof Long){
+			id = ((Long)pobj).intValue();
+		}else if(pobj instanceof BigDecimal){
+			id = ((BigDecimal)pobj).intValue();
+		}else{
+			throw new RuntimeException("类型不支持。");
+		}
+		for(int i=0; i<reports.size(); i++){
+			Map<String, Object> report = (Map<String, Object>)reports.get(i);
+			int cataId;
+			Object cobj = report.get("cataId");
+			if(cobj instanceof Integer){
+				cataId = (Integer)cobj;
+			}else if(cobj instanceof Long){
+				cataId = ((Long)cobj).intValue();
+			}else if(cobj instanceof BigDecimal){
+				cataId = ((BigDecimal)cobj).intValue();
+			}else{
+				throw new RuntimeException("类型不支持。");
+			}
+			if(id == cataId){
+				ret.add(report);
+			}
+		}
+		return ret;
+	}
+}

+ 33 - 0
src/main/java/com/ruisitech/bi/web/LoginController.java

@@ -0,0 +1,33 @@
+package com.ruisitech.bi.web;
+
+import com.ruisitech.bi.service.frame.UserService;
+import com.ruisitech.bi.util.BaseController;
+import com.ruisitech.bi.util.RSBIUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping(value = "/")
+public class LoginController extends BaseController {
+
+	@Autowired
+	private UserService userService;
+
+	@RequestMapping(value="/doLogin.action", method = RequestMethod.POST)
+	public @ResponseBody
+    Object doLogin(String userName, String password) {
+		String msg = userService.shiroLogin(userName, password);
+		if("SUC".equals(msg)){
+			//更新登陆次数及时间
+			Integer userId = RSBIUtils.getLoginUserInfo().getUserId();
+			userService.updateLogDateAndCnt(userId);
+			return super.buildSucces();
+		}else{
+			return super.buildError(msg);
+		}
+	}
+}

+ 26 - 0
src/main/java/com/ruisitech/bi/web/LogoutController.java

@@ -0,0 +1,26 @@
+package com.ruisitech.bi.web;
+
+import com.ruisitech.bi.util.BaseController;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/frame")
+public class LogoutController extends BaseController {
+
+	@RequestMapping(value="/Logout.action")
+	public @ResponseBody Object logout(){
+		Subject subject = SecurityUtils.getSubject();
+		if (subject != null) {  
+	        try{  
+	            subject.logout();  
+	        }catch(Exception ex){  
+	        	ex.printStackTrace();
+	        }  
+	    }  
+		return super.buildSucces();
+	}
+}

+ 60 - 0
src/main/java/com/ruisitech/bi/web/app/AppLoginController.java

@@ -0,0 +1,60 @@
+package com.ruisitech.bi.web.app;
+
+import com.ruisitech.bi.entity.frame.User;
+import com.ruisitech.bi.service.frame.UserService;
+import com.ruisitech.bi.util.BaseController;
+import com.ruisitech.bi.util.RSBIUtils;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+@Controller
+@RequestMapping(value = "/app")
+public class AppLoginController extends BaseController {
+	
+	@Autowired
+	private UserService userService;
+
+	@RequestMapping(value="/Login!login.action")
+	public @ResponseBody
+    Object login(String userName, String password, String channel_id) {
+		String ret = userService.shiroLogin(userName, password);
+		Map<String, Object> obj = new HashMap<String, Object>();
+		if("SUC".equals(ret)){
+			obj.put("result", true);
+			User user = RSBIUtils.getLoginUserInfo();
+			String token = RSBIUtils.getMD5((user.getStaffId() + new Date().getTime()).getBytes());
+			obj.put("token", token);
+			Map<String, Object> u = new HashMap<String, Object>();
+			u.put("userId", "1");
+			obj.put("user", u);
+			//更新登录次数
+			userService.updateLogDateAndCnt(user.getUserId());
+		}else{
+			obj.put("result", false);
+			obj.put("msg", ret);
+		}
+		return obj;
+	}
+	
+	@RequestMapping(value="/Login!logout.action")
+	public @ResponseBody
+    Object logout(Integer userId) {
+		Subject subject = SecurityUtils.getSubject();
+		if (subject != null) {  
+	        try{  
+	            subject.logout();  
+	        }catch(Exception ex){  
+	        	
+	        }  
+	    }
+		return super.buildSucces();
+	}
+}

+ 0 - 0
src/main/java/com/ruisitech/bi/web/app/AppMenuController.java


Деякі файли не було показано, через те що забагато файлів було змінено