├── .gitattributes ├── .gitignore ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── img ├── consumer.png ├── customer.png ├── index.png └── test ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── hg │ │ ├── WebCustomerServiceApplication.java │ │ ├── config │ │ └── WebsocketConfiguration.java │ │ ├── controller │ │ └── IndexContorller.java │ │ ├── service │ │ └── IndexService.java │ │ ├── socket │ │ ├── Consumer.java │ │ ├── Customer.java │ │ ├── Manager.java │ │ ├── Message.java │ │ ├── Setting.java │ │ └── SocketServer.java │ │ ├── util │ │ └── DateFormat.java │ │ └── vo │ │ └── IndexPageInfo.java └── resources │ ├── application.properties │ ├── static │ ├── css │ │ ├── emotion │ │ │ └── emotion.css │ │ ├── font │ │ │ └── font.css │ │ └── pure │ │ │ ├── buttons-core-min.css │ │ │ ├── buttons-min.css │ │ │ └── tables-min.css │ ├── img │ │ ├── bridge-logo2-skin-0.png │ │ ├── dd.png │ │ ├── emotion │ │ │ └── arclist │ │ │ │ ├── 1.gif │ │ │ │ ├── 10.gif │ │ │ │ ├── 11.gif │ │ │ │ ├── 12.gif │ │ │ │ ├── 13.gif │ │ │ │ ├── 14.gif │ │ │ │ ├── 15.gif │ │ │ │ ├── 16.gif │ │ │ │ ├── 17.gif │ │ │ │ ├── 18.gif │ │ │ │ ├── 19.gif │ │ │ │ ├── 2.gif │ │ │ │ ├── 20.gif │ │ │ │ ├── 21.gif │ │ │ │ ├── 22.gif │ │ │ │ ├── 23.gif │ │ │ │ ├── 24.gif │ │ │ │ ├── 25.gif │ │ │ │ ├── 26.gif │ │ │ │ ├── 27.gif │ │ │ │ ├── 28.gif │ │ │ │ ├── 29.gif │ │ │ │ ├── 3.gif │ │ │ │ ├── 30.gif │ │ │ │ ├── 31.gif │ │ │ │ ├── 32.gif │ │ │ │ ├── 33.gif │ │ │ │ ├── 34.gif │ │ │ │ ├── 35.gif │ │ │ │ ├── 36.gif │ │ │ │ ├── 37.gif │ │ │ │ ├── 38.gif │ │ │ │ ├── 39.gif │ │ │ │ ├── 4.gif │ │ │ │ ├── 40.gif │ │ │ │ ├── 41.gif │ │ │ │ ├── 42.gif │ │ │ │ ├── 43.gif │ │ │ │ ├── 44.gif │ │ │ │ ├── 45.gif │ │ │ │ ├── 46.gif │ │ │ │ ├── 47.gif │ │ │ │ ├── 48.gif │ │ │ │ ├── 49.gif │ │ │ │ ├── 5.gif │ │ │ │ ├── 50.gif │ │ │ │ ├── 51.gif │ │ │ │ ├── 52.gif │ │ │ │ ├── 53.gif │ │ │ │ ├── 54.gif │ │ │ │ ├── 55.gif │ │ │ │ ├── 56.gif │ │ │ │ ├── 57.gif │ │ │ │ ├── 58.gif │ │ │ │ ├── 59.gif │ │ │ │ ├── 6.gif │ │ │ │ ├── 60.gif │ │ │ │ ├── 61.gif │ │ │ │ ├── 62.gif │ │ │ │ ├── 63.gif │ │ │ │ ├── 64.gif │ │ │ │ ├── 65.gif │ │ │ │ ├── 66.gif │ │ │ │ ├── 67.gif │ │ │ │ ├── 68.gif │ │ │ │ ├── 69.gif │ │ │ │ ├── 7.gif │ │ │ │ ├── 70.gif │ │ │ │ ├── 71.gif │ │ │ │ ├── 72.gif │ │ │ │ ├── 73.gif │ │ │ │ ├── 74.gif │ │ │ │ ├── 75.gif │ │ │ │ ├── 8.gif │ │ │ │ └── 9.gif │ │ ├── face.png │ │ ├── file.png │ │ ├── font.png │ │ ├── font │ │ │ ├── jc.png │ │ │ ├── xhx.png │ │ │ ├── xt.png │ │ │ └── ys.png │ │ ├── pic.png │ │ └── timg.jpg │ └── js │ │ ├── jquery │ │ └── jquery-3.2.1.min.js │ │ ├── page │ │ ├── consumerSocket.js │ │ ├── customerSocket.js │ │ └── index.js │ │ ├── socket.js │ │ ├── wangEditor.js │ │ └── wangEditor.min.js │ └── templates │ ├── consumerSocket.html │ ├── customerSocket.html │ ├── editAd.html │ ├── editReply.html │ └── index.html └── test └── java └── com └── hg └── WebCustomerServiceApplicationTests.java /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java 2 | *.css linguist-language=java 3 | *.html linguist-language=java 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebCustomerService 2 | web版在线客服聊天系统 3 | 1.支持自定制广告推送和自动答复,进入监控页面底部按钮自定制消息 4 | 2.开箱即用,直接启动项目通过IP:port/index进入监控页面,IP:port/customer注册并进入客服页面,IP:port/consumer注册并进入客户页面,无侵入随时嵌入其他 任何B/S系统。 5 | 3.可同时多客服多客户对接,系统自动为客户轮询分配客服。当只有一个客服时,所有客户都将对接到该客服 6 | 7 | # 监控页面 8 | ![image](https://github.com/liu513632815/WebCustomerService/blob/master/img/index.png) 9 | 10 | # 客服页面 11 | ![image](https://github.com/liu513632815/WebCustomerService/blob/master/img/customer.png) 12 | 13 | # 客户页面 14 | ![image](https://github.com/liu513632815/WebCustomerService/blob/master/img/consumer.png) 15 | 16 | -------------------------------------------------------------------------------- /img/consumer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/img/consumer.png -------------------------------------------------------------------------------- /img/customer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/img/customer.png -------------------------------------------------------------------------------- /img/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/img/index.png -------------------------------------------------------------------------------- /img/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.2.6.RELEASE 10 | 11 | 12 | com.hg 13 | WebCustomerService 14 | 0.0.1 15 | WebCustomerService 16 | web版客服聊天系统 17 | 18 | 19 | 1.8 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-test 31 | test 32 | 33 | 34 | org.junit.vintage 35 | junit-vintage-engine 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-websocket 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-thymeleaf 49 | 50 | 51 | 52 | 53 | com.google.code.gson 54 | gson 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/com/hg/WebCustomerServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.hg; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class WebCustomerServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(WebCustomerServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/hg/config/WebsocketConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.hg.config; 2 | 3 | import javax.servlet.ServletContext; 4 | import javax.servlet.ServletException; 5 | 6 | import org.springframework.boot.web.servlet.ServletContextInitializer; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.web.socket.server.standard.ServerEndpointExporter; 10 | import org.springframework.web.util.WebAppRootListener; 11 | 12 | 13 | @Configuration 14 | public class WebsocketConfiguration implements ServletContextInitializer{ 15 | 16 | @Bean 17 | public ServerEndpointExporter serverEndpointExporter() { 18 | return new ServerEndpointExporter(); 19 | } 20 | 21 | @Override 22 | public void onStartup(ServletContext servletContext) throws ServletException { 23 | servletContext.addListener(WebAppRootListener.class); 24 | servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","5242880");//5M 25 | servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize","1024000"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/hg/controller/IndexContorller.java: -------------------------------------------------------------------------------- 1 | package com.hg.controller; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | import javax.websocket.server.PathParam; 13 | 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Controller; 16 | import org.springframework.ui.Model; 17 | import org.springframework.util.ResourceUtils; 18 | import org.springframework.web.bind.annotation.ModelAttribute; 19 | import org.springframework.web.bind.annotation.RequestMapping; 20 | import org.springframework.web.bind.annotation.RequestParam; 21 | import org.springframework.web.bind.annotation.ResponseBody; 22 | import org.springframework.web.multipart.MultipartFile; 23 | 24 | import com.google.gson.Gson; 25 | import com.hg.service.IndexService; 26 | import com.hg.socket.Setting; 27 | 28 | @Controller 29 | public class IndexContorller { 30 | 31 | @Autowired 32 | private IndexService service; 33 | 34 | /** 35 | * 控制台 36 | * 37 | * @return 38 | */ 39 | @RequestMapping("/index") 40 | public String index(Model model) { 41 | model.addAttribute("data", service.getIndexPageInfo()); 42 | return "index"; 43 | } 44 | 45 | /** 46 | * 客服接口 47 | * 48 | * @return 49 | */ 50 | @RequestMapping("/customer") 51 | public String customerSocket() { 52 | return "customerSocket"; 53 | } 54 | 55 | /** 56 | * 客户接口 57 | * 58 | * @return 59 | */ 60 | @RequestMapping("/consumer") 61 | public String consumerSocket() { 62 | return "consumerSocket"; 63 | } 64 | 65 | /** 66 | * 编辑广告接口 67 | * 68 | * @return 69 | */ 70 | @RequestMapping("/editAd") 71 | public String editAd(Model model) { 72 | model.addAttribute("old_ad", Setting.adReply); 73 | return "editAd"; 74 | } 75 | 76 | @ResponseBody 77 | @RequestMapping("/saveAd") 78 | public String saveAd(@ModelAttribute("context") String context) { 79 | Setting.adReply = context; 80 | return new Gson().toJson("保存成功!"); 81 | } 82 | 83 | /** 84 | * 编辑回复接口 85 | * 86 | * @return 87 | */ 88 | @RequestMapping("/editReply") 89 | public String editReply(Model model) { 90 | model.addAttribute("old_reply", Setting.autoReply); 91 | return "editReply"; 92 | } 93 | 94 | @ResponseBody 95 | @RequestMapping("/saveReply") 96 | public String saveReply(@ModelAttribute("context") String context) { 97 | Setting.autoReply = context; 98 | return new Gson().toJson("保存成功!"); 99 | } 100 | 101 | /** 102 | * 文件/图片上传接口 103 | * 104 | * @param myFileName 105 | * @return 106 | * @throws IOException 107 | */ 108 | @ResponseBody 109 | @RequestMapping("/upload") 110 | public String fileUpload(MultipartFile myFileName) throws IOException { 111 | return null; 112 | } 113 | 114 | /** 115 | * 广告推送open/close 116 | * 117 | * @return 118 | */ 119 | @ResponseBody 120 | @RequestMapping("/contorAd") 121 | public String contorAd() { 122 | return service.contorAd(); 123 | } 124 | 125 | /** 126 | * 自动回复open/close 127 | * 128 | * @return 129 | */ 130 | @ResponseBody 131 | @RequestMapping("/contorAuto") 132 | public String contorAuto() { 133 | return service.contorAuto(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/hg/service/IndexService.java: -------------------------------------------------------------------------------- 1 | package com.hg.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.concurrent.LinkedBlockingQueue; 7 | 8 | import org.springframework.stereotype.Service; 9 | 10 | import com.hg.socket.Consumer; 11 | import com.hg.socket.Customer; 12 | import com.hg.socket.Manager; 13 | import com.hg.socket.Setting; 14 | import com.hg.vo.IndexPageInfo; 15 | 16 | /** 17 | * 业务实现 18 | * 19 | * @author Administrator 20 | * 21 | */ 22 | @Service 23 | public class IndexService { 24 | 25 | /** 26 | * 查询监控页信息 27 | * 28 | * @return 29 | */ 30 | public IndexPageInfo getIndexPageInfo() { 31 | 32 | IndexPageInfo ip = new IndexPageInfo(); 33 | 34 | List consumer = new ArrayList(); 35 | Manager.consumerQuenen.forEach((c) -> { 36 | c.setDurationTime(new Date()); 37 | consumer.add(c); 38 | }); 39 | ip.setConsumerList(consumer); 40 | 41 | List customer = new ArrayList(); 42 | Manager.customerQuenen.forEach((c) -> { 43 | c.setDurationTime(new Date()); 44 | customer.add(c); 45 | }); 46 | ip.setCustomerList(customer); 47 | 48 | return ip; 49 | } 50 | 51 | public String contorAd() { 52 | if (Setting.isAdReply) { 53 | Setting.isAdReply = false; 54 | } else { 55 | Setting.isAdReply = true; 56 | } 57 | return Setting.isAdReply.toString(); 58 | } 59 | 60 | public String contorAuto() { 61 | if (Setting.isAutoReply) { 62 | Setting.isAutoReply = false; 63 | } else { 64 | Setting.isAutoReply = true; 65 | } 66 | return Setting.isAutoReply.toString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import javax.websocket.Session; 9 | 10 | import com.hg.util.DateFormat; 11 | 12 | /** 13 | * 用户 14 | * 15 | * @author Administrator 16 | * 17 | */ 18 | public class Consumer { 19 | 20 | private String name; 21 | 22 | // 消息类型:1:普通String类型 2:图片类型 3:文件类型 23 | private String messageType; 24 | 25 | // 信息体 26 | private Object message; 27 | 28 | private Session session; 29 | 30 | /** 31 | * 上线时间 32 | */ 33 | private String onlineTime; 34 | 35 | /** 36 | * 累计时长 37 | */ 38 | private String durationTime; 39 | 40 | /** 41 | * 客服sessionId 42 | */ 43 | private String customerSessionId; 44 | 45 | Consumer() { 46 | 47 | } 48 | 49 | public Consumer(Session session) { 50 | this.session = session; 51 | } 52 | 53 | public Consumer(Session session, String name) { 54 | this.session = session; 55 | this.name = name.equals("null") ? session.getId() : name; 56 | } 57 | 58 | public Session getSession() { 59 | return session; 60 | } 61 | 62 | public String getName() { 63 | return name; 64 | } 65 | 66 | public void setName(String name) { 67 | this.name = name; 68 | } 69 | 70 | public String getMessageType() { 71 | return messageType; 72 | } 73 | 74 | public void setMessageType(String messageType) { 75 | this.messageType = messageType; 76 | } 77 | 78 | public Object getMessage() { 79 | return message; 80 | } 81 | 82 | public void setMessage(Object message) { 83 | this.message = message; 84 | } 85 | 86 | public void setSession(Session session) { 87 | this.session = session; 88 | } 89 | 90 | public String getOnlineTime() { 91 | return onlineTime; 92 | } 93 | 94 | public void setOnlineTime(Date date) { 95 | SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 96 | this.onlineTime = sf.format(date); 97 | } 98 | 99 | public String getDurationTime() { 100 | return this.durationTime; 101 | } 102 | 103 | public void setDurationTime(Date date) { 104 | SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 105 | long c = 0; 106 | try { 107 | c = (date.getTime()) - sf.parse(onlineTime).getTime(); 108 | } catch (ParseException e) { 109 | e.printStackTrace(); 110 | } 111 | this.durationTime = DateFormat.getHMS(c); 112 | } 113 | 114 | public void setCustomerSessionId(String sessionId) { 115 | this.customerSessionId = sessionId; 116 | } 117 | 118 | public String getCustomerSessionId() { 119 | return this.customerSessionId; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/Customer.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import javax.websocket.Session; 9 | 10 | import com.hg.util.DateFormat; 11 | 12 | /** 13 | * 客服 14 | * 15 | * @author Administrator 16 | * 17 | */ 18 | public class Customer { 19 | 20 | private String name; 21 | 22 | private Session session; 23 | 24 | /** 25 | * 上线时间 26 | */ 27 | private String onlineTime; 28 | 29 | /** 30 | * 累计时长 31 | */ 32 | private String durationTime; 33 | 34 | private Integer int_totalNumber; 35 | 36 | /** 37 | * 总对接客户数 38 | */ 39 | private AtomicInteger totalNumber = new AtomicInteger(0); 40 | 41 | private Integer int_currentNumber; 42 | /** 43 | * 当前正在对接的 44 | */ 45 | private AtomicInteger currentNumber = new AtomicInteger(0); 46 | 47 | Customer() { 48 | 49 | } 50 | 51 | Customer(Session session) { 52 | this.session = session; 53 | } 54 | 55 | Customer(Session session, String name) { 56 | this.session = session; 57 | this.name = name.equals("null") ? session.getId() : name; 58 | } 59 | 60 | public Session getSession() { 61 | return session; 62 | } 63 | 64 | public String getName() { 65 | return name; 66 | } 67 | 68 | public void setName(String name) { 69 | this.name = name; 70 | } 71 | 72 | public String getOnlineTime() { 73 | return onlineTime; 74 | } 75 | 76 | public void setOnlineTime(Date date) { 77 | SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 78 | this.onlineTime = sf.format(date); 79 | } 80 | 81 | public String getDurationTime() { 82 | return this.durationTime; 83 | } 84 | 85 | public void setDurationTime(Date date) { 86 | SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 87 | long c = 0; 88 | try { 89 | c = (date.getTime()) - sf.parse(onlineTime).getTime(); 90 | } catch (ParseException e) { 91 | e.printStackTrace(); 92 | } 93 | this.durationTime = DateFormat.getHMS(c); 94 | } 95 | 96 | /** 97 | * 新分配一个上线客户 98 | */ 99 | public void addOne() { 100 | totalNumber.incrementAndGet(); 101 | currentNumber.incrementAndGet(); 102 | } 103 | 104 | /** 105 | * 下线一个客户 106 | */ 107 | public void delOne() { 108 | currentNumber.decrementAndGet(); 109 | } 110 | 111 | public Integer getInt_totalNumber() { 112 | return totalNumber.get(); 113 | } 114 | 115 | public Integer getInt_currentNumber() { 116 | return currentNumber.get(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/Manager.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | import java.util.Iterator; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.LinkedBlockingQueue; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | 10 | import com.google.gson.Gson; 11 | 12 | /** 13 | * 14 | * @author Administrator 15 | * 16 | */ 17 | public class Manager { 18 | 19 | /** 20 | * 系统启动时间 21 | */ 22 | public static Date starupTime = new Date(); 23 | 24 | /** 25 | * 累计客服数 26 | */ 27 | public static AtomicInteger totalCustomer = new AtomicInteger(0); 28 | 29 | /** 30 | * 累计客户数 31 | */ 32 | public static AtomicInteger totalConsumer = new AtomicInteger(0); 33 | 34 | // 客服队列 35 | public static LinkedBlockingQueue customerQuenen = new LinkedBlockingQueue(); 36 | 37 | // 用户消息队列 38 | public static LinkedBlockingQueue consumerQuenen = new LinkedBlockingQueue(); 39 | 40 | // 客户-客服关系维护map 41 | public static ConcurrentHashMap ccmap = new ConcurrentHashMap<>(); 42 | 43 | private static AtomicInteger concurrentIndex = new AtomicInteger(0); 44 | 45 | public static void add(Customer c) throws Exception { 46 | if (null == c) { 47 | throw new Exception("Customer:" + c + "must nut be null"); 48 | } 49 | c.setOnlineTime(new Date()); 50 | totalCustomer.incrementAndGet(); 51 | customerQuenen.put(c); 52 | } 53 | 54 | public static void add(Consumer c) throws Exception { 55 | if (null == c) { 56 | throw new Exception("Consumer:" + c + "must nut be null"); 57 | } 58 | c.setOnlineTime(new Date()); 59 | totalConsumer.incrementAndGet(); 60 | consumerQuenen.put(c); 61 | } 62 | 63 | // 下线时删除信息 64 | public void remove(String sessionId) { 65 | if (!removeConsumerQuenen(sessionId)) { 66 | removeCustomerQuenen(sessionId); 67 | } 68 | } 69 | 70 | private Boolean removeConsumerQuenen(String sessionId) { 71 | Consumer c = null; 72 | Boolean removeResult = false; 73 | Iterator iterator = consumerQuenen.iterator(); 74 | while (iterator.hasNext()) { 75 | Consumer cu = (Consumer) iterator.next(); 76 | if (sessionId.equals(cu.getSession().getId())) { 77 | c = cu; 78 | removeResult = true; 79 | break; 80 | } 81 | } 82 | if (null != c) { 83 | consumerQuenen.remove(c); 84 | ConsumerRemoveRelevance(c); 85 | } 86 | return removeResult; 87 | } 88 | 89 | private void removeCustomerQuenen(String sessionId) { 90 | Customer c = null; 91 | Iterator iterator = customerQuenen.iterator(); 92 | while (iterator.hasNext()) { 93 | c = (Customer) iterator.next(); 94 | if (sessionId.equals(c.getSession().getId())) { 95 | break; 96 | } 97 | } 98 | if (null != c) { 99 | customerQuenen.remove(c); 100 | try { 101 | CustomerRemoveRelevance(c); 102 | } catch (InterruptedException e) { 103 | e.printStackTrace(); 104 | } 105 | } 106 | } 107 | 108 | // 客户下线,发送消息给客服并解除客户-客服映射关系 109 | // 存在一种情况:客户上线没有对接到客服,直接下线。此时没有对应关系不用解除 110 | private void ConsumerRemoveRelevance(Consumer c) { 111 | if (ccmap.get(c) != null) { 112 | sendOfflineMessage(ccmap.get(c), c);// 发送下线消息 113 | ccmap.get(c).delOne();// 当前对接客户数减一 114 | ccmap.remove(c);// 移除对应关系 115 | } 116 | } 117 | 118 | /** 119 | * 客服下线,移除ccmap存在的对应关系,将新的客服分配到客户 120 | * 121 | * @throws InterruptedException 122 | */ 123 | private void CustomerRemoveRelevance(Customer c) throws InterruptedException { 124 | Customer newCustomer = takeCustomer(); 125 | ccmap.forEach((k, v) -> { 126 | if (v == c) { 127 | // ccmap.remove(k); 128 | k.setCustomerSessionId(newCustomer.getSession().getId()); 129 | ccmap.replace(k, c, newCustomer); 130 | } 131 | }); 132 | } 133 | 134 | // 客户下线发送下线消息给客服 135 | private void sendOfflineMessage(Customer customer, Consumer consumer) { 136 | try { 137 | customer.getSession().getBasicRemote() 138 | .sendText(new Gson().toJson(new Message("2", consumer.getSession().getId(), null))); 139 | } catch (IOException e) { 140 | e.printStackTrace(); 141 | } 142 | } 143 | 144 | public static Integer getOnlineNum() { 145 | return customerQuenen.size() + consumerQuenen.size(); 146 | } 147 | 148 | public static Integer getOnlineCustomerNum() { 149 | return customerQuenen.size(); 150 | } 151 | 152 | public static Integer getOnlineConsumerNum() { 153 | return consumerQuenen.size(); 154 | } 155 | 156 | public static Integer getTotalConsumerNum() { 157 | return totalConsumer.get(); 158 | } 159 | 160 | public static Integer getTotalCustomerNum() { 161 | return totalCustomer.get(); 162 | } 163 | 164 | // 根据sessionId获取consumer 165 | public static Consumer getConsumerBySessionId(String sessionId) throws Exception { 166 | Iterator iterator = consumerQuenen.iterator(); 167 | while (iterator.hasNext()) { 168 | Consumer c = iterator.next(); 169 | if (sessionId.equals(c.getSession().getId())) { 170 | return c; 171 | } 172 | } 173 | return null; 174 | } 175 | 176 | // 从队列中轮流获取客服 177 | public static Customer takeCustomer() throws InterruptedException { 178 | if (customerQuenen.size() == 0) { 179 | return null; 180 | } 181 | if (!(concurrentIndex.get() < customerQuenen.size())) { 182 | concurrentIndex.set(0); 183 | } 184 | return (Customer) customerQuenen.toArray()[concurrentIndex.getAndIncrement()]; 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/Message.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | public class Message { 4 | 5 | /** 6 | * 0:自动答复 1:普通消息 2:下线通知消息 3:广告消息 7 | */ 8 | private String messageType; 9 | private String sessionId; 10 | private String message; 11 | 12 | public Message() { 13 | 14 | } 15 | 16 | public Message(String messageType) { 17 | this.messageType = messageType; 18 | } 19 | 20 | public Message(String messageType, String sessionId, String message) { 21 | this.messageType = messageType; 22 | this.sessionId = sessionId; 23 | this.message = message; 24 | } 25 | 26 | public String getMessageType() { 27 | return messageType; 28 | } 29 | 30 | public String getSessionId() { 31 | return sessionId; 32 | } 33 | 34 | public void setSessionId(String sessionId) { 35 | this.sessionId = sessionId; 36 | } 37 | 38 | public String getMessage() { 39 | return message; 40 | } 41 | 42 | public void setMessage(String message) { 43 | this.message = message; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/Setting.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | /** 4 | * 应答/广告设置 5 | * 6 | * @author Administrator 7 | * 8 | */ 9 | public class Setting { 10 | 11 | /** 12 | * 无客服在线时,是否开启自动应答。默认开启 13 | */ 14 | public static volatile Boolean isAutoReply = true; 15 | 16 | /** 17 | * 客户连接时是否推送广告。默认不推送 18 | */ 19 | public static volatile Boolean isAdReply = true; 20 | 21 | // 无可客服在线时自动答复内容 22 | public static String autoReply = "您好,现在客服正忙,建议您也可以加我们客服群QQ:XXXXXXXXXXX或QQ客服657706446,享受更便捷的服务,或咨询电话热线:26820611。"; 23 | 24 | // 推荐/广告 25 | public static String adReply = "

尊敬的客户:

" 26 | + "您好,深圳电信宽带优惠专区欢迎您!装宽带不排队,在线预约,足不出户办宽带,当天申请当天装(支持先装后付款,装好后可关注公众号支付,也可到深圳任何一个中国电信营业厅交现金,可开纸质发票或电子发票)感谢您对中国电信的支持与厚爱,我们将竭诚为您服务!" 27 | + "亲,加微信 XXXXXXXXXXX 获取最便宜的套餐资费哦. 特惠赠送:加微信额外送99元微信红包,欲购从速哦!" 28 | + " 服务热线:XXXXXXXX,XXXXXXXX宽带新装下单" 29 | + "

在线续约下单 在线续约下单 在线续约下单"; 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/hg/socket/SocketServer.java: -------------------------------------------------------------------------------- 1 | package com.hg.socket; 2 | 3 | import java.io.IOException; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import javax.annotation.Resource; 8 | import javax.websocket.OnClose; 9 | import javax.websocket.OnMessage; 10 | import javax.websocket.OnOpen; 11 | import javax.websocket.Session; 12 | import javax.websocket.server.PathParam; 13 | import javax.websocket.server.ServerEndpoint; 14 | 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.stereotype.Component; 17 | 18 | import com.google.gson.Gson; 19 | 20 | @ServerEndpoint(value = "/websocket/{userType}/{userName}") 21 | @Component 22 | public class SocketServer extends Manager { 23 | 24 | private static final String CUSTOMER = "customer"; 25 | private static final String CONSUMER = "consumer"; 26 | 27 | @OnOpen 28 | public void onOpen(Session session, @PathParam("userType") String userType, @PathParam("userName") String userName) 29 | throws Exception { 30 | register(session, userType, userName); 31 | } 32 | 33 | @OnClose 34 | public void onClose(Session session) { 35 | remove(session.getId()); 36 | } 37 | 38 | @OnMessage 39 | @SuppressWarnings("unchecked") 40 | public void onMessage(String mapString, Session session, @PathParam("userType") String userType) throws Exception { 41 | if (mapString != "" && mapString != null) { 42 | if (CUSTOMER.equals(userType)) {// 客服发送消息 43 | customerSendMsg(new Gson().fromJson(mapString, HashMap.class)); 44 | } else {// 客户发送消息 45 | consumerSendMsg(session, mapString); 46 | } 47 | } 48 | } 49 | 50 | private void customerSendMsg(HashMap map) throws Exception { 51 | sendMessage(getConsumerBySessionId(map.get("sessionId")).getSession(), map.get("message")); 52 | } 53 | 54 | private void consumerSendMsg(Session session, String message) throws Exception { 55 | Customer c = ccmap.get(getConsumerBySessionId(session.getId())); 56 | if (c == null) {// 客户发送消息时,客服下线 57 | if (!tryAllocationCustomer(session, message)) 58 | allocationRobot(session); 59 | } else { 60 | sendMessageWithSessionId(session, c.getSession(), message); 61 | } 62 | } 63 | 64 | /** 65 | * 尝试重新分配客服 66 | * 67 | * @param session 68 | * @param message 69 | * @return 70 | * @throws Exception 71 | */ 72 | private Boolean tryAllocationCustomer(Session session, String message) throws Exception { 73 | Boolean rs = true; 74 | Customer customer = takeCustomer(); 75 | if (customer != null) { 76 | ccmap.put(getConsumerBySessionId(session.getId()), customer); 77 | sendMessageWithSessionId(session, customer.getSession(), message); 78 | } else { 79 | rs = false; 80 | } 81 | return rs; 82 | } 83 | 84 | /** 85 | * 注册 86 | * 87 | * @param session 88 | * @param userType 89 | * @throws Exception 90 | */ 91 | private void register(Session session, String userType, String userName) throws Exception { 92 | if (CUSTOMER.equals(userType)) { 93 | add(new Customer(session, userName)); 94 | } else { 95 | add(new Consumer(session, userName)); 96 | sendAd(session); 97 | allocation(session); 98 | } 99 | } 100 | 101 | /** 102 | * 给客户分配客服 103 | * 104 | * @param session 105 | * @throws Exception 106 | */ 107 | private void allocation(Session session) throws Exception { 108 | Customer customer = takeCustomer(); 109 | Consumer consumer = getConsumerBySessionId(session.getId()); 110 | if (customer == null) {// 给客户分配客服时,无客服在线 111 | allocationRobot(session); 112 | } else { 113 | ccmap.put(consumer, customer); 114 | consumer.setCustomerSessionId(customer.getSession().getId()); 115 | customer.addOne();// 成功分配,客服对接客户数加一 116 | } 117 | } 118 | 119 | /** 120 | * 回复自动内容 121 | * 122 | * @param session 123 | * @throws IOException 124 | */ 125 | private void allocationRobot(Session session) throws IOException { 126 | if (Setting.isAutoReply) { 127 | session.getBasicRemote().sendText(new Gson().toJson(new Message("0", session.getId(), Setting.autoReply))); 128 | } 129 | } 130 | 131 | /** 132 | * 回复广告 133 | * 134 | * @param session 135 | * @throws IOException 136 | */ 137 | private void sendAd(Session session) throws IOException { 138 | if (Setting.isAdReply) { 139 | session.getBasicRemote().sendText(new Gson().toJson(new Message("3", session.getId(), Setting.adReply))); 140 | } 141 | } 142 | 143 | /** 144 | * 客户向客服发送消息 145 | * 146 | * @param send_session:客户session 147 | * @param session:客服session 148 | * @param message:信息 149 | * @throws Exception 150 | */ 151 | private void sendMessageWithSessionId(Session send_session, Session session, String message) throws Exception { 152 | session.getBasicRemote().sendText(new Gson().toJson(new Message("1", send_session.getId(), message))); 153 | } 154 | 155 | /** 156 | * 客服向客户发送消息 157 | * 158 | * @param session:客户session 159 | * @param message:信息 160 | * @throws IOException 161 | */ 162 | private void sendMessage(Session session, String message) throws IOException { 163 | session.getBasicRemote().sendText(new Gson().toJson(new Message("1", session.getId(), message))); 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /src/main/java/com/hg/util/DateFormat.java: -------------------------------------------------------------------------------- 1 | package com.hg.util; 2 | 3 | public class DateFormat { 4 | 5 | public static String getHMS(long time) { 6 | long hours = time / (1000 * 60 * 60); 7 | long minutes = (time - (hours * (1000 * 60 * 60))) / (1000 * 60); 8 | long second = (time - hours * (1000 * 60 * 60) - minutes * (1000 * 60)) / 1000; 9 | String diffTime = ""; 10 | if (minutes < 10) { 11 | diffTime = hours + "h" + minutes + "m" + second + "s"; 12 | } else { 13 | diffTime = hours + "h" + minutes + "m" + second + "s"; 14 | } 15 | return diffTime; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/hg/vo/IndexPageInfo.java: -------------------------------------------------------------------------------- 1 | package com.hg.vo; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | import com.hg.socket.Consumer; 9 | import com.hg.socket.Customer; 10 | import com.hg.socket.Manager; 11 | import com.hg.socket.Setting; 12 | import com.hg.util.DateFormat; 13 | 14 | /** 15 | * 监控页信息对应的实体类 16 | */ 17 | public class IndexPageInfo { 18 | 19 | /** 20 | * 系统启动时间 21 | */ 22 | private String starupTime; 23 | 24 | /** 25 | * 系统运行时长 26 | */ 27 | private String survivalTime; 28 | 29 | /** 30 | * 累计在线客服 31 | */ 32 | private Integer totalCustomer; 33 | 34 | /** 35 | * 累计在线客户 36 | */ 37 | private Integer totalConsumer; 38 | 39 | /** 40 | * 在线客服数 41 | */ 42 | private Integer onlineCustomer; 43 | 44 | /** 45 | * 在线客户数 46 | */ 47 | private Integer onlineConsumer; 48 | 49 | private Boolean isAutoReply; 50 | 51 | private Boolean isAdReply; 52 | 53 | private List consumerList; 54 | private List customerList; 55 | 56 | public IndexPageInfo() { 57 | this.starupTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Manager.starupTime); 58 | this.survivalTime = getDurationTime(new Date()); 59 | this.totalConsumer = Manager.getTotalConsumerNum(); 60 | this.totalCustomer = Manager.getTotalCustomerNum(); 61 | this.onlineConsumer = Manager.getOnlineConsumerNum(); 62 | this.onlineCustomer = Manager.getOnlineCustomerNum(); 63 | this.isAutoReply = Setting.isAutoReply; 64 | this.isAdReply = Setting.isAdReply; 65 | } 66 | 67 | public String getStarupTime() { 68 | return starupTime; 69 | } 70 | 71 | public void setStarupTime(String starupTime) { 72 | this.starupTime = starupTime; 73 | } 74 | 75 | public String getSurvivalTime() { 76 | return survivalTime; 77 | } 78 | 79 | public void setSurvivalTime(String survivalTime) { 80 | this.survivalTime = survivalTime; 81 | } 82 | 83 | public Integer getTotalCustomer() { 84 | return totalCustomer; 85 | } 86 | 87 | public void setTotalCustomer(Integer totalCustomer) { 88 | this.totalCustomer = totalCustomer; 89 | } 90 | 91 | public Integer getTotalConsumer() { 92 | return totalConsumer; 93 | } 94 | 95 | public void setTotalConsumer(Integer totalConsumer) { 96 | this.totalConsumer = totalConsumer; 97 | } 98 | 99 | public Integer getOnlineCustomer() { 100 | return onlineCustomer; 101 | } 102 | 103 | public void setOnlineCustomer(Integer onlineCustomer) { 104 | this.onlineCustomer = onlineCustomer; 105 | } 106 | 107 | public Integer getOnlineConsumer() { 108 | return onlineConsumer; 109 | } 110 | 111 | public void setOnlineConsumer(Integer onlineConsumer) { 112 | this.onlineConsumer = onlineConsumer; 113 | } 114 | 115 | public List getConsumerList() { 116 | return consumerList; 117 | } 118 | 119 | public void setConsumerList(List consumerList) { 120 | this.consumerList = consumerList; 121 | } 122 | 123 | public List getCustomerList() { 124 | return customerList; 125 | } 126 | 127 | public void setCustomerList(List customerList) { 128 | this.customerList = customerList; 129 | } 130 | 131 | private String getDurationTime(Date date) { 132 | SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 133 | long c = 0; 134 | try { 135 | c = (date.getTime()) - sf.parse(this.starupTime).getTime(); 136 | } catch (ParseException e) { 137 | e.printStackTrace(); 138 | } 139 | return DateFormat.getHMS(c); 140 | } 141 | 142 | public Boolean getIsAutoReply() { 143 | return isAutoReply; 144 | } 145 | 146 | public void setIsAutoReply(Boolean isAutoReply) { 147 | this.isAutoReply = isAutoReply; 148 | } 149 | 150 | public Boolean getIsAdReply() { 151 | return isAdReply; 152 | } 153 | 154 | public void setIsAdReply(Boolean isAdReply) { 155 | this.isAdReply = isAdReply; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | server.tomcat.uri-encoding=UTF-8 3 | 4 | 5 | spring.thymeleaf.cache=false 6 | spring.thymeleaf.encoding=UTF-8 7 | spring.thymeleaf.prefix=classpath:/templates/ 8 | spring.thymeleaf.suffix=.html 9 | spring.thymeleaf.mode=HTML5 -------------------------------------------------------------------------------- /src/main/resources/static/css/emotion/emotion.css: -------------------------------------------------------------------------------- 1 | #emo { 2 | display: flex; 3 | width: 500px; 4 | flex-wrap: wrap; 5 | background-color: #fff; 6 | box-shadow: 0px 0px 3px #333333; 7 | border-radius: 5px; 8 | display: none; 9 | } 10 | 11 | #emo img { 12 | border: 1px solid transparent; 13 | } 14 | 15 | #emo img:hover { 16 | border-color: #666666; 17 | cursor: pointer; 18 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/font/font.css: -------------------------------------------------------------------------------- 1 | #font_table, #colorTable { 2 | position: absolute; 3 | bottom: 170px; 4 | left: 50px; 5 | width: 500px; 6 | flex-wrap: wrap; 7 | background-color: #fff; 8 | box-shadow: 0px 0px 3px #333333; 9 | border-radius: 5px; 10 | } 11 | 12 | .font_img { 13 | width: 18px; 14 | height: 18px; 15 | cursor: pointer; 16 | margin-left: 10px; 17 | } 18 | 19 | .font_img_active { 20 | filter: brightness(30%); 21 | } 22 | 23 | #inner_div { 24 | line-height: 2.2; 25 | } 26 | 27 | .fontfamliy { 28 | position: absolute; 29 | top: 5px; 30 | left: 8px; 31 | } 32 | 33 | .fontsize { 34 | position: absolute; 35 | top: 5px; 36 | left: 90px; 37 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/pure/buttons-core-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v1.0.0 3 | Copyright 2013 Yahoo! 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto} -------------------------------------------------------------------------------- /src/main/resources/static/css/pure/buttons-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v1.0.0 3 | Copyright 2013 Yahoo! 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-.43em}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:transparent;background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{filter:alpha(opacity=90);background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto;margin:0;border-radius:0;border-right:1px solid #111;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none} -------------------------------------------------------------------------------- /src/main/resources/static/css/pure/tables-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.6.1 3 | Copyright 2013 Yahoo! 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | .pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td,.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} -------------------------------------------------------------------------------- /src/main/resources/static/img/bridge-logo2-skin-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/bridge-logo2-skin-0.png -------------------------------------------------------------------------------- /src/main/resources/static/img/dd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/dd.png -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/1.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/10.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/11.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/12.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/13.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/14.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/14.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/15.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/15.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/16.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/17.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/17.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/18.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/19.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/19.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/2.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/20.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/20.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/21.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/21.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/22.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/22.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/23.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/24.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/24.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/25.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/25.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/26.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/26.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/27.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/27.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/28.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/28.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/29.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/29.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/3.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/30.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/31.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/31.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/32.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/32.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/33.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/33.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/34.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/34.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/35.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/35.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/36.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/36.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/37.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/37.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/38.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/38.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/39.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/39.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/4.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/40.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/40.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/41.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/41.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/42.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/42.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/43.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/43.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/44.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/44.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/45.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/46.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/46.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/47.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/47.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/48.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/48.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/49.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/49.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/5.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/50.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/51.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/51.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/52.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/52.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/53.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/53.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/54.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/54.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/55.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/55.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/56.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/56.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/57.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/57.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/58.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/58.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/59.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/59.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/6.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/60.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/60.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/61.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/61.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/62.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/62.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/63.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/63.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/64.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/64.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/65.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/65.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/66.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/66.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/67.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/67.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/68.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/68.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/69.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/69.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/7.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/70.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/70.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/71.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/71.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/72.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/72.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/73.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/73.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/74.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/74.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/75.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/75.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/8.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/emotion/arclist/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/emotion/arclist/9.gif -------------------------------------------------------------------------------- /src/main/resources/static/img/face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/face.png -------------------------------------------------------------------------------- /src/main/resources/static/img/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/file.png -------------------------------------------------------------------------------- /src/main/resources/static/img/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/font.png -------------------------------------------------------------------------------- /src/main/resources/static/img/font/jc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/font/jc.png -------------------------------------------------------------------------------- /src/main/resources/static/img/font/xhx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/font/xhx.png -------------------------------------------------------------------------------- /src/main/resources/static/img/font/xt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/font/xt.png -------------------------------------------------------------------------------- /src/main/resources/static/img/font/ys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/font/ys.png -------------------------------------------------------------------------------- /src/main/resources/static/img/pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/pic.png -------------------------------------------------------------------------------- /src/main/resources/static/img/timg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu513632815/WebCustomerService/97d3771eedc18b9fd3d5517040bc54b56859991d/src/main/resources/static/img/timg.jpg -------------------------------------------------------------------------------- /src/main/resources/static/js/page/consumerSocket.js: -------------------------------------------------------------------------------- 1 | var _websocket = null; 2 | var editor = null; 3 | 4 | $(function() { 5 | consumerSocket.init(); 6 | /* 7 | * window.onbeforeunload = onbeforeunload_handler; window.onunload = 8 | * onunload_handler; function onbeforeunload_handler(){ var warning=""; 9 | * return warning; } 10 | * 11 | * function onunload_handler(){ var warning=""; alert(warning); } 12 | */ 13 | }) 14 | 15 | var consumerSocket = { 16 | 17 | init : function(){ 18 | consumerSocket.page(); 19 | consumerSocket.socket(); 20 | 21 | }, 22 | 23 | page : function(){ 24 | var win_width = $(document).width(); 25 | var win_height = $(document).height(); 26 | $("#content").height(win_height - 70); 27 | $("#content_left_top").height($("#content").height() - 300); 28 | $("#content_left").width(win_width - $("#content_right").outerWidth()); 29 | $("#content_left_bottom").width(win_width - $("#content_right").outerWidth()); 30 | 31 | $(window).resize(function(){ 32 | $("#content").height($(window).height() - 70); 33 | $("#content_left_top").height($("#content").height()-300); 34 | $("#content_left").width($(document).width() - $("#content_right").outerWidth()); 35 | $("#content_left_bottom").width($(document).width() - $("#content_right").outerWidth()); 36 | }); 37 | 38 | $(document).keydown(function(event) { 39 | if (event.keyCode == 13) { 40 | event.preventDefault(); 41 | consumerSocket.send(); 42 | } 43 | }); 44 | 45 | consumerSocket.emotion(); 46 | }, 47 | emotion : function(){ 48 | var E = window.wangEditor 49 | editor = new E('#input_menu','#msgInput'); 50 | editor.customConfig.menus = [ 51 | 'emoticon', 52 | 'fontName', 53 | 'fontSize', 54 | 'bold', 55 | 'italic', 56 | 'underline', 57 | 'foreColor', 58 | 'image' 59 | ]; 60 | editor.customConfig.uploadImgShowBase64 = true; 61 | // editor.customConfig.uploadImgServer = '/upload'; 62 | // editor.customConfig.uploadFileName = 'myFileName' 63 | editor.customConfig.emotions = [{ 64 | title: '表情', 65 | type: 'image', 66 | content: consumerSocket.initEmotion() 67 | }] 68 | editor.create(); 69 | }, 70 | socket:function(){ 71 | 72 | if ('WebSocket' in window) { 73 | _websocket = new WebSocket("ws://10.101.2.214:8080/websocket/consumer/null"); 74 | } else { 75 | alert("当前浏览器不支持WebSocket") 76 | } 77 | 78 | // 连接发生错误时回调 79 | _websocket.onerror = function(event) { 80 | console.log(event.data); 81 | }; 82 | 83 | // 建立连接时回调 84 | _websocket.onopen = function(event) { 85 | 86 | } 87 | 88 | // 接收到消息时回调 89 | _websocket.onmessage = function(event) { 90 | flashTitle(); 91 | consumerSocket.receive(event.data); 92 | consumerSocket.moveCursorEnd(); 93 | } 94 | 95 | // 连接关闭时回调 96 | _websocket.onclose = function(event) { 97 | // alert("连接已关闭") 98 | } 99 | }, 100 | moveCursorEnd : function(){// 移动光标到最低端 101 | $("#msgShow").children("div")[$("#msgShow").children("div").length-1].scrollIntoView(); 102 | }, 103 | receive : function(data){ 104 | var json = JSON.parse(data); 105 | if(json.messageType==0){// 自动回复 106 | consumerSocket.rebotReply(json.message); 107 | }else if(json.messageType==3){// 广告回复 108 | consumerSocket.adReply(json.message); 109 | }else{ 110 | $("#msgShow").append("
"+json.message+"

") 111 | } 112 | }, 113 | 114 | // 机器自动答复 115 | rebotReply : function(message){ 116 | $("#msgShow").append("
"+message+"
"); 117 | }, 118 | // 广告回复 119 | adReply : function(message){ 120 | $("#msgShow").append("
"+message+"
"); 121 | $("#msgShow").append("
"+new Date().Format("yyyy-MM-dd hh:mm:ss")+"开始沟通
"); 122 | }, 123 | send : function(){ 124 | var sendObj = $('#msgInput').children("div").children("p"); 125 | if(editor.txt.html().trim()!=""){ 126 | $("#msgShow").append("
"+sendObj.html()+"

") 127 | _websocket.send(sendObj.html()); 128 | editor.txt.clear(); 129 | } 130 | consumerSocket.moveCursorEnd(); 131 | }, 132 | 133 | initEmotion: function(){ 134 | var a = []; 135 | for (var i = 1; i < 76; i++) { 136 | var temp = {}; 137 | temp.alt=""; 138 | temp.src="img/emotion/arclist/"+i+".gif"; 139 | a.push(temp); 140 | } 141 | return a; 142 | } 143 | 144 | } 145 | 146 | // ================================================浏览器标题消息提示开始========================================== 147 | var isWindowFocus = true; 148 | function focusin() { isWindowFocus=true;} 149 | function focusout() { isWindowFocus=false;} 150 | // 注册焦点变化监听器 151 | if ("onfocusin" in document){// for IE 152 | document.onfocusin = focusin; 153 | document.onfocusout = focusout; 154 | } else { 155 | window.onblur = focusout; 156 | window.onfocus= focusin; 157 | } 158 | 159 | var flag = true; 160 | function flashTitle(){ 161 | // 仅窗口不在焦点时闪烁title,回到焦点时停止闪烁并将title恢复正常 162 | if(isWindowFocus){// 当前处于焦点 163 | document.title="在线咨询"; 164 | return;// 退出循环 165 | } 166 | 167 | if(flag){ 168 | document.title="【您有新的消息】"; 169 | flag = false; 170 | }else{ 171 | document.title="【      】"; 172 | flag = true; 173 | } 174 | setTimeout("flashTitle()",10); // 循环 175 | } 176 | // ================================================浏览器标题消息提示结束========================================== 177 | 178 | 179 | Date.prototype.Format = function (fmt) { 180 | var o = { 181 | "M+": this.getMonth() + 1, // 月份 182 | "d+": this.getDate(), // 日 183 | "h+": this.getHours(), // 小时 184 | "m+": this.getMinutes(), // 分 185 | "s+": this.getSeconds(), // 秒 186 | "q+": Math.floor((this.getMonth() + 3) / 3), // 季度 187 | "S": this.getMilliseconds() // 毫秒 188 | }; 189 | if (/(y+)/.test(fmt)) 190 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 191 | for (var k in o) 192 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 193 | return fmt; 194 | } 195 | -------------------------------------------------------------------------------- /src/main/resources/static/js/page/customerSocket.js: -------------------------------------------------------------------------------- 1 | var _websocket = null; 2 | // 当前聊天用户sessionId 3 | var selectedSessionId = null; 4 | // 当前聊天用户数 5 | var consumerlength = 0; 6 | 7 | var editor = null; 8 | 9 | $(function() { 10 | customerSocket.init(); 11 | }) 12 | 13 | var customerSocket = { 14 | 15 | init : function(){ 16 | customerSocket.page(); 17 | customerSocket.socket(); 18 | }, 19 | 20 | page : function(){ 21 | win_width = $(document).width(); 22 | win_height = $(document).height(); 23 | $("#content").height(win_height - 70); 24 | $("#content_right").width(win_width - $("#content_left").outerWidth()); 25 | $("#content_right_top").height($("#content_right").height()-300); 26 | 27 | $(window).resize(function(){ 28 | $("#content").height($(window).height() - 70); 29 | $("#content_right").width($(document).width() - $("#content_left").outerWidth()); 30 | $("#content_right_top").height($("#content_right").height()-300); 31 | }); 32 | 33 | $(document).keydown(function(event) { 34 | if (event.keyCode == 13) { 35 | event.preventDefault(); 36 | customerSocket.send(); 37 | } 38 | }); 39 | 40 | customerSocket.emotion(); 41 | }, 42 | 43 | emotion : function(){ 44 | var E = window.wangEditor 45 | editor = new E('#input_menu','#msgInput'); 46 | editor.customConfig.menus = [ 47 | 'emoticon', 48 | 'fontName', 49 | 'fontSize', 50 | 'bold', 51 | 'italic', 52 | 'underline', 53 | 'foreColor', 54 | 'image' 55 | ]; 56 | editor.customConfig.uploadImgShowBase64 = true; 57 | editor.customConfig.emotions = [{ 58 | title: '表情', 59 | type: 'image', 60 | content: customerSocket.initEmotion() 61 | }]; 62 | editor.customConfig.onfocus = function () { 63 | customerSocket.readMessage(); 64 | }; 65 | editor.create(); 66 | }, 67 | 68 | initEmotion: function(){ 69 | var a = []; 70 | for (var i = 1; i < 76; i++) { 71 | var temp = {}; 72 | temp.alt=""; 73 | temp.src="img/emotion/arclist/"+i+".gif"; 74 | a.push(temp); 75 | } 76 | return a; 77 | }, 78 | 79 | socket : function() { 80 | 81 | if ('WebSocket' in window) { 82 | _websocket = new WebSocket("ws://10.101.2.214:8080/websocket/customer/null"); 83 | } else { 84 | alert("当前浏览器不支持WebSocket") 85 | } 86 | 87 | // 连接发生错误时回调 88 | _websocket.onerror = function(event) { 89 | console.log(event.data); 90 | }; 91 | 92 | // 建立连接时回调 93 | _websocket.onopen = function(event) { 94 | 95 | } 96 | 97 | // 接收到消息时回调 98 | _websocket.onmessage = function(event) { 99 | flashTitle(); 100 | customerSocket.recevie(event.data); 101 | customerSocket.moveCursorEnd(); 102 | } 103 | 104 | // 连接关闭时回调 105 | _websocket.onclose = function(event) { 106 | //alert("连接已关闭") 107 | } 108 | }, 109 | moveCursorEnd : function(){// 移动光标到最低端 110 | $("#content_right_top").children("div:visible").children("div")[[$("#content_right_top").children("div:visible").children("div").length-1]].scrollIntoView(); 111 | }, 112 | recevie : function(data){ 113 | var json = JSON.parse(data); 114 | if (json.messageType==2) {// 下线消息 115 | customerSocket.offlineConsumer(json); 116 | } else {// 输出消息 117 | customerSocket.addConsumerList(json); 118 | } 119 | }, 120 | 121 | send : function(){ 122 | var sendObj = $('#msgInput').children("div").children("p"); 123 | if(editor.txt.html()!=""){ 124 | customerSocket.showMessageTab(sendObj.html(),selectedSessionId); 125 | _websocket.send(JSON.stringify({ 126 | "sessionId" : selectedSessionId, 127 | "message" : sendObj.html() 128 | })); 129 | editor.txt.clear(); 130 | } 131 | customerSocket.moveCursorEnd(); 132 | }, 133 | 134 | addConsumerList:function(json){ 135 | if (!($("#list_div_" + json.sessionId).length > 0)){//客户列表去重 136 | consumerlength++;// 记录当前聊天用户数 137 | if($("#content_left").find("div").length>0){ 138 | $("#content_left").append("
编号"+json.sessionId+"用户
"); 139 | }else{ 140 | $("#content_left").append("
编号"+json.sessionId+"用户
"); 141 | } 142 | $("#list_div_"+json.sessionId).append(""); 143 | } 144 | customerSocket.recevieMessageTab(json); 145 | }, 146 | 147 | recevieMessageTab : function(json){ 148 | var html = ""; 149 | 150 | if($("#msg_div_"+json.sessionId).length>0){ 151 | html += "
"; 152 | html += "
"+json.message+"
" 153 | html += "

"; 154 | $("#msg_div_"+json.sessionId).append(html); 155 | }else{ 156 | if(consumerlength==1){ 157 | html += "
"; 158 | selectedSessionId = json.sessionId; 159 | }else{ 160 | html += ""; 166 | $("#content_right_top").append(html); 167 | } 168 | 169 | // 设置信息数和消息提示 170 | var old_m = $("#list_div_" + json.sessionId).attr("msg_num"); 171 | var new_m = parseInt(old_m) + 1; 172 | $("#list_div_" + json.sessionId).attr("msg_num",new_m); 173 | customerSocket.messageTip(json); 174 | }, 175 | 176 | //设置消息提示 177 | messageTip:function(json){ 178 | $("#msgTip_"+json.sessionId).show(); 179 | $("#msgTip_"+json.sessionId).html($("#list_div_" + json.sessionId).attr("msg_num")); 180 | }, 181 | 182 | // 在客户列表点击用户 183 | clickConsumer:function(sessionId,obj){ 184 | selectedSessionId = sessionId; 185 | // tab页设置 186 | $("#content_right_top").children("div").hide(); 187 | $("#msg_div_"+sessionId).show(); 188 | // 客户列表设置 189 | $("#content_left").children("div").removeClass("selected"); 190 | $(obj).addClass("selected"); 191 | 192 | customerSocket.readMessage(sessionId); 193 | }, 194 | 195 | // 鼠标移到列表上,显示删除ICO 196 | showRemoveIco :function(session_id,obj){ 197 | $("#label_remove_"+session_id).show(); 198 | }, 199 | // 鼠标移到列表上,隐藏删除ICO 200 | hideRemoveIco :function(session_id,obj){ 201 | $("#label_remove_"+session_id).hide(); 202 | }, 203 | 204 | // 删除列表用户 205 | deleteConsumerList : function(session_id,obj){ 206 | $("#list_div_"+session_id).remove(); 207 | $("#msg_div_"+session_id).remove(); 208 | 209 | $("#content_left").children("div:first").addClass("selected"); 210 | $("#content_right_top").children("div:first").show(); 211 | event.stopPropagation(); 212 | }, 213 | 214 | // 消息已读,去除红点提示 215 | readMessage : function(sessionId) { 216 | if(sessionId){ 217 | $("#msgTip_"+sessionId).hide(); 218 | $("#list_div_" + sessionId).attr("msg_num",0); 219 | }else{ 220 | $("#msgTip_"+selectedSessionId).hide(); 221 | $("#list_div_" + selectedSessionId).attr("msg_num",0); 222 | } 223 | }, 224 | 225 | // 用户下线消息处理:1.图像置灰 2.在列表中往后排 226 | offlineConsumer : function(json){ 227 | 228 | }, 229 | 230 | // 客服自己发送的消息显示在tab页面上 231 | showMessageTab : function(message,consumerSessionId){ 232 | var html = ""; 233 | html += "
"; 234 | html += "
"+message+"
" 235 | html += "

"; 236 | $("#msg_div_"+consumerSessionId).append(html); 237 | } 238 | 239 | } 240 | 241 | 242 | //================================================浏览器标题消息提示开始========================================== 243 | var isWindowFocus = true; 244 | function focusin() { isWindowFocus=true;} 245 | function focusout() { isWindowFocus=false;} 246 | //注册焦点变化监听器 247 | if ("onfocusin" in document){//for IE 248 | document.onfocusin = focusin; 249 | document.onfocusout = focusout; 250 | } else { 251 | window.onblur = focusout; 252 | window.onfocus= focusin; 253 | } 254 | 255 | var flag = true; 256 | function flashTitle(){ 257 | //仅窗口不在焦点时闪烁title,回到焦点时停止闪烁并将title恢复正常 258 | if(isWindowFocus){//当前处于焦点 259 | document.title="客服"; 260 | return;//退出循环 261 | } 262 | 263 | if(flag){ 264 | document.title="【您有新的消息】"; 265 | flag = false; 266 | }else{ 267 | document.title="【      】"; 268 | flag = true; 269 | } 270 | setTimeout("flashTitle()",10); //循环 271 | } 272 | //================================================浏览器标题消息提示结束========================================== 273 | 274 | 275 | Date.prototype.Format = function (fmt) { 276 | var o = { 277 | "M+": this.getMonth() + 1, // 月份 278 | "d+": this.getDate(), // 日 279 | "h+": this.getHours(), // 小时 280 | "m+": this.getMinutes(), // 分 281 | "s+": this.getSeconds(), // 秒 282 | "q+": Math.floor((this.getMonth() + 3) / 3), // 季度 283 | "S": this.getMilliseconds() // 毫秒 284 | }; 285 | if (/(y+)/.test(fmt)) 286 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 287 | for (var k in o) 288 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 289 | return fmt; 290 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/page/index.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | }) 4 | 5 | var _index = { 6 | 7 | CloseAd : function() {// 关闭广告推送 8 | $.ajax({ 9 | url : "/contorAd", 10 | dataType : "json", 11 | success : function(data) { 12 | if (JSON.parse(data)) { 13 | $("#ad").text("close Ad"); 14 | } else { 15 | $("#ad").text("open Ad"); 16 | } 17 | } 18 | }) 19 | }, 20 | CloseAuto : function() {// 关闭自动回复 21 | $.ajax({ 22 | url : "/contorAuto", 23 | dataType : "json", 24 | success : function(data) { 25 | if (JSON.parse(data)) { 26 | $("#auto").text("close Reply"); 27 | } else { 28 | $("#auto").text("open Reply"); 29 | } 30 | } 31 | }) 32 | }, 33 | setInfo : function(type) {// 设置信息:自动回复/广告 34 | if (type == 1) {// 广告 35 | window.location.href = "/editAd"; 36 | } else {// 自动回复 37 | window.location.href = "/editReply"; 38 | } 39 | }, 40 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/socket.js: -------------------------------------------------------------------------------- 1 | /** 2 | * socket 3 | */ 4 | 5 | var _websocket = null; 6 | 7 | var _socket = { 8 | init : function(url) { 9 | if ('WebSocket' in window) { 10 | _websocket = new WebSocket(url); 11 | } else { 12 | alert("当前浏览器不支持WebSocket") 13 | } 14 | 15 | // 连接发生错误时回调 16 | _websocket.onerror = function(event) { 17 | 18 | }; 19 | 20 | // 建立连接时回调 21 | _websocket.onopen = function(event) { 22 | 23 | } 24 | 25 | // 接收到消息时回调 26 | _websocket.onmessage = function(event) { 27 | var json = JSON.parse(event.data); 28 | // 输出event.data信息到页面 29 | $('#text').append(json.message).append('\n'); 30 | 31 | $('#sessionIdList').append( 32 | ""); 34 | } 35 | 36 | // 连接关闭时回调 37 | _websocket.onclose = function(event) { 38 | // 调用websocket.close()或关闭页面时 39 | } 40 | }, 41 | send : function() { 42 | _websocket.send($('#text').val()); 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/wangEditor.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.wangEditor=t()}(this,function(){"use strict";function e(e){var t=void 0;return t=document.createElement("div"),t.innerHTML=e,t.children}function t(e){return!!e&&(e instanceof HTMLCollection||e instanceof NodeList)}function n(e){var n=document.querySelectorAll(e);return t(n)?n:[n]}function i(o){if(o){if(o instanceof i)return o;this.selector=o;var A=o.nodeType,r=[];9===A?r=[o]:1===A?r=[o]:t(o)||o instanceof Array?r=o:"string"==typeof o&&(o=o.replace("/\n/mg","").trim(),r=0===o.indexOf("<")?e(o):n(o));var c=r.length;if(!c)return this;var a=void 0;for(a=0;a/gm,">").replace(/"/gm,""").replace(/(\r\n|\r|\n)/g,"
")}function s(e){return"function"==typeof e}function l(e){this.editor=e,this.$elem=o('
\n \n
'),this.type="click",this._active=!1}function d(e,t){var n=this,i=e.editor;this.menu=e,this.opt=t;var A=o('
'),r=t.$title,c=void 0;r&&(c=r.html(),c=O(i,c),r.html(c),r.addClass("w-e-dp-title"),A.append(r));var a=t.list||[],s=t.type||"list",l=t.onClick||$,d=o('
    ');A.append(d),a.forEach(function(e){var t=e.$elem,A=t.html();A=O(i,A),t.html(A);var r=e.value,c=o('
  • ');t&&(c.append(t),d.append(c),c.on("click",function(e){l(r),n.hideTimeoutId=setTimeout(function(){n.hide()},0)}))}),A.on("mouseleave",function(e){n.hideTimeoutId=setTimeout(function(){n.hide()},0)}),this.$container=A,this._rendered=!1,this._show=!1}function u(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist",this._active=!1,this.droplist=new d(this,{width:100,$title:o("

    设置标题

    "),type:"list",list:[{$elem:o("

    H1

    "),value:"

    "},{$elem:o("

    H2

    "),value:"

    "},{$elem:o("

    H3

    "),value:"

    "},{$elem:o("

    H4

    "),value:"

    "},{$elem:o("

    H5
    "),value:"
    "},{$elem:o("

    正文

    "),value:"

    "}],onClick:function(e){t._command(e)}})}function h(e){var t=this;this.editor=e,this.$elem=o('

    '),this.type="droplist",this._active=!1,this.droplist=new d(this,{width:160,$title:o("

    字号

    "),type:"list",list:[{$elem:o('x-small'),value:"1"},{$elem:o('small'),value:"2"},{$elem:o("normal"),value:"3"},{$elem:o('large'),value:"4"},{$elem:o('x-large'),value:"5"},{$elem:o('xx-large'),value:"6"}],onClick:function(e){t._command(e)}})}function p(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist",this._active=!1;var n=e.config,i=n.fontNames||[];this.droplist=new d(this,{width:100,$title:o("

    字体

    "),type:"list",list:i.map(function(e){return{$elem:o(''+e+""),value:e}}),onClick:function(e){t._command(e)}})}function f(e,t){this.menu=e,this.opt=t}function m(e){this.editor=e,this.$elem=o('
    '),this.type="panel",this._active=!1}function g(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function w(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function v(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function E(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function b(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function B(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist",this._active=!1,this.droplist=new d(this,{width:120,$title:o("

    设置列表

    "),type:"list",list:[{$elem:o(' 有序列表'),value:"insertOrderedList"},{$elem:o(' 无序列表'),value:"insertUnorderedList"}],onClick:function(e){t._command(e)}})}function y(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist",this._active=!1,this.droplist=new d(this,{width:100,$title:o("

    对齐方式

    "),type:"list",list:[{$elem:o(' 靠左'),value:"justifyLeft"},{$elem:o(' 居中'),value:"justifyCenter"},{$elem:o(' 靠右'),value:"justifyRight"}],onClick:function(e){t._command(e)}})}function C(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist";var n=e.config,i=n.colors||[];this._active=!1,this.droplist=new d(this,{width:120,$title:o("

    文字颜色

    "),type:"inline-block",list:i.map(function(e){return{$elem:o(''),value:e}}),onClick:function(e){t._command(e)}})}function x(e){var t=this;this.editor=e,this.$elem=o('
    '),this.type="droplist";var n=e.config,i=n.colors||[];this._active=!1,this.droplist=new d(this,{width:120,$title:o("

    背景色

    "),type:"inline-block",list:i.map(function(e){return{$elem:o(''),value:e}}),onClick:function(e){t._command(e)}})}function I(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="click",this._active=!1}function Q(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="panel",this._active=!1}function M(e){this.editor=e,this.$elem=o('
    \n \n
    '),this.type="panel",this._active=!1}function S(e){this.editor=e,this.$elem=o('
    '),this.type="panel",this._active=!1}function k(e){this.editor=e,this.$elem=o('
    '),this.type="panel",this._active=!1}function D(e){this.editor=e;var t=c("w-e-img");this.$elem=o('
    '),e.imgMenuId=t,this.type="panel",this._active=!1}function _(e){this.editor=e,this.menus={}}function N(e){var t=e.clipboardData||e.originalEvent&&e.originalEvent.clipboardData,n=void 0;return n=null==t?window.clipboardData&&window.clipboardData.getData("text"):t.getData("text/plain"),a(n)}function F(e,t,n){var i=e.clipboardData||e.originalEvent&&e.originalEvent.clipboardData,o=void 0,A=void 0;if(null==i?o=window.clipboardData&&window.clipboardData.getData("text"):(o=i.getData("text/plain"),A=i.getData("text/html")),!A&&o&&(A="

    "+a(o)+"

    "),A){var r=A.split("");return 2===r.length&&(A=r[0]),A=A.replace(/<(meta|script|link).+?>/gim,""),A=A.replace(//gm,""),A=A.replace(/\s?data-.+?=('|").+?('|")/gim,""),n&&(A=A.replace(//gim,"")),A=t?A.replace(/\s?(class|style)=('|").*?('|")/gim,""):A.replace(/\s?class=('|").*?('|")/gim,"")}}function T(e){var t=[];if(N(e))return t;var n=e.clipboardData||e.originalEvent&&e.originalEvent.clipboardData||{},i=n.items;return i?(A(i,function(e,n){var i=n.type;/image/i.test(i)&&t.push(n.getAsFile())}),t):t}function R(e){var t=[];return(e.childNodes()||[]).forEach(function(e){var n=void 0,i=e.nodeType;if(3===i&&(n=e.textContent,n=a(n)),1===i){n={},n.tag=e.nodeName.toLowerCase();for(var A=[],r=e.attributes||{},c=r.length||0,s=0;s
    ')}function L(e){this.editor=e}function j(e,t){if(null==e)throw new Error("错误:初始化编辑器时候未传入任何参数,请查阅文档");this.id="wangEditor-"+W++,this.toolbarSelector=e,this.textSelector=t,this.customConfig={}}var G=[];i.prototype={constructor:i,forEach:function(e){var t=void 0;for(t=0;t=t&&(e%=t),o(this[e])},first:function(){return this.get(0)},last:function(){var e=this.length;return this.get(e-1)},on:function(e,t,n){n||(n=t,t=null);var i=[];return i=e.split(/\s+/),this.forEach(function(e){i.forEach(function(i){if(i){if(G.push({elem:e,type:i,fn:n}),!t)return void e.addEventListener(i,n);e.addEventListener(i,function(e){var i=e.target;i.matches(t)&&n.call(i,e)})}})})},off:function(e,t){return this.forEach(function(n){n.removeEventListener(e,t)})},attr:function(e,t){return null==t?this[0].getAttribute(e):this.forEach(function(n){n.setAttribute(e,t)})},addClass:function(e){return e?this.forEach(function(t){var n=void 0;t.className?(n=t.className.split(/\s/),n=n.filter(function(e){return!!e.trim()}),n.indexOf(e)<0&&n.push(e),t.className=n.join(" ")):t.className=e}):this},removeClass:function(e){return e?this.forEach(function(t){var n=void 0;t.className&&(n=t.className.split(/\s/),n=n.filter(function(t){return!(!(t=t.trim())||t===e)}),t.className=n.join(" "))}):this},css:function(e,t){var n=e+":"+t+";";return this.forEach(function(t){var i=(t.getAttribute("style")||"").trim(),o=void 0,A=[];i?(o=i.split(";"),o.forEach(function(e){var t=e.split(":").map(function(e){return e.trim()});2===t.length&&A.push(t[0]+":"+t[1])}),A=A.map(function(t){return 0===t.indexOf(e)?n:t}),A.indexOf(n)<0&&A.push(n),t.setAttribute("style",A.join("; "))):t.setAttribute("style",n)})},show:function(){return this.css("display","block")},hide:function(){return this.css("display","none")},children:function(){var e=this[0];return e?o(e.children):null},childNodes:function(){var e=this[0];return e?o(e.childNodes):null},append:function(e){return this.forEach(function(t){e.forEach(function(e){t.appendChild(e)})})},remove:function(){return this.forEach(function(e){if(e.remove)e.remove();else{var t=e.parentElement;t&&t.removeChild(e)}})},isContain:function(e){var t=this[0],n=e[0];return t.contains(n)},getSizeData:function(){return this[0].getBoundingClientRect()},getNodeName:function(){return this[0].nodeName},find:function(e){return o(this[0].querySelectorAll(e))},text:function(e){return e?this.forEach(function(t){t.innerHTML=e}):this[0].innerHTML.replace(/<.*?>/g,function(){return""})},html:function(e){var t=this[0];return null==e?t.innerHTML:(t.innerHTML=e,this)},val:function(){return this[0].value.trim()},focus:function(){return this.forEach(function(e){e.focus()})},parent:function(){return o(this[0].parentElement)},parentUntil:function(e,t){var n=document.querySelectorAll(e),i=n.length;if(!i)return null;var A=t||this[0];if("BODY"===A.nodeName)return null;var r=A.parentElement,c=void 0;for(c=0;c=0)){var n=t.editor,i=o("body"),A=n.$textContainerElem,r=this.opt,c=o('
    '),a=r.width||300;c.css("width",a+"px").css("margin-left",(0-a)/2+"px");var s=o('');c.append(s),s.on("click",function(){e.hide()});var l=o('
      '),d=o('
      ');c.append(l).append(d);var u=r.height;u&&d.css("height",u+"px").css("overflow-y","auto");var h=r.tabs||[],p=[],f=[];h.forEach(function(e,t){if(e){var i=e.title||"",A=e.tpl||"";i=O(n,i),A=O(n,A);var r=o('
    • '+i+"
    • ");l.append(r);var c=o(A);d.append(c),r._index=t,p.push(r),f.push(c),0===t?(r._active=!0,r.addClass("w-e-active")):c.hide(),r.on("click",function(e){r._active||(p.forEach(function(e){e._active=!1,e.removeClass("w-e-active")}),f.forEach(function(e){e.hide()}),r._active=!0,r.addClass("w-e-active"),c.show())})}}),c.on("click",function(e){e.stopPropagation()}),i.on("click",function(t){e.hide()}),A.append(c),h.forEach(function(t,n){if(t){(t.events||[]).forEach(function(t){var i=t.selector,o=t.type,A=t.fn||V;f[n].find(i).on(o,function(t){t.stopPropagation(),A(t)&&e.hide()})})}});var m=c.find("input[type=text],textarea");m.length&&m.get(0).focus(),this.$container=c,this._hideOtherPanels(),K.push(t)}},hide:function(){var e=this.menu,t=this.$container;t&&t.remove(),K=K.filter(function(t){return t!==e})},_hideOtherPanels:function(){K.length&&K.forEach(function(e){var t=e.panel||{};t.hide&&t.hide()})}},m.prototype={constructor:m,onClick:function(e){var t=this.editor,n=void 0;if(this._active){if(!(n=t.selection.getSelectionContainerElem()))return;t.selection.createRangeByElem(n),t.selection.restoreSelection(),this._createPanel(n.text(),n.attr("href"))}else t.selection.isSelectionEmpty()?this._createPanel("",""):this._createPanel(t.selection.getSelectionText(),"")},_createPanel:function(e,t){var n=this,i=c("input-link"),A=c("input-text"),r=c("btn-ok"),a=c("btn-del"),s=this._active?"inline-block":"none",l=new f(this,{width:300,tabs:[{title:"链接",tpl:'
      \n \n \n
      \n \n \n
      \n
      ',events:[{selector:"#"+r,type:"click",fn:function(){var e=o("#"+i),t=o("#"+A),r=e.val(),c=t.val();return n._insertLink(c,r),!0}},{selector:"#"+a,type:"click",fn:function(){return n._delLink(),!0}}]}]});l.show(),this.panel=l},_delLink:function(){if(this._active){var e=this.editor;if(e.selection.getSelectionContainerElem()){var t=e.selection.getSelectionText();e.cmd.do("insertHTML",""+t+"")}}},_insertLink:function(e,t){var n=this.editor,i=n.config,o=i.linkCheck,A=!0;o&&"function"==typeof o&&(A=o(e,t)),!0===A?n.cmd.do("insertHTML",''+e+""):alert(A)},tryChangeActive:function(e){var t=this.editor,n=this.$elem,i=t.selection.getSelectionContainerElem();i&&("A"===i.getNodeName()?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active")))}},g.prototype={constructor:g,onClick:function(e){var t=this.editor,n=t.selection.isSelectionEmpty();n&&t.selection.createEmptyRange(),t.cmd.do("italic"),n&&(t.selection.collapseRange(),t.selection.restoreSelection())},tryChangeActive:function(e){var t=this.editor,n=this.$elem;t.cmd.queryCommandState("italic")?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}},w.prototype={constructor:w,onClick:function(e){this.editor.cmd.do("redo")}},v.prototype={constructor:v,onClick:function(e){var t=this.editor,n=t.selection.isSelectionEmpty();n&&t.selection.createEmptyRange(),t.cmd.do("strikeThrough"),n&&(t.selection.collapseRange(),t.selection.restoreSelection())},tryChangeActive:function(e){var t=this.editor,n=this.$elem;t.cmd.queryCommandState("strikeThrough")?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}},E.prototype={constructor:E,onClick:function(e){var t=this.editor,n=t.selection.isSelectionEmpty();n&&t.selection.createEmptyRange(),t.cmd.do("underline"),n&&(t.selection.collapseRange(),t.selection.restoreSelection())},tryChangeActive:function(e){var t=this.editor,n=this.$elem;t.cmd.queryCommandState("underline")?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}},b.prototype={constructor:b,onClick:function(e){this.editor.cmd.do("undo")}},B.prototype={constructor:B,_command:function(e){var t=this.editor,n=t.$textElem;if(t.selection.restoreSelection(),!t.cmd.queryCommandState(e)){t.cmd.do(e);var i=t.selection.getSelectionContainerElem();if("LI"===i.getNodeName()&&(i=i.parent()),!1!==/^ol|ul$/i.test(i.getNodeName())&&!i.equal(n)){var o=i.parent();o.equal(n)||(i.insertAfter(o),o.remove())}}},tryChangeActive:function(e){var t=this.editor,n=this.$elem;t.cmd.queryCommandState("insertUnOrderedList")||t.cmd.queryCommandState("insertOrderedList")?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}},y.prototype={constructor:y,_command:function(e){this.editor.cmd.do(e)}},C.prototype={constructor:C,_command:function(e){this.editor.cmd.do("foreColor",e)}},x.prototype={constructor:x,_command:function(e){this.editor.cmd.do("backColor",e)}},I.prototype={constructor:I,onClick:function(e){var t=this.editor,n=t.selection.getSelectionContainerElem(),i=n.getNodeName();if(!J.isIE())return void("BLOCKQUOTE"===i?t.cmd.do("formatBlock","

      "):t.cmd.do("formatBlock","

      "));var A=void 0,r=void 0;if("P"===i)return A=n.text(),r=o("
      "+A+"
      "),r.insertAfter(n),void n.remove();"BLOCKQUOTE"===i&&(A=n.text(),r=o("

      "+A+"

      "),r.insertAfter(n),n.remove())},tryChangeActive:function(e){var t=this.editor,n=this.$elem,i=/^BLOCKQUOTE$/i,o=t.cmd.queryCommandValue("formatBlock");i.test(o)?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}},Q.prototype={constructor:Q,onClick:function(e){var t=this.editor,n=t.selection.getSelectionStartElem(),i=t.selection.getSelectionEndElem(),A=t.selection.isSelectionEmpty(),r=t.selection.getSelectionText(),c=void 0;return n.equal(i)?A?void(this._active?this._createPanel(n.html()):this._createPanel()):(c=o(""+r+""),t.cmd.do("insertElem",c),t.selection.createRangeByElem(c,!1),void t.selection.restoreSelection()):void t.selection.restoreSelection()},_createPanel:function(e){var t=this;e=e||"";var n=e?"edit":"new",i=c("texxt"),A=c("btn"),r=new f(this,{width:500,tabs:[{title:"插入代码",tpl:'
      \n \n
      \n \n
      \n
      ',events:[{selector:"#"+A,type:"click",fn:function(){var e=o("#"+i),A=e.val()||e.html();return A=a(A),"new"===n?t._insertCode(A):t._updateCode(A),!0}}]}]});r.show(),this.panel=r},_insertCode:function(e){this.editor.cmd.do("insertHTML","
      "+e+"


      ")},_updateCode:function(e){var t=this.editor,n=t.selection.getSelectionContainerElem();n&&(n.html(e),t.selection.restoreSelection())},tryChangeActive:function(e){var t=this.editor,n=this.$elem,i=t.selection.getSelectionContainerElem();if(i){var o=i.parent();"CODE"===i.getNodeName()&&"PRE"===o.getNodeName()?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}}},M.prototype={constructor:M,onClick:function(){this._createPanel()},_createPanel:function(){var e=this,t=this.editor,n=t.config,i=n.emotions||[],A=[];i.forEach(function(t){var n=t.type,i=t.content||[],r="";"emoji"===n&&i.forEach(function(e){e&&(r+=''+e+"")}),"image"===n&&i.forEach(function(e){var t=e.src,n=e.alt;t&&(r+=''+n+'')}),A.push({title:t.title,tpl:'
      '+r+"
      ",events:[{selector:"span.w-e-item",type:"click",fn:function(t){var n=t.target,i=o(n),A=i.getNodeName(),r=void 0;return r="IMG"===A?i.parent().html():""+i.html()+"",e._insert(r),!0}}]})});var r=new f(this,{width:300,height:200,tabs:A});r.show(),this.panel=r},_insert:function(e){this.editor.cmd.do("insertHTML",e)}},S.prototype={constructor:S,onClick:function(){this._active?this._createEditPanel():this._createInsertPanel()},_createInsertPanel:function(){var e=this,t=c("btn"),n=c("row"),i=c("col"),A=new f(this,{width:250,tabs:[{title:"插入表格",tpl:'
      \n

      \n 创建\n \n 行\n \n 列的表格\n

      \n
      \n \n
      \n
      ',events:[{selector:"#"+t,type:"click",fn:function(){var t=parseInt(o("#"+n).val()),A=parseInt(o("#"+i).val());return t&&A&&t>0&&A>0&&e._insert(t,A),!0}}]}]});A.show(),this.panel=A},_insert:function(e,t){var n=void 0,i=void 0,o='';for(n=0;n",0===n)for(i=0;i ";else for(i=0;i ";o+=""}o+="


      ";var A=this.editor;A.cmd.do("insertHTML",o),A.cmd.do("enableObjectResizing",!1),A.cmd.do("enableInlineTableEditing",!1)},_createEditPanel:function(){var e=this,t=c("add-row"),n=c("add-col"),i=c("del-row"),o=c("del-col"),A=c("del-table");new f(this,{width:320,tabs:[{title:"编辑表格",tpl:'
      \n
      \n \n \n \n \n
      \n
      \n \n \n
      ',events:[{selector:"#"+t,type:"click",fn:function(){return e._addRow(),!0}},{selector:"#"+n,type:"click",fn:function(){return e._addCol(),!0}},{selector:"#"+i,type:"click",fn:function(){return e._delRow(),!0}},{selector:"#"+o,type:"click",fn:function(){return e._delCol(),!0}},{selector:"#"+A,type:"click",fn:function(){return e._delTable(),!0}}]}]}).show()},_getLocationData:function(){var e={},t=this.editor,n=t.selection.getSelectionContainerElem();if(n){var i=n.getNodeName();if("TD"===i||"TH"===i){var o=n.parent(),A=o.children(),r=A.length;A.forEach(function(t,i){if(t===n[0])return e.td={index:i,elem:t,length:r},!1});var c=o.parent(),a=c.children(),s=a.length;return a.forEach(function(t,n){if(t===o[0])return e.tr={index:n,elem:t,length:s},!1}),e}}},_addRow:function(){var e=this._getLocationData();if(e){var t=e.tr,n=o(t.elem),i=e.td,A=i.length,r=document.createElement("tr"),c="",a=void 0;for(a=0;a ";r.innerHTML=c,o(r).insertAfter(n)}},_addCol:function(){var e=this._getLocationData();if(e){var t=e.tr,n=e.td,i=n.index;o(t.elem).parent().children().forEach(function(e){var t=o(e),n=t.children(),A=n.get(i),r=A.getNodeName().toLowerCase();o(document.createElement(r)).insertAfter(A)})}},_delRow:function(){var e=this._getLocationData();if(e){o(e.tr.elem).remove()}},_delCol:function(){var e=this._getLocationData();if(e){var t=e.tr,n=e.td,i=n.index;o(t.elem).parent().children().forEach(function(e){o(e).children().get(i).remove()})}},_delTable:function(){var e=this.editor,t=e.selection.getSelectionContainerElem();if(t){var n=t.parentUntil("table");n&&n.remove()}},tryChangeActive:function(e){var t=this.editor,n=this.$elem,i=t.selection.getSelectionContainerElem();if(i){var o=i.getNodeName();"TD"===o||"TH"===o?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}}},k.prototype={constructor:k,onClick:function(){this._createPanel()},_createPanel:function(){var e=this,t=c("text-val"),n=c("btn"),i=new f(this,{width:350,tabs:[{title:"插入视频",tpl:'
      \n \n
      \n \n
      \n
      ',events:[{selector:"#"+n,type:"click",fn:function(){var n=o("#"+t),i=n.val().trim();return i&&e._insert(i),!0}}]}]});i.show(),this.panel=i},_insert:function(e){this.editor.cmd.do("insertHTML",e+"


      ")}},D.prototype={constructor:D,onClick:function(){this.editor.config.qiniu||(this._active?this._createEditPanel():this._createInsertPanel())},_createEditPanel:function(){var e=this.editor,t=c("width-30"),n=c("width-50"),i=c("width-100"),o=c("del-btn"),A=[{title:"编辑图片",tpl:'
      \n
      \n 最大宽度:\n \n \n \n
      \n
      \n \n \n
      ',events:[{selector:"#"+t,type:"click",fn:function(){var t=e._selectedImg;return t&&t.css("max-width","30%"),!0}},{selector:"#"+n,type:"click",fn:function(){var t=e._selectedImg;return t&&t.css("max-width","50%"),!0}},{selector:"#"+i,type:"click",fn:function(){var t=e._selectedImg;return t&&t.css("max-width","100%"),!0}},{selector:"#"+o,type:"click",fn:function(){var t=e._selectedImg;return t&&t.remove(),!0}}]}],r=new f(this,{width:300,tabs:A});r.show(),this.panel=r},_createInsertPanel:function(){var e=this.editor,t=e.uploadImg,n=e.config,i=c("up-trigger"),A=c("up-file"),r=c("link-url"),a=c("link-btn"),s=[{title:"上传图片",tpl:'
      \n
      \n \n
      \n
      \n \n
      \n
      ',events:[{selector:"#"+i,type:"click",fn:function(){var e=o("#"+A),t=e[0];if(!t)return!0;t.click()}},{selector:"#"+A,type:"change",fn:function(){var e=o("#"+A),n=e[0];if(!n)return!0;var i=n.files;return i.length&&t.uploadImg(i),!0}}]},{title:"网络图片", 2 | tpl:'
      \n \n
      \n \n
      \n
      ',events:[{selector:"#"+a,type:"click",fn:function(){var e=o("#"+r),n=e.val().trim();return n&&t.insertLinkImg(n),!0}}]}],l=[];(n.uploadImgShowBase64||n.uploadImgServer||n.customUploadImg)&&window.FileReader&&l.push(s[0]),n.showLinkImg&&l.push(s[1]);var d=new f(this,{width:300,tabs:l});d.show(),this.panel=d},tryChangeActive:function(e){var t=this.editor,n=this.$elem;t._selectedImg?(this._active=!0,n.addClass("w-e-active")):(this._active=!1,n.removeClass("w-e-active"))}};var q={};q.bold=l,q.head=u,q.fontSize=h,q.fontName=p,q.link=m,q.italic=g,q.redo=w,q.strikeThrough=v,q.underline=E,q.undo=b,q.list=B,q.justify=y,q.foreColor=C,q.backColor=x,q.quote=I,q.code=Q,q.emoticon=M,q.table=S,q.video=k,q.image=D,_.prototype={constructor:_,init:function(){var e=this,t=this.editor;((t.config||{}).menus||[]).forEach(function(n){var i=q[n];i&&"function"==typeof i&&(e.menus[n]=new i(t))}),this._addToToolbar(),this._bindEvent()},_addToToolbar:function(){var e=this.editor,t=e.$toolbarElem,n=this.menus,i=e.config,o=i.zIndex+1;A(n,function(e,n){var i=n.$elem;i&&(i.css("z-index",o),t.append(i))})},_bindEvent:function(){var e=this.menus,t=this.editor;A(e,function(e,n){var i=n.type;if(i){var o=n.$elem,A=n.droplist;n.panel;"click"===i&&n.onClick&&o.on("click",function(e){null!=t.selection.getRange()&&n.onClick(e)}),"droplist"===i&&A&&o.on("mouseenter",function(e){null!=t.selection.getRange()&&(A.showTimeoutId=setTimeout(function(){A.show()},200))}).on("mouseleave",function(e){A.hideTimeoutId=setTimeout(function(){A.hide()},0)}),"panel"===i&&n.onClick&&o.on("click",function(e){e.stopPropagation(),null!=t.selection.getRange()&&n.onClick(e)})}})},changeActive:function(){A(this.menus,function(e,t){t.tryChangeActive&&setTimeout(function(){t.tryChangeActive()},100)})}},U.prototype={constructor:U,init:function(){this._bindEvent()},clear:function(){this.html("


      ")},html:function(e){var t=this.editor,n=t.$textElem,i=void 0;if(null==e)return i=n.html(),i=i.replace(/\u200b/gm,""),i;n.html(e),t.initSelection()},getJSON:function(){return R(this.editor.$textElem)},text:function(e){var t=this.editor,n=t.$textElem,i=void 0;if(null==e)return i=n.text(),i=i.replace(/\u200b/gm,""),i;n.text("

      "+e+"

      "),t.initSelection()},append:function(e){var t=this.editor;t.$textElem.append(o(e)),t.initSelection()},_bindEvent:function(){this._saveRangeRealTime(),this._enterKeyHandle(),this._clearHandle(),this._pasteHandle(),this._tabHandle(),this._imgHandle(),this._dragHandle()},_saveRangeRealTime:function(){function e(e){t.selection.saveRange(),t.menus.changeActive()}var t=this.editor,n=t.$textElem;n.on("keyup",e),n.on("mousedown",function(t){n.on("mouseleave",e)}),n.on("mouseup",function(t){e(),n.off("mouseleave",e)})},_enterKeyHandle:function(){function e(e){var t=o("


      ");t.insertBefore(e),i.selection.createRangeByElem(t,!0),i.selection.restoreSelection(),e.remove()}function t(t){var n=i.selection.getSelectionContainerElem(),o=n.parent();if("
      "===o.html())return void e(n);if(o.equal(A)){"P"!==n.getNodeName()&&(n.text()||e(n))}}function n(e){var t=i.selection.getSelectionContainerElem();if(t){var n=t.parent(),A=t.getNodeName(),r=n.getNodeName();if("CODE"===A&&"PRE"===r&&i.cmd.queryCommandSupported("insertHTML")){if(!0===i._willBreakCode){var c=o("


      ");return c.insertAfter(n),i.selection.createRangeByElem(c,!0),i.selection.restoreSelection(),i._willBreakCode=!1,void e.preventDefault()}var a=i.selection.getRange().startOffset;i.cmd.do("insertHTML","\n"),i.selection.saveRange(),i.selection.getRange().startOffset===a&&i.cmd.do("insertHTML","\n");var s=t.html().length;i.selection.getRange().startOffset+1===s&&(i._willBreakCode=!0),e.preventDefault()}}}var i=this.editor,A=i.$textElem;A.on("keyup",function(e){13===e.keyCode&&t(e)}),A.on("keydown",function(e){if(13!==e.keyCode)return void(i._willBreakCode=!1);n(e)})},_clearHandle:function(){var e=this.editor,t=e.$textElem;t.on("keydown",function(e){if(8===e.keyCode){return"


      "===t.html().toLowerCase().trim()?void e.preventDefault():void 0}}),t.on("keyup",function(n){if(8===n.keyCode){var i=void 0,A=t.html().toLowerCase().trim();A&&"
      "!==A||(i=o("


      "),t.html(""),t.append(i),e.selection.createRangeByElem(i,!1,!0),e.selection.restoreSelection())}})},_pasteHandle:function(){function e(){var e=Date.now(),t=!1;return e-a>=100&&(t=!0),a=e,t}function t(){a=0}var n=this.editor,i=n.config,o=i.pasteFilterStyle,A=i.pasteTextHandle,r=i.pasteIgnoreImg,c=n.$textElem,a=0;c.on("paste",function(i){if(!J.isIE()&&(i.preventDefault(),e())){var c=F(i,o,r),a=N(i);a=a.replace(/\n/gm,"
      ");var l=n.selection.getSelectionContainerElem();if(l){var d=l.getNodeName();if("CODE"===d||"PRE"===d)return A&&s(A)&&(a=""+(A(a)||"")),void n.cmd.do("insertHTML","

      "+a+"

      ");if(!c)return void t();try{A&&s(A)&&(c=""+(A(c)||"")),n.cmd.do("insertHTML",c)}catch(e){A&&s(A)&&(a=""+(A(a)||"")),n.cmd.do("insertHTML","

      "+a+"

      ")}}}}),c.on("paste",function(t){if(!J.isIE()&&(t.preventDefault(),e())){var i=T(t);if(i&&i.length){var o=n.selection.getSelectionContainerElem();if(o){var A=o.getNodeName();if("CODE"!==A&&"PRE"!==A){n.uploadImg.uploadImg(i)}}}}})},_tabHandle:function(){var e=this.editor;e.$textElem.on("keydown",function(t){if(9===t.keyCode&&e.cmd.queryCommandSupported("insertHTML")){var n=e.selection.getSelectionContainerElem();if(n){var i=n.parent(),o=n.getNodeName(),A=i.getNodeName();"CODE"===o&&"PRE"===A?e.cmd.do("insertHTML"," "):e.cmd.do("insertHTML","    "),t.preventDefault()}}})},_imgHandle:function(){var e=this.editor,t=e.$textElem;t.on("click","img",function(t){var n=this,i=o(n);"1"!==i.attr("data-w-e")&&(e._selectedImg=i,e.selection.createRangeByElem(i),e.selection.restoreSelection())}),t.on("click keyup",function(t){t.target.matches("img")||(e._selectedImg=null)})},_dragHandle:function(){var e=this.editor;o(document).on("dragleave drop dragenter dragover",function(e){e.preventDefault()}),e.$textElem.on("drop",function(t){t.preventDefault();var n=t.dataTransfer&&t.dataTransfer.files;n&&n.length&&e.uploadImg.uploadImg(n)})}},Y.prototype={constructor:Y,do:function(e,t){var n=this.editor;if(n._useStyleWithCSS||(document.execCommand("styleWithCSS",null,!0),n._useStyleWithCSS=!0),n.selection.getRange()){n.selection.restoreSelection();var i="_"+e;this[i]?this[i](t):this._execCommand(e,t),n.menus.changeActive(),n.selection.saveRange(),n.selection.restoreSelection(),n.change&&n.change()}},_insertHTML:function(e){var t=this.editor,n=t.selection.getRange();this.queryCommandSupported("insertHTML")?this._execCommand("insertHTML",e):n.insertNode?(n.deleteContents(),n.insertNode(o(e)[0])):n.pasteHTML&&n.pasteHTML(e)},_insertElem:function(e){var t=this.editor,n=t.selection.getRange();n.insertNode&&(n.deleteContents(),n.insertNode(e[0]))},_execCommand:function(e,t){document.execCommand(e,!1,t)},queryCommandValue:function(e){return document.queryCommandValue(e)},queryCommandState:function(e){return document.queryCommandState(e)},queryCommandSupported:function(e){return document.queryCommandSupported(e)}},P.prototype={constructor:P,getRange:function(){return this._currentRange},saveRange:function(e){if(e)return void(this._currentRange=e);var t=window.getSelection();if(0!==t.rangeCount){var n=t.getRangeAt(0),i=this.getSelectionContainerElem(n);if(i&&"false"!==i.attr("contenteditable")&&!i.parentUntil("[contenteditable=false]")){this.editor.$textElem.isContain(i)&&(this._currentRange=n)}}},collapseRange:function(e){null==e&&(e=!1);var t=this._currentRange;t&&t.collapse(e)},getSelectionText:function(){return this._currentRange?this._currentRange.toString():""},getSelectionContainerElem:function(e){e=e||this._currentRange;var t=void 0;if(e)return t=e.commonAncestorContainer,o(1===t.nodeType?t:t.parentNode)},getSelectionStartElem:function(e){e=e||this._currentRange;var t=void 0;if(e)return t=e.startContainer,o(1===t.nodeType?t:t.parentNode)},getSelectionEndElem:function(e){e=e||this._currentRange;var t=void 0;if(e)return t=e.endContainer,o(1===t.nodeType?t:t.parentNode)},isSelectionEmpty:function(){var e=this._currentRange;return!(!e||!e.startContainer||e.startContainer!==e.endContainer||e.startOffset!==e.endOffset)},restoreSelection:function(){var e=window.getSelection();e.removeAllRanges(),e.addRange(this._currentRange)},createEmptyRange:function(){var e=this.editor,t=this.getRange(),n=void 0;if(t&&this.isSelectionEmpty())try{J.isWebkit()?(e.cmd.do("insertHTML","​"),t.setEnd(t.endContainer,t.endOffset+1),this.saveRange(t)):(n=o(""),e.cmd.do("insertElem",n),this.createRangeByElem(n,!0))}catch(e){}},createRangeByElem:function(e,t,n){if(e.length){var i=e[0],o=document.createRange();n?o.selectNodeContents(i):o.selectNode(i),"boolean"==typeof t&&o.collapse(t),this.saveRange(o)}}},H.prototype={constructor:H,show:function(e){var t=this;if(!this._isShow){this._isShow=!0;var n=this.$bar;if(this._isRender)this._isRender=!0;else{this.$textContainer.append(n)}Date.now()-this._time>100&&e<=1&&(n.css("width",100*e+"%"),this._time=Date.now());var i=this._timeoutId;i&&clearTimeout(i),i=setTimeout(function(){t._hide()},500)}},_hide:function(){this.$bar.remove(),this._time=0,this._isShow=!1,this._isRender=!1}};var X="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};L.prototype={constructor:L,_alert:function(e,t){var n=this.editor,i=n.config.debug,o=n.config.customAlert;if(i)throw new Error("wangEditor: "+(t||e));o&&"function"==typeof o?o(e):alert(e)},insertLinkImg:function(e){var t=this;if(e){var n=this.editor,i=n.config,o=i.linkImgCheck,A=void 0;if(o&&"function"==typeof o&&"string"==typeof(A=o(e)))return void alert(A);n.cmd.do("insertHTML",'');var r=document.createElement("img");r.onload=function(){var t=i.linkImgCallback;t&&"function"==typeof t&&t(e),r=null},r.onerror=function(){r=null,t._alert("插入图片错误",'wangEditor: 插入图片出错,图片链接是 "'+e+'",下载该链接失败')},r.onabort=function(){r=null},r.src=e}},uploadImg:function(e){var t=this;if(e&&e.length){var n=this.editor,i=n.config,o=i.uploadImgServer,c=i.uploadImgShowBase64,a=i.uploadImgMaxSize,s=a/1024/1024,l=i.uploadImgMaxLength||1e4,d=i.uploadFileName||"",u=i.uploadImgParams||{},h=i.uploadImgParamsWithUrl,p=i.uploadImgHeaders||{},f=i.uploadImgHooks||{},m=i.uploadImgTimeout||3e3,g=i.withCredentials;null==g&&(g=!1);var w=i.customUploadImg;if(w||o||c){var v=[],E=[];if(r(e,function(e){var t=e.name,n=e.size;if(t&&n)return!1===/\.(jpg|jpeg|png|bmp|gif|webp)$/i.test(t)?void E.push("【"+t+"】不是图片"):al)return void this._alert("一次最多上传"+l+"张图片");if(w&&"function"==typeof w)return void w(v,this.insertLinkImg.bind(this));var b=new FormData;if(r(v,function(e){var t=d||e.name;b.append(t,e)}),o&&"string"==typeof o){var B=o.split("#");o=B[0];var y=B[1]||"";A(u,function(e,t){h&&(o.indexOf("?")>0?o+="&":o+="?",o=o+e+"="+t),b.append(e,t)}),y&&(o+="#"+y);var C=new XMLHttpRequest;if(C.open("POST",o),C.timeout=m,C.ontimeout=function(){f.timeout&&"function"==typeof f.timeout&&f.timeout(C,n),t._alert("上传图片超时")},C.upload&&(C.upload.onprogress=function(e){var t=void 0,i=new H(n);e.lengthComputable&&(t=e.loaded/e.total,i.show(t))}),C.onreadystatechange=function(){var e=void 0;if(4===C.readyState){if(C.status<200||C.status>=300)return f.error&&"function"==typeof f.error&&f.error(C,n),void t._alert("上传图片发生错误","上传图片发生错误,服务器返回状态是 "+C.status);if(e=C.responseText,"object"!==(void 0===e?"undefined":X(e)))try{e=JSON.parse(e)}catch(i){return f.fail&&"function"==typeof f.fail&&f.fail(C,n,e),void t._alert("上传图片失败","上传图片返回结果错误,返回结果是: "+e)}if(f.customInsert||"0"==e.errno){if(f.customInsert&&"function"==typeof f.customInsert)f.customInsert(t.insertLinkImg.bind(t),e,n);else{(e.data||[]).forEach(function(e){t.insertLinkImg(e)})}f.success&&"function"==typeof f.success&&f.success(C,n,e)}else f.fail&&"function"==typeof f.fail&&f.fail(C,n,e),t._alert("上传图片失败","上传图片返回结果错误,返回结果 errno="+e.errno)}},f.before&&"function"==typeof f.before){var x=f.before(C,n,v);if(x&&"object"===(void 0===x?"undefined":X(x))&&x.prevent)return void this._alert(x.msg)}return A(p,function(e,t){C.setRequestHeader(e,t)}),C.withCredentials=g,void C.send(b)}c&&r(e,function(e){var n=t,i=new FileReader;i.readAsDataURL(e),i.onload=function(){n.insertLinkImg(this.result)}})}}}};var W=1;j.prototype={constructor:j,_initConfig:function(){var e={};this.config=Object.assign(e,z,this.customConfig);var t=this.config.lang||{},n=[];A(t,function(e,t){n.push({reg:new RegExp(e,"img"),val:t})}),this.config.langArgs=n},_initDom:function(){var e=this,t=this.toolbarSelector,n=o(t),i=this.textSelector,A=this.config,r=A.zIndex,a=void 0,s=void 0,l=void 0,d=void 0;null==i?(a=o("
      "),s=o("
      "),d=n.children(),n.append(a).append(s),a.css("background-color","#f1f1f1").css("border","1px solid #ccc"),s.css("border","1px solid #ccc").css("border-top","none").css("height","300px")):(a=n,s=o(i),d=s.children()),l=o("
      "),l.attr("contenteditable","true").css("width","100%").css("height","100%"),d&&d.length?l.append(d):l.append(o("


      ")),s.append(l),a.addClass("w-e-toolbar"),s.addClass("w-e-text-container"),s.css("z-index",r),l.addClass("w-e-text");var u=c("toolbar-elem");a.attr("id",u);var h=c("text-elem");l.attr("id",h),this.$toolbarElem=a,this.$textContainerElem=s,this.$textElem=l,this.toolbarElemId=u,this.textElemId=h;var p=!0;s.on("compositionstart",function(){p=!1}),s.on("compositionend",function(){p=!0}),s.on("click keyup",function(){p&&e.change&&e.change()}),a.on("click",function(){this.change&&this.change()}),(A.onfocus||A.onblur)&&(this.isFocus=!1,o(document).on("click",function(t){var n=l.isContain(o(t.target)),i=a.isContain(o(t.target)),A=a[0]==t.target;if(n)e.isFocus||e.onfocus&&e.onfocus(),e.isFocus=!0;else{if(i&&!A)return;e.isFocus&&e.onblur&&e.onblur(),e.isFocus=!1}}))},_initCommand:function(){this.cmd=new Y(this)},_initSelectionAPI:function(){this.selection=new P(this)},_initUploadImg:function(){this.uploadImg=new L(this)},_initMenus:function(){this.menus=new _(this),this.menus.init()},_initText:function(){this.txt=new U(this),this.txt.init()},initSelection:function(e){var t=this.$textElem,n=t.children();if(!n.length)return t.append(o("


      ")),void this.initSelection();var i=n.last();if(e){var A=i.html().toLowerCase(),r=i.getNodeName();if("
      "!==A&&"
      "!==A||"P"!==r)return t.append(o("


      ")),void this.initSelection()}this.selection.createRangeByElem(i,!1,!0),this.selection.restoreSelection()},_bindEvent:function(){var e=0,t=this.txt.html(),n=this.config,i=n.onchangeTimeout;(!(i=parseInt(i,10))||i<=0)&&(i=200);var o=n.onchange;o&&"function"==typeof o&&(this.change=function(){var n=this.txt.html();n.length===t.length&&n===t||(e&&clearTimeout(e),e=setTimeout(function(){o(n),t=n},i))});var A=n.onblur;A&&"function"==typeof A&&(this.onblur=function(){var e=this.txt.html();A(e)});var r=n.onfocus;r&&"function"==typeof r&&(this.onfocus=function(){r()})},create:function(){this._initConfig(),this._initDom(),this._initCommand(),this._initSelectionAPI(),this._initText(),this._initMenus(),this._initUploadImg(),this.initSelection(!0),this._bindEvent()},_offAllEvent:function(){o.offAll()}};try{document}catch(e){throw new Error("请在浏览器环境下运行")}!function(){"function"!=typeof Object.assign&&(Object.assign=function(e,t){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var n=Object(e),i=1;i=0&&t.item(n)!==this;);return n>-1})}();var Z=document.createElement("style");return Z.type="text/css", 3 | Z.innerHTML='.w-e-toolbar,.w-e-text-container,.w-e-menu-panel { padding: 0; margin: 0; box-sizing: border-box;}.w-e-toolbar *,.w-e-text-container *,.w-e-menu-panel * { padding: 0; margin: 0; box-sizing: border-box;}.w-e-clear-fix:after { content: ""; display: table; clear: both;}.w-e-toolbar .w-e-droplist { position: absolute; left: 0; top: 0; background-color: #fff; border: 1px solid #f1f1f1; border-right-color: #ccc; border-bottom-color: #ccc;}.w-e-toolbar .w-e-droplist .w-e-dp-title { text-align: center; color: #999; line-height: 2; border-bottom: 1px solid #f1f1f1; font-size: 13px;}.w-e-toolbar .w-e-droplist ul.w-e-list { list-style: none; line-height: 1;}.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item { color: #333; padding: 5px 0;}.w-e-toolbar .w-e-droplist ul.w-e-list li.w-e-item:hover { background-color: #f1f1f1;}.w-e-toolbar .w-e-droplist ul.w-e-block { list-style: none; text-align: left; padding: 5px;}.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item { display: inline-block; *display: inline; *zoom: 1; padding: 3px 5px;}.w-e-toolbar .w-e-droplist ul.w-e-block li.w-e-item:hover { background-color: #f1f1f1;}@font-face { font-family: \'w-e-icon\'; src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAABhQAAsAAAAAGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIPBGNtYXAAAAFoAAABBAAAAQQrSf4BZ2FzcAAAAmwAAAAIAAAACAAAABBnbHlmAAACdAAAEvAAABLwfpUWUWhlYWQAABVkAAAANgAAADYQp00kaGhlYQAAFZwAAAAkAAAAJAfEA+FobXR4AAAVwAAAAIQAAACEeAcD7GxvY2EAABZEAAAARAAAAERBSEX+bWF4cAAAFogAAAAgAAAAIAAsALZuYW1lAAAWqAAAAYYAAAGGmUoJ+3Bvc3QAABgwAAAAIAAAACAAAwAAAAMD3gGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA8fwDwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEAOgAAAA2ACAABAAWAAEAIOkG6Q3pEulH6Wbpd+m56bvpxunL6d/qDepc6l/qZepo6nHqefAN8BTxIPHc8fz//f//AAAAAAAg6QbpDekS6UfpZel36bnpu+nG6cvp3+oN6lzqX+pi6mjqcep38A3wFPEg8dzx/P/9//8AAf/jFv4W+Bb0FsAWoxaTFlIWURZHFkMWMBYDFbUVsxWxFa8VpxWiEA8QCQ7+DkMOJAADAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAB//8ADwABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAACAAD/wAQAA8AABAATAAABNwEnAQMuAScTNwEjAQMlATUBBwGAgAHAQP5Anxc7MmOAAYDA/oDAAoABgP6ATgFAQAHAQP5A/p0yOxcBEU4BgP6A/YDAAYDA/oCAAAQAAAAABAADgAAQACEALQA0AAABOAExETgBMSE4ATEROAExITUhIgYVERQWMyEyNjURNCYjBxQGIyImNTQ2MzIWEyE1EwEzNwPA/IADgPyAGiYmGgOAGiYmGoA4KCg4OCgoOED9AOABAEDgA0D9AAMAQCYa/QAaJiYaAwAaJuAoODgoKDg4/biAAYD+wMAAAAIAAABABAADQAA4ADwAAAEmJy4BJyYjIgcOAQcGBwYHDgEHBhUUFx4BFxYXFhceARcWMzI3PgE3Njc2Nz4BNzY1NCcuAScmJwERDQED1TY4OXY8PT8/PTx2OTg2CwcICwMDAwMLCAcLNjg5djw9Pz89PHY5ODYLBwgLAwMDAwsIBwv9qwFA/sADIAgGBggCAgICCAYGCCkqKlktLi8vLi1ZKiopCAYGCAICAgIIBgYIKSoqWS0uLy8uLVkqKin94AGAwMAAAAAAAgDA/8ADQAPAABsAJwAAASIHDgEHBhUUFx4BFxYxMDc+ATc2NTQnLgEnJgMiJjU0NjMyFhUUBgIAQjs6VxkZMjJ4MjIyMngyMhkZVzo7QlBwcFBQcHADwBkZVzo7Qnh9fcxBQUFBzH19eEI7OlcZGf4AcFBQcHBQUHAAAAEAAAAABAADgAArAAABIgcOAQcGBycRISc+ATMyFx4BFxYVFAcOAQcGBxc2Nz4BNzY1NCcuAScmIwIANTIyXCkpI5YBgJA1i1BQRUZpHh4JCSIYGB5VKCAgLQwMKCiLXl1qA4AKCycbHCOW/oCQNDweHmlGRVArKClJICEaYCMrK2I2NjlqXV6LKCgAAQAAAAAEAAOAACoAABMUFx4BFxYXNyYnLgEnJjU0Nz4BNzYzMhYXByERByYnLgEnJiMiBw4BBwYADAwtICAoVR4YGCIJCR4eaUZFUFCLNZABgJYjKSlcMjI1al1eiygoAYA5NjZiKysjYBohIEkpKCtQRUZpHh48NJABgJYjHBsnCwooKIteXQAAAAACAAAAQAQBAwAAJgBNAAATMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgEhMhceARcWFRQHDgEHBiMiJy4BJyY1JzQ3PgE3NjMVIgYHDgEHPgHhLikpPRESEhE9KSkuLikpPRESASMjelJRXUB1LQkQBwgSAkkuKSk9ERISET0pKS4uKSk9ERIBIyN6UlFdQHUtCRAHCBICABIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCARIRPSkpLi4pKT0REhIRPSkpLiBdUVJ6IyOAMC4IEwoCAQAABgBA/8AEAAPAAAMABwALABEAHQApAAAlIRUhESEVIREhFSEnESM1IzUTFTMVIzU3NSM1MxUVESM1MzUjNTM1IzUBgAKA/YACgP2AAoD9gMBAQECAwICAwMCAgICAgIACAIACAIDA/wDAQP3yMkCSPDJAku7+wEBAQEBAAAYAAP/ABAADwAADAAcACwAXACMALwAAASEVIREhFSERIRUhATQ2MzIWFRQGIyImETQ2MzIWFRQGIyImETQ2MzIWFRQGIyImAYACgP2AAoD9gAKA/YD+gEs1NUtLNTVLSzU1S0s1NUtLNTVLSzU1SwOAgP8AgP8AgANANUtLNTVLS/61NUtLNTVLS/61NUtLNTVLSwADAAAAAAQAA6AAAwANABQAADchFSElFSE1EyEVITUhJQkBIxEjEQAEAPwABAD8AIABAAEAAQD9YAEgASDggEBAwEBAAQCAgMABIP7g/wABAAAAAAACAB7/zAPiA7QAMwBkAAABIiYnJicmNDc2PwE+ATMyFhcWFxYUBwYPAQYiJyY0PwE2NCcuASMiBg8BBhQXFhQHDgEjAyImJyYnJjQ3Nj8BNjIXFhQPAQYUFx4BMzI2PwE2NCcmNDc2MhcWFxYUBwYPAQ4BIwG4ChMIIxISEhIjwCNZMTFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PCBMKuDFZIyMSEhISI1gPLA8PD1gpKRQzHBwzFMApKQ8PDysQIxISEhIjwCNZMQFECAckLS1eLS0kwCIlJSIkLS1eLS0kVxAQDysPWCl0KRQVFRTAKXQpDysQBwj+iCUiJC0tXi0tJFcQEA8rD1gpdCkUFRUUwCl0KQ8rEA8PJC0tXi0tJMAiJQAAAAAFAAD/wAQAA8AAGwA3AFMAXwBrAAAFMjc+ATc2NTQnLgEnJiMiBw4BBwYVFBceARcWEzIXHgEXFhUUBw4BBwYjIicuAScmNTQ3PgE3NhMyNz4BNzY3BgcOAQcGIyInLgEnJicWFx4BFxYnNDYzMhYVFAYjIiYlNDYzMhYVFAYjIiYCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMVisrKlEmJiMFHBtWODc/Pzc4VhscBSMmJlEqK9UlGxslJRsbJQGAJRsbJSUbGyVAKCiLXl1qal1eiygoKCiLXl1qal1eiygoA6AhIHFMTFZWTExxICEhIHFMTFZWTExxICH+CQYGFRAQFEM6OlYYGRkYVjo6QxQQEBUGBvcoODgoKDg4KCg4OCgoODgAAAMAAP/ABAADwAAbADcAQwAAASIHDgEHBhUUFx4BFxYzMjc+ATc2NTQnLgEnJgMiJy4BJyY1NDc+ATc2MzIXHgEXFhUUBw4BBwYTBycHFwcXNxc3JzcCAGpdXosoKCgoi15dampdXosoKCgoi15dalZMTHEgISEgcUxMVlZMTHEgISEgcUxMSqCgYKCgYKCgYKCgA8AoKIteXWpqXV6LKCgoKIteXWpqXV6LKCj8YCEgcUxMVlZMTHEgISEgcUxMVlZMTHEgIQKgoKBgoKBgoKBgoKAAAQBl/8ADmwPAACkAAAEiJiMiBw4BBwYVFBYzLgE1NDY3MAcGAgcGBxUhEzM3IzceATMyNjcOAQMgRGhGcVNUbRobSUgGDWVKEBBLPDxZAT1sxizXNC1VJi5QGB09A7AQHh1hPj9BTTsLJjeZbwN9fv7Fj5AjGQIAgPYJDzdrCQcAAAAAAgAAAAAEAAOAAAkAFwAAJTMHJzMRIzcXIyURJyMRMxUhNTMRIwcRA4CAoKCAgKCggP8AQMCA/oCAwEDAwMACAMDAwP8AgP1AQEACwIABAAADAMAAAANAA4AAFgAfACgAAAE+ATU0Jy4BJyYjIREhMjc+ATc2NTQmATMyFhUUBisBEyMRMzIWFRQGAsQcIBQURi4vNf7AAYA1Ly5GFBRE/oRlKjw8KWafn58sPj4B2yJULzUvLkYUFPyAFBRGLi81RnQBRks1NUv+gAEASzU1SwAAAAACAMAAAANAA4AAHwAjAAABMxEUBw4BBwYjIicuAScmNREzERQWFx4BMzI2Nz4BNQEhFSECwIAZGVc6O0JCOzpXGRmAGxgcSSgoSRwYG/4AAoD9gAOA/mA8NDVOFhcXFk41NDwBoP5gHjgXGBsbGBc4Hv6ggAAAAAABAIAAAAOAA4AACwAAARUjATMVITUzASM1A4CA/sCA/kCAAUCAA4BA/QBAQAMAQAABAAAAAAQAA4AAPQAAARUjHgEVFAYHDgEjIiYnLgE1MxQWMzI2NTQmIyE1IS4BJy4BNTQ2Nz4BMzIWFx4BFSM0JiMiBhUUFjMyFhcEAOsVFjUwLHE+PnEsMDWAck5OcnJO/gABLAIEATA1NTAscT4+cSwwNYByTk5yck47bisBwEAdQSI1YiQhJCQhJGI1NExMNDRMQAEDASRiNTViJCEkJCEkYjU0TEw0NEwhHwAAAAcAAP/ABAADwAADAAcACwAPABMAGwAjAAATMxUjNzMVIyUzFSM3MxUjJTMVIwMTIRMzEyETAQMhAyMDIQMAgIDAwMABAICAwMDAAQCAgBAQ/QAQIBACgBD9QBADABAgEP2AEAHAQEBAQEBAQEBAAkD+QAHA/oABgPwAAYD+gAFA/sAAAAoAAAAABAADgAADAAcACwAPABMAFwAbAB8AIwAnAAATESERATUhFR0BITUBFSE1IxUhNREhFSElIRUhETUhFQEhFSEhNSEVAAQA/YABAP8AAQD/AED/AAEA/wACgAEA/wABAPyAAQD/AAKAAQADgPyAA4D9wMDAQMDAAgDAwMDA/wDAwMABAMDA/sDAwMAAAAUAAAAABAADgAADAAcACwAPABMAABMhFSEVIRUhESEVIREhFSERIRUhAAQA/AACgP2AAoD9gAQA/AAEAPwAA4CAQID/AIABQID/AIAAAAAABQAAAAAEAAOAAAMABwALAA8AEwAAEyEVIRchFSERIRUhAyEVIREhFSEABAD8AMACgP2AAoD9gMAEAPwABAD8AAOAgECA/wCAAUCA/wCAAAAFAAAAAAQAA4AAAwAHAAsADwATAAATIRUhBSEVIREhFSEBIRUhESEVIQAEAPwAAYACgP2AAoD9gP6ABAD8AAQA/AADgIBAgP8AgAFAgP8AgAAAAAABAD8APwLmAuYALAAAJRQPAQYjIi8BBwYjIi8BJjU0PwEnJjU0PwE2MzIfATc2MzIfARYVFA8BFxYVAuYQThAXFxCoqBAXFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBDDFhBOEBCoqBAQThAWFxCoqBAXFxBOEBCoqBAQThAXFxCoqBAXAAAABgAAAAADJQNuABQAKAA8AE0AVQCCAAABERQHBisBIicmNRE0NzY7ATIXFhUzERQHBisBIicmNRE0NzY7ATIXFhcRFAcGKwEiJyY1ETQ3NjsBMhcWExEhERQXFhcWMyEyNzY3NjUBIScmJyMGBwUVFAcGKwERFAcGIyEiJyY1ESMiJyY9ATQ3NjsBNzY3NjsBMhcWHwEzMhcWFQElBgUIJAgFBgYFCCQIBQaSBQUIJQgFBQUFCCUIBQWSBQUIJQgFBQUFCCUIBQVJ/gAEBAUEAgHbAgQEBAT+gAEAGwQGtQYEAfcGBQg3Ghsm/iUmGxs3CAUFBQUIsSgIFxYXtxcWFgkosAgFBgIS/rcIBQUFBQgBSQgFBgYFCP63CAUFBQUIAUkIBQYGBQj+twgFBQUFCAFJCAUGBgX+WwId/eMNCwoFBQUFCgsNAmZDBQICBVUkCAYF/eMwIiMhIi8CIAUGCCQIBQVgFQ8PDw8VYAUFCAACAAcASQO3Aq8AGgAuAAAJAQYjIi8BJjU0PwEnJjU0PwE2MzIXARYVFAcBFRQHBiMhIicmPQE0NzYzITIXFgFO/vYGBwgFHQYG4eEGBh0FCAcGAQoGBgJpBQUI/dsIBQUFBQgCJQgFBQGF/vYGBhwGCAcG4OEGBwcGHQUF/vUFCAcG/vslCAUFBQUIJQgFBQUFAAAAAQAjAAAD3QNuALMAACUiJyYjIgcGIyInJjU0NzY3Njc2NzY9ATQnJiMhIgcGHQEUFxYXFjMWFxYVFAcGIyInJiMiBwYjIicmNTQ3Njc2NzY3Nj0BETQ1NDU0JzQnJicmJyYnJicmIyInJjU0NzYzMhcWMzI3NjMyFxYVFAcGIwYHBgcGHQEUFxYzITI3Nj0BNCcmJyYnJjU0NzYzMhcWMzI3NjMyFxYVFAcGByIHBgcGFREUFxYXFhcyFxYVFAcGIwPBGTMyGhkyMxkNCAcJCg0MERAKEgEHFf5+FgcBFQkSEw4ODAsHBw4bNTUaGDExGA0HBwkJCwwQDwkSAQIBAgMEBAUIEhENDQoLBwcOGjU1GhgwMRgOBwcJCgwNEBAIFAEHDwGQDgcBFAoXFw8OBwcOGTMyGRkxMRkOBwcKCg0NEBEIFBQJEREODQoLBwcOAAICAgIMCw8RCQkBAQMDBQxE4AwFAwMFDNRRDQYBAgEICBIPDA0CAgICDAwOEQgJAQIDAwUNRSEB0AINDQgIDg4KCgsLBwcDBgEBCAgSDwwNAgICAg0MDxEICAECAQYMULYMBwEBBwy2UAwGAQEGBxYPDA0CAgICDQwPEQgIAQECBg1P/eZEDAYCAgEJCBEPDA0AAAIAAP+3A/8DtwATADkAAAEyFxYVFAcCBwYjIicmNTQ3ATYzARYXFh8BFgcGIyInJicmJyY1FhcWFxYXFjMyNzY3Njc2NzY3NjcDmygeHhq+TDdFSDQ0NQFtISn9+BcmJy8BAkxMe0c2NiEhEBEEExQQEBIRCRcIDxITFRUdHR4eKQO3GxooJDP+mUY0NTRJSTABSx/9sSsfHw0oek1MGhsuLzo6RAMPDgsLCgoWJRsaEREKCwQEAgABAAAAAAAA9evv618PPPUACwQAAAAAANbEBFgAAAAA1sQEWAAA/7cEAQPAAAAACAACAAAAAAAAAAEAAAPA/8AAAAQAAAD//wQBAAEAAAAAAAAAAAAAAAAAAAAhBAAAAAAAAAAAAAAAAgAAAAQAAAAEAAAABAAAAAQAAMAEAAAABAAAAAQAAAAEAABABAAAAAQAAAAEAAAeBAAAAAQAAAAEAABlBAAAAAQAAMAEAADABAAAgAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAMlAD8DJQAAA74ABwQAACMD/wAAAAAAAAAKABQAHgBMAJQA+AE2AXwBwgI2AnQCvgLoA34EHgSIBMoE8gU0BXAFiAXgBiIGagaSBroG5AcoB+AIKgkcCXgAAQAAACEAtAAKAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAA4ArgABAAAAAAABAAcAAAABAAAAAAACAAcAYAABAAAAAAADAAcANgABAAAAAAAEAAcAdQABAAAAAAAFAAsAFQABAAAAAAAGAAcASwABAAAAAAAKABoAigADAAEECQABAA4ABwADAAEECQACAA4AZwADAAEECQADAA4APQADAAEECQAEAA4AfAADAAEECQAFABYAIAADAAEECQAGAA4AUgADAAEECQAKADQApGljb21vb24AaQBjAG8AbQBvAG8AblZlcnNpb24gMS4wAFYAZQByAHMAaQBvAG4AIAAxAC4AMGljb21vb24AaQBjAG8AbQBvAG8Abmljb21vb24AaQBjAG8AbQBvAG8AblJlZ3VsYXIAUgBlAGcAdQBsAGEAcmljb21vb24AaQBjAG8AbQBvAG8AbkZvbnQgZ2VuZXJhdGVkIGJ5IEljb01vb24uAEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAEkAYwBvAE0AbwBvAG4ALgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) format(\'truetype\'); font-weight: normal; font-style: normal;}[class^="w-e-icon-"],[class*=" w-e-icon-"] { /* use !important to prevent issues with browser extensions that change fonts */ font-family: \'w-e-icon\' !important; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; /* Better Font Rendering =========== */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;}.w-e-icon-close:before { content: "\\f00d";}.w-e-icon-upload2:before { content: "\\e9c6";}.w-e-icon-trash-o:before { content: "\\f014";}.w-e-icon-header:before { content: "\\f1dc";}.w-e-icon-pencil2:before { content: "\\e906";}.w-e-icon-paint-brush:before { content: "\\f1fc";}.w-e-icon-image:before { content: "\\e90d";}.w-e-icon-play:before { content: "\\e912";}.w-e-icon-location:before { content: "\\e947";}.w-e-icon-undo:before { content: "\\e965";}.w-e-icon-redo:before { content: "\\e966";}.w-e-icon-quotes-left:before { content: "\\e977";}.w-e-icon-list-numbered:before { content: "\\e9b9";}.w-e-icon-list2:before { content: "\\e9bb";}.w-e-icon-link:before { content: "\\e9cb";}.w-e-icon-happy:before { content: "\\e9df";}.w-e-icon-bold:before { content: "\\ea62";}.w-e-icon-underline:before { content: "\\ea63";}.w-e-icon-italic:before { content: "\\ea64";}.w-e-icon-strikethrough:before { content: "\\ea65";}.w-e-icon-table2:before { content: "\\ea71";}.w-e-icon-paragraph-left:before { content: "\\ea77";}.w-e-icon-paragraph-center:before { content: "\\ea78";}.w-e-icon-paragraph-right:before { content: "\\ea79";}.w-e-icon-terminal:before { content: "\\f120";}.w-e-icon-page-break:before { content: "\\ea68";}.w-e-icon-cancel-circle:before { content: "\\ea0d";}.w-e-icon-font:before { content: "\\ea5c";}.w-e-icon-text-heigh:before { content: "\\ea5f";}.w-e-toolbar { display: -webkit-box; display: -ms-flexbox; display: flex; padding: 0 5px; /* flex-wrap: wrap; */ /* 单个菜单 */}.w-e-toolbar .w-e-menu { position: relative; text-align: center; padding: 5px 10px; cursor: pointer;}.w-e-toolbar .w-e-menu i { color: #999;}.w-e-toolbar .w-e-menu:hover i { color: #333;}.w-e-toolbar .w-e-active i { color: #1e88e5;}.w-e-toolbar .w-e-active:hover i { color: #1e88e5;}.w-e-text-container .w-e-panel-container { position: absolute; top: 0; left: 50%; border: 1px solid #ccc; border-top: 0; box-shadow: 1px 1px 2px #ccc; color: #333; background-color: #fff; /* 为 emotion panel 定制的样式 */ /* 上传图片的 panel 定制样式 */}.w-e-text-container .w-e-panel-container .w-e-panel-close { position: absolute; right: 0; top: 0; padding: 5px; margin: 2px 5px 0 0; cursor: pointer; color: #999;}.w-e-text-container .w-e-panel-container .w-e-panel-close:hover { color: #333;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title { list-style: none; display: -webkit-box; display: -ms-flexbox; display: flex; font-size: 14px; margin: 2px 10px 0 10px; border-bottom: 1px solid #f1f1f1;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-item { padding: 3px 5px; color: #999; cursor: pointer; margin: 0 3px; position: relative; top: 1px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-title .w-e-active { color: #333; border-bottom: 1px solid #333; cursor: default; font-weight: 700;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content { padding: 10px 15px 10px 15px; font-size: 16px; /* 输入框的样式 */ /* 按钮的样式 */}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input:focus,.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus,.w-e-text-container .w-e-panel-container .w-e-panel-tab-content button:focus { outline: none;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea { width: 100%; border: 1px solid #ccc; padding: 5px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content textarea:focus { border-color: #1e88e5;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text] { border: none; border-bottom: 1px solid #ccc; font-size: 14px; height: 20px; color: #333; text-align: left;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].small { width: 30px; text-align: center;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text].block { display: block; width: 100%; margin: 10px 0;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content input[type=text]:focus { border-bottom: 2px solid #1e88e5;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button { font-size: 14px; color: #1e88e5; border: none; padding: 5px 10px; background-color: #fff; cursor: pointer; border-radius: 3px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.left { float: left; margin-right: 10px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.right { float: right; margin-left: 10px;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.gray { color: #999;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button.red { color: #c24f4a;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container button:hover { background-color: #f1f1f1;}.w-e-text-container .w-e-panel-container .w-e-panel-tab-content .w-e-button-container:after { content: ""; display: table; clear: both;}.w-e-text-container .w-e-panel-container .w-e-emoticon-container .w-e-item { cursor: pointer; font-size: 18px; padding: 0 3px; display: inline-block; *display: inline; *zoom: 1;}.w-e-text-container .w-e-panel-container .w-e-up-img-container { text-align: center;}.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn { display: inline-block; *display: inline; *zoom: 1; color: #999; cursor: pointer; font-size: 60px; line-height: 1;}.w-e-text-container .w-e-panel-container .w-e-up-img-container .w-e-up-btn:hover { color: #333;}.w-e-text-container { position: relative;}.w-e-text-container .w-e-progress { position: absolute; background-color: #1e88e5; bottom: 0; left: 0; height: 1px;}.w-e-text { padding: 0 10px; overflow-y: scroll;}.w-e-text p,.w-e-text h1,.w-e-text h2,.w-e-text h3,.w-e-text h4,.w-e-text h5,.w-e-text table,.w-e-text pre { margin: 10px 0; line-height: 1.5;}.w-e-text ul,.w-e-text ol { margin: 10px 0 10px 20px;}.w-e-text blockquote { display: block; border-left: 8px solid #d0e5f2; padding: 5px 10px; margin: 10px 0; line-height: 1.4; font-size: 100%; background-color: #f1f1f1;}.w-e-text code { display: inline-block; *display: inline; *zoom: 1; background-color: #f1f1f1; border-radius: 3px; padding: 3px 5px; margin: 0 3px;}.w-e-text pre code { display: block;}.w-e-text table { border-top: 1px solid #ccc; border-left: 1px solid #ccc;}.w-e-text table td,.w-e-text table th { border-bottom: 1px solid #ccc; border-right: 1px solid #ccc; padding: 3px 5px;}.w-e-text table th { border-bottom: 2px solid #ccc; text-align: center;}.w-e-text:focus { outline: none;}.w-e-text img { cursor: pointer;}.w-e-text img:hover { box-shadow: 0 0 5px #333;}',document.getElementsByTagName("HEAD").item(0).appendChild(Z),window.wangEditor||j}); 4 | //# sourceMappingURL=wangEditor.min.js.map 5 | -------------------------------------------------------------------------------- /src/main/resources/templates/consumerSocket.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 在线咨询 7 | 8 | 9 | 10 | 11 | 12 | 13 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |
      210 |
      211 |
      易网通星级客服工号13360061080正在为您服务
      212 |
      213 | 214 |
      215 |
      216 |
      217 | 218 | 219 |
      220 | 221 |
      222 | 223 | 224 |
      225 |
      226 |
      227 |
      228 | 229 | 230 |
      231 | 232 |
      233 | 234 |
      235 | 236 | 237 |
      238 | 239 |
      240 | 241 | 242 |
      243 |
      244 | 246 |
      247 |
      248 |
      249 | 250 |
      251 | 252 | 253 |
      254 |
      255 | 256 |
      257 |
      258 | 欢迎您的光临,我们将竭诚为您服务! 259 |
      260 |
      261 |
      262 | 263 | 264 | 265 | -------------------------------------------------------------------------------- /src/main/resources/templates/customerSocket.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 客服 7 | 8 | 9 | 10 | 11 | 12 | 13 | 208 | 209 | 210 | 211 | 212 | 213 |
      214 |
      215 |
      易网通在线客服系统
      216 |
      217 |
      218 |
      219 | 220 |
      221 | 222 | 223 |
      224 | 225 | 226 |
      227 | 228 | 229 |
      230 |
      231 | 232 | 233 |
      234 | 235 |
      236 |
      237 | 238 | 239 |
      240 | 241 | 242 |
      243 |
      244 | 246 |
      247 |
      248 | 249 |
      250 | 251 |
      252 |
      253 | 254 | -------------------------------------------------------------------------------- /src/main/resources/templates/editAd.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 编辑广告 8 | 9 | 10 | 11 | 12 | 13 |
      14 |
      15 |
      16 |
      17 | 18 | 19 |
      20 | 21 | 22 | 23 | 80 | -------------------------------------------------------------------------------- /src/main/resources/templates/editReply.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 编辑回复 8 | 9 | 10 | 11 | 12 |
      13 |

      14 |
      15 |
      16 | 17 | 18 |
      19 | 20 | 21 | 69 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 在线客服控制台 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 |
      23 | 24 |

      OnlineCustomerService Monitoring

      25 | 26 |
      27 |

      System:

      28 | startup time:; 29 | survival time:; 30 | total customer:; 31 | total consumer:; 32 |
      33 | 34 | 35 |
      36 |

      Customer:

      37 | online: 38 |
      39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
      session IdOnline timecurrent numbertotal numbertotal duration
      60 |
      61 |
      62 | 63 |
      64 |

      Consumer:

      65 | online: 66 |
      67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
      session Idonline timecustomer session idconsultation durationoperation
      88 |
      89 |
      90 | 91 |
      92 |

      setting:

      93 | Advertisement: 94 | 98 | ; 99 | AutoReply: 100 | 104 | 105 |
      106 |
      107 | 108 | 109 | -------------------------------------------------------------------------------- /src/test/java/com/hg/WebCustomerServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.hg; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class WebCustomerServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------