NaiboWang-Alienware пре 3 година
родитељ
комит
3646513d5b
73 измењених фајлова са 4857 додато и 533 уклоњено
  1. 7 0
      .gitignore
  2. 2 0
      ExcuteStage/.gitignore
  3. 2 0
      ExcuteStage/Readme.md
  4. 147 98
      ExcuteStage/ServiceWrapper_ExcuteStage.py
  5. BIN
      Extension/ServiceWrapper.crx
  6. 26 26
      Extension/ServiceWrapper.pem
  7. 1 1
      Extension/ServiceWrapper/scripts/baozhuangscript.js
  8. 180 180
      Extension/ServiceWrapper/scripts/contentscript.js
  9. 1 1
      Extension/ServiceWrapper/scripts/messageInteraction.js
  10. 674 0
      LICENSE
  11. 134 10
      Readme.md
  12. 3 0
      ServiceGrid/backEnd/.gitignore
  13. 1 0
      ServiceGrid/backEnd/backEnd/.gitignore
  14. 1 0
      ServiceGrid/backEnd/backEnd/settings.py
  15. 0 2
      ServiceGrid/backEnd/backEnd/urls.py
  16. 44 31
      ServiceGrid/backEnd/backEnd/view.py
  17. BIN
      ServiceGrid/backEnd/db.sqlite3
  18. 40 0
      ServiceGrid/backEnd/server.conf
  19. 92 68
      ServiceGrid/frontEnd/FlowChart.html
  20. 20 20
      ServiceGrid/frontEnd/FlowChart.js
  21. 277 0
      ServiceGrid/frontEnd/FlowChart_CN.html
  22. 561 0
      ServiceGrid/frontEnd/FlowChart_CN.js
  23. 22 21
      ServiceGrid/frontEnd/invokeService.html
  24. 43 26
      ServiceGrid/frontEnd/logic.js
  25. 335 0
      ServiceGrid/frontEnd/logic_CN.js
  26. 4 4
      ServiceGrid/frontEnd/newService.html
  27. 33 32
      ServiceGrid/frontEnd/serviceInfo.html
  28. 17 13
      ServiceGrid/frontEnd/serviceList.html
  29. 1 0
      ServiceGrid/static/.gitattributes
  30. 2 0
      ServiceWrapperEntry/.gitignore
  31. 11 0
      ServiceWrapperEntry/Readme.md
  32. 25 0
      ServiceWrapperEntry/ServiceWrapperEntry.sln
  33. 1 0
      ServiceWrapperEntry/ServiceWrapperEntry/.gitignore
  34. 6 0
      ServiceWrapperEntry/ServiceWrapperEntry/App.config
  35. 174 0
      ServiceWrapperEntry/ServiceWrapperEntry/Class1.cs
  36. 88 0
      ServiceWrapperEntry/ServiceWrapperEntry/Flow.Designer.cs
  37. 119 0
      ServiceWrapperEntry/ServiceWrapperEntry/Flow.cs
  38. 408 0
      ServiceWrapperEntry/ServiceWrapperEntry/Flow.resx
  39. 99 0
      ServiceWrapperEntry/ServiceWrapperEntry/Program.cs
  40. 36 0
      ServiceWrapperEntry/ServiceWrapperEntry/Properties/AssemblyInfo.cs
  41. 63 0
      ServiceWrapperEntry/ServiceWrapperEntry/Properties/Resources.Designer.cs
  42. 117 0
      ServiceWrapperEntry/ServiceWrapperEntry/Properties/Resources.resx
  43. 26 0
      ServiceWrapperEntry/ServiceWrapperEntry/Properties/Settings.Designer.cs
  44. 7 0
      ServiceWrapperEntry/ServiceWrapperEntry/Properties/Settings.settings
  45. 32 0
      ServiceWrapperEntry/ServiceWrapperEntry/PublicVariable.cs
  46. 179 0
      ServiceWrapperEntry/ServiceWrapperEntry/ServiceWrapperEntry.csproj
  47. 13 0
      ServiceWrapperEntry/ServiceWrapperEntry/ServiceWrapperEntry.csproj.user
  48. 107 0
      ServiceWrapperEntry/ServiceWrapperEntry/Start.Designer.cs
  49. 256 0
      ServiceWrapperEntry/ServiceWrapperEntry/Start.cs
  50. 408 0
      ServiceWrapperEntry/ServiceWrapperEntry/Start.resx
  51. 2 0
      ServiceWrapperEntry/ServiceWrapperEntry/bin/x64/Debug/.gitignore
  52. BIN
      ServiceWrapperEntry/ServiceWrapperEntry/favicon.ico
  53. 10 0
      ServiceWrapperEntry/ServiceWrapperEntry/packages.config
  54. BIN
      media/Picture.png
  55. BIN
      media/Picture1.png
  56. BIN
      media/Picture10.png
  57. BIN
      media/Picture11.png
  58. BIN
      media/Picture12.png
  59. BIN
      media/Picture13.png
  60. BIN
      media/Picture14.png
  61. BIN
      media/Picture15.png
  62. BIN
      media/Picture16.png
  63. BIN
      media/Picture17.png
  64. BIN
      media/Picture18.png
  65. BIN
      media/Picture2.png
  66. BIN
      media/Picture4.png
  67. BIN
      media/Picture5.png
  68. BIN
      media/Picture6.png
  69. BIN
      media/Picture7.png
  70. BIN
      media/Picture8.png
  71. BIN
      media/Picture9.png
  72. BIN
      media/Picture90.png
  73. BIN
      media/Picture91.png

+ 7 - 0
.gitignore

@@ -1,2 +1,9 @@
 .idea/
 node_modules/
+ServiceWrapper/
+Data/
+/GPUCache
+*.exe
+*.ini
+*.7z
+*.mp4

+ 2 - 0
ExcuteStage/.gitignore

@@ -7,3 +7,5 @@ dist/
 build/
 __pycache__/
 *.spec
+Chrome/
+Data/

+ 2 - 0
ExcuteStage/Readme.md

@@ -0,0 +1,2 @@
+pyinstaller -F --icon=favicon.ico ServiceWrapper_ExcuteStage.py
+出现permission denied请关闭杀毒软件

+ 147 - 98
ExcuteStage/ServiceWrapper_ExcuteStage.py

@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+import atexit  # 遇到错误退出时应执行的代码
 import json
 import re
 import sys
@@ -17,21 +18,32 @@ from selenium.webdriver.common.by import By
 from selenium.common.exceptions import NoSuchElementException
 from selenium.common.exceptions import TimeoutException
 from selenium.common.exceptions import StaleElementReferenceException
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
 import random
 import numpy
 import csv
 import os
+from selenium.webdriver.common.by import By
+
+
+saveName, log, OUTPUT, browser, SAVED = None, "", "", None, False
+
+desired_capabilities = DesiredCapabilities.CHROME
+desired_capabilities["pageLoadStrategy"] = "none"
+
 
 class Time:
-    def __init__(self,type1=""):
-        self.t =  int(round(time.time() * 1000))
+    def __init__(self, type1=""):
+        self.t = int(round(time.time() * 1000))
         self.type = type1
-    
+
     def end(self):
         at = int(round(time.time() * 1000))
         Log(str(self.type)+":"+str(at-self.t))
 
 # 记录log
+
+
 def recordLog(str=""):
     global log
     log = log + str + "\n"
@@ -43,17 +55,48 @@ def Log(text, text2=""):
     if switch:
         print(text, text2)
 
+# 屏幕滚动函数
+
+
+def scrollDown(para, rt=""):
+    try:
+        if para["scrollType"] != 0 and para["scrollCount"] > 0:  # 控制屏幕向下滚动
+            for i in range(para["scrollCount"]):
+                time.sleep(1)  # 下拉完等1秒
+                Log("下拉完等待1秒")
+                body = browser.find_element_by_css_selector("body")
+                if para["scrollType"] == 1:
+                    body.send_keys(Keys.PGDN)
+                else:
+                    body.send_keys(Keys.END)
+    except TimeoutException:
+        Log('time out after 10 seconds when scrolling. ')
+        recordLog('time out after 10 seconds when scrolling')
+        browser.execute_script('window.stop()')
+        if para["scrollType"] != 0 and para["scrollCount"] > 0:  # 控制屏幕向下滚动
+            for i in range(para["scrollCount"]):
+                time.sleep(1)  # 下拉完等1秒
+                Log("下拉完等待1秒")
+                body = browser.find_element_by_css_selector("body")
+                if para["scrollType"] == 1:
+                    body.send_keys(Keys.PGDN)
+                else:
+                    body.send_keys(Keys.END)
+        if rt != "":
+            rt.end()
+
 
 # 执行节点关键函数部分
 def excuteNode(nodeId, loopValue="", clickPath="", index=0):
     node = procedure[nodeId]
     WebDriverWait(browser, 10).until
-    (EC.visibility_of_element_located((By.XPATH, node["parameters"]["xpath"])))  # 等待元素出现才进行操作,10秒内未出现则报错
+    # 等待元素出现才进行操作,10秒内未出现则报错
+    (EC.visibility_of_element_located((By.XPATH, node["parameters"]["xpath"])))
 
     # 根据不同选项执行不同操作
     if node["option"] == 0 or node["option"] == 10:  # root操作,条件分支操作
         for i in node["sequence"]:  # 从根节点开始向下读取
-            excuteNode(i, loopValue,clickPath,index)
+            excuteNode(i, loopValue, clickPath, index)
     elif node["option"] == 1:  # 打开网页操作
         recordLog("openPage")
         openPage(node["parameters"], loopValue)
@@ -67,10 +110,10 @@ def excuteNode(nodeId, loopValue="", clickPath="", index=0):
         inputInfo(node["parameters"], loopValue)
     elif node["option"] == 8:  # 循环
         recordLog("loop")
-        loopExcute(node, loopValue,clickPath,index)  # 执行循环
+        loopExcute(node, loopValue, clickPath, index)  # 执行循环
     elif node["option"] == 9:  # 条件分支
         recordLog("judge")
-        judgeExcute(node, loopValue,clickPath,index)
+        judgeExcute(node, loopValue, clickPath, index)
 
     # 执行完之后进行等待
     if node["option"] != 0:
@@ -82,7 +125,7 @@ def excuteNode(nodeId, loopValue="", clickPath="", index=0):
 
 
 # 对判断条件的处理
-def judgeExcute(node, loopElement,clickPath="",index=0):
+def judgeExcute(node, loopElement, clickPath="", index=0):
     rt = Time("条件判断")
     global bodyText  # 引入bodyText
     excuteBranchId = 0  # 要执行的BranchId
@@ -101,7 +144,7 @@ def judgeExcute(node, loopElement,clickPath="",index=0):
                 continue
         elif tType == 2:  # 当前页面包含元素
             try:
-                if browser.find_element_by_xpath(cnode["parameters"]["value"]):
+                if browser.find_element(By.XPATH, cnode["parameters"]["value"]):
                     excuteBranchId = i
                     break
             except:  # 找不到元素或者xpath写错了,下一个条件
@@ -115,22 +158,23 @@ def judgeExcute(node, loopElement,clickPath="",index=0):
                 continue
         elif tType == 4:  # 当前循环元素包括元素
             try:
-                if loopElement.find_element_by_xpath(cnode["parameters"]["value"][1:]):
+                if loopElement.find_element(By.XPATH, cnode["parameters"]["value"][1:]):
                     excuteBranchId = i
                     break
             except:  # 找不到元素或者xpath写错了,下一个条件
                 continue
     rt.end()
-    excuteNode(excuteBranchId, loopElement,clickPath,index)
+    excuteNode(excuteBranchId, loopElement, clickPath, index)
 
 
 # 对循环的处理
-def loopExcute(node, loopValue,clickPath="",index=0):
+def loopExcute(node, loopValue, clickPath="", index=0):
     time.sleep(0.1)  # 第一次执行循环的时候强制等待1秒
     Log("循环执行前等待0.1秒")
     global history
     thisHandle = browser.current_window_handle  # 记录本次循环内的标签页的ID
-    thisHistoryLength = browser.execute_script('return history.length')  # 记录本次循环内的history的length
+    thisHistoryLength = browser.execute_script(
+        'return history.length')  # 记录本次循环内的history的length
     history["index"] = thisHistoryLength
     history["handle"] = thisHandle
 
@@ -139,9 +183,10 @@ def loopExcute(node, loopValue,clickPath="",index=0):
         count = 0  # 执行次数
         while True:  # do while循环
             try:
-                element = browser.find_element_by_xpath(node["parameters"]["xpath"])
+                element = browser.find_element(By.XPATH,
+                                               node["parameters"]["xpath"])
                 for i in node["sequence"]:  # 挨个执行操作
-                    excuteNode(i, element, node["parameters"]["xpath"],0)
+                    excuteNode(i, element, node["parameters"]["xpath"], 0)
                 Log("click: ", node["parameters"]["xpath"])
                 recordLog("click:" + node["parameters"]["xpath"])
             except NoSuchElementException:
@@ -153,14 +198,17 @@ def loopExcute(node, loopValue,clickPath="",index=0):
             count = count + 1
             Log("页数:", count)
             recordLog("页数:" + str(count))
+            # print(node["parameters"]["exitCount"], "-------")
             if node["parameters"]["exitCount"] == count:  # 如果达到设置的退出循环条件的话
                 break
     elif int(node["parameters"]["loopType"]) == 1:  # 不固定元素列表
         try:
-            elements = browser.find_elements_by_xpath(node["parameters"]["xpath"])
+            elements = browser.find_elements(By.XPATH,
+                                             node["parameters"]["xpath"])
             for index in range(len(elements)):
                 for i in node["sequence"]:  # 挨个执行操作
-                    excuteNode(i, elements[index], node["parameters"]["xpath"], index)
+                    excuteNode(i, elements[index],
+                               node["parameters"]["xpath"], index)
                 if browser.current_window_handle != thisHandle:  # 如果执行完一次循环之后标签页的位置发生了变化
                     while True:  # 一直关闭窗口直到当前标签页
                         browser.close()  # 关闭使用完的标签页
@@ -168,9 +216,11 @@ def loopExcute(node, loopValue,clickPath="",index=0):
                         if browser.current_window_handle == thisHandle:
                             break
                 if history["index"] != thisHistoryLength and history[
-                    "handle"] == browser.current_window_handle:  # 如果执行完一次循环之后历史记录发生了变化,注意当前页面的判断
-                    difference = thisHistoryLength - history["index"]  # 计算历史记录变化差值
-                    browser.execute_script('history.go(' + str(difference) + ')')  # 回退历史记录
+                        "handle"] == browser.current_window_handle:  # 如果执行完一次循环之后历史记录发生了变化,注意当前页面的判断
+                    difference = thisHistoryLength - \
+                        history["index"]  # 计算历史记录变化差值
+                    browser.execute_script(
+                        'history.go(' + str(difference) + ')')  # 回退历史记录
                     if node["parameters"]["historyWait"] > 2:  # 回退后要等待的时间
                         time.sleep(node["parameters"]["historyWait"])
                     else:
@@ -186,7 +236,7 @@ def loopExcute(node, loopValue,clickPath="",index=0):
     elif int(node["parameters"]["loopType"]) == 2:  # 固定元素列表
         for path in node["parameters"]["pathList"].split("\n"):  # 千万不要忘了分割!!
             try:
-                element = browser.find_element_by_xpath(path)
+                element = browser.find_element(By.XPATH, path)
                 for i in node["sequence"]:  # 挨个执行操作
                     excuteNode(i, element, path, 0)
                 if browser.current_window_handle != thisHandle:  # 如果执行完一次循环之后标签页的位置发生了变化
@@ -196,9 +246,11 @@ def loopExcute(node, loopValue,clickPath="",index=0):
                         if browser.current_window_handle == thisHandle:
                             break
                 if history["index"] != thisHistoryLength and history[
-                    "handle"] == browser.current_window_handle:  # 如果执行完一次循环之后历史记录发生了变化,注意当前页面的判断
-                    difference = thisHistoryLength - history["index"]  # 计算历史记录变化差值
-                    browser.execute_script('history.go(' + str(difference) + ')')  # 回退历史记录
+                        "handle"] == browser.current_window_handle:  # 如果执行完一次循环之后历史记录发生了变化,注意当前页面的判断
+                    difference = thisHistoryLength - \
+                        history["index"]  # 计算历史记录变化差值
+                    browser.execute_script(
+                        'history.go(' + str(difference) + ')')  # 回退历史记录
                     if node["parameters"]["historyWait"] > 2:  # 回退后要等待的时间
                         time.sleep(node["parameters"]["historyWait"])
                     else:
@@ -216,16 +268,18 @@ def loopExcute(node, loopValue,clickPath="",index=0):
         for text in textList:
             recordLog("input: " + text)
             for i in node["sequence"]:  # 挨个执行操作
-                excuteNode(i, text, "",0)
+                excuteNode(i, text, "", 0)
     elif int(node["parameters"]["loopType"]) == 4:  # 固定网址列表
         pass  # 以后再做
     history["index"] = thisHistoryLength
     history["handle"] = browser.current_window_handle
+    scrollDown(node["parameters"])
 
 
 # 打开网页事件
 def openPage(para, loopValue):
     rt = Time("打开网页")
+    time.sleep(2)  # 打开网页后强行等待至少2秒
     global links
     global urlId
     global history
@@ -248,18 +302,7 @@ def openPage(para, loopValue):
         browser.execute_script('window.stop()')
         history["index"] = browser.execute_script("return history.length")
         rt.end()
-    try:
-        if para["scrollType"] != 0 and para["scrollCount"] > 0:  # 控制屏幕向下滚动
-            for i in range(para["scrollCount"]):
-                time.sleep(1)  # 下拉完等1秒
-                Log("下拉等待1秒")
-                body = browser.find_element_by_css_selector("body")
-                body.send_keys(Keys.END)
-    except TimeoutException:
-        Log('time out after 10 seconds when loading page: ' + url)
-        recordLog('time out after 10 seconds when loading page: ' + url)
-        browser.execute_script('window.stop()')
-        rt.end()
+    scrollDown(para, rt)  # 控制屏幕向下滚动
     if containJudge:
         global bodyText  # 每次执行点击,输入元素和打开网页操作后,需要更新bodyText
         try:
@@ -285,7 +328,7 @@ def inputInfo(para, loopValue):
     Log("输入前等待1秒")
     rt = Time("输入文字")
     try:
-        textbox = browser.find_element_by_xpath(para["xpath"])
+        textbox = browser.find_element(By.XPATH, para["xpath"])
     except:
         Log("找不到输入框元素:" + para["xpath"] + "请尝试执行前等待")
         recordLog("找不到输入框元素:" + para["xpath"] + "请尝试执行前等待")
@@ -313,7 +356,8 @@ def clickElement(para, loopElement=None, clickPath="", index=0):
         path = para["xpath"]  # 不然使用元素定义的xpath
     tempHandleNum = len(browser.window_handles)  # 记录之前的窗口位置
     try:
-        script = 'var result = document.evaluate(`' + path + '`, document, null, XPathResult.ANY_TYPE, null);for(let i=0;i<arguments[0];i++){result.iterateNext();} result.iterateNext().click();'
+        script = 'var result = document.evaluate(`' + path + \
+            '`, document, null, XPathResult.ANY_TYPE, null);for(let i=0;i<arguments[0];i++){result.iterateNext();} result.iterateNext().click();'
         browser.execute_script(script, str(index))  # 用js的点击方法
 
     except TimeoutException:
@@ -343,24 +387,7 @@ def clickElement(para, loopElement=None, clickPath="", index=0):
             history["index"] = browser.execute_script("return history.length")
             rt.end()
         # 如果打开了新窗口,切换到新窗口
-    try:
-        if para["scrollType"] != 0 and para["scrollCount"] > 0:  # 控制屏幕向下滚动
-            for i in range(para["scrollCount"]):
-                time.sleep(1)  # 下拉完等1秒
-                Log("下拉完等待1秒")
-                body = browser.find_element_by_css_selector("body")
-                body.send_keys(Keys.END)
-    except TimeoutException:
-        Log('time out after 10 seconds when scrolling. ')
-        recordLog('time out after 10 seconds when scrolling')
-        browser.execute_script('window.stop()')
-        if para["scrollType"] != 0 and para["scrollCount"] > 0:  # 控制屏幕向下滚动
-            for i in range(para["scrollCount"]):
-                time.sleep(1)  # 下拉完等1秒
-                Log("下拉完等待1秒")
-                body = browser.find_element_by_css_selector("body")
-                body.send_keys(Keys.END)
-        rt.end()
+    scrollDown(para, rt)  # 根据参数配置向下滚动
     if containJudge:  # 有判断语句才执行以下操作
         global bodyText  # 每次执行点击,输入元素和打开网页操作后,需要更新bodyText
         try:
@@ -393,13 +420,19 @@ def getData(para, loopElement, isInLoop=True):
                 if p["relativeXpath"] == "":  # 相对xpath有时候就是元素本身,不需要二次查找
                     element = loopElement
                 else:
-                    element = loopElement.find_element_by_xpath(p["relativeXpath"][1:])
+                    element = loopElement.find_element(By.XPATH,
+                                                       p["relativeXpath"][1:])
             else:
-                element = browser.find_element_by_xpath(p["relativeXpath"])
+                element = browser.find_element(By.XPATH, p["relativeXpath"])
         except NoSuchElementException:  # 找不到元素的时候,使用默认值
-            outputParameters[p["name"]] = p["default"]
-            Log('Element not found,use default')
-            recordLog('Element not found,use default')
+            # print(p)
+            try:
+                content = p["default"]
+            except Exception as e:
+                content = ""
+            outputParameters[p["name"]] = content
+            Log('Element %s not found,use default' % p["relativeXpath"])
+            recordLog('Element %s not found, use default' % p["relativeXpath"])
             continue
         except TimeoutException:  # 超时的时候设置超时值
             Log('time out after 10 seconds when getting data')
@@ -409,9 +442,10 @@ def getData(para, loopElement, isInLoop=True):
                 if p["relativeXpath"] == "":  # 相对xpath有时候就是元素本身,不需要二次查找
                     element = loopElement
                 else:
-                    element = loopElement.find_element_by_xpath(p["relativeXpath"][1:])
+                    element = loopElement.find_element(By.XPATH,
+                                                       p["relativeXpath"][1:])
             else:
-                element = browser.find_element_by_xpath(p["relativeXpath"])
+                element = browser.find_element(By.XPATH, p["relativeXpath"])
             rt.end()
         try:
             if p["contentType"] == 2:
@@ -428,7 +462,8 @@ def getData(para, loopElement, isInLoop=True):
                 }\
                 var str = arr.join(" "); \
                 return str;'
-                content = browser.execute_script(command, element).replace("\n", "").replace("\\s+", " ")
+                content = browser.execute_script(command, element).replace(
+                    "\n", "").replace("\\s+", " ")
                 if p["nodeType"] == 2:
                     if element.get_attribute("href") != None:
                         content = element.get_attribute("href")
@@ -461,19 +496,22 @@ def getData(para, loopElement, isInLoop=True):
                         content = element.get_attribute("src")
                     else:
                         content = ""
-        except StaleElementReferenceException: #发生找不到元素的异常后,等待几秒重新查找
+        except StaleElementReferenceException:  # 发生找不到元素的异常后,等待几秒重新查找
             recordLog('StaleElementReferenceException:'+p["relativeXpath"])
-            time.sleep(3) 
+            time.sleep(3)
             try:
                 if p["relative"]:  # 是否相对xpath
                     if p["relativeXpath"] == "":  # 相对xpath有时候就是元素本身,不需要二次查找
                         element = loopElement
                         recordLog('StaleElementReferenceException:loopElement')
                     else:
-                        element = loopElement.find_element_by_xpath(p["relativeXpath"][1:])
-                        recordLog('StaleElementReferenceException:loopElement+relativeXPath')
+                        element = loopElement.find_element(By.XPATH,
+                                                           p["relativeXpath"][1:])
+                        recordLog(
+                            'StaleElementReferenceException:loopElement+relativeXPath')
                 else:
-                    element = browser.find_element_by_xpath(p["relativeXpath"])
+                    element = browser.find_element(
+                        By.XPATH, p["relativeXpath"])
                     recordLog('StaleElementReferenceException:relativeXpath')
                 if p["contentType"] == 2:
                     content = element.get_attribute('innerHTML')
@@ -489,7 +527,8 @@ def getData(para, loopElement, isInLoop=True):
                     }\
                     var str = arr.join(" "); \
                     return str;'
-                    content = browser.execute_script(command, element).replace("\n", "").replace("\\s+", " ")
+                    content = browser.execute_script(command, element).replace(
+                        "\n", "").replace("\\s+", " ")
                     if p["nodeType"] == 2:
                         if element.get_attribute("href") != None:
                             content = element.get_attribute("href")
@@ -524,7 +563,7 @@ def getData(para, loopElement, isInLoop=True):
                             content = ""
             except StaleElementReferenceException:
                 recordLog('StaleElementReferenceException:'+p["relativeXpath"])
-                continue # 再出现类似问题直接跳过
+                continue  # 再出现类似问题直接跳过
         outputParameters[p["name"]] = content
     global OUTPUT
     line = []
@@ -541,13 +580,12 @@ def isnull(s):
     return len(s) != 0
 
 
-import atexit #遇到错误退出时应执行的代码
[email protected] 
-def clean(): 
-    global saveName,log, OUTPUT,browser,SAVED
[email protected]
+def clean():
+    global saveName, log, OUTPUT, browser, SAVED
     if not SAVED:
         print('清理环境保存数据')
-        with open("Data/"+saveName + '_log.txt', 'w',encoding='utf-8-sig') as file_obj:
+        with open("Data/"+saveName + '_log.txt', 'w', encoding='utf-8-sig') as file_obj:
             file_obj.write(log)
             file_obj.close()
         with open("Data/"+saveName + '.csv', 'w', encoding='utf-8-sig', newline="") as f:
@@ -557,42 +595,53 @@ def clean():
             f.close()
         browser.quit()
 
+
 if __name__ == '__main__':
     options = Options()
+    exe_path = "chromedriver.exe"
     if os.path.exists(os.getcwd()+"/ServiceWrapper"):
-        options.binary_location="ServiceWrapper/Chrome/chrome.exe" #指定chrome位置
+        options.binary_location = "ServiceWrapper/Chrome/chrome.exe"  # 指定chrome位置
+        exe_path = "ServiceWrapper/Chrome/chromedriver.exe"
     elif os.path.exists(os.getcwd()+"/Debug"):
-        options.binary_location="Debug/Chrome/chrome.exe" #指定chrome位置
-    elif os.getcwd().find("ExcuteStage") >= 0: #如果直接执行
-        options.binary_location = "../../bin/x64/Debug/Chrome/chrome.exe"  # 指定chrome位置
+        options.binary_location = "Debug/Chrome/chrome.exe"  # 指定chrome位置
+        exe_path = "Debug/Chrome/chromedriver.exe"
+    elif os.getcwd().find("ExcuteStage") >= 0:  # 如果直接执行
+        options.binary_location = "./Chrome/chrome.exe"  # 指定chrome位置
+        exe_path = "./Chrome/chromedriver.exe"
     else:
-        options.binary_location="chrome.exe" #指定chrome位置
-    browser = webdriver.Chrome(chrome_options=options)
+        options.binary_location = "chrome.exe"  # 指定chrome位置
+    browser = webdriver.Chrome(options=options, executable_path=exe_path)
     browser.get('about:blank')
-    browser.set_page_load_timeout(10) # 加载页面最大超时时间
-    if len(sys.argv)>1:
-        id = int(sys.argv[1]) #taskId这里修改
+    browser.set_page_load_timeout(10)  # 加载页面最大超时时间
+    browser.set_script_timeout(10)
+    if len(sys.argv) > 1:
+        id = int(sys.argv[1])  # taskId这里修改
+    else:
+        id = 7  # 设置默认值
+    print("id:", id)
+    if len(sys.argv) > 2:
+        backEndAddress = sys.argv[2]
     else:
-        id = 7 #设置默认值
-    print("id:",id)
-    if len(sys.argv)>2:
-        saveName = "task_" + str(id) + "_" + sys.argv[2]  # 保存文件的名字
+        backEndAddress = "http://servicewrapper.naibo.wang"
+    if len(sys.argv) > 3:
+        saveName = "task_" + str(id) + "_" + sys.argv[3]  # 保存文件的名字
     else:
-        saveName = "task_" + str(id) + "_" + str(random.randint(0, 999999999))  # 保存文件的名字
-    content = requests.get("http://183.129.170.180:8041/backEnd/queryTask?id=" + str(id))
+        saveName = "task_" + str(id) + "_" + \
+            str(random.randint(0, 999999999))  # 保存文件的名字
+    content = requests.get(backEndAddress + "/backEnd/queryTask?id=" + str(id))
     service = json.loads(content.text)  # 加载服务信息
-    print("name:",service["name"])
+    print("name:", service["name"])
     procedure = service["graph"]  # 程序执行流程
     links = list(filter(isnull, service["links"].split("\n")))  # 要执行的link的列表
     OUTPUT = []  # 采集的数据
     OUTPUT.append([])  # 添加表头
-    containJudge = service["containJudge"] #是否含有判断语句
+    containJudge = service["containJudge"]  # 是否含有判断语句
     bodyText = ""  # 记录bodyText
     tOut = service["outputParameters"]  # 生成输出参数对象
     outputParameters = {}
     log = ""  # 记下现在总共开了多少个标签页
-    history = {"index":0,"handle":None} #记录页面现在所以在的历史记录的位置
-    SAVED=False #记录是否已经存储了
+    history = {"index": 0, "handle": None}  # 记录页面现在所以在的历史记录的位置
+    SAVED = False  # 记录是否已经存储了
     for para in tOut:
         outputParameters[para["name"]] = ""
         OUTPUT[0].append(para["name"])
@@ -604,7 +653,7 @@ if __name__ == '__main__':
     print("执行完成!")
     recordLog("Done!")
     # dataPath = os.path.abspath(os.path.join(os.getcwd(), "../Data"))
-    with open("Data/"+saveName + '_log.txt', 'w',encoding='utf-8-sig') as file_obj:
+    with open("Data/"+saveName + '_log.txt', 'w', encoding='utf-8-sig') as file_obj:
         file_obj.write(log)
         file_obj.close()
     with open("Data/"+saveName + '.csv', 'w', encoding='utf-8-sig', newline="") as f:
@@ -614,4 +663,4 @@ if __name__ == '__main__':
         f.close()
     SAVED = True
     browser.quit()
-    sys.exit(0)
+    sys.exit(0)

BIN
Extension/ServiceWrapper.crx


+ 26 - 26
Extension/ServiceWrapper.pem

@@ -1,28 +1,28 @@
 -----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCuAZmXoS3RN1dQ
-IWpPjMZMX08JQRiR9XF8fPuZ4r/aauafNKncQmC2FEFylAcBMaRVSjAsZlXVqTlE
-s1LRtt9PiJEiDv73alerwznzNfuN0Dqrj2YpvKlck/sdFDeJNGi3dAl4kWZOKlE0
-kpHXO6BQBKB9t9Up5qBku0epGYNZ6/foCl82U5bw8bBaZ5p0F2hhE4/PWP0p/MED
-HR7yvnr5qO0B6qQia/59q4opxH6sswa6XAc3mgU1Yq8m1cXRctmvxCBt7biU7Gpw
-jLB4Qdgikq02hWxn1YUbGAjHRjLrNxOIFBP6Sx2SNllM664bUmzwchnEzsLILyDQ
-jzKlafobAgMBAAECggEAGdp7APXIYkbKs56DYSvAECYzuWLxTPPJgimVExmG+o4v
-kzAL8iyamfMLK676wMlTaqi0h6RHfztpcDUEn8wqrx0naIa53fZFmGulTJGUvU6s
-U5k2y19l+oSyJsaTidCTo85F1KLQhISdFCaYLKvbTIhOIDUUIumf+IIq9OD+4c6C
-nhAKhkjspDt1ctyFy9QXE5Wbi6o8AdOuaw9QW+y7msi1kcTWovxFBQkN1Ck4D2m7
-y72M5dDYq3nWEyQDJvioDM2yxvywiX3piHjULBj60Ybt52EEyRNlBMkbafU0puYU
-aajlPSv0X0mQjdtYLmd2dEVTH5rNLkVRwtx0i5MYoQKBgQDnJkJY6sj6HzhnFtWo
-NiorwAteNG6fIchZPAJjdtAQNu2stakGtnRoQ3WfVi2ePUKntoyqS4WanJE/z4pX
-lTMAePB8madwqe+AgSJzl0+YnOqBQCk6DeIrJ9u0O+nb7wlkZMbaULj6Sx8bg+N4
-jM/MSD4uo1eYJdo6bIq6KNHXTQKBgQDAtqJlZ+EweMD9K652htwW0HE0IXD7zxMh
-8rODaubAp+glapW77GYltFrJ++Q8ObBdm+jLo8CbWUTus61qpsinv+CV//dIEiYp
-vbdf+oFnCEHvFTN1opzsS9ThYZhRnnonuxYmMCWsx55GG7oyAVtYLBUERm6XurLY
-FXkceAvzBwKBgD/UB8Qn6SFwV5HX813EvzZfjIQR9G4K1RkXAg3XNDMWB+GGNEt/
-PHvCDQvXrzcf8XUAaq1nt1fvXgiB1dDDiVbbDoVJpLvuoQ0aG5pRsRASXIseXYQD
-a23BTuDhHn217yEC1wpX+gxbjBZ7/+c88vCVDl6wijKgWTeC23f2Z6ONAoGAP2CQ
-3cqg+2DrDxe7g41sejBI2n0Y/CcowqRftxuEEd3mcc+wuKHRIhtDNGQbtla+krqA
-f+A1qqFcEyiSIp4BJXHr+Ui52UDmvhl/YhgvUGQd0vPk/Y3iD7AMraZ8AnOc9s4H
-Rb3V1hG8EpBx1potoTy2GLbVDh8/S+Mb9mngfCcCgYEAlL/oEGR6j7K/29gF8KjQ
-J6HfNxdisP0b14her/mX0NSSv8WNFX77XO6pjXmpiIQPsm4I1KlzeFEVBy9RetGb
-5OKLQdfILNe8aDrYxMKcjbuA9zLqIzYep8siLdrYI1RDSxKt7ZUW6JejPthV0vr5
-408+uF8kwRJscoRPn7+x7Uk=
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCr3o0YTuz2UMy7
+qolwd4CWXet3SjJL0XawKKgp3ZRo78zER1Z/LQ5/rZqc6DISBPCycAoOCBk2EcBZ
+IlPKQFxq1PMj10ccyswjjb+4mf4ZRVveeflBqT9I4khrzwk9gymSZiD7TbkDc4fp
+oxoHCv2f7VMR5m/IwsnXEsm7QyuRSA6ETbhp2Faa2CIGI4l6r+gtuVYkUSGEN/0H
+0dk3kfh6rcjwvroLSzWcGJnhyOLDYxnV1kTHZDUBzGj0UOqL0fdpAuyXxSikadxa
+Ec4BZ4s3GHIlFR5N7itrwYN28IInLObxUQXJ3unEdnon/T/XhC5KsdjMp8D6Xb8/
+0dObgaG/AgMBAAECggEAR0xyZQCs/fwECuBS1uTEY9y/h4OwvNI+9hJPvNpurF+6
+pzxe7jBPYPkweGI9D0ucXLHtAegrKUqQ7Ik4kGFF1Y3U9evjVNbue9tciyTbDDnB
+RFh+ZlZjagVxfMPtNeb5MoIKsaYLGBrv6aUfcYeGMre96+GYQwVHvWDOblCNvN0k
+fBInSGlDcLkx9EJ9vFbCf8IErg4RWtiEdSvSG1s99IPc17j4cJn4qq9OyQrECpdz
+y7AnkvsMOiOzQawO+C2I5SgA26eaxNJrz/3ph4r1x1iCdPvY7iD/awkQXCgid6kq
+Z0R8ByxTbwqr4NYXtUyHVkwiL9QZSKjnvrOfdmm0iQKBgQDkQ5KRMftmDi9cJfOj
+0xY/TwCymsWp+MdMQ6YKAd57oMM+2DzgZ//LFgo4rcYWjTGlErE8tXhT4fM5PEUQ
+1CgwozmkPcVnRzLyiNWNpiMCzPVPsXDxzoEQFHL0qLA/Xj7npH5d+Eg6yunDc9JS
+D/OlqSEZQ6W4lWFvAkz7Mh5M6QKBgQDAwMFzAMYVXwcRmH0gvzmqA46MqjdfaXyq
+NzNADiVCaGgqYpNygeftiHGCBQiXr3QkVVp+XihbY/5KnzVYiS0ICKMCwqxizvRT
+gR3N4+UyVaK9FTWLgtSu8VN4JM3E+nigBO/QfD4WI4VZ3tZEsOveV70j97NpfaPN
+lhjr2J0wZwKBgG3pj7i0bY5dxDZF3ASFjw/a9cYKuqU2spipdlkZP00eQwWOz/lq
+eoQKz88s9dZEFKSc1JUb+J3Djf+AYu1Qiy2oWwgX6mbppMGeW95CIlel43WFRpJY
+0lKw1g2y8HMC6Z1W2rZa6ETPEjLYIWz8W2DoiJSGu1SfMXRnkjPelTKJAoGACvbs
+Ci6xFeYh8M5Lz+EQ1qr9IONN4w+NF+Gr+KjVVcG6qy6QVKMvHkP0sQC4TGieorJ4
+Q1f307sMbBJCZpbnCN305+NLCxPasiVWHLAqCYL1juv178mxb4IqzVrKmbnlwrSF
+L8bhgUDkBQi4B5BI2o0DJVihzA5pkvhG0qOvzWECgYAHITSiOJBF1Lr0hw7JnS5r
+Hre8bQdbDeqSd5iRM/+0MJnBvkp7RDgvh0c01Wc90A0gjhhPqBS9z5UNptiJKhJQ
+kYDP7iiftM7FsG45IGKf6RrulLk6pCyFEFb/roBlC1xy/6uNCqAHbd+6K6UjQAFB
++c9hCtSDDh3/irZrY34lDw==
 -----END PRIVATE KEY-----

+ 1 - 1
Extension/ServiceWrapper/scripts/baozhuangscript.js

@@ -1,6 +1,6 @@
 //表现层的处理
 
-if (window.location.href.indexOf("183.129.170.180") >= 0) {
+if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
     throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
 }
 

+ 180 - 180
Extension/ServiceWrapper/scripts/contentscript.js

@@ -1,50 +1,50 @@
 //表现逻辑层的处理
 
-if (window.location.href.indexOf("183.129.170.180") >= 0) {
+if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
     throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
 }
 
-//Vue元素
+//Vueelement
 var app;
 generateToolkit();
 //生成Toolkit
 function generateToolkit() {
     $(".tooltips").html(`
     <div id="realcontent">
-    <div class="tooldrag">✍操作提示框(可点此拖动)</div>
+    <div class="tooldrag">✍Operation Toolbox (Can drag)</div>
     <div class="realcontent">
         <div v-if="page==0">
             <input type="checkbox" style="width:15px;height:15px;vertical-align:middle;" v-on:mousedown="specialSelect"> </input>
-            <p style="margin-bottom:10px;display:inline-block">特殊点选模式</p>
+            <p style="margin-bottom:10px;display:inline-block">Special click mode</p>
             <div v-if="list.nl.length==0">
-                <p style="color:black">● 鼠标移动到元素上后,请<strong>右键</strong>点击或者按<strong>F7</strong>键选中页面元素。</p>
-                <p style="color:black">● 如果不小心左键点选了元素导致页面跳转,直接后退或者切换回标签页即可。</p>
+                <p style="color:black">● When your mouse moves to the element, please use your<strong>right mouse button</strong>or<strong>F7</strong> on the keyboard to select it.</p>
+                <p style="color:black">● You can click the back button to go back to the page</p>
                 {{initial()}}
             </div>
             <div v-if="list.nl.length==1">
                 <div v-if="tname()!='null'">
-                    ● 已选中{{numOfList()}}个{{tname()}},<span v-if="numOfReady()>0&&tname()!='下一页元素'">同时发现{{numOfReady()}}个同类元素,</span>您可以:
+                    ● Already selected {{numOfList()}} {{tname()}},<span v-if="numOfReady()>0&&tname()!='Elements in next page'">, meanwhile we find {{numOfReady()}} element with the same type, </span>you can:
                     <div class="innercontent">
-                        <div v-if="numOfReady()>0 && !selectStatus"> <a v-on:mousedown="selectAll">选中全部</a> <span title="">☺</span></div>
-                        <div v-if="existDescendents()&& !selectStatus &&(tname()=='元素' || tname()=='链接')"> <a v-on:mousedown="selectDescendents">选中子元素</a> <span title="">☺</span></div>
+                        <div v-if="numOfReady()>0 && !selectStatus"> <a v-on:mousedown="selectAll">Select All</a> <span title="">☺</span></div>
+                        <div v-if="existDescendents()&& !selectStatus &&(tname()=='element' || tname()=='link')"> <a v-on:mousedown="selectDescendents">Select child elements</a> <span title="">☺</span></div>
                         <div v-if="!selectedDescendents && !selectStatus" id="Single">
-                            <div v-if="tname()=='选择框'"> <a>循环切换下拉选项</a><span title="">☺</span></div>
-                            <div v-if="tname()=='文本框'"> <a v-on:mousedown="setInput">输入文字</a><span title="">☺</span></div>
-                            <div v-if="tname()!='图片'"> <a v-on:mousedown="getText">采集该{{tname()}}的文本</a><span title="采集文本">☺</span></div>
-                            <div v-if="tname()=='选择框'"> <a>采集选中项的文本</a><span title="">☺</span></div>
-                            <div v-if="tname()=='链接'||tname()=='图片'"> <a v-on:mousedown="getLink">采集该{{tname()}}的地址</a><span title="">☺</span></div>
-                            <div v-if="tname()!='选择框' && tname()!='文本框'"> <a v-on:mousedown="clickElement">点击该{{tname()}}</a><span title="">☺</span></div>
-                            <div v-if="tname()!='选择框' && tname()!='文本框'"> <a v-on:mousedown="loopClickSingleElement">循环点击该{{tname()}}</a><span title="">☺</span></div>
-                            <div v-if="tname()=='链接'||tname()=='元素'"> <a v-on:mousedown="getInnerHtml">采集该{{tname()}}的Inner Html</a><span title="">☺</span></div>
+                            <div v-if="tname()=='selection box'"> <a>---------</a><span title="">☺</span></div>
+                            <div v-if="tname()=='text box'"> <a v-on:mousedown="setInput">Input Text</a><span title="">☺</span></div>
+                            <div v-if="tname()!='Image'"> <a v-on:mousedown="getText">Collect {{tname()}}'s text</a><span title="collet text">☺</span></div>
+                            <div v-if="tname()=='selection box'"> <a>采集选中项的text</a><span title="">☺</span></div>
+                            <div v-if="tname()=='link'||tname()=='Image'"> <a v-on:mousedown="getLink">采集该{{tname()}}的Address</a><span title="">☺</span></div>
+                            <div v-if="tname()!='selection box' && tname()!='text box'"> <a v-on:mousedown="clickElement">点击该{{tname()}}</a><span title="">☺</span></div>
+                            <div v-if="tname()!='selection box' && tname()!='text box'"> <a v-on:mousedown="loopClickSingleElement">循环点击该{{tname()}}</a><span title="">☺</span></div>
+                            <div v-if="tname()=='link'||tname()=='element'"> <a v-on:mousedown="getInnerHtml">采集该{{tname()}}的Inner Html</a><span title="">☺</span></div>
                             <div> <a v-on:mousedown="getOuterHtml">采集该{{tname()}}的Outer Html</a><span title="">☺</span></div>
-                            <div> <a href="#">鼠标移动到该{{tname()}}上</a><span title="">☺</span></div>
-                            <div v-if="tname()=='文本框'"> <a>识别验证码</a><span title="">☺</span></div>
+                            <div> <a href="#">----{{tname()}}-</a><span title="">☺</span></div>
+                            <div v-if="tname()=='text box'"> <a>-----</a><span title="">☺</span></div>
                         </div>
                         <div v-if="selectedDescendents" id="Single">
-                            <div><a v-on:mousedown="confirmCollectSingle">采集数据</a><span title="">☺</span></div>
+                            <div><a v-on:mousedown="confirmCollectSingle">Collect Data</a><span title="">☺</span></div>
                         </div>
                         <div v-if="selectStatus" id="Confirm">
-                            <div><a v-on:mousedown="confirmCollectSingle">确认采集</a><span title="">☺</span></div>
+                            <div><a v-on:mousedown="confirmCollectSingle">Confirm Collect</a><span title="">☺</span></div>
                         </div>
                     </div>
                 </div>
@@ -53,21 +53,21 @@ function generateToolkit() {
             <div v-if="list.nl.length>1">
 
                 <div v-if="option==100">
-                    ● 已选择了以下元素,您可以:
+                    ● 已select了以下element,您可以:
                     <div class="innercontent">
                         <div> <a v-on:mousedown="confirmCollectMulti">采集数据</a><span title="">☺</span> </div>
-                        <div> <a v-on:mousedown="revoke">撤销本次选择</a><span title="">☺</span></div>
+                        <div> <a v-on:mousedown="revoke">撤销本次selection</a><span title="">☺</span></div>
                     </div>
                 </div>
 
                 <div v-if="option!=100">
-                    ● 已选择了{{numOfList()}}个同类元素,<span v-if="numOfReady()>0">另外发现{{numOfReady()}}个同类元素,</span>您可以:
+                    ● 已select了{{numOfList()}}个同类element,<span v-if="numOfReady()>0">另外发现{{numOfReady()}}个同类element,</span>您可以:
                     <div class="innercontent">
                         <div v-if="numOfReady()>0"> <a v-on:mousedown="selectAll">选中全部</a><span title="">☺</span></div>
-                        <div v-if="existDescendents()&&(tname()=='元素' || tname()=='链接')"> <a v-on:mousedown="selectDescendents">选中子元素</a><span title="">☺</span></div>
+                        <div v-if="existDescendents()&&(tname()=='element' || tname()=='link')"> <a v-on:mousedown="selectDescendents">选中子element</a><span title="">☺</span></div>
                         <div> <a v-on:mousedown="confirmCollectMultiAndDescendents">采集数据</a><span title="">☺</span></div>
-                        <div v-if="tname()!='选择框' && tname()!='文本框' && !selectedDescendents"> <a  v-on:mousedown="loopClickEveryElement">循环点击每个{{tname()}}</a><span title="">☺</span></div>
-                        <div> <a v-on:mousedown="revoke">撤销本次选择</a><span title="">☺</span></div>
+                        <div v-if="tname()!='selection box' && tname()!='text box' && !selectedDescendents"> <a  v-on:mousedown="loopClickEveryElement">循环点击每个{{tname()}}</a><span title="">☺</span></div>
+                        <div> <a v-on:mousedown="revoke">撤销本次selection</a><span title="">☺</span></div>
                     </div>
                 </div>
             
@@ -91,11 +91,11 @@ function generateToolkit() {
                 </div>
             </div>
             
-            <div v-if="valTable.length==0&&tname()!='下一页元素'">{{setWidth("230px")}}</div>
+            <div v-if="valTable.length==0&&tname()!='Elements in next page'">{{setWidth("230px")}}</div>
 
             <div v-if="list.nl.length>0" style="bottom:12px;position:absolute;color:black!important;left:17px;font-size:13px">
                 <div style="margin-bottom:5px">
-                    <button v-on:mousedown="cancel">取消选择</button>
+                    <button v-on:mousedown="cancel">取消selection</button>
                     <button v-if="!selectStatus" v-on:mousedown="enlarge">扩大选区</button>
                 </div>
                 <p style="margin-left:16px;margin-bottom:0px">{{lastElementXPath()}}</p>
@@ -116,14 +116,14 @@ function generateToolkit() {
         data: {
             option: 0,
             list: { nl: nodeList, opp: outputParameters },
-            valTable: [], // 用来存储转换后的参数列表
-            special: false, //是否为特殊选择模式
-            selectedDescendents: false, // 标记是否选中了子元素
-            selectStatus: false, //标记单个元素是否点击了采集
+            valTable: [], // 用来存储转换后的para列表
+            special: false, //是否为特殊selection模式
+            selectedDescendents: false, // 标记是否选中了子element
+            selectStatus: false, //标记单个element是否点击了采集
             page: 0, //默认页面,1为输入文字页面
             text: "", // 记录输入的文字
             tNodeName: "", // 记录临时节点列表
-            nowPath: "", //现在元素的xpath
+            nowPath: "", //现在element的xpath
         },
         watch: {
             nowPath: { //变量发生变化的时候进行一些操作
@@ -133,34 +133,34 @@ function generateToolkit() {
             }
         },
         methods: {
-            initial: function() { //每当元素是0的时候,执行值的初始化操作
+            initial: function() { //每当element是0的时候,执行值的初始化操作
                 this.selectedDescendents = false;
                 this.selectStatus = false;
                 this.nowPath = "";
             },
-            confirmCollectSingle: function() { //单元素确认采集
+            confirmCollectSingle: function() { //单element确认采集
                 collectSingle();
                 clearEl();
             },
-            confirmCollectMulti: function() { //无规律多元素确认采集
+            confirmCollectMulti: function() { //无规律多element确认采集
                 collectMultiNoPattern();
                 clearEl();
             },
-            confirmCollectMultiAndDescendents: function() { //有规律多元素确认采集
+            confirmCollectMultiAndDescendents: function() { //有规律多element确认采集
                 collectMultiWithPattern();
                 clearEl();
             },
-            deleteSingleLine: function(event) { //删除单行元素
+            deleteSingleLine: function(event) { //删除单行element
                 let at = new Date().getTime()
-                    //流程图送元素的时候,默认的使用不固定循环列表,但是一旦有删除元素的操作发生,则按照固定元素列表采集元素
+                    //流程图送element的时候,默认的使用不固定循环列表,但是一旦有删除element的操作发生,则按照固定element列表采集element
                 index = event.target.getAttribute("index");
-                let tnode = nodeList.splice(index, 1)[0]; //删掉当前元素
+                let tnode = nodeList.splice(index, 1)[0]; //删掉当前element
                 tnode["node"].style.backgroundColor = tnode["bgColor"];
                 tnode["node"].style.boxShadow = tnode["boxShadow"];
                 if (nodeList.length > 1) { // 如果删到没有就没有其他的操作了
                     handleElement();
                     if (this.selectedDescendents) {
-                        handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
+                        handleDescendents(); //如果之前有选中子element,新加入的节点又则这里也需要重新selection子element
                     }
                 } else {
                     this.valTable = [];
@@ -170,25 +170,25 @@ function generateToolkit() {
                 let at2 = parseInt(new Date().getTime());
                 console.log("delete:", at2, at, at2 - at);
             },
-            clickElement: function() { //点击元素操作
+            clickElement: function() { //点击element操作
                 sendSingleClick();
                 //先发送数据
-                nodeList[0]["node"].focus(); //获得元素焦点
-                nodeList[0]["node"].click(); //点击元素
+                nodeList[0]["node"].focus(); //获得element焦点
+                nodeList[0]["node"].click(); //点击element
                 clearEl();
             },
-            loopClickSingleElement: function() { //循环点击单个元素
-                sendLoopClickSingle(this.tname()); //识别下一页,循环点击单个元素和点击多个元素
-                if (this.tname() != "下一页元素") { //下一页元素不进行点击操作
-                    nodeList[0]["node"].focus(); //获得元素焦点
-                    nodeList[0]["node"].click(); //点击元素
+            loopClickSingleElement: function() { //循环点击单个element
+                sendLoopClickSingle(this.tname()); //识别下一页,循环点击单个element和点击多个element
+                if (this.tname() != "Elements in next page") { //Elements in next page不进行点击操作
+                    nodeList[0]["node"].focus(); //获得element焦点
+                    nodeList[0]["node"].click(); //点击element
                 }
                 clearEl();
             },
-            loopClickEveryElement: function() { //循环点击每个元素
-                sendLoopClickEvery(); //识别下一页,循环点击单个元素和点击多个元素
-                nodeList[0]["node"].focus(); //获得元素焦点
-                nodeList[0]["node"].click(); //点击元素
+            loopClickEveryElement: function() { //循环点击每个element
+                sendLoopClickEvery(); //识别下一页,循环点击单个element和点击多个element
+                nodeList[0]["node"].focus(); //获得element焦点
+                nodeList[0]["node"].click(); //点击element
                 clearEl();
             },
             setInput: function() { //输入文字
@@ -199,7 +199,7 @@ function generateToolkit() {
             },
             getInput: function() { //得到输入的文字
                 nodeList[0]["node"].focus(); //获得文字焦点
-                // nodeList[0]["node"].setAttribute("value", this.text); // 设置输入内容
+                // nodeList[0]["node"].setAttribute("value", this.text); // 设置输入 box内容
                 input(this.text); // 设置输入
                 this.text = "";
                 clearEl();
@@ -207,7 +207,7 @@ function generateToolkit() {
             cancelInput: function() {
                 this.page = 0;
             },
-            setWidth: function(width) { //根据是否出现表格调整最外宽度
+            setWidth: function(width) { //根据是否出现表格调整最外 box宽度
                 $(".tooltips").css("width", width);
                 return "";
             },
@@ -216,7 +216,7 @@ function generateToolkit() {
                 this.selectStatus = true;
                 clearReady();
             },
-            getLink: function() { //采集链接地址
+            getLink: function() { //采集linkAddress
                 generateParameters(0, false, true);
                 this.selectStatus = true;
                 clearReady();
@@ -243,22 +243,22 @@ function generateToolkit() {
                     return "null";
                 } else if ($(nodeList[0]["node"]).contents().filter(function() { return this.nodeType === 3; }).text().indexOf("下一页") >= 0) {
                     this.setWidth("250px");
-                    return "下一页元素";
+                    return "Elements in next page";
                 } else if (tag == "A") {
-                    return "链接";
+                    return "link";
                 } else if (tag == "IMG") {
-                    return "图片";
+                    return "Image";
                 } else if (tag == "BUTTON" || (tag == "INPUT" && (inputType == "button" || inputType == "submit"))) {
-                    return "按钮";
-                } else if (tag == "TEXTAREA" || (tag == "INPUT" && (inputType != "checkbox" || inputType != "ratio"))) { //普通输入
-                    return "文本框";
+                    return "Button";
+                } else if (tag == "TEXTAREA" || (tag == "INPUT" && (inputType != "checkbox" || inputType != "ratio"))) { //普通输入 box
+                    return "text box";
                 } else if (tag == "SELECT") {
-                    return "选择框";
+                    return "selection box";
                 } else {
-                    return "元素";
+                    return "element";
                 }
             },
-            existDescendents: function() { //检测选中的元素是否存在子元素,已经选中了子元素也不要再出现了
+            existDescendents: function() { //检测选中的element是否存在子element,已经选中了子element也不要再出现了
                 return nodeList.length > 0 && nodeList[0]["node"].children.length > 0 && !this.selectedDescendents;
             },
             numOfReady: function() {
@@ -267,11 +267,11 @@ function generateToolkit() {
             numOfList: function() {
                 return nodeList.length;
             },
-            lastElementXPath: function() { //用来显示元素的最大最后5个xpath路劲元素
+            lastElementXPath: function() { //用来显示element的最大最后5个xpath路劲element
                 path = nodeList[nodeList.length - 1]["xpath"];
                 path = path.split("/");
                 tp = "";
-                if (path.length > 5) { //只保留最后五个元素
+                if (path.length > 5) { //只保留最后五个element
                     path = path.splice(path.length - 5, 5);
                     tp = ".../"
                 }
@@ -285,7 +285,7 @@ function generateToolkit() {
             cancel: function() {
                 clearEl();
             },
-            specialSelect: function() { //特殊选择模式
+            specialSelect: function() { //特殊selection模式
                 if (mousemovebind) {
                     tdiv.style.pointerEvents = "none";
                     this.special = false;
@@ -294,10 +294,10 @@ function generateToolkit() {
                 }
                 mousemovebind = !mousemovebind;
             },
-            enlarge: function() { // 扩大选区功能,总是扩大最后一个选中的元素的选区
+            enlarge: function() { // 扩大选区功能,总是扩大最后一个选中的element的选区
                 if (nodeList[nodeList.length - 1]["node"].tagName != "BODY") {
-                    nodeList[nodeList.length - 1]["node"].style.backgroundColor = nodeList[nodeList.length - 1]["bgColor"]; //之前元素恢复原来的背景颜色
-                    nodeList[nodeList.length - 1]["node"].style.boxShadow = nodeList[nodeList.length - 1]["boxShadow"]; //之前元素恢复原来的背景颜色
+                    nodeList[nodeList.length - 1]["node"].style.backgroundColor = nodeList[nodeList.length - 1]["bgColor"]; //之前element恢复原来的背景颜色
+                    nodeList[nodeList.length - 1]["node"].style.boxShadow = nodeList[nodeList.length - 1]["boxShadow"]; //之前element恢复原来的背景颜色
                     tNode = nodeList[nodeList.length - 1]["node"].parentNode; //向上走一层
                     if (tNode != NowNode) { //扩大选区之后背景颜色的判断,当前正好选中的颜色应该是不同的
                         sty = tNode.style.backgroundColor;
@@ -307,7 +307,7 @@ function generateToolkit() {
                     nodeList[nodeList.length - 1]["node"] = tNode;
                     nodeList[nodeList.length - 1]["bgColor"] = sty;
                     nodeList[nodeList.length - 1]["xpath"] = readXPath(tNode, 1);
-                    //显示
+                    //显示 box
                     var pos = tNode.getBoundingClientRect();
                     div.style.display = "block";
                     div.style.height = tNode.offsetHeight + "px";
@@ -316,39 +316,39 @@ function generateToolkit() {
                     div.style.top = pos.top + "px";
                     div.style.zIndex = 2147483645;
                     div.style.pointerEvents = "none";
-                    handleElement(); //每次数组元素有变动,都需要重新处理下
+                    handleElement(); //每次数组element有变动,都需要重新处理下
                     oe = tNode;
                     tNode.style.backgroundColor = "rgba(0,191,255,0.5)";
                     this.selectedDescendents = false;
                 }
             },
-            selectAll: function() { //选中全部元素
+            selectAll: function() { //选中全部element
                 step++;
                 readyToList(step, false);
                 handleElement();
                 if (this.selectedDescendents) {
-                    handleDescendents(); //如果之前有选中子元素,新加入的节点又则这里也需要重新选择子元素
+                    handleDescendents(); //如果之前有选中子element,新加入的节点又则这里也需要重新selection子element
                 }
             },
-            revoke: function() { //撤销选择当前节点
+            revoke: function() { //撤销selection当前节点
                 var tstep = step;
                 step--; //步数-1
-                while (tstep == nodeList[nodeList.length - 1]["step"]) //删掉所有当前步数的元素节点
+                while (tstep == nodeList[nodeList.length - 1]["step"]) //删掉所有当前步数的element节点
                 {
                     let node = nodeList.splice(nodeList.length - 1, 1)[0]; //删除数组最后一项
-                    node["node"].style.backgroundColor = node["bgColor"]; //还原原始属性和边
+                    node["node"].style.backgroundColor = node["bgColor"]; //还原原始属性和边 box
                     node["node"].style.boxShadow = node["boxShadow"];
                     if (NowNode == node["node"]) {
                         style = node["bgColor"];
                     }
-                    //处理已经有选中子元素的情况
+                    //处理已经有选中子element的情况
                     // if (this.selectedDescendents) {
                     clearParameters(); //直接撤销重选
                     // }
                 }
-                handleElement(); //每次数组元素有变动,都需要重新处理下
+                handleElement(); //每次数组element有变动,都需要重新处理下
             },
-            selectDescendents: function() { //选择所有子元素操作
+            selectDescendents: function() { //selection所有子element操作
                 handleDescendents();
             }
         },
@@ -358,7 +358,7 @@ function generateToolkit() {
     if (difference > 0) {
         $(".tooldrag").css("cssText", "height:" + (26 + difference) + "px!important")
     }
-    timer = setInterval(function() { //时刻监测相应元素是否存在(防止出现如百度一样元素消失重写body的情况),如果不存在,添加进来
+    timer = setInterval(function() { //时刻监测相应element是否存在(防止出现如百度一样element消失重写body的情况),如果不存在,添加进来
         if (document.body != null && document.getElementById("wrapperToolkit") == null) {
             this.clearInterval(); //先取消原来的计时器,再设置新的计时器
             document.body.append(div); //默认如果toolkit不存在则div和tdiv也不存在
@@ -381,10 +381,10 @@ function generateToolkit() {
     }, 3000);
 }
 
-//每次对元素进行增删之后需要执行的操作
+//每次对element进行增删之后需要执行的操作
 function handleElement() {
-    clearReady(); //预备元素每次处理都先处理掉
-    if (nodeList.length > 1) { //选中了许多元素的情况
+    clearReady(); //预备element每次处理都先处理掉
+    if (nodeList.length > 1) { //选中了许多element的情况
         app._data.option = relatedTest();
         if (app._data.option == 100) {
             generateMultiParameters();
@@ -392,13 +392,13 @@ function handleElement() {
             generateParameters(0);
         }
     } else if (nodeList.length == 1) {
-        findRelated(); //寻找和元素相关的元素
+        findRelated(); //寻找和element相关的element
     }
 }
 
-function clearParameters(deal = true) //清空参数列表
+function clearParameters(deal = true) //清空para列表
 {
-    if (deal) //是否取消对选中的子元素进行处理
+    if (deal) //是否取消对选中的子element进行处理
     {
         app._data.selectedDescendents = false;
     }
@@ -406,20 +406,20 @@ function clearParameters(deal = true) //清空参数列表
         o["node"].style.boxShadow = o["boxShadow"];
     }
     outputParameterNodes.splice(0);
-    outputParameters.splice(0); //清空原来的参数列表
+    outputParameters.splice(0); //清空原来的para列表
     app._data.valTable = []; //清空展现数组
     app._data.selectStatus = false;
 }
 
 
-//根据nodelist列表内的元素生成参数列表
-//适合:nodelist中的元素为同类型元素
-//type:0为全部文本 1为节点内直接的文字 2为innerhtml 3为outerhtml
+//根据nodelist列表内的element生成para列表
+//适合:nodelist中的element为同类型element
+//type:0为全部text 1为节点内直接的文字 2为innerhtml 3为outerhtml
 //nodetype:0,对应全type0123
-//nodetype:1 链接,对应type0123
-//nodetype:2 链接地址 对应type0
-//nodetype:3 按钮和输入文本框 对应type
-//nodetype:4 按钮和输入文本框 对应type
+//nodetype:1 link,对应type0123
+//nodetype:2 linkAddress 对应type0
+//nodetype:3 按钮和输入text box 对应type
+//nodetype:4 按钮和输入text box 对应type
 
 function generateParameters(type, linktext = true, linkhref = true) {
     clearParameters(false);
@@ -432,23 +432,23 @@ function generateParameters(type, linktext = true, linkhref = true) {
             ndPath = nodeList[num]["xpath"];
             outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow });
             nd.style.boxShadow = boxShadowColor;
-            let pname = "文本";
+            let pname = "text";
             let ndText = "";
             if (type == 0) {
                 ndText = $(nd).text();
-                pname = "文本";
+                pname = "text";
                 if (nd.tagName == "IMG") {
                     ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src");
-                    pname = "地址";
+                    pname = "Address";
                 } else if (nd.tagName == "INPUT") {
                     ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
                 }
             } else if (type == 1) {
                 ndText = $(nd).contents().filter(function() { return this.nodeType === 3; }).text().replace(/\s+/g, '');
-                pname = "文本";
+                pname = "text";
                 if (nd.tagName == "IMG") {
                     ndText = nd.getAttribute("src") == null ? "" : $(nd).prop("src");
-                    pname = "地址";
+                    pname = "Address";
                 } else if (nd.tagName == "INPUT") {
                     ndText = nd.getAttribute("value") == null ? "" : nd.getAttribute("value");
                 }
@@ -460,24 +460,24 @@ function generateParameters(type, linktext = true, linkhref = true) {
                 pname = "outerHTML";
             }
             if (num == 0) { //第一个节点新建,后面的增加即可
-                if (nd.tagName == "IMG") { //如果元素是图片
+                if (nd.tagName == "IMG") { //如果element是Image
                     outputParameters.push({
                         "nodeType": 4, //节点类型
                         "contentType": type, // 内容类型
                         "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                        "name": "参数" + (n++) + "_图片" + pname,
-                        "desc": "", //参数描述
+                        "name": "para" + (n++) + "_Image" + pname,
+                        "desc": "", //para描述
                         "relativeXpath": nodeList.length > 1 ? "" : ndPath,
                         "exampleValues": [{ "num": num, "value": ndText }]
                     });
-                } else if (nd.tagName == "A") { //如果元素是超链接
+                } else if (nd.tagName == "A") { //如果element是超link
                     if (linktext) {
                         outputParameters.push({
                             "nodeType": 1,
                             "contentType": type, // 内容类型
                             "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                            "name": "参数" + (n++) + "_链接" + pname,
-                            "desc": "", //参数描述
+                            "name": "para" + (n++) + "_link" + pname,
+                            "desc": "", //para描述
                             "relativeXpath": nodeList.length > 1 ? "" : ndPath,
                             "exampleValues": [{ "num": num, "value": ndText }]
                         });
@@ -487,19 +487,19 @@ function generateParameters(type, linktext = true, linkhref = true) {
                             "nodeType": 2,
                             "contentType": type, // 内容类型
                             "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                            "name": "参数" + (n++) + "_链接地址",
-                            "desc": "", //参数描述
+                            "name": "para" + (n++) + "_linkAddress",
+                            "desc": "", //para描述
                             "relativeXpath": nodeList.length > 1 ? "" : ndPath,
                             "exampleValues": [{ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }]
                         });
                     }
-                } else if (nd.tagName == "INPUT") { //如果元素是输入项
+                } else if (nd.tagName == "INPUT") { //如果element是输入项
                     outputParameters.push({
                         "nodeType": 3,
                         "contentType": type, // 内容类型
                         "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                        "name": "参数" + (n++) + "_" + pname,
-                        "desc": "", //参数描述
+                        "name": "para" + (n++) + "_" + pname,
+                        "desc": "", //para描述
                         "relativeXpath": nodeList.length > 1 ? "" : ndPath,
                         "exampleValues": [{ "num": num, "value": ndText }]
                     });
@@ -508,19 +508,19 @@ function generateParameters(type, linktext = true, linkhref = true) {
                         "nodeType": 0,
                         "contentType": type, // 内容类型
                         "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                        "name": "参数" + (n++) + "_" + pname,
-                        "desc": "", //参数描述
+                        "name": "para" + (n++) + "_" + pname,
+                        "desc": "", //para描述
                         "relativeXpath": nodeList.length > 1 ? "" : ndPath,
                         "exampleValues": [{ "num": num, "value": ndText }]
                     });
                 }
-            } else { //如果元素节点已经存在,则只需要插入值就可以了
-                if (nd.tagName == "IMG") { //如果元素是图片
+            } else { //如果element节点已经存在,则只需要插入值就可以了
+                if (nd.tagName == "IMG") { //如果element是Image
                     outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
-                } else if (nd.tagName == "A") { //如果元素是超链接
+                } else if (nd.tagName == "A") { //如果element是超link
                     outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
                     outputParameters[1]["exampleValues"].push({ "num": num, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") });
-                } else if (nd.tagName == "INPUT") { //如果元素是输入项
+                } else if (nd.tagName == "INPUT") { //如果element是输入项
                     outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
                 } else { //其他所有情况
                     outputParameters[0]["exampleValues"].push({ "num": num, "value": ndText });
@@ -536,8 +536,8 @@ function generateParameters(type, linktext = true, linkhref = true) {
 
 }
 
-//根据nodelist列表内的元素生成参数列表
-//适合:nodelist中的元素为不同类型元素
+//根据nodelist列表内的element生成para列表
+//适合:nodelist中的element为不同类型element
 function generateMultiParameters() {
     clearParameters(false);
     let n = 1;
@@ -550,23 +550,23 @@ function generateMultiParameters() {
             outputParameterNodes.push({ "node": nd, "boxShadow": nd.style.boxShadow == "" || boxShadowColor ? "none" : nd.style.boxShadow });
             nd.style.boxShadow = boxShadowColor;
             ndText = $(nd).text();
-            if (nd.tagName == "IMG") { //如果元素是图片
+            if (nd.tagName == "IMG") { //如果element是Image
                 outputParameters.push({
                     "nodeType": 4, //节点类型
                     "contentType": 0, // 内容类型
                     "relative": false, //是否为相对xpath路径
-                    "name": "参数" + (n++) + "_图片地址",
-                    "desc": "", //参数描述
+                    "name": "para" + (n++) + "_imageAddress",
+                    "desc": "", //para描述
                     "relativeXpath": ndPath,
                     "exampleValues": [{ "num": 0, "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src") }]
                 });
-            } else if (nd.tagName == "A") { //如果元素是超链接
+            } else if (nd.tagName == "A") { //如果element是超link
                 outputParameters.push({
                     "nodeType": 1,
                     "contentType": 0, // 内容类型
                     "relative": false, //是否为相对xpath路径
-                    "name": "参数" + (n++) + "_链接文本",
-                    "desc": "", //参数描述
+                    "name": "para" + (n++) + "_linktext",
+                    "desc": "", //para描述
                     "relativeXpath": ndPath,
                     "exampleValues": [{ "num": 0, "value": ndText }]
                 });
@@ -574,18 +574,18 @@ function generateMultiParameters() {
                     "nodeType": 2,
                     "contentType": 0, // 内容类型
                     "relative": false, //是否为相对xpath路径
-                    "name": "参数" + (n++) + "_链接地址",
-                    "desc": "", //参数描述
+                    "name": "para" + (n++) + "_linkAddress",
+                    "desc": "", //para描述
                     "relativeXpath": ndPath,
                     "exampleValues": [{ "num": 0, "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href") }]
                 });
-            } else if (nd.tagName == "INPUT") { //如果元素是输入项
+            } else if (nd.tagName == "INPUT") { //如果element是输入项
                 outputParameters.push({
                     "nodeType": 3,
                     "contentType": 0, // 内容类型
                     "relative": false, //是否为相对xpath路径
-                    "name": "参数" + (n++) + "_文本",
-                    "desc": "", //参数描述
+                    "name": "para" + (n++) + "_text",
+                    "desc": "", //para描述
                     "relativeXpath": ndPath,
                     "exampleValues": [{ "num": 0, "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value") }]
                 });
@@ -594,8 +594,8 @@ function generateMultiParameters() {
                     "nodeType": 0,
                     "contentType": 0, // 内容类型
                     "relative": false, //是否为相对xpath路径
-                    "name": "参数" + (n++) + "_文本",
-                    "desc": "", //参数描述
+                    "name": "para" + (n++) + "_text",
+                    "desc": "", //para描述
                     "relativeXpath": ndPath,
                     "exampleValues": [{ "num": 0, "value": ndText }]
                 });
@@ -610,22 +610,22 @@ function generateMultiParameters() {
 }
 
 
-//处理子元素,对于每个块中多出的特殊元素,需要特殊处理
+//处理子element,对于每个块中多出的特殊element,需要特殊处理
 function handleDescendents() {
     let n = 1;
     chrome.storage.local.get({ parameterNum: 1 }, function(items) {
         let at = parseInt(new Date().getTime());
         n = items.parameterNum;
-        clearParameters(); //清除原来的参数列表
+        clearParameters(); //清除原来的para列表
         app._data.selectedDescendents = true;
         for (let num = 0; num < nodeList.length; num++) {
             let tnode = nodeList[num]["node"];
-            let stack = new Array(); //深度优先搜索遍历元素
+            let stack = new Array(); //深度优先搜索遍历element
             stack.push(tnode); //从此节点开始
             while (stack.length > 0) {
-                let nd = stack.pop(); // 挨个取出元素
+                let nd = stack.pop(); // 挨个取出element
                 if (nd.parentNode.tagName == "A" && nd.tagName == "SPAN") {
-                    continue; //对A标签内的SPAN元素不进行处理,剪枝,此时子元素根本不加入stack,即实现了此功能
+                    continue; //对A标签内的SPANelement不进行处理,剪枝,此时子element根本不加入stack,即实现了此功能
                 }
                 ndPath = readXPath(nd, 1, tnode);
                 let index = -1;
@@ -643,29 +643,29 @@ function handleDescendents() {
                 ndText = $(nd).contents().filter(function() {
                     return this.nodeType === 3;
                 }).text().replace(/\s+/g, '');
-                if (index == -1) { //从第二个节点开始,只插入那些不在参数列表中的元素,根据xpath进行寻址
-                    //如果当前节点除了子元素外仍然有其他文字或者该元素是图片/表单项,加入子元素节点
+                if (index == -1) { //从第二个节点开始,只插入那些不在para列表中的element,根据xpath进行寻址
+                    //如果当前节点除了子element外仍然有其他文字或者该element是Image/表单项,加入子element节点
                     if (ndText != "" || nd.tagName == "IMG" || nd.tagName == "INPUT" || nd.tagName == "A") {
-                        if (nd.tagName == "IMG") { //如果元素是图片
+                        if (nd.tagName == "IMG") { //如果element是Image
                             outputParameters.push({
                                 "nodeType": 4, //节点类型
                                 "contentType": 1, // 内容类型
-                                "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只选择了子元素没有选中全部的时候,需要判断
-                                "name": "参数" + (n++) + "_图片地址",
-                                "desc": "", //参数描述
+                                "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径,注意当只selection了子element没有选中全部的时候,需要判断
+                                "name": "para" + (n++) + "_imageAddress",
+                                "desc": "", //para描述
                                 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd), //同理需要判断
                                 "exampleValues": [{
                                     "num": num,
                                     "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src")
                                 }]
                             });
-                        } else if (nd.tagName == "A") { //如果元素是超链接
+                        } else if (nd.tagName == "A") { //如果element是超link
                             outputParameters.push({
                                 "nodeType": 1,
                                 "contentType": 0, // 内容类型
                                 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                                "name": "参数" + (n++) + "_链接文本",
-                                "desc": "", //参数描述
+                                "name": "para" + (n++) + "_linktext",
+                                "desc": "", //para描述
                                 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
                                 "exampleValues": [{ "num": num, "value": $(nd).text() }] //注意这里的ndtext是整个a的文字!!!
                             });
@@ -673,21 +673,21 @@ function handleDescendents() {
                                 "nodeType": 2,
                                 "contentType": 0, // 内容类型
                                 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                                "name": "参数" + (n++) + "_链接地址",
-                                "desc": "", //参数描述
+                                "name": "para" + (n++) + "_linkAddress",
+                                "desc": "", //para描述
                                 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
                                 "exampleValues": [{
                                     "num": num,
                                     "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href")
                                 }]
                             });
-                        } else if (nd.tagName == "INPUT") { //如果元素是输入项
+                        } else if (nd.tagName == "INPUT") { //如果element是输入项
                             outputParameters.push({
                                 "nodeType": 3,
                                 "contentType": 1, // 内容类型
                                 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                                "name": "参数" + (n++) + "_文本",
-                                "desc": "", //参数描述
+                                "name": "para" + (n++) + "_text",
+                                "desc": "", //para描述
                                 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
                                 "exampleValues": [{
                                     "num": num,
@@ -699,27 +699,27 @@ function handleDescendents() {
                                 "nodeType": 0,
                                 "contentType": 1, // 内容类型
                                 "relative": nodeList.length > 1 ? true : false, //是否为相对xpath路径
-                                "name": "参数" + (n++) + "_文本",
-                                "desc": "", //参数描述
+                                "name": "para" + (n++) + "_text",
+                                "desc": "", //para描述
                                 "relativeXpath": nodeList.length > 1 ? ndPath : readXPath(nd),
                                 "exampleValues": [{ "num": num, "value": ndText }]
                             });
                         }
                     }
-                } else //如果元素节点已经存在,则只需要插入值就可以了
+                } else //如果element节点已经存在,则只需要插入值就可以了
                 {
-                    if (nd.tagName == "IMG") { //如果元素是图片
+                    if (nd.tagName == "IMG") { //如果element是Image
                         outputParameters[index]["exampleValues"].push({
                             "num": num,
                             "value": nd.getAttribute("src") == null ? "" : $(nd).prop("src")
                         });
-                    } else if (nd.tagName == "A") { //如果元素是超链接
+                    } else if (nd.tagName == "A") { //如果element是超link
                         outputParameters[index]["exampleValues"].push({ "num": num, "value": $(nd).text() });
                         outputParameters[index + 1]["exampleValues"].push({
                             "num": num,
                             "value": nd.getAttribute("href") == null ? "" : $(nd).prop("href")
                         });
-                    } else if (nd.tagName == "INPUT") { //如果元素是输入项
+                    } else if (nd.tagName == "INPUT") { //如果element是输入项
                         outputParameters[index]["exampleValues"].push({
                             "num": num,
                             "value": nd.getAttribute("value") == null ? "" : nd.getAttribute("value")
@@ -734,14 +734,14 @@ function handleDescendents() {
             }
         }
         let at2 = parseInt(new Date().getTime());
-        console.log("选中子元素", at2, at, at2 - at);
+        console.log("选中子element", at2, at, at2 - at);
         generateValTable();
     });
 
 }
 
 
-//根据参数列表生成可视化参数界面
+//根据para列表生成可视化para界面
 function generateValTable(multiline = true) {
     let paravalues = [];
     for (let i = 0; i < outputParameters.length; i++) {
@@ -764,7 +764,7 @@ function generateValTable(multiline = true) {
 
 // 选中第一个节点,自动寻找同类节点
 // 方法:/div[1]/div[2]/div[2]/a[1]
-// 从倒数第一个节点开始找,看去掉方括号之后是否元素数目变多,如上面的变成/div[1]/div[2]/div[2]/a
+// 从倒数第一个节点开始找,看去掉方括号之后是否element数目变多,如上面的变成/div[1]/div[2]/div[2]/a
 // 如果没有,则恢复原状,然后试试倒数第二个:/div[1]/div[2]/div/a[1]
 // 直到找到第一个变多的节点或者追溯到根节点为止
 function findRelated() {
@@ -789,9 +789,9 @@ function findRelated() {
         tempIndexList[i] = -1; //删除索引值
         tempPath = combineXpath(nodeNameList, tempIndexList); //生成新的xpath
         var result = document.evaluate(tempPath, document, null, XPathResult.ANY_TYPE, null);
-        result.iterateNext(); //枚举第一个元素
-        if (result.iterateNext() != null) { //如果能枚举到第二个元素,说明存在同类元素,选中同类元素,结束循环
-            app.$data.nowPath = tempPath; //标记此元素xpath
+        result.iterateNext(); //枚举第一个element
+        if (result.iterateNext() != null) { //如果能枚举到第二个element,说明存在同类element,选中同类element,结束循环
+            app.$data.nowPath = tempPath; //标记此elementxpath
             pushToReadyList(tempPath);
             break;
         }
@@ -801,11 +801,11 @@ function findRelated() {
 }
 
 
-//根据path将元素放入readylist中
+//根据path将element放入readylist中
 function pushToReadyList(path) {
     result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null);
-    var node = result.iterateNext(); //枚举第一个元素
-    while (node) { //只添加不在已选中列表内的元素
+    var node = result.iterateNext(); //枚举第一个element
+    while (node) { //只添加不在已选中列表内的element
         let exist = false;
         for (o of nodeList) {
             if (o["node"] == node) {
@@ -817,19 +817,19 @@ function pushToReadyList(path) {
             readyList.push({ "node": node, "bgColor": node.style.backgroundColor, "boxShadow": node.style.boxShadow == "" || boxShadowColor ? "none" : node.style.boxShadow });
         }
         node.style.boxShadow = boxShadowColor;
-        node = result.iterateNext(); //枚举下一个元素
+        node = result.iterateNext(); //枚举下一个element
     }
 }
 
-//将readyList中的元素放入选中节点中
+//将readyList中的element放入选中节点中
 function readyToList(step, dealparameters = true) {
     for (o of readyList) {
         nodeList.push({ node: o["node"], "step": step, bgColor: o["bgColor"], "boxShadow": o["boxShadow"], xpath: readXPath(o["node"], 1) });
         o["node"].style.backgroundColor = selectedColor;
     }
     clearReady();
-    if (dealparameters) { //防止出现先选中子元素再选中全部失效的问题
-        generateParameters(0); //根据nodelist列表内的元素生成参数列表,0代表纯文本
+    if (dealparameters) { //防止出现先选中子element再选中全部失效的问题
+        generateParameters(0); //根据nodelist列表内的element生成para列表,0代表纯text
     }
 
 }
@@ -847,7 +847,7 @@ function combineXpath(nameList, indexList) {
     return finalPath;
 }
 
-//专门测试已经选中的这些元素之间有没有相关性
+//专门测试已经选中的这些element之间有没有相关性
 // 举例:
 // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[1]/div[3]/a[22]
 // /html/body/div[3]/div[1]/div[1]/div[1]/div[3]/div[2]/div[3]/a[25]
@@ -859,7 +859,7 @@ function relatedTest() {
     var testpath = "";
     for (i = 0; i < nodeList.length; i++) {
         var testnumList = []; //用于比较节点索引号不同
-        var tpath = nodeList[i]["xpath"].split("/").splice(1); //清理第一个空元素
+        var tpath = nodeList[i]["xpath"].split("/").splice(1); //清理第一个空element
         for (j = 0; j < tpath.length; j++) {
             if (tpath[j].indexOf("[") >= 0) { //如果存在索引值
                 testnumList.push(parseInt(tpath[j].split("[")[1].replace("]", ""))); //只留下数字
@@ -869,16 +869,16 @@ function relatedTest() {
             tpath[j] = tpath[j].split("[")[0];
         }
         tp = tpath.join("/");
-        if (i > 0 && testpath != tp) { //如果去除括号后元素内存在不一致情况,直接返回默认情况代码100
-            app.$data.nowPath = ""; //标记此元素xpath
+        if (i > 0 && testpath != tp) { //如果去除括号后element内存在不一致情况,直接返回默认情况代码100
+            app.$data.nowPath = ""; //标记此elementxpath
             return 100;
         }
         testpath = tp;
         testList.push(testnumList);
     }
-    testpath = testpath.split("/"); //清理第一个空元素
+    testpath = testpath.split("/"); //清理第一个空element
     var indexList = []; //记录新生成的xpath
-    //如果选中的元素属于同样的序列,则计算出序列的最佳xpath表达式
+    //如果选中的element属于同样的序列,则计算出序列的最佳xpath表达式
     for (j = 0; j < testList[0].length; j++) {
         indexList.push(testList[0][j]);
         for (i = 1; i < testList.length; i++) {
@@ -889,14 +889,14 @@ function relatedTest() {
         }
     }
     var finalPath = combineXpath(testpath, indexList);
-    app.$data.nowPath = finalPath; //标记此元素xpath
+    app.$data.nowPath = finalPath; //标记此elementxpath
     pushToReadyList(finalPath);
     let at2 = parseInt(new Date().getTime());
     console.log("手动:", at2, at, at2 - at);
     return 50; //先返回给默认码
 }
 
-//实现提示拖拽功能
+//实现提示 box拖拽功能
 $('.tooldrag').mousedown(function(e) {
     // e.pageX
     var positionDiv = $(this).offset();

+ 1 - 1
Extension/ServiceWrapper/scripts/messageInteraction.js

@@ -1,6 +1,6 @@
 //实现与后台和流程图部分的交互
 
-if (window.location.href.indexOf("183.129.170.180") >= 0) {
+if (window.location.href.indexOf("backEndAddressServiceWrapper") >= 0) {
     throw "serviceGrid"; //如果是服务器网页页面,则不执行工具
 }
 

+ 674 - 0
LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.

+ 134 - 10
Readme.md

@@ -1,31 +1,155 @@
+# 请您Star Please Star
+
+如果你觉得此工具不错,请轻轻点击此页面右上角**Star**按钮增加项目曝光度,谢谢!
+
+If you think this tool is good, please gently click the **Star** button in the upper right corner at this page to increase the project exposure, thank you!
+
+# 无代码服务可视化Web数据采集爬虫器 Code-Free Visual Web Data Crawler/Spider (Service Wrapper)
+
+一个可以可视化无代码设计和执行的面向服务架构的爬虫软件(服务包装器)。
+A service oriented architecture GUI visual code-free web crawler/spider (service wrapper).
+
 
 # 发布版本
-## Windows版本可执行程序:<http://naibo.wang/exe/ServiceWrapper.7z>
-打开压缩包内的ServiceWrapper.exe即可在Windows10系统执行,无需配置环境。
+## Windows版本可执行程序:<https://github.com/NaiboWang/ServiceWrapper/releases/download/v0.5.0/ServiceWrapper.7z>
+打开压缩包内的ServiceWrapper.exe即可在Windows10/11或以上系统执行,无需配置环境(其余Windows系统需手动安装.net Framework 4.5)
 数据存储后放在Data/文件夹内
-## 视频教程:<http://naibo.wang/exe/tutorial.mp4>
+## 中文视频教程:<https://github.com/NaiboWang/ServiceWrapper/releases/download/v0.5.0/tutorial_CN.mp4>
+
+
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+# 目录
+注:文档待完善
+- [请您Star Please Star](#请您star-please-star)
+- [无代码服务可视化Web数据采集爬虫器 Code-Free Visual Web Data Crawler/Spider (Service Wrapper)](#无代码服务可视化web数据采集爬虫器-code-free-visual-web-data-crawlerspider-service-wrapper)
+- [发布版本](#发布版本)
+  - [Windows版本可执行程序:<https://github.com/NaiboWang/ServiceWrapper/releases/download/v0.5.0/ServiceWrapper.7z>](#windows版本可执行程序httpsgithubcomnaibowangservicewrapperreleasesdownloadv050servicewrapper7z)
+  - [中文视频教程:<https://github.com/NaiboWang/ServiceWrapper/releases/download/v0.5.0/tutorial_CN.mp4>](#中文视频教程httpsgithubcomnaibowangservicewrapperreleasesdownloadv050tutorial_cnmp4)
+- [目录](#目录)
+  - [界面截图](#界面截图)
+      - [软件界面示例](#软件界面示例)
+      - [块和子块及表单定义](#块和子块及表单定义)
+      - [已选中和待选择示例](#已选中和待选择示例)
+      - [京东商品块选择示例:](#京东商品块选择示例)
+      - [京东商品标题自动匹配选择示例](#京东商品标题自动匹配选择示例)
+      - [分块选择所有子元素示例](#分块选择所有子元素示例)
+      - [同类型元素自动和手动匹配示例](#同类型元素自动和手动匹配示例)
+      - [四种选择方式示例](#四种选择方式示例)
+      - [输入文字示例](#输入文字示例)
+      - [循环点击58同城房屋标题以进入详情页采集示例](#循环点击58同城房屋标题以进入详情页采集示例)
+      - [采集元素文本示例](#采集元素文本示例)
+      - [流程图界面介绍](#流程图界面介绍)
+      - [循环选项示例](#循环选项示例)
+      - [循环点击下一页示例](#循环点击下一页示例)
+      - [条件分支示例](#条件分支示例)
+      - [完整采集流程图示例](#完整采集流程图示例)
+      - [完整采集流程图转换为常规流程图示例](#完整采集流程图转换为常规流程图示例)
+      - [服务信息示例](#服务信息示例)
+      - [服务调用示例](#服务调用示例)
+      - [58 同城房源信息采集服务部分采集结果展示](#58-同城房源信息采集服务部分采集结果展示)
+  - [服务包装手动版程序结构](#服务包装手动版程序结构)
+    - [Chrome插件部分](#chrome插件部分)
+    - [后台流程图部分](#后台流程图部分)
+    - [服务展示部分](#服务展示部分)
+    - [C#部分](#c部分)
+    - [后台服务页面](#后台服务页面)
+    - [服务执行](#服务执行)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+## 界面截图
+
+#### 软件界面示例
+
+![pic](media/Picture.png)
+#### 块和子块及表单定义
+
+![pic](media/Picture2.png)
+#### 已选中和待选择示例
+
+![pic](media/Picture7.png)
+#### 京东商品块选择示例:
+
+![pic](media/Picture1.png)
+
+
+#### 京东商品标题自动匹配选择示例
+
+![pic](media/Picture5.png)
+#### 分块选择所有子元素示例
+
+![pic](media/Picture6.png)
+
+#### 同类型元素自动和手动匹配示例
+
+![pic](media/Picture8.png)
+#### 四种选择方式示例
+
+![pic](media/Picture90.png)
+#### 输入文字示例
+
+![pic](media/Picture10.png)
+#### 循环点击58同城房屋标题以进入详情页采集示例
+
+![pic](media/Picture12.png)
+#### 采集元素文本示例
+
+![pic](media/Picture14.png)
+#### 流程图界面介绍
+
+![pic](media/Picture4.png)
+#### 循环选项示例
+
+![pic](media/Picture9.png)
+
+#### 循环点击下一页示例
+
+![pic](media/Picture11.png)
+
+#### 条件分支示例
+
+![pic](media/Picture13.png)
+#### 完整采集流程图示例
+
+![pic](media/Picture16.png)
+#### 完整采集流程图转换为常规流程图示例
+
+![pic](media/Picture91.png)
+#### 服务信息示例
+
+![pic](media/Picture15.png)
+
+#### 服务调用示例
+
+![pic](media/Picture17.png)
+
+
+#### 58 同城房源信息采集服务部分采集结果展示
+![pic](media/Picture18.png)
 
-# 服务包装手动版程序结构
-## Chrome插件部分
+## 服务包装手动版程序结构
+### Chrome插件部分
 * Extension/app内的文件
 
-## 后台流程图部分
+### 后台流程图部分
 * ServiceGrid/frontEnd/FlowChart.html
 * ServiceGrid/frontEnd/FlowChart.js
 * ServiceGrid/frontEnd/FlowChart.css
 * ServiceGrid/frontEnd/logic.css
 
-## 服务展示部分
+### 服务展示部分
 * 服务列表:ServiceGrid/frontEnd/serviceList.html
 * 服务信息:ServiceGrid/frontEnd/serviceInfo.html
 * 新服务:ServiceGrid/frontEnd/newService.html
 * 调用服务:ServiceGrid/frontEnd/invokeService.html
 
-## C#部分
+### C#部分
 * C#/内的文件
 
-## 后台服务页面
+### 后台服务页面
 * Django后台:ServiceGrid/backEnd/*
 
-## 服务执行
+### 服务执行
 * ExcuteStage/ServiceWrapper_ExcuteStage.py

+ 3 - 0
ServiceGrid/backEnd/.gitignore

@@ -0,0 +1,3 @@
+__pycache__/
+nohup.out
+*.pid

+ 1 - 0
ServiceGrid/backEnd/backEnd/.gitignore

@@ -0,0 +1 @@
+dbconfig.py

+ 1 - 0
ServiceGrid/backEnd/backEnd/settings.py

@@ -38,6 +38,7 @@ INSTALLED_APPS = [
     'django.contrib.messages',
     'corsheaders',
     'django.contrib.staticfiles',
+    'sslserver',
 ]
 
 MIDDLEWARE = [

+ 0 - 2
ServiceGrid/backEnd/backEnd/urls.py

@@ -27,6 +27,4 @@ urlpatterns = [
     path('backEnd/invokeService',view.invokeService), #调用服务接口
     path('backEnd/queryTask',view.queryTask), #调用服务接口
     path('backEnd/queryTasks',view.queryTasks), #调用服务接口
-    path('backEnd/dongcang/insertInfo',view.insertInfo), 
-    path('backEnd/dongcang/queryInfos',view.queryInfos), 
 ]

+ 44 - 31
ServiceGrid/backEnd/backEnd/view.py

@@ -3,49 +3,49 @@ from django.http import HttpResponse
 import pymongo
 import json
 from bson import json_util
-
+from dbconfig import myclient, mycol, taskcol
 """
-高分服务器地址:192.168.14.113
-用户名:root
-密码:zju.edu.cn
-ftp用户:naibowang
-密码:qq
-程序位置:/root/servicewrapper
+uncomment this to deploy database
 """
+# myclient = pymongo.MongoClient('mongodb://username:password@localhost:27017/')
+# mydb = myclient['service']
+# mycol = mydb["services"]
+# taskcol = mydb["tasks"]  # 生成新任务并返回ID
+
 
 def hello(request):
     return HttpResponse("Hello world ! ")
 
 
-myclient = pymongo.MongoClient('mongodb://localhost:27017/')
-mydb = myclient['service']
-mycol = mydb["services"]
-taskcol = mydb["tasks"] #生成新任务并返回ID
-
 def queryServices(request):
-    result = mycol.find({"id" : { "$ne" : -2 }},{ "name": 1, "id": 1, "url": 1, "_id": 0 }) #查询id不为-2的元素
+    result = mycol.find({"id": {"$ne": -2}}, {"name": 1,
+                        "id": 1, "url": 1, "_id": 0})  # 查询id不为-2的元素
     return HttpResponse(json.dumps(list(result)), content_type="application/json")
 
+
 def queryTasks(request):
-    result = taskcol.find({"id" : { "$ne" : -2 }},{ "name": 1, "id": 1, "url": 1, "_id": 0 }) #查询id不为-2的元素
+    result = taskcol.find(
+        {"id": {"$ne": -2}}, {"name": 1, "id": 1, "url": 1, "_id": 0})  # 查询id不为-2的元素
     return HttpResponse(json.dumps(list(result)), content_type="application/json")
 
+
 def queryService(request):
     if 'id' in request.GET:
         tid = request.GET['id']
     else:
         tid = "0"
-    result = mycol.find({"id":int(tid)},{"_id":0})
+    result = mycol.find({"id": int(tid)}, {"_id": 0})
     r = list(result)[0]
     return HttpResponse(json.dumps(r), content_type="application/json")
 
+
 def queryTask(request):
     if 'id' in request.GET:
         tid = request.GET['id']
     else:
         tid = "0"
-    
-    result = taskcol.find({"id":int(tid)},{"_id":0})
+
+    result = taskcol.find({"id": int(tid)}, {"_id": 0})
     r = list(result)[0]
     return HttpResponse(json.dumps(r), content_type="application/json")
 
@@ -54,55 +54,68 @@ def manageService(request):
     data = request.POST['paras']
     data = json.loads(data)
     if int(data["id"]) == -1:
-        count = mycol.find({}).count()
-        data["id"] = count #修改id
-        mycol.insert_one(data) 
+        count = mycol.count_documents({})
+        data["id"] = count  # 修改id
+        mycol.insert_one(data)
     else:
-        mycol.delete_one({"id":int(data["id"])})
+        mycol.delete_one({"id": int(data["id"])})
         mycol.insert_one(data)
     return HttpResponse(data["id"])
 
+
 def deleteService(request):
     if 'id' in request.GET:
         tid = request.GET['id']
-        myquery = { "id": int(tid) }
-        newvalues = { "$set": { "id": -2 } } #删除就是将服务id变成-2,并没有真正删除
+        myquery = {"id": int(tid)}
+        newvalues = {"$set": {"id": -2}}  # 删除就是将服务id变成-2,并没有真正删除
         mycol.update_one(myquery, newvalues)
     return HttpResponse("Done!")
 
 # 调用服务
+
+
 def invokeService(request):
     tid = request.POST['id']
     data = json.loads(request.POST['paras'])
-    result = mycol.find({"id":int(tid)},{"_id":0})
+    result = mycol.find({"id": int(tid)}, {"_id": 0})
     service = list(result)[0]
-    for key,value in data.items():
+    try:
+        service["links"] = data["urlList_0"]
+    except:
+        pass
+    for key, value in data.items():
         for i in range(len(service["inputParameters"])):
-            if key == service["inputParameters"][i]["name"]: #能调用
+            if key == service["inputParameters"][i]["name"]:  # 能调用
                 nodeId = int(service["inputParameters"][i]["nodeId"])
                 node = service["graph"][nodeId]
                 if node["option"] == 1:
                     node["parameters"]["links"] = value
                 elif node["option"] == 4:
                     node["parameters"]["value"] = value
+                elif node["option"] == 8 and node["parameters"]["loopType"] == 0:
+                    # print("loopType 0", value)
+                    node["parameters"]["exitCount"] = int(value)
+                    # print(node)
                 elif node["option"] == 8:
                     node["parameters"]["textList"] = value
                 break
-    count = taskcol.find({}).count()
-    service["id"] = count #修改id
-    taskcol.insert_one(service) 
+    count = taskcol.count_documents({})
+    service["id"] = count  # 修改id
+    taskcol.insert_one(service)
     return HttpResponse(count)
 
+
 def insertInfo(request):
     request.GET = request.GET.copy()
     data = request.GET
     dbd = myclient['dongcang']
     cold = dbd["redirect"]
-    cold.insert_one(data) 
+    cold.insert_one(data)
     return HttpResponse("200")
 
+
 def queryInfos(request):
     dbd = myclient['dongcang']
     cold = dbd["redirect"]
     result = cold.find()
-    return HttpResponse(json_util.dumps(result).encode('utf-8').decode('unicode_escape'), content_type="application/json")
+    return HttpResponse(json_util.dumps(result).encode('utf-8').decode('unicode_escape'), content_type="application/json")

BIN
ServiceGrid/backEnd/db.sqlite3


+ 40 - 0
ServiceGrid/backEnd/server.conf

@@ -0,0 +1,40 @@
+server {
+        listen 443 ssl;
+
+        server_name servicewrapper.naibo.wang;
+
+        #ssl_certificate cert/5640170_naibo.wang.pem;
+        #ssl_certificate_key cert/5640170_naibo.wang.key;
+        ssl_certificate /etc/letsencrypt/live/servicewrapper.naibo.wang/fullchain.pem;
+        ssl_certificate_key /etc/letsencrypt/live/servicewrapper.naibo.wang/privkey.pem;
+
+        ssl_session_timeout 5m;
+        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
+        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
+        ssl_prefer_server_ciphers on;
+        
+        root /home/naibo/server/ServiceWrapper/ServiceGrid/frontEnd;
+        index serviceList.html;     
+
+  
+	location /backEnd {
+            include uwsgi_params;
+            uwsgi_connect_timeout 30;
+            uwsgi_pass  127.0.0.1:8072;
+        }
+
+        location /static {
+            autoindex on;
+            autoindex_localtime on;
+            alias /home/naibo/static;
+            try_files $uri $uri/ =404;
+        }
+}
+
+
+server {
+    listen 80;
+    listen [::]:80;
+    server_name xtra3090.d2.comp.nus.edu.sg naibo.wang gui.naibo.wang servicewrapper.naibo.wang; #需要将yourdomain.com替换成证书绑定的域名。
+    return 301 https://$host$request_uri;
+}

+ 92 - 68
ServiceGrid/frontEnd/FlowChart.html

@@ -16,29 +16,29 @@
 
 <body>
     <div id="tip" class="alert alert-success alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
-        <button type="button" class="close" data-dismiss="alert">&times;</button> 提示:保存成功!
+        <button type="button" class="close" data-dismiss="alert">&times;</button> Hint: Save Successfully!
     </div>
     <div style="display:flex">
         <div style="width: 200px;float:left">
             <div class="toolbox" style="text-align:center;margin: 20px;border-radius:10px;border:navy solid;background-color:rgb(242,243,245);z-index: 9999;">
-                <div style="padding: 10px;border-radius:10px;font-size: 20px;">工具箱</div>
-                <button type="button" id="save" data-toggle="modal" data-target="#myModal" onmousedown="$('#myModal').modal('show');" class="btn btn-primary">保存服务</button>
+                <div style="padding: 10px;border-radius:10px;font-size: 20px;">Toolbox</div>
+                <button type="button" id="save" data-toggle="modal" data-target="#myModal" onmousedown="$('#myModal').modal('show');" class="btn btn-primary">Save Service</button>
                 <!-- <button type="button" data=1 class="btn btn-outline-primary options">打开网页</button> -->
-                <button type="button" data=2 class="btn btn-outline-primary options">点击元素</button>
-                <button type="button" data=3 class="btn btn-outline-primary options">提取数据</button>
-                <button type="button" data=4 class="btn btn-outline-primary options">输入文字</button>
-                <button type="button" data=5 class="btn btn-outline-primary options">识别验证码</button>
-                <button type="button" data=6 style="font-size: 14px!important;" class="btn btn-outline-primary options">切换下拉选项</button>
-                <button type="button" data=7 class="btn btn-outline-primary options">移动到元素</button>
-                <button type="button" data=8 class="btn btn-outline-primary options">循环</button>
-                <button type="button" data=9 class="btn btn-outline-primary options">判断条件</button>
+                <button type="button" data=2 class="btn btn-outline-primary options">Click Element</button>
+                <button type="button" data=3 class="btn btn-outline-primary options">Extract Data</button>
+                <button type="button" data=4 class="btn btn-outline-primary options">Input Text</button>
+                <!-- <button type="button" data=5 class="btn btn-outline-primary options">-</button> -->
+                <!-- <button type="button" data=6 style="font-size: 14px!important;" class="btn btn-outline-primary options">Change Option</button> -->
+                <!-- <button type="button" data=7 class="btn btn-outline-primary options">-</button> -->
+                <button type="button" data=8 class="btn btn-outline-primary options">Loop</button>
+                <button type="button" data=9 class="btn btn-outline-primary options">If Condition</button>
                 <div>-----------------</div>
-                <button type="button" data=13 class="btn btn-outline-primary options" title="调整下一个要插入的节点的位置">调整锚点</button>
-                <button type="button" data=10 class="btn btn-outline-primary options">剪切元素</button>
-                <button type="button" data=11 class="btn btn-outline-primary options">复制元素</button>
-                <button type="button" data=12 class="btn btn-outline-primary options">删除元素</button>
-                <button type="button" data=0 class="btn btn-outline-primary2 options">取消操作</button>
-                <div style="text-align: left;margin: 10px;font-size:15px!important">提示:点击上方操作按钮后点击要放置元素的位置处的箭头,可按取消操作按钮取消。</div>
+                <button type="button" data=13 class="btn btn-outline-primary options" title="调整下一个要插入的节点的位置">Set Anchor</button>
+                <button type="button" data=10 class="btn btn-outline-primary options">Cut Element</button>
+                <button type="button" data=11 class="btn btn-outline-primary options">Copy Element</button>
+                <button type="button" data=12 class="btn btn-outline-primary options">Del Element</button>
+                <button type="button" data=0 class="btn btn-outline-primary2 options">Cancel</button>
+                <div style="text-align: left;margin: 10px;font-size:15px!important"></div>
             </div>
         </div>
         <div style="margin-top:20px;border: solid;height:850px;overflow: auto;width:58%;float:right">
@@ -54,47 +54,47 @@
             </div> -->
             <div class="Modify" id="app">
                 <div>
-                    <label>选项名称:</label>
+                    <label>Option Name:</label>
                     <input onkeydown="inputDelete(event)" class="form-control" v-model='list.nl[index.nowNodeIndex]["title"]'></input>
                 </div>
                 <!-- 下面是10种不同类型操作选项的不同的配置页面 -->
                 <div class="elements" v-if="nodeType==1">
                     <div v-if="nowNode['isInLoop']">
                         <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
-                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的链接</p>
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>Use link inside the Loop</p>
                     </div>
                     <div v-if='!useLoop'>
                         <label>url:</label>
                         <input onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["url"]'></input>
-                        <label>填入的全部链接:</label>
+                        <label>All links filled:</label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["links"]'></textarea>
                     </div>
-                    <label>执行完是否向下滚动:</label>
+                    <label>After executed, whether scroll down:</label>
                     <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
-                        <option value = 0>不滚动</option>
-                        <option value = 1>向下滚动一屏</option>
-                        <option value = 2>滚动到底部</option>
+                        <option value = 0>No</option>
+                        <option value = 1>Scroll one screen</option>
+                        <option value = 2>Scroll to the end</option>
                       </select>
-                    <label>滚动次数:</label>
+                    <label>Scroll Times:</label>
                     <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
                 </div>
 
                 <div class="elements" v-if="nodeType==2">
                     <div v-if="nowNode['isInLoop']">
                         <!-- 如果在循环内才显示此行元素 -->
-                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的元素</p>
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>Use element inside the Loop</p>
                     </div>
                     <div v-if='!useLoop'>
                         <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
                     </div>
-                    <label>执行完是否向下滚动:</label>
+                    <label>After executed, whether scroll down:</label>
                     <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
-                        <option value = 0>不滚动</option>
-                        <option value = 1>向下滚动一屏</option>
-                        <option value = 2>滚动到底部</option>
+                        <option value = 0>No</option>
+                        <option value = 1>Scroll one screen</option>
+                        <option value = 2>Scroll to the end</option>
                       </select>
-                    <label>滚动次数:</label>
+                    <label>Scroll Times:</label>
                     <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
 
                 </div>
@@ -103,9 +103,9 @@
                     <div class="toolkitcontain">
                         <table class="toolkittb2" cellspacing="0">
                             <tbody>
-                                <th>字段名</th>
-                                <th style="width:200px">示例值</th>
-                                <th>操作</th>
+                                <th>Field Name</th>
+                                <th style="width:200px">Example Value</th>
+                                <th>Operations</th>
                             </tbody>
                         </table>
                         <table class="toolkittb4" cellspacing="0">
@@ -115,22 +115,37 @@
                                     </td>
                                     <td style="width:200px">{{paras.parameters[i-1]["exampleValues"][0]["value"]}}</td>
                                     <td>
-                                        <a v-on:mousedown="modifyParas(i-1)">修改</a>
-                                        <a v-on:mousedown="deleteParas(i-1)">删除</a>
-                                        <a v-on:mousedown="upParas(i-1)">上移</a>
-                                        <a v-on:mousedown="downParas(i-1)">下移</a>
+                                        <a v-on:mousedown="modifyParas(i-1)">Modify</a>
+                                        <a v-on:mousedown="deleteParas(i-1)">Delete</a>
+                                        <a v-on:mousedown="upParas(i-1)">Up</a>
+                                        <a v-on:mousedown="downParas(i-1)">Down</a>
                                     </td>
                                 </tr>
                         </table>
                     </div>
                     <div style="font-size: 13px;" v-if="paraIndex<paras.parameters.length">
-                        <label>当前编辑参数名: <strong>{{paras.parameters[paraIndex]["name"]}}</strong></label>
-                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='paras.parameters[paraIndex]["relative"]'></input>使用相对循环内的XPATH</p>
+                        <label>Current parameter name: <strong>{{paras.parameters[paraIndex]["name"]}}</strong></label>
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='paras.parameters[paraIndex]["relative"]'></input>Use relative XPATH</p>
                         <label>XPATH: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='paras.parameters[paraIndex]["relativeXpath"]'></textarea>
-                        <label>参数描述:</label>
+                        <label>Extraction Type</label>
+                        <select v-model='paras.parameters[paraIndex]["contentType"]' class="form-control">
+                            <option :value = 0>Text (include child element)</option>
+                            <option :value = 1>Text (exclude child element)</option>
+                            <option :value = 2>innerHTML</option>
+                            <option :value = 3>outerHTML</option>
+                        </select>
+                        <label>Node Type</label>
+                        <select v-model='paras.parameters[paraIndex]["nodeType"]' class="form-control">
+                            <option :value = 0>Ordinary Node</option>
+                            <option :value = 1>Link Text</option>
+                            <option :value = 2>Link Address</option>
+                            <option :value = 3>Form Value</option>
+                            <option :value = 4>Image Address</option>
+                        </select>
+                        <label>Parameter Description:</label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='paras.parameters[paraIndex]["desc"]'></textarea>
-                        <label>元素找不到时的值:</label>
+                        <label>Absent value when cannot find the element:</label>
                         <input onkeydown="inputDelete(event)" class="form-control" v-model='paras.parameters[paraIndex]["default"]'></textarea>
                     </div>
 
@@ -140,10 +155,10 @@
                 <div class="elements" v-if="nodeType==4">
                     <div v-if="nowNode['isInLoop']">
                         <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
-                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的文本</p>
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>Use text inside the Loop</p>
                     </div>
                     <div v-if='!useLoop'>
-                        <label>输入值:</label>
+                        <label>Input Value:</label>
                         <input onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["value"]'></input>
                     </div>
 
@@ -165,31 +180,40 @@
 
                 <div class="elements" v-if="nodeType==8">
                     <!-- 循环选项 -->
-                    <label>循环类型:</label>
+                    <label>Loop Type:</label>
                     <select v-model='loopType' class="form-control">
-                        <option value = 0>单个元素</option>
-                        <option value = 1>不固定元素列表</option>
-                        <option value = 2>固定元素列表</option>
-                        <option value = 3>文本列表</option>
-                        <option value = 4>网址列表</option>
+                        <option value = 0>Single Element</option>
+                        <option value = 1>Unfixed Element List</option>
+                        <option value = 2>Fixed Element List</option>
+                        <option value = 3>Text List</option>
+                        <option value = 4>Weblink List</option>
                       </select>
                     <div v-if='parseInt(loopType) < 2'>
                         <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
                     </div>
                     <div v-if='parseInt(loopType) == 2'>
-                        <label>XPath列表:</label>
+                        <label>XPath List:</label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["pathList"]'></textarea>
                     </div>
                     <div v-if='parseInt(loopType) > 2'>
-                        <label>内容列表:</label>
+                        <label>Content List:</label>
                         <textarea onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["textList"]'></textarea>
                     </div>
                     <!-- 这里添加退出循环条件,找不到元素肯定退出循环 -->
-                    <label v-if='parseInt(loopType) == 0'>最多执行循环次数(0代表不设置):</label>
+                    <label v-if='parseInt(loopType) == 0'>Max Loop time(0 means infinite):</label>
                     <input onkeydown="inputDelete(event)" required v-if='parseInt(loopType) == 0' class="form-control" type="number" v-model.number='nowNode["parameters"]["exitCount"]'></input>
-                    <label><b>历史记录回退后</b>等待秒数:</label>
+                    <label><b>History back</b> wait time:</label>
                     <input onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["historyWait"]'></input>
+                    <label>After executed, whether scroll down:</label>
+                    <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
+                        <option value = 0>No</option>
+                        <option value = 1>Scroll one screen</option>
+                        <option value = 2>Scroll to the end</option>
+                      </select>
+                    <label>Scroll Times:</label>
+                    <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
+
                 </div>
 
                 <div class="elements" v-if="nodeType==9">
@@ -197,22 +221,22 @@
                 </div>
 
                 <div class="elements" v-if="nodeType==10">
-                    <label>条件类型:</label>
+                    <label>Condition Type:</label>
                     <select v-model='TClass' class="form-control">
-                        <option value = 0>无条件</option>
-                        <option value = 1>当前页面包括文本</option>
-                        <option value = 2>当前页面包括元素</option>
-                        <option v-if="nowNode['isInLoop']" value = 3>当前循环项包括文本</option>
-                        <option v-if="nowNode['isInLoop']" value = 4>当前循环项包括元素</option>
+                        <option value = 0>No Condition</option>
+                        <option value = 1>Text inside current page</option>
+                        <option value = 2>Element inside current page</option>
+                        <option v-if="nowNode['isInLoop']" value = 3>Text inside current loop</option>
+                        <option v-if="nowNode['isInLoop']" value = 4>Element inside current loop</option>
                       </select>
-                    <label v-if='TClass'>包含的文字/元素XPATH: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                    <label v-if='TClass'>Text/Xpath of Element: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
                     <textarea onkeydown="inputDelete(event)" required placeholder="如果是当前循环包含元素,则输入相对元素的xpath。" v-if='TClass' class="form-control" rows="3" v-model='nowNode["parameters"]["value"]'></textarea>
                 </div>
                 <div style="margin-top:5px">
-                    <label><b>执行后</b>等待秒数:</label>
+                    <label>Seconds <b>after executed</b>:</label>
                     <input onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["wait"]'></input>
                 </div>
-                <button class="btn btn-outline-primary" style="margin-top: 20px;" id="confirm">确定</button>
+                <button class="btn btn-outline-primary" style="margin-top: 20px;" id="confirm">Confirm</button>
 
             </div>
 
@@ -225,20 +249,20 @@
         <div class="modal-dialog">
             <div class="modal-content">
                 <div class="modal-header">
-                    <h4 class="modal-title" id="myModalLabel">保存服务</h4>
+                    <h4 class="modal-title" id="myModalLabel">Save Service</h4>
                     <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                 </div>
                 <div class="modal-body">
                     <input onkeydown="inputDelete(event)" id="serviceId" type="hidden" name="serviceId" value="-1"></input>
                     <input onkeydown="inputDelete(event)" id="url" type="hidden" name="url" value="about:blank"></input>
-                    <label>服务名称:</label>
+                    <label>Service Name:</label>
                     <input onkeydown="inputDelete(event)" required name="serviceName" value="新web服务" id="serviceName" class="form-control"></input>
-                    <label>服务描述:</label>
+                    <label>Service Description:</label>
                     <textarea onkeydown="inputDelete(event)" id="serviceDescription" name="serviceDescription" class="form-control" rows="3"></textarea>
                 </div>
                 <div class="modal-footer">
-                    <button type="button" id="saveAsButton" class="btn btn-outline-primary">另存为</button>
-                    <button type="button" id="saveButton" class="btn btn-primary">保存</button>
+                    <button type="button" id="saveAsButton" class="btn btn-outline-primary">Save as</button>
+                    <button type="button" id="saveButton" class="btn btn-primary">Save</button>
                 </div>
             </div>
             <!-- /.modal-content -->

+ 20 - 20
ServiceGrid/frontEnd/FlowChart.js

@@ -116,13 +116,13 @@ var app = new Vue({
                 return "OuterHTML";
             }
             if (nodeType == 2) {
-                return "链接地址";
+                return "Link Address";
             } else if (nodeType == 1) {
-                return "链接文本";
+                return "Link Text";
             } else if (nodeType == 4) {
-                return "图片地址";
+                return "Image Address";
             } else {
-                return "文本";
+                return "Text";
             }
         }
     }
@@ -160,7 +160,7 @@ function newNode(node) {
     {
         return `<div class="loop clk" dataType=${type} data="${id}" position=${node["position"]} pId=${node["parentId"]}>
                     <p style="background:#d6d6d6;text-align:left;padding:2px">${title}</p>
-                    <p class="branchAdd" data="${id}">点击此处在最左边增加条件分支</p>
+                    <p class="branchAdd" data="${id}">Click here to add a new condition to the left most</p>
                     <div class="judge" id = "${id}">
                     </div></div>
                     <p class="arrow" data = "${id}" position=${node["position"]} pId=${node["parentId"]}>↓</p></div>`;
@@ -199,7 +199,7 @@ function branchMouseDown(e) {
             parentId: 0,
             type: 3,
             option: 10,
-            title: "条件分支",
+            title: "Condition",
             sequence: [],
             isInLoop: false,
         };
@@ -232,7 +232,7 @@ function branchClick(e) {
         parentId: 0,
         type: 3,
         option: 10,
-        title: "条件分支",
+        title: "Condition",
         sequence: [],
         isInLoop: false,
     };
@@ -269,7 +269,7 @@ function arrowClick(e) {
 function addElement(op, para) {
     option = op;
     if (option == 1) { //打开网页选项
-        title = "打开网页";
+        title = "Open Page";
     } else {
         title = $(".options")[option - 2].innerHTML; //获取新增操作名称
     }
@@ -287,7 +287,7 @@ function toolBoxKernel(e, para = null) {
         if (nowNode == null) {
             e.stopPropagation(); //防止冒泡
         } else if (nowNode.getAttribute("dataType") > 0) {
-            alert("循环和判断、条件分支不可复制!");
+            alert("Cannot copy loop, if and condition!");
             e.stopPropagation(); //防止冒泡
         } else {
             let position = parseInt(nowNode.getAttribute('position'));
@@ -309,7 +309,7 @@ function toolBoxKernel(e, para = null) {
         if (nowNode == null) {
             e.stopPropagation(); //防止冒泡
         } else if ($(nowNode).is(".branch")) {
-            alert("判断分支不可移动!");
+            alert("Cannot move condition branch!");
             e.stopPropagation(); //防止冒泡
         } else {
             let position = parseInt(nowNode.getAttribute('position'));
@@ -341,7 +341,7 @@ function toolBoxKernel(e, para = null) {
                 app._data.nowArrow = { "position": nodeList[element[0]]["position"], "pId": nodeList[element[0]]["parentId"], "num": 0 };
                 $("#" + nodeList[element[0]]["id"]).click();
             } else {
-                alert("自己不能移动到自己的节点里!");
+                alert("Cannot move inside self!");
             }
             e.stopPropagation(); //防止冒泡
         }
@@ -371,7 +371,7 @@ function toolBoxKernel(e, para = null) {
                 index: l + 1,
                 type: 3,
                 option: 10,
-                title: "条件分支",
+                title: "Condition",
                 sequence: [],
                 isInLoop: false,
             };
@@ -381,7 +381,7 @@ function toolBoxKernel(e, para = null) {
                 index: l + 2,
                 type: 3,
                 option: 10,
-                title: "条件分支",
+                title: "Condition",
                 sequence: [],
                 isInLoop: false,
             };
@@ -426,7 +426,7 @@ $(".options").mousedown(function() {
     option = parseInt(this.getAttribute("data"));
     title = this.innerHTML;
     if (option >= 10 && option <= 12 && (nowNode == null || nowNode.getAttribute("id") == 0)) {
-        alert("目前未选中元素");
+        alert("No element is selected now!");
     } else if (option == 12) {
         deleteElement();
         $(".options")[12].click();
@@ -501,13 +501,13 @@ function refresh(nowArrowReset = true) {
 
 function deleteElement() {
     if (nowNode.getAttribute("id") == 0) {
-        alert("当前未选中元素!"); //root
-        return;
-    }
-    if (nodeList[actionSequence[nowNode.getAttribute("data")]]["option"] == 1) {
-        alert("打开网页操作不可删除!");
+        alert("No element is selected now!"); //root
         return;
     }
+    // if (nodeList[actionSequence[nowNode.getAttribute("data")]]["option"] == 1) {
+    //     alert("Cannot delete the element of Open Page!");
+    //     return;
+    // }
     let position = parseInt(nowNode.getAttribute('position'));
     let pId = nowNode.getAttribute('pId');
     let tnode = nodeList[actionSequence[pId]]["sequence"].splice(position, 1); //在相应位置删除元素
@@ -539,7 +539,7 @@ document.oncontextmenu = function() {
     //删除元素
 document.onkeydown = function(e) {
     if (nowNode != null && e.keyCode == 46) {
-        if (confirm("确定要删除元素吗?")) {
+        if (confirm("Do you really want to delete the selected element?")) {
             deleteElement();
         }
     } else { //ctrl+s保存服务

+ 277 - 0
ServiceGrid/frontEnd/FlowChart_CN.html

@@ -0,0 +1,277 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+    <script src="jquery-3.4.1.min.js"></script>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <script src="bootstrap/js/bootstrap.js"></script>
+    <script src="vue.js"></script>
+    <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
+    <link rel="stylesheet" href="FlowChart.css"></link>
+    <title>设计流程</title>
+
+</head>
+
+<body>
+    <div id="tip" class="alert alert-success alert-dismissible fade show" style="position: fixed; width:100%;display: none;">
+        <button type="button" class="close" data-dismiss="alert">&times;</button> 提示:保存成功!
+    </div>
+    <div style="display:flex">
+        <div style="width: 200px;float:left">
+            <div class="toolbox" style="text-align:center;margin: 20px;border-radius:10px;border:navy solid;background-color:rgb(242,243,245);z-index: 9999;">
+                <div style="padding: 10px;border-radius:10px;font-size: 20px;">工具箱</div>
+                <button type="button" id="save" data-toggle="modal" data-target="#myModal" onmousedown="$('#myModal').modal('show');" class="btn btn-primary">保存服务</button>
+                <!-- <button type="button" data=1 class="btn btn-outline-primary options">打开网页</button> -->
+                <button type="button" data=2 class="btn btn-outline-primary options">点击元素</button>
+                <button type="button" data=3 class="btn btn-outline-primary options">提取数据</button>
+                <button type="button" data=4 class="btn btn-outline-primary options">输入文字</button>
+                <button type="button" data=5 class="btn btn-outline-primary options">识别验证码</button>
+                <button type="button" data=6 style="font-size: 14px!important;" class="btn btn-outline-primary options">切换下拉选项</button>
+                <button type="button" data=7 class="btn btn-outline-primary options">移动到元素</button>
+                <button type="button" data=8 class="btn btn-outline-primary options">循环</button>
+                <button type="button" data=9 class="btn btn-outline-primary options">判断条件</button>
+                <div>-----------------</div>
+                <button type="button" data=13 class="btn btn-outline-primary options" title="调整下一个要插入的节点的位置">调整锚点</button>
+                <button type="button" data=10 class="btn btn-outline-primary options">剪切元素</button>
+                <button type="button" data=11 class="btn btn-outline-primary options">复制元素</button>
+                <button type="button" data=12 class="btn btn-outline-primary options">删除元素</button>
+                <button type="button" data=0 class="btn btn-outline-primary2 options">取消操作</button>
+                <div style="text-align: left;margin: 10px;font-size:15px!important">提示:点击上方操作按钮后点击要放置元素的位置处的箭头,可按取消操作按钮取消。</div>
+            </div>
+        </div>
+        <div style="margin-top:20px;border: solid;height:850px;overflow: auto;width:58%;float:right">
+            <div id="0" class="clk" data="0">
+            </div>
+            <div style="border-radius: 50%;width: 40px;height: 40px;border:solid black;margin: 5px auto;background-color:lightcyan">
+                <p style="font-size: 22px!important;text-align: center;margin-left: 1px;">■</p>
+            </div>
+        </div>
+        <div style="margin-top:20px;border: solid navy;height:850px;overflow: auto;margin-left:10px;width:30%;float:right;min-width:300px">
+            <!-- <div style="display: inline-block;border-bottom:solid 2px;width:100%">
+                <input style="float:left;margin-left:10px;margin-top:10px;margin-bottom:10px" type="button" class="btn-primary" value="保存服务"></input>
+            </div> -->
+            <div class="Modify" id="app">
+                <div>
+                    <label>选项名称:</label>
+                    <input onkeydown="inputDelete(event)" class="form-control" v-model='list.nl[index.nowNodeIndex]["title"]'></input>
+                </div>
+                <!-- 下面是10种不同类型操作选项的不同的配置页面 -->
+                <div class="elements" v-if="nodeType==1">
+                    <div v-if="nowNode['isInLoop']">
+                        <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的链接</p>
+                    </div>
+                    <div v-if='!useLoop'>
+                        <label>url:</label>
+                        <input onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["url"]'></input>
+                        <label>填入的全部链接:</label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["links"]'></textarea>
+                    </div>
+                    <label>执行完是否向下滚动:</label>
+                    <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
+                        <option value = 0>不滚动</option>
+                        <option value = 1>向下滚动一屏</option>
+                        <option value = 2>滚动到底部</option>
+                      </select>
+                    <label>滚动次数:</label>
+                    <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
+                </div>
+
+                <div class="elements" v-if="nodeType==2">
+                    <div v-if="nowNode['isInLoop']">
+                        <!-- 如果在循环内才显示此行元素 -->
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的元素</p>
+                    </div>
+                    <div v-if='!useLoop'>
+                        <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
+                    </div>
+                    <label>执行完是否向下滚动:</label>
+                    <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
+                        <option value = 0>不滚动</option>
+                        <option value = 1>向下滚动一屏</option>
+                        <option value = 2>滚动到底部</option>
+                      </select>
+                    <label>滚动次数:</label>
+                    <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
+
+                </div>
+
+                <div class="elements" v-if="nodeType==3">
+                    <div class="toolkitcontain">
+                        <table class="toolkittb2" cellspacing="0">
+                            <tbody>
+                                <th>字段名</th>
+                                <th style="width:200px">示例值</th>
+                                <th>操作</th>
+                            </tbody>
+                        </table>
+                        <table class="toolkittb4" cellspacing="0">
+                            <tbody>
+                                <tr v-for="i in paras.parameters.length">
+                                    <td style="padding-left:0px"><input onkeydown="inputDelete(event)" style='padding-left:2px;font-size:13px!important;height:100%' v-model='paras.parameters[i-1]["name"]'></input>
+                                    </td>
+                                    <td style="width:200px">{{paras.parameters[i-1]["exampleValues"][0]["value"]}}</td>
+                                    <td>
+                                        <a v-on:mousedown="modifyParas(i-1)">修改</a>
+                                        <a v-on:mousedown="deleteParas(i-1)">删除</a>
+                                        <a v-on:mousedown="upParas(i-1)">上移</a>
+                                        <a v-on:mousedown="downParas(i-1)">下移</a>
+                                    </td>
+                                </tr>
+                        </table>
+                    </div>
+                    <div style="font-size: 13px;" v-if="paraIndex<paras.parameters.length">
+                        <label>当前编辑参数名: <strong>{{paras.parameters[paraIndex]["name"]}}</strong></label>
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='paras.parameters[paraIndex]["relative"]'></input>使用相对循环内的XPATH</p>
+                        <label>XPATH: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='paras.parameters[paraIndex]["relativeXpath"]'></textarea>
+                        <label>采集内容类型</label>
+                        <select v-model='paras.parameters[paraIndex]["contentType"]' class="form-control">
+                            <option :value = 0>文本(包括子元素)</option>
+                            <option :value = 1>文本(不包括子元素)</option>
+                            <option :value = 2>innerHTML</option>
+                            <option :value = 3>outerHTML</option>
+                        </select>
+                        <label>节点类型</label>
+                        <select v-model='paras.parameters[paraIndex]["nodeType"]' class="form-control">
+                            <option :value = 0>普通节点</option>
+                            <option :value = 1>链接文本</option>
+                            <option :value = 2>链接地址</option>
+                            <option :value = 3>表单值</option>
+                            <option :value = 4>图片地址</option>
+                        </select>
+                        <label>参数描述:</label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='paras.parameters[paraIndex]["desc"]'></textarea>
+                        <label>元素找不到时的值:</label>
+                        <input onkeydown="inputDelete(event)" class="form-control" v-model='paras.parameters[paraIndex]["default"]'></textarea>
+                    </div>
+
+                </div>
+
+
+                <div class="elements" v-if="nodeType==4">
+                    <div v-if="nowNode['isInLoop']">
+                        <!-- 如果在循环内且循环内是固定文本才显示此行元素 -->
+                        <p><input onkeydown="inputDelete(event)" type="checkbox" v-model='useLoop'></input>使用循环内的文本</p>
+                    </div>
+                    <div v-if='!useLoop'>
+                        <label>输入值:</label>
+                        <input onkeydown="inputDelete(event)" class="form-control" v-model='nowNode["parameters"]["value"]'></input>
+                    </div>
+
+                    <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                    <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
+                </div>
+
+                <div class="elements" v-if="nodeType==5">
+
+                </div>
+
+                <div class="elements" v-if="nodeType==6">
+
+                </div>
+
+                <div class="elements" v-if="nodeType==7">
+
+                </div>
+
+                <div class="elements" v-if="nodeType==8">
+                    <!-- 循环选项 -->
+                    <label>循环类型:</label>
+                    <select v-model='loopType' class="form-control">
+                        <option value = 0>单个元素</option>
+                        <option value = 1>不固定元素列表</option>
+                        <option value = 2>固定元素列表</option>
+                        <option value = 3>文本列表</option>
+                        <option value = 4>网址列表</option>
+                      </select>
+                    <div v-if='parseInt(loopType) < 2'>
+                        <label>XPath: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="2" v-model='nowNode["parameters"]["xpath"]'></textarea>
+                    </div>
+                    <div v-if='parseInt(loopType) == 2'>
+                        <label>XPath列表:</label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["pathList"]'></textarea>
+                    </div>
+                    <div v-if='parseInt(loopType) > 2'>
+                        <label>内容列表:</label>
+                        <textarea onkeydown="inputDelete(event)" class="form-control" rows="3" v-model='nowNode["parameters"]["textList"]'></textarea>
+                    </div>
+                    <!-- 这里添加退出循环条件,找不到元素肯定退出循环 -->
+                    <label v-if='parseInt(loopType) == 0'>最多执行循环次数(0代表不设置):</label>
+                    <input onkeydown="inputDelete(event)" required v-if='parseInt(loopType) == 0' class="form-control" type="number" v-model.number='nowNode["parameters"]["exitCount"]'></input>
+                    <label><b>历史记录回退后</b>等待秒数:</label>
+                    <input onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["historyWait"]'></input>
+                    <label>执行完是否向下滚动:</label>
+                    <select v-model='nowNode["parameters"]["scrollType"]' class="form-control">
+                        <option value = 0>不滚动</option>
+                        <option value = 1>向下滚动一屏</option>
+                        <option value = 2>滚动到底部</option>
+                    </select>
+                    <label>滚动次数:</label>
+                    <input onkeydown="inputDelete(event)" class="form-control" v-model.number="nowNode['parameters']['scrollCount']" type="number" required></input>
+
+                </div>
+
+                <div class="elements" v-if="nodeType==9">
+
+                </div>
+
+                <div class="elements" v-if="nodeType==10">
+                    <label>条件类型:</label>
+                    <select v-model='TClass' class="form-control">
+                        <option value = 0>无条件</option>
+                        <option value = 1>当前页面包括文本</option>
+                        <option value = 2>当前页面包括元素</option>
+                        <option v-if="nowNode['isInLoop']" value = 3>当前循环项包括文本</option>
+                        <option v-if="nowNode['isInLoop']" value = 4>当前循环项包括元素</option>
+                      </select>
+                    <label v-if='TClass'>包含的文字/元素XPATH: <span style="font-size: 30px!important;" title="相对XPATH写法:以/开头,如循环项XPATH为/html/body/div[1],您的输入为/*[@id='tab-customer'],则最终寻址的xpath为:/html/body/div[1]/*[@id='tab-customer']">☺</span></label>
+                    <textarea onkeydown="inputDelete(event)" required placeholder="如果是当前循环包含元素,则输入相对元素的xpath。" v-if='TClass' class="form-control" rows="3" v-model='nowNode["parameters"]["value"]'></textarea>
+                </div>
+                <div style="margin-top:5px">
+                    <label><b>执行后</b>等待秒数:</label>
+                    <input onkeydown="inputDelete(event)" required type="number" class="form-control" v-model.number='list.nl[index.nowNodeIndex]["parameters"]["wait"]'></input>
+                </div>
+                <button class="btn btn-outline-primary" style="margin-top: 20px;" id="confirm">确定</button>
+
+            </div>
+
+
+        </div>
+
+    </div>
+
+    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+        <div class="modal-dialog">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h4 class="modal-title" id="myModalLabel">保存服务</h4>
+                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                </div>
+                <div class="modal-body">
+                    <input onkeydown="inputDelete(event)" id="serviceId" type="hidden" name="serviceId" value="-1"></input>
+                    <input onkeydown="inputDelete(event)" id="url" type="hidden" name="url" value="about:blank"></input>
+                    <label>服务名称:</label>
+                    <input onkeydown="inputDelete(event)" required name="serviceName" value="新web服务" id="serviceName" class="form-control"></input>
+                    <label>服务描述:</label>
+                    <textarea onkeydown="inputDelete(event)" id="serviceDescription" name="serviceDescription" class="form-control" rows="3"></textarea>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" id="saveAsButton" class="btn btn-outline-primary">另存为</button>
+                    <button type="button" id="saveButton" class="btn btn-primary">保存</button>
+                </div>
+            </div>
+            <!-- /.modal-content -->
+        </div>
+        <!-- /.modal -->
+    </div>
+</body>
+<script src="FlowChart_CN.js"></script>
+<script src="logic_CN.js"></script>
+
+
+</html>

+ 561 - 0
ServiceGrid/frontEnd/FlowChart_CN.js

@@ -0,0 +1,561 @@
+//处理表现层
+var nodeList = Array(); //所有新生成的节点全部存储在这里,并且有唯一索引号,所有的定位均通过index进行,即将图保存下来了
+var root = {
+    index: 0, //在nodeList中的索引号
+    id: 0,
+    parentId: 0,
+    type: -1,
+    option: 0,
+    title: "root",
+    sequence: [],
+    parameters: {
+        history: 1,
+        tabIndex: 0,
+        useLoop: false, //是否使用循环中的元素
+        xpath: "", //xpath
+        wait: 0,
+    },
+    isInLoop: false, //是否处于循环内
+};
+nodeList.push(root);
+var queue = new Array();
+var actionSequence = new Array(); //存储图结构,每个元素为在nodelist里面的索引值,下面的id和pid根据此数组进行索引,然后再在nodelist里找
+var nowNode = null; //存储现在所在的节点
+var vueData = { nowNodeIndex: 0 }; //存储目前所在节点的索引号,不能直接使用变量而需要用对象包起来
+var option = 0; //工具箱选项
+var title = "";
+var parameterNum = 1; //记录目前的参数个数
+
+//处理逻辑层
+var app = new Vue({
+    el: '#app',
+    data: {
+        list: { nl: nodeList },
+        index: vueData,
+        nodeType: 0, // 当前元素的类型
+        nowNode: null, // 用来临时存储元素的节点
+        loopType: -1, //点击循环时候用来循环选项
+        useLoop: false, //记录是否使用循环内元素
+        nowArrow: { "position": -1, "pId": 0, "num": 0 },
+        paras: { "parameters": [] }, //提取数据的参数列表
+        TClass: -1, //条件分支的条件类别
+        paraIndex: 0, //当前参数的index
+    },
+    watch: {
+        nowArrow: { //变量发生变化的时候进行一些操作
+            deep: true,
+            handler: function(newVal, oldVal) {
+                let arrlist = document.getElementsByClassName("arrow");
+                if (oldVal != null) {
+                    for (let i = 0; i < arrlist.length; i++) {
+                        if (arrlist[i].getAttribute("position") == oldVal["position"] &&
+                            arrlist[i].getAttribute("pid") == oldVal["pId"]) {
+                            arrlist[i].style.backgroundColor = ""; // 时刻指示现在应该插入的节点的位置
+                            break;
+                        }
+                    }
+                }
+                for (let i = 0; i < arrlist.length; i++) {
+                    if (arrlist[i].getAttribute("position") == newVal["position"] &&
+                        arrlist[i].getAttribute("pid") == newVal["pId"]) {
+                        arrlist[i].style.backgroundColor = "lavender"; // 时刻指示现在应该插入的节点的位置
+                        break;
+                    }
+                }
+            }
+        },
+        loopType: {
+            handler: function(newVal, oldVal) {
+                this.nowNode["parameters"]["loopType"] = newVal;
+            }
+        },
+        TClass: {
+            handler: function(newVal, oldVal) {
+                this.nowNode["parameters"]["class"] = newVal;
+            }
+        },
+        useLoop: {
+            handler: function(newVal, oldVal) {
+                this.nowNode["parameters"]["useLoop"] = newVal;
+            }
+        },
+        paras: {
+            handler: function(newVal, oldVal) {
+                this.nowNode["parameters"]["paras"] = newVal["parameters"];
+            }
+        },
+    },
+    methods: {
+        modifyParas: function(i) { //修改第i个参数
+            this.paraIndex = i;
+        },
+        deleteParas: function(i) { //删除第i个参数
+            this.nowNode["parameters"]["paras"].splice(i, 1);
+            //如果参数删除完了,就把提取数据也删掉
+            if (this.nowNode["parameters"]["paras"].length == 0) {
+                deleteElement();
+            }
+        },
+        upParas: function(i) { //上移第i个参数
+            if (i != 0) {
+                let t = this.nowNode["parameters"]["paras"].splice(i, 1)[0];
+                this.nowNode["parameters"]["paras"].splice(i - 1, 0, t);
+            }
+        },
+        downParas: function(i) { //下移第i个参数
+            if (i != this.nowNode["parameters"]["paras"].length - 1) {
+                let t = this.nowNode["parameters"]["paras"].splice(i, 1)[0];
+                this.nowNode["parameters"]["paras"].splice(i + 1, 0, t);
+            }
+        },
+
+        getType: function(nodeType, contentType) { //根据类型得到字段名称
+            if (contentType == 2) {
+                return "InnerHTML";
+            } else if (contentType == 3) {
+                return "OuterHTML";
+            }
+            if (nodeType == 2) {
+                return "链接地址";
+            } else if (nodeType == 1) {
+                return "链接文本";
+            } else if (nodeType == 4) {
+                return "图片地址";
+            } else {
+                return "文本";
+            }
+        }
+    }
+})
+
+//深复制
+function DeepClone(obj) {
+    if (obj === null || typeof obj !== 'object') return obj;
+    var cpObj = obj instanceof Array ? [] : {};
+    for (var key in obj) cpObj[key] = DeepClone(obj[key]);
+    return cpObj;
+}
+
+// 根据元素类型返回不同元素的样式
+function newNode(node) {
+    id = node["id"];
+    title = node["title"];
+    type = node["type"];
+    if (type == 0) //顺序
+    {
+        return `<div class="sequence"><div class="node clk" data="${id}" dataType=${type} id = "${id}" position=${node["position"]} pId=${node["parentId"]}>
+                <div >
+                    <p>${title}</p>
+                </div>
+            </div>
+            <p class="arrow" position=${node["position"]} data = "${id}" pId=${node["parentId"]}>↓</p></div>`;
+    } else if (type == 1) //循环
+    {
+        return `<div class="loop clk" data="${id}" dataType=${type} id = "${id}" position=${node["position"]} pId=${node["parentId"]}>
+             <p style="background:#d6d6d6;text-align:left;padding:2px">${title}</p>
+                <p class="arrow" position=-1 data = "${id}" pId=${id}>↓</p>
+            </div>
+            <p class="arrow" data = "${id}" position=${node["position"]} pId=${node["parentId"]}>↓</p></div>`;
+    } else if (type == 2) //判断
+    {
+        return `<div class="loop clk" dataType=${type} data="${id}" position=${node["position"]} pId=${node["parentId"]}>
+                    <p style="background:#d6d6d6;text-align:left;padding:2px">${title}</p>
+                    <p class="branchAdd" data="${id}">点击此处在最左边增加条件分支</p>
+                    <div class="judge" id = "${id}">
+                    </div></div>
+                    <p class="arrow" data = "${id}" position=${node["position"]} pId=${node["parentId"]}>↓</p></div>`;
+    } else //判断分支
+    {
+        return `<div class="branch clk" dataType=${type} data="${id}" position=${node["position"]} pId=${node["parentId"]}>
+                    <p style="background:#d6d6d6;text-align:left;padding:2px">${title}</p>
+                    <p data = "${id}" class="arrow" position=-1 pId=${id}>↓</p>
+                    <div id = "${id}">
+                    </div></div>`;
+    }
+}
+
+function elementMousedown(e) {
+    if (e.button == 2) //右键点击
+    {
+        if (nowNode != null) {
+            nowNode.style.borderColor = "skyblue";
+        }
+        nowNode = this;
+        vueData.nowNodeIndex = actionSequence[this.getAttribute("data")];
+        this.style.borderColor = "blue";
+        handleElement(); //处理元素
+    }
+    e.stopPropagation(); //防止冒泡
+}
+
+function branchMouseDown(e) {
+    if (e.button == 2) //右键点击
+    {
+        let judgeId = this.getAttribute('data');
+        var l = nodeList.length;
+        var t = {
+            index: l,
+            id: 0,
+            parentId: 0,
+            type: 3,
+            option: 10,
+            title: "条件分支",
+            sequence: [],
+            isInLoop: false,
+        };
+        addParameters(t)
+        nodeList.push(t);
+        nodeList[actionSequence[judgeId]]["sequence"].splice(0, 0, t.index);
+        refresh();
+        app._data.nowArrow = { "position": -1, "pId": t["id"], "num": 0 };
+        $("#" + t["id"]).click();
+    }
+    e.stopPropagation(); //防止冒泡
+}
+
+function arrowMouseDown(e) {
+    if (e.button == 2) //右键点击
+    {
+        if (option != 0) {
+            app._data.nowArrow = { "position": this.getAttribute('position'), "pId": this.getAttribute('pId'), "num": 0 };
+        }
+        toolBoxKernel(e);
+    }
+}
+//增加分支点击事件
+function branchClick(e) {
+    let judgeId = this.getAttribute('data');
+    var l = nodeList.length;
+    var t = {
+        index: l,
+        id: 0,
+        parentId: 0,
+        type: 3,
+        option: 10,
+        title: "条件分支",
+        sequence: [],
+        isInLoop: false,
+    };
+    addParameters(t);
+    nodeList.push(t);
+    nodeList[actionSequence[judgeId]]["sequence"].splice(0, 0, t.index);
+    refresh();
+    app._data.nowArrow = { "position": -1, "pId": t["id"], "num": 0 };
+    $("#" + t["id"]).click();
+    e.stopPropagation(); //防止冒泡
+}
+
+//元素点击事件
+function elementClick(e) {
+    if (nowNode != null) {
+        nowNode.style.borderColor = "skyblue";
+    }
+    nowNode = this;
+    vueData.nowNodeIndex = actionSequence[this.getAttribute("data")];
+    this.style.borderColor = "blue";
+    handleElement(); //处理元素
+    e.stopPropagation(); //防止冒泡
+}
+
+//箭头点击事件
+function arrowClick(e) {
+    if (option != 0) {
+        app._data.nowArrow = { "position": this.getAttribute('position'), "pId": this.getAttribute('pId'), "num": 0 };
+    }
+    toolBoxKernel(e);
+}
+
+//增加元素函数
+function addElement(op, para) {
+    option = op;
+    if (option == 1) { //打开网页选项
+        title = "打开网页";
+    } else {
+        title = $(".options")[option - 2].innerHTML; //获取新增操作名称
+    }
+
+    toolBoxKernel(null, para);
+}
+
+// 工具箱操作函数
+function toolBoxKernel(e, para = null) {
+    if (option == 13) { //调整锚点
+        // let tarrow = DeepClone(app.$data.nowArrow);
+        // refresh();
+        // app._data.nowArrow =tarrow;
+    } else if (option == 11) { //复制操作
+        if (nowNode == null) {
+            e.stopPropagation(); //防止冒泡
+        } else if (nowNode.getAttribute("dataType") > 0) {
+            alert("循环和判断、条件分支不可复制!");
+            e.stopPropagation(); //防止冒泡
+        } else {
+            let position = parseInt(nowNode.getAttribute('position'));
+            let pId = nowNode.getAttribute('pId');
+            var tt = nodeList[nodeList[actionSequence[pId]]["sequence"][position]]; //在相应位置添加新元素
+            t = DeepClone(tt); //浅复制元素
+            var l = nodeList.length;
+            t.index = l;
+            nodeList.push(t);
+            var position2 = parseInt(app._data.nowArrow['position']);
+            var pId2 = app._data.nowArrow['pId'];
+            nodeList[actionSequence[pId2]]["sequence"].splice(position2 + 1, 0, t.index); //在相应位置添加新元素
+            refresh(); //重新渲染页面
+            app._data.nowArrow = { "position": t["position"], "pId": t["parentId"], "num": 0 };
+            $("#" + t["id"]).click(); //复制后点击复制后的元素
+            e.stopPropagation(); //防止冒泡
+        }
+    } else if (option == 10) { //剪切操作
+        if (nowNode == null) {
+            e.stopPropagation(); //防止冒泡
+        } else if ($(nowNode).is(".branch")) {
+            alert("判断分支不可移动!");
+            e.stopPropagation(); //防止冒泡
+        } else {
+            let position = parseInt(nowNode.getAttribute('position'));
+            let pId = nowNode.getAttribute('pId');
+            var position2 = parseInt(app._data.nowArrow['position']);
+            var pId2 = app._data.nowArrow['pId'];
+            var id = nowNode.getAttribute('data');
+            var pidt = pId2;
+            var move = true;
+            console.log(pidt, id);
+            while (pidt != 0) {
+                if (pidt == id) {
+                    move = false;
+                    break;
+                }
+                pidt = nodeList[actionSequence[pidt]]["parentId"];
+            }
+            if (move) //如果自己要移动到自己节点里就不允许移动
+            {
+                let element = nodeList[actionSequence[pId]]["sequence"].splice(position, 1); //在相应位置删除元素
+                if (pId == pId2 && position < position2) //如果要移动的位置属于同一层并且是从前往后移动,注意需要控制数组插入位置向前错位
+                {
+                    position2--;
+                }
+                console.log(element);
+                nodeList[actionSequence[pId2]]["sequence"].splice(position2 + 1, 0, element[0]); //在相应位置添加新元素
+                refresh(); //重新渲染页面
+                console.log(nodeList[element[0]]);
+                app._data.nowArrow = { "position": nodeList[element[0]]["position"], "pId": nodeList[element[0]]["parentId"], "num": 0 };
+                $("#" + nodeList[element[0]]["id"]).click();
+            } else {
+                alert("自己不能移动到自己的节点里!");
+            }
+            e.stopPropagation(); //防止冒泡
+        }
+    } else if (option > 0) { //新增操作
+        var l = nodeList.length;
+        var t = {
+            id: 0,
+            index: l,
+            parentId: 0,
+            type: 0,
+            option: option,
+            title: title,
+            sequence: [],
+            isInLoop: false,
+        };
+        nodeList.push(t);
+        if (option == 8) //循环
+        {
+            t["type"] = 1;
+        } else if (option == 9) //判断
+        {
+            t["type"] = 2;
+            // 增加两个分支
+            var nt = {
+                id: 0,
+                parentId: 0,
+                index: l + 1,
+                type: 3,
+                option: 10,
+                title: "条件分支",
+                sequence: [],
+                isInLoop: false,
+            };
+            var nt2 = {
+                id: 0,
+                parentId: 0,
+                index: l + 2,
+                type: 3,
+                option: 10,
+                title: "条件分支",
+                sequence: [],
+                isInLoop: false,
+            };
+            t["sequence"].push(nt.index);
+            t["sequence"].push(nt2.index);
+            nodeList.push(nt)
+            nodeList.push(nt2);
+            addParameters(nt); //增加选项的默认参数
+            addParameters(nt2); //增加选项的默认参数
+        }
+        let position = parseInt(app._data.nowArrow['position']);
+        let pId = app._data.nowArrow['pId'];
+        nodeList[actionSequence[pId]]["sequence"].splice(position + 1, 0, t.index); //在相应位置添加新元素
+        refresh(); //重新渲染页面
+        //下面是确定添加元素之后下一个要插入的节点的位置
+        app._data.nowArrow = { "position": t["position"], "pId": t["parentId"], "num": 0 };
+        addParameters(t); //增加选项的默认参数
+        if (para != null) {
+            modifyParameters(t, para);
+        }
+        if (option == 8) //循环情况下应插入在循环里面
+        {
+            app._data.nowArrow = { "position": -1, "pId": t["id"], "num": 0 };
+            $("#" + t["id"]).click();
+        } else if (option == 9) //判断插入到第一个判断条件中
+        {
+            app._data.nowArrow = { "position": -1, "pId": nt["id"], "num": 0 };
+            $("#" + nt["id"]).click();
+        } else {
+            $("#" + t["id"]).click();
+        }
+
+        if (e != null)
+            e.stopPropagation(); //防止冒泡
+        option = 0;
+        return t;
+    }
+    option = 0;
+}
+
+$(".options").mousedown(function() {
+    option = parseInt(this.getAttribute("data"));
+    title = this.innerHTML;
+    if (option >= 10 && option <= 12 && (nowNode == null || nowNode.getAttribute("id") == 0)) {
+        alert("目前未选中元素");
+    } else if (option == 12) {
+        deleteElement();
+        $(".options")[12].click();
+    }
+});
+
+function bindEvents() {
+    // 清空原来的listener然后再添加新的listener
+    //以下绑定了左右键的行为
+    let rect = document.getElementsByClassName('clk');
+    for (let i = 0, rule; rule = rect[i++];) {
+        rule.removeEventListener('mousedown', elementMousedown);
+        rule.addEventListener('mousedown', elementMousedown);
+        rule.removeEventListener('click', elementClick);
+        rule.addEventListener('click', elementClick);
+    }
+    let arr = document.getElementsByClassName('arrow');
+    for (let i = 0, rule; rule = arr[i++];) {
+        rule.removeEventListener('click', arrowClick);
+        rule.addEventListener('click', arrowClick);
+        rule.removeEventListener('mousedown', arrowMouseDown);
+        rule.addEventListener('mousedown', arrowMouseDown);
+    }
+    let branch = document.getElementsByClassName('branchAdd');
+    for (let i = 0, rule; rule = branch[i++];) {
+        rule.removeEventListener('click', branchClick);
+        rule.addEventListener('click', branchClick);
+        rule.removeEventListener('mousedown', branchMouseDown);
+        rule.addEventListener('mousedown', branchMouseDown);
+    }
+}
+
+//重新画图
+function refresh(nowArrowReset = true) {
+    $("#0").empty();
+    $("#0").append(`<div style="border-radius: 50%;width: 40px;height: 40px;border:solid;border-color:seagreen;margin:5px auto;background-color:lightcyan;margin-top:20px">
+                        <p style="font-size: 24px!important;text-align: center;margin-left: 6px;font-family:'Times New Roman'">▶</p>
+                        </div>
+                        <p id="firstArrow" class="arrow" position=-1 pId=0>↓</p>`);
+    actionSequence.splice(0);
+    queue.splice(0);
+    var idd = 1;
+    queue.push(0);
+    actionSequence.push(0);
+    while (queue.length != 0) {
+        var nd = queue.shift(); //取出父元素并建立对子元素的链接
+        for (i = 0; i < nodeList[nd].sequence.length; i++) {
+            nodeList[nodeList[nd].sequence[i]].parentId = nodeList[nd].id;
+            nodeList[nodeList[nd].sequence[i]]["position"] = i;
+            nodeList[nodeList[nd].sequence[i]].id = idd++;
+            //检测元素是否位于循环内
+            if (nodeList[nd].option == 8 || nodeList[nd].isInLoop) {
+                nodeList[nodeList[nd].sequence[i]].isInLoop = true;
+            } else {
+                nodeList[nodeList[nd].sequence[i]].isInLoop = false;
+            }
+            queue.push(nodeList[nd].sequence[i]);
+            actionSequence.push(nodeList[nd].sequence[i]);
+        }
+    }
+    if (nowArrowReset) //如果要重置锚点位置
+    {
+        app._data.nowArrow = { "position": -1, "pId": 0, "num": 0 }; //设置默认要添加的位置是元素流程最开头处
+    }
+    //第一个元素不渲染
+    for (i = 1; i < actionSequence.length; i++) {
+        parentId = nodeList[actionSequence[i]]["parentId"];
+        $("#" + parentId).append(newNode(nodeList[actionSequence[i]]));
+    }
+    bindEvents();
+}
+
+function deleteElement() {
+    if (nowNode.getAttribute("id") == 0) {
+        alert("当前未选中元素!"); //root
+        return;
+    }
+    // if (nodeList[actionSequence[nowNode.getAttribute("data")]]["option"] == 1) {
+    //     alert("打开网页操作不可删除!");
+    //     return;
+    // }
+    let position = parseInt(nowNode.getAttribute('position'));
+    let pId = nowNode.getAttribute('pId');
+    let tnode = nodeList[actionSequence[pId]]["sequence"].splice(position, 1); //在相应位置删除元素
+    //循环的标记已经被删除的元素,因为删除循环后,循环内的元素也会
+    let queue = new Array();
+    queue.push(tnode[0]);
+    while (queue.length > 0) {
+        let index = queue.shift();
+        nodeList[index]["id"] = -1; //标记服务已被删除
+        for (let i = 0; i < nodeList[index]["sequence"].length; i++) {
+            queue.push(nodeList[index]["sequence"][i]);
+        }
+    }
+    app._data["nowNode"] = null;
+    app._data["nodeType"] = 0;
+    vueData.nowNodeIndex = 0;
+    if (nowNode.getAttribute("datatype") == 3) { //如果删掉的是条件分支的话
+        pId = nowNode.parentNode.parentNode.getAttribute('pId');
+        position = nowNode.parentNode.parentNode.getAttribute('position');
+    }
+    app.$data.nowArrow = { position: position - 1, "pId": pId, "num": 0 }; //删除元素后锚点跳转到当前元素的上一个节点
+    refresh(false); //重新渲染页面
+    nowNode = null; //取消选择
+}
+
+document.oncontextmenu = function() {
+        return false;
+    } //屏蔽右键菜单
+    //删除元素
+document.onkeydown = function(e) {
+    if (nowNode != null && e.keyCode == 46) {
+        if (confirm("确定要删除元素吗?")) {
+            deleteElement();
+        }
+    } else { //ctrl+s保存服务
+        var currKey = 0,
+            e = e || event || window.event;
+        currKey = e.keyCode || e.which || e.charCode;
+        if (currKey == 83 && (e.ctrlKey || e.metaKey)) {
+            $('#save').click();
+            return false;
+        }
+
+    }
+}
+
+function inputDelete(e) {
+    if (e.keyCode == 46) {
+        e.stopPropagation(); //输入框按delete应该正常运行
+    }
+}

+ 22 - 21
ServiceGrid/frontEnd/invokeService.html

@@ -8,7 +8,7 @@
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <script src="vue.js"></script>
     <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
-    <title>服务调用</title>
+    <title>Service Invoke</title>
     <style>
         table {
             table-layout: auto;
@@ -35,20 +35,20 @@
 <body>
     <div class="row" style="margin-top: 40px;">
         <div class="col-md-6" style="margin:0 auto" id="serviceList" v-if="show">
-            <h4 style="text-align: center;">服务信息</h4>
-            <p>服务名称:{{service["name"]}}</p>
-            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">服务描述:{{service["desc"]}}</p>
-            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">任务号调用URL:http://183.129.170.180:8041/backEnd/invokeService?id={{service["id"]}}</p>
-            <p>请输入参数:</p>
+            <h4 style="text-align: center;">Service Information</h4>
+            <p>Service Name: {{service["name"]}}</p>
+            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">Service Description: {{service["desc"]}}</p>
+            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">URL: {{backEndAddressServiceWrapper}}/backEnd/invokeService?id={{service["id"]}}</p>
+            <p>Please Input Parameters: </p>
             <form id="form">
                 <table class="table table-bordered">
                     <tbody>
                         <tr>
                             <th style="min-width: 50px;">ID</th>
-                            <th>参数名称</th>
-                            <th>调用名称</th>
-                            <th>参数类型</th>
-                            <th>参数值</th>
+                            <th>Parameter Name</th>
+                            <th>Invoke Name</th>
+                            <th>Parameter Type</th>
+                            <th>Parameter Value</th>
                         </tr>
 
                         <tr v-if="service.inputParameters.length>0" v-for="i in service.inputParameters.length">
@@ -62,16 +62,16 @@
                 </table>
             </form>
 
-            <button style="margin-left: 5px;" v-on:click="localExcuteInstant" class="btn btn-primary">直接本地执行</button>
-            <button style="margin-left: 5px;" v-on:click="remoteExcuteInstant" class="btn btn-primary">直接远程执行</button>
+            <button style="margin-left: 5px;" v-on:click="localExcuteInstant" class="btn btn-primary">Directly Run locally</button>
+            <button style="margin-left: 5px;" v-on:click="remoteExcuteInstant" class="btn btn-primary">Directly Run Remotely</button>
             <div style="margin-bottom: 10px;">
-                <label style="margin-top: 10px;">任务ID:</label>
+                <label style="margin-top: 10px;">Task ID:</label>
                 <input class="form-control" v-model="ID"></input>
                 <p></p>
                 <p>提示:点击下方按钮获得任务ID,然后根据此ID进行服务执行;也可自己POST调用接口得到ID,具体参照POST调用文档。</p>
-                <a href="javascript:void(0)" v-on:click="invokeService" class="btn btn-primary">获得任务ID</a>
-                <button v-on:click="localExcute" style="margin-left: 8px;" class="btn btn-primary">本地执行任务</button>
-                <button v-on:click="remoteExcute" style="margin-left: 8px;" class="btn btn-primary">远程执行任务</button></div>
+                <a href="javascript:void(0)" v-on:click="invokeService" class="btn btn-primary">Get Task ID</a>
+                <button v-on:click="localExcute" style="margin-left: 8px;" class="btn btn-primary">Run locally</button>
+                <button v-on:click="remoteExcute" style="margin-left: 8px;" class="btn btn-primary">Run remotely</button></div>
         </div>
 
     </div>
@@ -85,7 +85,7 @@
         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
         var r = window.location.search.substr(1).match(reg); //匹配目标参数
         if (r != null) return unescape(r[2]);
-        return null; //返回参数值
+        return ""; //返回参数值,默认后台地址
     }
 
     var sId = getUrlParam('id');
@@ -95,6 +95,7 @@
             service: {},
             show: false, //是否渲染
             ID: "暂无",
+            backEndAddressServiceWrapper: getUrlParam("backEndAddressServiceWrapper"),
         },
         methods: {
             invokeService: function() {
@@ -104,7 +105,7 @@
                     t.forEach(function(item, index) {
                         para[item.name] = item.value;
                     });
-                    $.post("http://183.129.170.180:8041/backEnd/invokeService?id=" + sId, {
+                    $.post(app.$data.backEndAddressServiceWrapper + "/backEnd/invokeService?id=" + sId, {
                         id: this.service.id,
                         paras: JSON.stringify(para)
                     }, function(result) {
@@ -149,7 +150,7 @@
                     t.forEach(function(item, index) {
                         para[item.name] = item.value;
                     });
-                    $.post("http://183.129.170.180:8041/backEnd/invokeService?id=" + sId, {
+                    $.post(app.$data.backEndAddressServiceWrapper + "/backEnd/invokeService?id=" + sId, {
                         id: this.service.id,
                         paras: JSON.stringify(para)
                     }, function(result) {
@@ -170,7 +171,7 @@
                     t.forEach(function(item, index) {
                         para[item.name] = item.value;
                     });
-                    $.post("http://183.129.170.180:8041/backEnd/invokeService?id=" + sId, {
+                    $.post(app.$data.backEndAddressServiceWrapper + "/backEnd/invokeService?id=" + sId, {
                         id: this.service.id,
                         paras: JSON.stringify(para)
                     }, function(result) {
@@ -180,7 +181,7 @@
             },
         }
     });
-    $.get("http://183.129.170.180:8041/backEnd/queryService?id=" + sId, function(result) {
+    $.get(app.$data.backEndAddressServiceWrapper + "/backEnd/queryService?id=" + sId, function(result) {
         app.$data.service = result;
         app.$data.show = true;
     });

+ 43 - 26
ServiceGrid/frontEnd/logic.js

@@ -125,6 +125,8 @@ function addParameters(t) {
     } else if (t.option == 4) { //输入文字
         t["parameters"]["value"] = "";
     } else if (t.option == 8) { //循环
+        t["parameters"]["scrollType"] = 0; //滚动类型,0不滚动,1向下滚动1屏,2滚动到底部
+        t["parameters"]["scrollCount"] = 0; //滚动次数
         t["parameters"]["loopType"] = 0; //默认循环类型
         t["parameters"]["xpath"] = "";
         t["parameters"]["pathList"] = "";
@@ -158,9 +160,9 @@ function modifyParameters(t, para) {
         t["parameters"]["loopType"] = para["loopType"];
         t["parameters"]["xpath"] = para["xpath"];
         if (para["nextPage"]) { //循环点击下一页的情况下
-            t["title"] = "循环点击下一页"
+            t["title"] = "Loop click next page"
         } else {
-            t["title"] = "循环"
+            t["title"] = "Loop"
         }
         if (para["loopType"] == 2) //如果是固定元素列表
         {
@@ -190,12 +192,23 @@ $("#confirm").mousedown(function() {
     }
 });
 
+//获取url中的参数
+function getUrlParam(name) {
+    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
+    var r = window.location.search.substr(1).match(reg); //匹配目标参数
+    if (r != null) return unescape(r[2]);
+    return "";
+}
+
+var sId = getUrlParam('id');
+var backEndAddressServiceWrapper = getUrlParam("backEndAddressServiceWrapper");
+
 function saveService(type) {
     var serviceId = $("#serviceId").val();
-    var text = "确认要保存服务吗?";
+    var text = "Confirm to save service?";
     if (type == 1) { //服务另存为
         serviceId = -1;
-        text = "确认要另存为服务吗?";
+        text = "Confirm to save as service?";
     }
     if (confirm(text)) {
         let serviceName = $("#serviceName").val();
@@ -222,7 +235,7 @@ function saveService(type) {
                             value: nodeList[i]["parameters"]["links"],
                             desc: "要采集的网址列表,多行以\\n分开",
                             type: "string",
-                            exampleValue: "https://www.jd.com"
+                            exampleValue: nodeList[i]["parameters"]["links"]
                         });
                         links = nodeList[i]["parameters"]["links"];
                     }
@@ -243,17 +256,30 @@ function saveService(type) {
                     }
                 } else if (nodeList[i]["option"] == 8) //循环操作
                 {
-                    if (parseInt(nodeList[i]["parameters"]["loopType"]) > 2) //循环中的循环输入文本或循环输入网址
+                    if (parseInt(nodeList[i]["parameters"]["loopType"]) > 2) {
+                        inputParameters.push({
+                            id: inputIndex,
+                            name: "loopText_" + inputIndex++,
+                            nodeId: i,
+                            nodeName: nodeList[i]["title"],
+                            desc: "要输入的文本/网址,多行以\\n分开",
+                            type: "string",
+                            exampleValue: nodeList[i]["parameters"]["textList"],
+                            value: nodeList[i]["parameters"]["textList"],
+                        });
+                    } //循环中的循环输入文本或循环输入网址
+                    else if (parseInt(nodeList[i]["parameters"]["loopType"]) == 0) {
                         inputParameters.push({
-                        id: inputIndex,
-                        name: "loopText_" + inputIndex++,
-                        nodeId: i,
-                        nodeName: nodeList[i]["title"],
-                        desc: "要输入的文本/网址,多行以\\n分开",
-                        type: "string",
-                        exampleValue: nodeList[i]["parameters"]["textList"],
-                        value: nodeList[i]["parameters"]["textList"],
-                    });
+                            id: inputIndex,
+                            name: "loopTimes_" + nodeList[i]["title"] + "_" + inputIndex++,
+                            nodeId: i,
+                            nodeName: nodeList[i]["title"],
+                            desc: "循环" + nodeList[i]["title"] + "执行的次数(0代表无限循环)",
+                            type: "int",
+                            exampleValue: nodeList[i]["parameters"]["exitCount"],
+                            value: nodeList[i]["parameters"]["exitCount"],
+                        });
+                    }
                 } else if (nodeList[i]["option"] == 3) //提取数据操作
                 {
                     for (let j = 0; j < nodeList[i]["parameters"]["paras"].length; j++) {
@@ -285,7 +311,7 @@ function saveService(type) {
             "outputParameters": outputParameters,
             "graph": nodeList, //图结构要存储下来
         };
-        $.post("http://183.129.170.180:8041/backEnd/manageService", { paras: JSON.stringify(serviceInfo) }, function(result) { $("#serviceId").val(parseInt(result)) });
+        $.post(backEndAddressServiceWrapper + "/backEnd/manageService", { paras: JSON.stringify(serviceInfo) }, function(result) { $("#serviceId").val(parseInt(result)) });
         // alert("保存成功!");
         $('#myModal').modal('hide');
         $("#tip").slideDown(); //提示框
@@ -305,19 +331,10 @@ $("#saveAsButton").mousedown(function() {
     saveService(1);
 });
 
-//获取url中的参数
-function getUrlParam(name) {
-    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
-    var r = window.location.search.substr(1).match(reg); //匹配目标参数
-    if (r != null) return unescape(r[2]);
-    return null; //返回参数值
-}
-
-var sId = getUrlParam('id');
 
 if (sId != null && sId != -1) //加载服务
 {
-    $.get("http://183.129.170.180:8041/backEnd/queryService?id=" + sId, function(result) {
+    $.get(backEndAddressServiceWrapper + "/backEnd/queryService?id=" + sId, function(result) {
         nodeList = result["graph"];
         app.$data.list.nl = nodeList;
         $("#serviceName").val(result["name"]);

+ 335 - 0
ServiceGrid/frontEnd/logic_CN.js

@@ -0,0 +1,335 @@
+exampleMsg = { //示例消息
+    "type": 0, //消息类型,1代表增加操作
+    "data": {
+        "option": 1, //增加选项
+        "parameters": { //传入的参数
+            "url": "https://www.baidu.com"
+        }
+    }
+}
+console.log(JSON.stringify(exampleMsg));
+ws = new WebSocket("ws://localhost:8084");
+ws.onopen = function() {
+    // Web Socket 已连接上,使用 send() 方法发送数据
+    console.log("已连接");
+    message = {
+        type: 0, //消息类型,0代表链接操作
+        message: {
+            id: 2, //socket id
+        }
+    };
+    this.send(JSON.stringify(message));
+};
+ws.onclose = function() {
+    // 关闭 websocket
+    console.log("连接已关闭...");
+};
+var ttt;
+ws.onmessage = function(evt) {
+    evt = JSON.parse(evt.data);
+    console.log(evt);
+    if (evt["type"] == "special") { //如果不是特殊处理的话,默认全部是增加元素操作
+
+    } else {
+        handleAddElement(evt); //处理增加元素操作
+    }
+
+};
+
+function handleAddElement(msg) {
+    if (msg["type"] == "openPage") {
+        addElement(1, msg);
+    } else if (msg["type"] == "InputText") {
+        addElement(4, msg);
+    } else if (msg["type"] == "singleClick") {
+        addElement(2, msg);
+    } else if (msg["type"] == "loopClickSingle") {
+        addElement(8, msg);
+        addElement(2, msg);
+        app._data.nowArrow["position"] = -1; //循环点击单个元素,下一个要插入的位置一般在元素上方
+    } else if (msg["type"] == "loopClickEvery") {
+        addElement(8, msg);
+        addElement(2, msg);
+    } else if (msg["type"] == "singleCollect" || msg["type"] == "multiCollectNoPattern") {
+        if (app._data.nowNode != null && app._data["nowNode"]["option"] == 3) { //如果当前点击的动作就是提取数据
+            for (let i = 0; i < msg["parameters"].length; i++) {
+                app._data["nowNode"]["parameters"]["paras"].push(msg["parameters"][i]);
+            }
+            app._data.paras.parameters = app._data["nowNode"]["parameters"]["paras"];
+        } else {
+            addElement(3, msg);
+        }
+        notifyParameterNum(msg["parameters"].length); //通知浏览器端参数的个数变化
+    } else if (msg["type"] == "multiCollectWithPattern") {
+        addElement(8, msg);
+        addElement(3, msg);
+        notifyParameterNum(msg["parameters"].length); //通知浏览器端参数的个数变化
+    }
+}
+
+
+function notifyParameterNum(num) {
+    parameterNum += num;
+    let message = {
+        type: 3, //消息类型,3代表元素增加事件
+        from: 1, //0代表从浏览器到流程图,1代表从流程图到浏览器
+        message: { "pipe": JSON.stringify({ "type": 0, "value": parameterNum }) } // {}全选{BS}退格
+    };
+    window.ws.send(JSON.stringify(message));
+}
+// function isExtract() { //检测当前锚点之前的元素是否为提取数据字段
+//     if (app.$data.nowArrow["position"] == -1) {
+//         return false;
+//     } else if (nodeList[nodeList[app.$data.nowArrow["pId"]].sequence[app.$data.nowArrow["position"]]]["option"] == 3) {
+//         return true;
+//     } else {
+//         return false;
+//     }
+// }
+
+// 流程图元素点击后的处理逻辑
+function handleElement() {
+    app._data["nowNode"] = nodeList[vueData.nowNodeIndex];
+    app._data["nodeType"] = app._data["nowNode"]["option"];
+    app._data.useLoop = app._data["nowNode"]["parameters"]["useLoop"];
+    if (app._data["nodeType"] == 8) {
+        app._data.loopType = app._data["nowNode"]["parameters"]["loopType"];
+    } else if (app._data["nodeType"] == 3) {
+        app._data.paraIndex = 0; //参数索引初始化
+        app._data.paras.parameters = app._data["nowNode"]["parameters"]["paras"];
+    } else if (app._data["nodeType"] == 10) {
+        app._data.TClass = app._data["nowNode"]["parameters"]["class"];
+    }
+}
+
+// 新增元素时的默认参数处理
+function addParameters(t) {
+    t["parameters"] = {
+        history: 1,
+        tabIndex: 0,
+        useLoop: false, //是否使用循环中的元素
+        xpath: "", //xpath
+        wait: 0, //执行后等待
+    }; //公共参数处理
+    if (t.option == 1) {
+        t["parameters"]["url"] = "about:blank";
+        t["parameters"]["links"] = "about:blank";
+        t["parameters"]["scrollType"] = 0; //滚动类型,0不滚动,1向下滚动1屏,2滚动到底部
+        t["parameters"]["scrollCount"] = 0; //滚动次数
+    } else if (t.option == 2) { //点击元素
+        t["parameters"]["scrollType"] = 0; //滚动类型,0不滚动,1向下滚动1屏,2滚动到底部
+        t["parameters"]["scrollCount"] = 0; //滚动次数
+        t["parameters"]["paras"] = []; //默认参数列表
+    } else if (t.option == 3) { //提取数据
+        t["parameters"]["paras"] = []; //默认参数列表
+    } else if (t.option == 4) { //输入文字
+        t["parameters"]["value"] = "";
+    } else if (t.option == 8) { //循环
+        t["parameters"]["scrollType"] = 0; //滚动类型,0不滚动,1向下滚动1屏,2滚动到底部
+        t["parameters"]["scrollCount"] = 0; //滚动次数
+        t["parameters"]["loopType"] = 0; //默认循环类型
+        t["parameters"]["xpath"] = "";
+        t["parameters"]["pathList"] = "";
+        t["parameters"]["textList"] = "";
+        t["parameters"]["exitCount"] = 0; //执行多少次后退出循环,0代表不设置此条件
+        t["parameters"]["historyWait"] = 2; //历史记录回退时间,用于循环点击每个链接的情况下点击链接后不打开新标签页的情况
+    } else if (t.option == 9) { //条件
+
+    } else if (t.option == 10) { //条件分支
+        t["parameters"]["class"] = 0; //0代表什么条件都没有,1代表当前页面包括文本,2代表当前页面包括元素,3代表当前循环包括文本,4代表当前循环包括元素
+        t["parameters"]["value"] = ""; //相关值
+    }
+}
+
+//修改元素参数
+function modifyParameters(t, para) {
+    t["parameters"]["history"] = para["history"];
+    t["parameters"]["tabIndex"] = para["tabIndex"];
+    if (t.option == 1) {
+        t["parameters"]["url"] = para["url"];
+        t["parameters"]["links"] = para["links"];
+        $("#serviceDescription").val(para["url"]);
+        $("#url").val(para["url"]);
+    } else if (t.option == 4) { //输入文字事件
+        t["parameters"]["value"] = para["value"];
+        t["parameters"]["xpath"] = para["xpath"];
+    } else if (t.option == 2) { //鼠标点击事件
+        t["parameters"]["xpath"] = para["xpath"];
+        t["parameters"]["useLoop"] = para["useLoop"];
+    } else if (t.option == 8) { //循环事件
+        t["parameters"]["loopType"] = para["loopType"];
+        t["parameters"]["xpath"] = para["xpath"];
+        if (para["nextPage"]) { //循环点击下一页的情况下
+            t["title"] = "循环点击下一页"
+        } else {
+            t["title"] = "循环"
+        }
+        if (para["loopType"] == 2) //如果是固定元素列表
+        {
+            t["parameters"]["pathList"] = para["pathList"].join("\n");
+        }
+    } else if (t.option == 3) { //采集数据
+        for (let i = 0; i < para["parameters"].length; i++) {
+            para["parameters"][i]["default"] = ""; //找不到元素时候的默认值
+        }
+        t["parameters"]["paras"] = para["parameters"];
+    }
+}
+
+//点击确定按钮时的处理
+$("#confirm").mousedown(function() {
+    refresh(false);
+    app.$data.nowArrow["num"]++; //改变元素的值,通知画图,重新对锚点画图
+    let tnodes = document.getElementsByClassName("clk");
+    let position = nodeList[vueData.nowNodeIndex]["position"];
+    let pid = nodeList[vueData.nowNodeIndex]["parentId"];
+    for (let i = 0; i < tnodes.length; i++) {
+        if (position == tnodes[i].getAttribute("position") && pid == tnodes[i].getAttribute("pId")) {
+            tnodes[i].style.borderColor = "blue"; // 点击了确定按钮之后需要重新对选中的颜色画框
+            nowNode = tnodes[i];
+            break;
+        }
+    }
+});
+
+//获取url中的参数
+function getUrlParam(name) {
+    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
+    var r = window.location.search.substr(1).match(reg); //匹配目标参数
+    if (r != null) return unescape(r[2]);
+    return "";
+}
+
+var sId = getUrlParam('id');
+var backEndAddressServiceWrapper = getUrlParam("backEndAddressServiceWrapper");
+
+function saveService(type) {
+    var serviceId = $("#serviceId").val();
+    var text = "确认要保存服务吗?";
+    if (type == 1) { //服务另存为
+        serviceId = -1;
+        text = "确认要另存为服务吗?";
+    }
+    if (confirm(text)) {
+        let serviceName = $("#serviceName").val();
+        let url = $("#url").val();
+        let serviceDescription = $("#serviceDescription").val();
+        let inputParameters = [];
+        let outputParameters = [];
+        let outputNames = [];
+        let inputIndex = 0;
+        let outputIndex = 0;
+        let links = ""; //记录所有的link
+        let containJudge = false; //是否含有判断语句
+        for (let i = 1; i < nodeList.length; i++) {
+            if (nodeList[i]["id"] != -1) { //已经被删除的节点不进行统计
+                if (nodeList[i]["option"] == 1) //打开网页操作,统计输入框输入操作
+                {
+                    if (!nodeList[i]["parameters"]["useLoop"]) //如果不是使用循环里的文本
+                    {
+                        inputParameters.push({
+                            id: inputIndex,
+                            name: "urlList_" + inputIndex++,
+                            nodeId: i, //记录操作位于的节点位置,重要!!!
+                            nodeName: nodeList[i]["title"],
+                            value: nodeList[i]["parameters"]["links"],
+                            desc: "要采集的网址列表,多行以\\n分开",
+                            type: "string",
+                            exampleValue: "https://www.jd.com"
+                        });
+                        links = nodeList[i]["parameters"]["links"];
+                    }
+                } else if (nodeList[i]["option"] == 4) //输入文字操作
+                {
+                    if (!nodeList[i]["parameters"]["useLoop"]) //如果不是使用循环里的文本
+                    {
+                        inputParameters.push({
+                            id: inputIndex,
+                            name: "inputText_" + inputIndex++,
+                            nodeName: nodeList[i]["title"],
+                            nodeId: i,
+                            desc: "要输入的文本,如京东搜索框输入:电脑",
+                            type: "string",
+                            exampleValue: nodeList[i]["parameters"]["value"],
+                            value: nodeList[i]["parameters"]["value"],
+                        });
+                    }
+                } else if (nodeList[i]["option"] == 8) //循环操作
+                {
+                    if (parseInt(nodeList[i]["parameters"]["loopType"]) > 2) //循环中的循环输入文本或循环输入网址
+                        inputParameters.push({
+                        id: inputIndex,
+                        name: "loopText_" + inputIndex++,
+                        nodeId: i,
+                        nodeName: nodeList[i]["title"],
+                        desc: "要输入的文本/网址,多行以\\n分开",
+                        type: "string",
+                        exampleValue: nodeList[i]["parameters"]["textList"],
+                        value: nodeList[i]["parameters"]["textList"],
+                    });
+                } else if (nodeList[i]["option"] == 3) //提取数据操作
+                {
+                    for (let j = 0; j < nodeList[i]["parameters"]["paras"].length; j++) {
+                        if (outputNames.indexOf(nodeList[i]["parameters"]["paras"][j]["name"]) < 0) { //参数名称还未被添加
+                            outputNames.push(nodeList[i]["parameters"]["paras"][j]["name"]);
+                            outputParameters.push({
+                                id: outputIndex++,
+                                name: nodeList[i]["parameters"]["paras"][j]["name"],
+                                desc: nodeList[i]["parameters"]["paras"][j]["desc"],
+                                type: "string",
+                                exampleValue: nodeList[i]["parameters"]["paras"][j]["exampleValues"][0]["value"],
+                            });
+                        }
+                    }
+                } else if (nodeList[i]["option"] == 9) //条件判断
+                {
+                    containJudge = true;
+                }
+            }
+        }
+        let serviceInfo = {
+            "id": parseInt(serviceId),
+            "name": serviceName,
+            "url": url,
+            "links": links,
+            "containJudge": containJudge,
+            "desc": serviceDescription,
+            "inputParameters": inputParameters,
+            "outputParameters": outputParameters,
+            "graph": nodeList, //图结构要存储下来
+        };
+        $.post(backEndAddressServiceWrapper + "/backEnd/manageService", { paras: JSON.stringify(serviceInfo) }, function(result) { $("#serviceId").val(parseInt(result)) });
+        // alert("保存成功!");
+        $('#myModal').modal('hide');
+        $("#tip").slideDown(); //提示框
+        fadeout = setTimeout(function() {
+            $("#tip").slideUp();
+        }, 2000);
+
+    }
+}
+
+//点击保存服务按钮时的处理
+$("#saveButton").mousedown(function() {
+    saveService(0);
+});
+//点击另存为服务按钮时的处理
+$("#saveAsButton").mousedown(function() {
+    saveService(1);
+});
+
+
+if (sId != null && sId != -1) //加载服务
+{
+    $.get(backEndAddressServiceWrapper + "/backEnd/queryService?id=" + sId, function(result) {
+        nodeList = result["graph"];
+        app.$data.list.nl = nodeList;
+        $("#serviceName").val(result["name"]);
+        $("#serviceId").val(result["id"]);
+        $("#url").val(result["url"]);
+        $("#serviceDescription").val(result["desc"]);
+        refresh();
+    });
+} else {
+    refresh(); //新增服务
+}

+ 4 - 4
ServiceGrid/frontEnd/newService.html

@@ -8,20 +8,20 @@
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <script src="bootstrap/js/bootstrap.js"></script>
     <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
-    <title>新服务</title>
+    <title>New Service</title>
 
 </head>
 
 <body>
     <div class="row" style="margin-top: 40px;">
         <div class="col-md-6" style="margin:0 auto" style="text-align: center;">
-            <h4 style="text-align: center;">新服务</h4>
+            <h4 style="text-align: center;">New Service</h4>
             <div class="form-group">
-                <label for="exampleInputEmail1">输入要执行的网址(带http或https):</label>
+                <label for="exampleInputEmail1">URL(http or https):</label>
                 <textarea class="form-control" id="links" placeholder="links" style="min-height: 200px;">https://www.jd.com</textarea>
             </div>
 
-            <button type="submit" id="send" class="btn btn-primary">开始包装</button>
+            <button type="submit" id="send" class="btn btn-primary">Start Wrapping</button>
         </div>
     </div>
 

+ 33 - 32
ServiceGrid/frontEnd/serviceInfo.html

@@ -8,7 +8,7 @@
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <script src="vue.js"></script>
     <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
-    <title>服务信息</title>
+    <title>Service Information</title>
     <style>
         table {
             table-layout: auto;
@@ -35,20 +35,20 @@
 <body>
     <div class="row" style="margin-top: 40px;">
         <div class="col-md-6" style="margin:0 auto" id="serviceList" v-if="show">
-            <h4 style="text-align: center;">服务信息</h4>
-            <p>服务名称:{{service["name"]}}</p>
-            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">服务描述:{{service["desc"]}}</p>
-            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">服务示例URL:{{service["url"]}}</p>
-            <p>输入参数:</p>
+            <h4 style="text-align: center;">Service Information</h4>
+            <p>Service Name: {{service["name"]}}</p>
+            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">Service Description: {{service["desc"]}}</p>
+            <p style="word-wrap: break-word;word-break: break-all;overflow: hidden;max-height: 100px;">Example URL: {{service["url"]}}</p>
+            <p>Input Parameters:</p>
             <table class="table table-bordered">
                 <tbody>
                     <tr>
                         <th style="min-width: 50px;">ID</th>
-                        <th>参数名称</th>
-                        <th>调用名称</th>
-                        <th>参数类型</th>
-                        <th>示例值</th>
-                        <th>参数描述</th>
+                        <th>Parameter Name</th>
+                        <th>Invoke Name</th>
+                        <th>Parameter Type</th>
+                        <th>Example Value</th>
+                        <th>Parameter Description</th>
                     </tr>
                     <tr v-if="service.inputParameters.length>0" v-for="i in service.inputParameters.length">
                         <td style="min-width: 50px;">{{i}}</td>
@@ -59,12 +59,12 @@
                         <td>{{service.inputParameters[i-1]["desc"]}}</td>
                     </tr>
                     <tr v-if="service.inputParameters.length==0">
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
                     </tr>
                 </tbody>
             </table>
@@ -73,10 +73,10 @@
                 <tbody>
                     <tr>
                         <th style="min-width: 50px;">ID</th>
-                        <th>参数名称</th>
-                        <th>参数类型</th>
-                        <th>示例值</th>
-                        <th>参数描述</th>
+                        <th>Parameter Name</th>
+                        <th>Parameter Type</th>
+                        <th>Example Value</th>
+                        <th>Parameter Description</th>
                     </tr>
                     <tr v-if="service.outputParameters.length>0" v-for="i in service.outputParameters.length">
                         <td style="min-width: 50px;">{{i}}</td>
@@ -86,16 +86,16 @@
                         <td>{{service.outputParameters[i-1]["desc"]}}</td>
                     </tr>
                     <tr v-if="service.outputParameters.length==0">
-                        <td style="min-width: 50px;">暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
-                        <td>暂无</td>
+                        <td style="min-width: 50px;">Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
+                        <td>Empty</td>
                     </tr>
                 </tbody>
             </table>
-            <a style="margin-top: 5px;" href="javascript:void(0)" v-on:click="modifyService(service['id'],service['url'])" class="btn btn-primary">修改服务</a>
-            <a style="margin-top: 5px;" href="javascript:void(0)" v-on:click="invokeService(service['id'],service['url'])" class="btn btn-primary">调用服务</a>
+            <a style="margin-top: 5px;" href="javascript:void(0)" v-on:click="modifyService(service['id'],service['url'])" class="btn btn-primary">Modify Service</a>
+            <a style="margin-top: 5px;" href="javascript:void(0)" v-on:click="invokeService(service['id'],service['url'])" class="btn btn-primary">Invoke Service</a>
         </div>
     </div>
 
@@ -107,7 +107,7 @@
         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
         var r = window.location.search.substr(1).match(reg); //匹配目标参数
         if (r != null) return unescape(r[2]);
-        return null; //返回参数值
+        return ""; //返回参数值,默认后台地址
     }
 
     var sId = getUrlParam('id');
@@ -116,6 +116,7 @@
         data: {
             service: {},
             show: false, //是否渲染
+            backEndAddressServiceWrapper: getUrlParam("backEndAddressServiceWrapper"),
         },
         methods: {
             modifyService: function(id, url) {
@@ -127,14 +128,14 @@
                 };
                 // ws.send(JSON.stringify(message));
                 // window.location.href = url; //跳转链接
-                window.location.href = "FlowChart.html?id=" + id;
+                window.location.href = "FlowChart.html?id=" + id + "&backEndAddressServiceWrapper="+ app.$data.backEndAddressServiceWrapper
             },
             invokeService: function(id) {
-                window.location.href = "invokeService.html?id=" + id;
+                window.location.href = "invokeService.html?id=" + id + "&backEndAddressServiceWrapper="+ app.$data.backEndAddressServiceWrapper;
             },
         }
     });
-    $.get("http://183.129.170.180:8041/backEnd/queryService?id=" + sId, function(result) {
+    $.get(app.$data.backEndAddressServiceWrapper + "/backEnd/queryService?id=" + sId, function(result) {
         app.$data.service = result;
         app.$data.show = true;
     });

+ 17 - 13
ServiceGrid/frontEnd/serviceList.html

@@ -8,22 +8,22 @@
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <script src="vue.js"></script>
     <link rel="stylesheet" href="bootstrap/css/bootstrap.css"></link>
-    <title>开始使用</title>
+    <title>Start</title>
 
 </head>
 
 <body>
     <div class="row" style="margin-top: 40px;">
         <div style="margin:0 auto;width: 60%;min-width: 500px;" id="serviceList">
-            <h4 style="text-align: center;">服务列表</h4>
+            <h4 style="text-align: center;">Service List</h4>
             <div style="max-height: 700px;overflow: auto;margin-bottom: 10px">
                 <table style="table-layout: fixed;" class="table table-hover">
                     <thead>
                         <tr>
                             <th>ID</th>
-                            <th>服务名称</th>
+                            <th>Service Name</th>
                             <th>URL</th>
-                            <th v-bind:colspan="type">操作</th>
+                            <th v-bind:colspan="type">Operations</th>
                         </tr>
                     </thead>
                     <tbody>
@@ -31,14 +31,14 @@
                             <td>{{i}}</td>
                             <td style="overflow: hidden;">{{list[i-1]["name"]}}</td>
                             <td style="height: 30px;white-space: nowrap;overflow: hidden;">{{list[i-1]["url"]}}</td>
-                            <td><a href="javascript:void(0)" v-on:click="browseService(list[i-1]['id'])">查看服务信息</a></td>
-                            <td v-if="type==3"><a href="javascript:void(0)" v-on:click="modifyService(list[i-1]['id'],list[i-1]['url'])">修改服务</a></td>
-                            <td><a href="javascript:void(0)" v-on:click="deleteService(list[i-1]['id'])">删除服务</a></td>
+                            <td><a href="javascript:void(0)" v-on:click="browseService(list[i-1]['id'])">Service Information</a></td>
+                            <td v-if="type==3"><a href="javascript:void(0)" v-on:click="modifyService(list[i-1]['id'],list[i-1]['url'])">Modify Service</a></td>
+                            <td><a href="javascript:void(0)" v-on:click="deleteService(list[i-1]['id'])">Delete Service</a></td>
                         </tr>
                     </tbody>
                 </table>
             </div>
-            <a v-if="type==3" href="newService.html" class="btn btn-primary">新服务</a>
+            <a v-if="type==3" href="javascript:void(0)" v-on:click="newService" class="btn btn-primary">New Service</a>
         </div>
     </div>
 
@@ -50,7 +50,7 @@
         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
         var r = window.location.search.substr(1).match(reg); //匹配目标参数
         if (r != null) return unescape(r[2]);
-        return null; //返回参数值
+        return ""; //返回参数值,默认后台地址
     }
 
     var app = new Vue({
@@ -58,8 +58,12 @@
         data: {
             list: [],
             type: 3, //记录服务行为
+            backEndAddressServiceWrapper: getUrlParam("backEndAddressServiceWrapper"),
         },
         methods: {
+            newService: function (){
+                window.location.href = "newService.html?backEndAddressServiceWrapper="+ app.$data.backEndAddressServiceWrapper;;
+            },
             modifyService: function(id, url) {
                 let message = { //显示flowchart
                     type: 1, //消息类型,传递链接
@@ -71,12 +75,12 @@
                 window.location.href = url; //跳转链接
             },
             browseService: function(id) {
-                window.location.href = "serviceInfo.html?id=" + id; //跳转链接
+                window.location.href = "serviceInfo.html?id=" + id + "&backEndAddressServiceWrapper="+ app.$data.backEndAddressServiceWrapper; //跳转链接
             },
             deleteService: function(id) {
                 if (confirm("确定要删除服务吗?")) {
-                    $.get("http://183.129.170.180:8041/backEnd/deleteService?id=" + id, function(res) {
-                        $.get("http://183.129.170.180:8041/backEnd/queryServices", function(re) {
+                    $.get(app.$data.backEndAddressServiceWrapper + "/backEnd/deleteService?id=" + id, function(res) {
+                        $.get(app.$data.backEndAddressServiceWrapper + "/backEnd/queryServices", function(re) {
                             result = re.sort(desc);
                             app.$data.list = result;
                         });
@@ -90,7 +94,7 @@
     var desc = function(x, y) {
         return (x["id"] < y["id"]) ? 1 : -1
     }
-    $.get("http://183.129.170.180:8041/backEnd/queryServices", function(re) {
+    $.get(app.$data.backEndAddressServiceWrapper + "/backEnd/queryServices", function(re) {
         result = re.sort(desc);
         app.$data.list = result;
         if (getUrlParam("type") == "1") {

+ 1 - 0
ServiceGrid/static/.gitattributes

@@ -0,0 +1 @@
+ServiceWrapper.7z filter=lfs diff=lfs merge=lfs -text

+ 2 - 0
ServiceWrapperEntry/.gitignore

@@ -0,0 +1,2 @@
+.vs
+packages

+ 11 - 0
ServiceWrapperEntry/Readme.md

@@ -0,0 +1,11 @@
+# 客户端开发编译方式
+
+0. 安装VS2019或以上版本,勾选windows应用程序开发(.Net Framework 4.7.2版本及以上)。
+
+1. 拷贝客户端(可执行程序)servicewrapper文件夹内所有文件到\ServiceWrapperEntry\bin\x64\Debug文件夹(包括Chrome文件夹)
+
+2. 打开sln文件,右键点击解决方案,点击“清理解决方案”后,再点击“还原Nuget包”。
+
+3. 右键点击项目,点击“清理”后,再点击“重新生成项目”。
+
+4. 编译即成功。

+ 25 - 0
ServiceWrapperEntry/ServiceWrapperEntry.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29728.190
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceWrapperEntry", "ServiceWrapperEntry\ServiceWrapperEntry.csproj", "{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x64 = Debug|x64
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}.Debug|x64.ActiveCfg = Debug|x64
+		{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}.Debug|x64.Build.0 = Debug|x64
+		{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}.Release|x64.ActiveCfg = Release|x64
+		{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {F3EC44B3-E8DF-40FA-ABEB-9F5BAC89A723}
+	EndGlobalSection
+EndGlobal

+ 1 - 0
ServiceWrapperEntry/ServiceWrapperEntry/.gitignore

@@ -0,0 +1 @@
+obj/*

+ 6 - 0
ServiceWrapperEntry/ServiceWrapperEntry/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
+    </startup>
+</configuration>

+ 174 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Class1.cs

@@ -0,0 +1,174 @@
+using CefSharp;
+using CefSharp.Internals;
+using CefSharp.Web;
+using CefSharp.WinForms;
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+
+namespace ServiceWrapper
+{
+    public class MouseHelper
+    {
+        [System.Runtime.InteropServices.DllImport("user32")]
+        public static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
+        //移动鼠标 
+        public const int MOUSEEVENTF_MOVE = 0x0001;
+        //模拟鼠标左键按下 
+        public const int MOUSEEVENTF_LEFTDOWN = 0x0002;
+        //模拟鼠标左键抬起 
+        public const int MOUSEEVENTF_LEFTUP = 0x0004;
+        //模拟鼠标右键按下 
+        public const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
+        //模拟鼠标右键抬起 
+        public const int MOUSEEVENTF_RIGHTUP = 0x0010;
+        //模拟鼠标中键按下 
+        public const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
+        //模拟鼠标中键抬起 
+        public const int MOUSEEVENTF_MIDDLEUP = 0x0040;
+        //标示是否采用绝对坐标 
+        public const int MOUSEEVENTF_ABSOLUTE = 0x8000;
+        [DllImport("user32.dll")]
+        public static extern bool SetCursorPos(int X, int Y);
+    }
+    public class Parameters
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public string url { get; set; }
+    }
+
+    public class Data
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public int option { get; set; }
+        /// <summary>
+        /// 
+        /// </summary>
+        public Parameters parameters { get; set; }
+    }
+
+    public class FlowMessage
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public int type { get; set; }
+        /// <summary>
+        /// 
+        /// </summary>
+        public Data data { get; set; }
+    }
+
+    public class Message
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public int id { get; set; }
+        public string links { get; set; }
+        public string link { get; set; }
+        //键盘输入的值
+        public string keyboardStr { get; set; }
+        //直接转接流程图的消息
+        public string pipe { get; set; }
+    }
+
+
+    public class Msg
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        public int type { get; set; }
+        /// <summary>
+        /// 从哪里来
+        /// </summary>
+        public int from { get; set; }
+        public Message message { get; set; }
+    }
+
+    public class RequestContextHandler : IRequestContextHandler
+    {
+        public IResourceRequestHandler GetResourceRequestHandler(IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
+        {
+            return null;
+        }
+
+        public bool OnBeforePluginLoad(string mimeType, string url, bool isMainFrame, string topOriginUrl, WebPluginInfo pluginInfo, ref PluginPolicy pluginPolicy)
+        {
+            return true;
+        }
+
+        public void OnRequestContextInitialized(IRequestContext requestContext)
+        {
+           
+        }
+    }
+    //加载窗口时的事件设置
+    public class RenderProcessMessageHandler : IRenderProcessMessageHandler
+    {
+        public void OnContextReleased(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame)
+        {
+            //throw new NotImplementedException();
+        }
+
+        public void OnFocusedNodeChanged(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IDomNode node)
+        {
+            //throw new NotImplementedException();
+        }
+
+        public void OnUncaughtException(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, JavascriptException exception)
+        {
+            //throw new NotImplementedException();
+        }
+
+        // Wait for the underlying JavaScript Context to be created. This is only called for the main frame.
+        // If the page has no JavaScript, no context will be created.
+        void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
+        {
+            //MessageBox.Show("zhixing");
+            
+        }
+    }
+
+    /// <summary>
+    /// 在自己窗口打开链接
+    /// </summary>
+    internal class OpenPageSelf : ILifeSpanHandler
+    {
+        public bool DoClose(IWebBrowser browserControl, IBrowser browser)
+        {
+            return false;
+        }
+
+        public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser)
+        {
+           
+        }
+
+        public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser)
+        {
+
+        }
+
+        public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl,
+string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures,
+IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
+        {
+            newBrowser = null;
+            var chromiumWebBrowser = (ChromiumWebBrowser)browserControl;
+            chromiumWebBrowser.Load(targetUrl);
+            return true; //Return true to cancel the popup creation copyright by codebye.com.
+        }
+    }
+}

+ 88 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Flow.Designer.cs

@@ -0,0 +1,88 @@
+namespace ServiceWrapper
+{
+    partial class Flow
+    {
+        /// <summary>
+        /// 必需的设计器变量。
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// 清理所有正在使用的资源。
+        /// </summary>
+        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows 窗体设计器生成的代码
+
+        /// <summary>
+        /// 设计器支持所需的方法 - 不要修改
+        /// 使用代码编辑器修改此方法的内容。
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Flow));
+            this.panel1 = new System.Windows.Forms.Panel();
+            this.button1 = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // panel1
+            // 
+            this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.panel1.AutoSize = true;
+            this.panel1.Location = new System.Drawing.Point(4, 6);
+            this.panel1.Margin = new System.Windows.Forms.Padding(6);
+            this.panel1.Name = "panel1";
+            this.panel1.Size = new System.Drawing.Size(1846, 1352);
+            this.panel1.TabIndex = 0;
+            // 
+            // button1
+            // 
+            this.button1.AutoSize = true;
+            this.button1.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.button1.Font = new System.Drawing.Font("宋体", 16.125F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
+            this.button1.Location = new System.Drawing.Point(0, 1373);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(1862, 53);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "←";
+            this.button1.UseVisualStyleBackColor = true;
+            this.button1.Visible = false;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // Flow
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 24F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(1862, 1426);
+            this.Controls.Add(this.button1);
+            this.Controls.Add(this.panel1);
+            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            this.Margin = new System.Windows.Forms.Padding(6);
+            this.Name = "Flow";
+            this.Text = "服务包装手动版";
+            this.Load += new System.EventHandler(this.Flow_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+
+
+
+        #endregion
+
+        private System.Windows.Forms.Panel panel1;
+        private System.Windows.Forms.Button button1;
+    }
+}
+

+ 119 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Flow.cs

@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using CefSharp;
+using CefSharp.WinForms;
+using System.Runtime.InteropServices; //引用此名称空间,简化后面的代码
+using System.Net;
+using System.Diagnostics;
+
+namespace ServiceWrapper
+{
+
+    public partial class Flow : Form, IMessageFilter
+    {
+        public ChromiumWebBrowser chromeBrowser;
+        public bool ChromeNow = false; //标记现在所在窗口是否为chrome
+        public static string flowChartUrl = PublicVariable.frontEndAddress + "/FlowChart.html?id="; //流程图所在的位置
+        public string url = flowChartUrl + "-1&backEndAddressServiceWrapper=" + PublicVariable.backEndAddress;
+        public Flow()
+        {
+            InitializeComponent();
+        }
+        public Flow(string link)
+        {
+            InitializeComponent();
+            url = link;
+            button1.Show();
+        }
+        // P/Invoke declarations
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetForegroundWindow();
+        [DllImport("user32.dll")]
+        private extern static bool SwapMouseButton(bool fSwap);
+        [System.Runtime.InteropServices.DllImport("user32.dll")]
+        public static extern int SetForegroundWindow(IntPtr hwnd);
+        public const int WM_CLOSE = 0x10;
+        public bool closedriver = true;
+        [DllImport("user32.dll", EntryPoint = "SendMessage")]
+        private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
+
+        public bool PreFilterMessage(ref System.Windows.Forms.Message SystemMessage)
+        {
+            if (SystemMessage.Msg >= 513 && SystemMessage.Msg <= 515)
+            {//不响应鼠标左键消息                
+                return true;
+            }
+            return false;
+        }
+        private void Flow_Load(object sender, EventArgs e)
+        {
+            InitializeChromium();
+            PublicVariable.isInitialized = true;
+            //保证并排平铺
+            int width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size.Width;
+            int height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size.Height;
+            StartPosition = FormStartPosition.Manual; //窗体的位置由Location属性决定
+            Location = (Point)new Size(0, 0);         //窗体的起始位置为(x,y)
+            Width = width;
+            Height = Convert.ToInt32(height * 0.8);
+            FormClosing += Flow_FormClosing;
+        }
+
+        //初始化浏览器并启动
+        public void InitializeChromium()
+        {
+            if (!PublicVariable.isInitialized)//只初始化一次
+            {
+                CefSettings settings = new CefSettings();
+                Cef.Initialize(settings);
+            }
+            // Create a browser component
+            chromeBrowser = new ChromiumWebBrowser(url);
+            //跨域访问允许
+            chromeBrowser.BrowserSettings.FileAccessFromFileUrls = CefState.Enabled;
+            chromeBrowser.BrowserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
+            //textBox1.Text = url;
+            // Add it to the form and fill it to the form window.
+            panel1.Controls.Add(chromeBrowser);
+            chromeBrowser.Dock = DockStyle.Fill;
+            chromeBrowser.RenderProcessMessageHandler = new RenderProcessMessageHandler();
+        }
+
+        //窗体关闭时,记得停止浏览器
+        private void Flow_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            if(closedriver)
+            {
+                //Cef.Shutdown();//关掉内嵌控件
+                try
+                {
+                    //PublicVariable.chrome.Kill();//关掉chrome
+                    //SendMessage(Start.chromeId, WM_CLOSE, 0, 0);//关掉chrome
+                    Start.browser.Quit();//关掉chromedriver
+                }
+                catch (Exception)
+                {
+                }
+            }
+            PublicVariable.start.Show(); //重新显示初始框
+        }
+
+        private void panel1_Paint(object sender, PaintEventArgs e)
+        {
+            SetForegroundWindow(Start.chromeId); //打开流程图窗口后将chrome窗口显示到最前方
+        }
+
+        private void button1_Click(object sender, EventArgs e)
+        {
+            chromeBrowser.Back();
+        }
+
+    }
+}

+ 408 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Flow.resx

@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA
+        AAD/////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7//v7+///////+/v7//v7+////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////v7+//7+/v/+/v7/////////
+        /////////////////////////v7+//7+/v//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+///////+/v7//v7+//////////////////7+/v/+/v7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////+/v7//v7+/////////////v7+//7+/v/+/v7////////////+/v7//v7+//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+////
+        /////////v7+//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v//////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//7+/v/+/v7////////////////////////////+/v7/+vr6/5eX
+        l/+YmJj/+vr6//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7/////////////////////////
+        ///9/f3/4uLi/0lJSf8AAAD/AAAA/0lJSf/j4+P//f39////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////9/f3/ubm5/xkZGf8BAQH/AAAA/wAAAP8BAQH/GRkZ/7m5uf/+/v7//v7+////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////9/f3/kpKS/wYGBv8AAAD/AAAA/wAAAP8AAAD/AAAA/wEB
+        Af8GBgb/kpKS//7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////9/f3/hoaG/wICAv8AAAD/AAAA/wAA
+        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv+FhYX//f39////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/q6ur/wQE
+        BP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC/6ysrP/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7/9PT0/x8fH/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEB
+        Af8dHR3/9fX1////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+/7W1tf8AAAD/AAAA/wICAv8aGhr/AwMD/wAAAP8AAAD/AAAA/wAA
+        AP8EBAT/Ghoa/wICAv8AAAD/AAAA/7a2tv//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v+RkZH/AAAA/wAAAP8gICD/+/v7/9fX
+        1/9UVFT/AgIC/wICAv9VVVX/2NjY//v7+/8fHx//AAAA/wAAAP+SkpL/////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/mpqa/wAA
+        AP8AAAD/Nzc3//7+/v/+/v7/ysrK/8TExP/Dw8P/ycnJ//7+/v/9/f3/ODg4/wAAAP8AAAD/mpqa////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+/8PDw/8AAAD/AAAA/zU1Nf/+/v7//v7+/83Nzf+Wlpb/lpaW/87Ozv/+/v7//f39/zU1
+        Nf8AAAD/AAAA/8PDw///////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////7+/v/19fX/EBAQ/wAAAP8YGBj/4uLi/6mpqf8tLS3/AgIC/wEB
+        Af8tLS3/qqqq/+Hh4f8YGBj/AAAA/xAQEP/19fX/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////v7+//7+/v/+/v7//v7+/1lZWf8AAAD/AQEB/wMD
+        A/8DAwP/Li4u/2xsbP9vb2//NDQ0/wICAv8DAwP/AAAA/wAAAP9ZWVn//f39////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/////////
+        //+0tLT/AAAA/wAAAP8JCQn/np6e/+/v7/+1tbX/srKy/+7u7v+qqqr/DAwM/wAAAP8BAQH/tLS0////
+        //////////////7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+////////////+Pj4/x4eHv8CAgL/mJiY/8XFxf8fHx//AQEB/wAAAP8aGhr/vr6+/6Wl
+        pf8BAQH/HR0d//j4+P/////////////////+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v99fX3/LS0t/+bm5v8YGBj/AAAA/wAA
+        AP8AAAD/AAAA/xQUFP/j4+P/MjIy/319ff/9/f3/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/3t7e/4GB
+        gf+BgYH/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/enp6/4WFhf/e3t7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////39/f/n5+f/MzMz/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zIyMv/o6Oj//f39////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+////
+        ///////////////////////////////////+/v7/7+/v/wcHB/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+        AP8HBwf/8fHx//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v///////////////////////////////////////f39/9jY2P+IiIj/fX19/zEx
+        Mf8ICAj/CAgI/y4uLv99fX3/iIiI/9nZ2f/+/v7/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////Hx
+        8f9mZmb/KSkp/zY2Nv+ioqL/QUFB/z09Pf+kpKT/PDw8/ygoKP9oaGj/8fHx//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+//7+/v+CgoL/BwcH/wcHB/8BAQH/DQ0N/7Gxsf+rq6v/Dg4O/wEBAf8GBgb/BwcH/4OD
+        g//9/f3//v7+////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+//7+/v/+/v7//v7+//j4+P/29vb/LCws/wcHB/8HBwf/AAAA/wMDA/9lZWX/Y2Nj/wAA
+        AP8AAAD/BgYG/wcHB/8sLCz/9fX1//f39//+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//Pz8//X19f/vr6+/4iIiP8yMjL/srKy/wEBAf8GBgb/BAQE/wEB
+        Af8nJyf/aGho/2FhYf8lJSX/AQEB/wcHB/8HBwf/AQEB/7Kysv80NDT/iIiI/729vf/X19f/8vLy//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////6Ojo/1RUVP8FBQX/AAAA/wAAAP8AAAD/AgIC/6Cg
+        oP/V1dX/rq6u/62trf+rq6v/ioqK/05OTv9QUFD/kJCQ/7CwsP+pqan/rq6u/9XV1f+fn5//AwMD/wAA
+        AP8AAAD/AAAA/wYGBv9UVFT/6enp//7+/v//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////+vr6/z8/P/8BAQH/AAAA/wAA
+        AP8AAAD/AAAA/wcHB/+vr6//+fn5/xQUFP8ICAj/CAgI/wcHB/8JCQn/CAgI/wcHB/8HBwf/CAgI/xQU
+        FP/4+Pj/sLCw/wYGBv8AAAD/AAAA/wAAAP8AAAD/AAAA/0BAQP/6+vr/////////////////////////
+        /////////////////////////v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+/6am
+        pv8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAf+Li4v//v7+//z8/P++vr7/v7+//4ODg/95eXn/2NjY/9LS
+        0v9ycnL/eXl5/8DAwP+9vb3//Pz8//39/f+Li4v/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/p6en//7+
+        /v////////////////////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        /////////v7+//z8/P86Ojr/AAAA/wAAAP8AAAD/AAAA/wEBAf9QUFD/+/v7//7+/v/q6ur/GBgY/wkJ
+        Cf+ampr//f39//7+/v/+/v7//f39/5mZmf8ICAj/GBgY/+vr6//+/v7/+vr6/09PT/8BAQH/AAAA/wAA
+        AP8AAAD/AAAA/zo6Ov/8/Pz/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////7+/v/c3Nz/BQUF/wAAAP8AAAD/AAAA/wgICP9nZ2f/8vLy//7+
+        /v/+/v7/pqam/wAAAP8BAQH/m5ub//7+/v////////////////+ampr/AAAA/wEBAf+mpqb//v7+//7+
+        /v/y8vL/Z2dn/wgICP8BAQH/AAAA/wAAAP8EBAT/3Nzc////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7/+fn5/93d3f/Gxsb/vLy8/8nJ
+        yf/v7+///f39//7+/v///////f39/0RERP8AAAD/AgIC/+Dg4P//////////////////////39/f/wEB
+        Af8AAAD/Q0ND//39/f/+/v7//v7+//39/f/v7+//ycnJ/729vf/Gxsb/3Nzc//n5+f//////////////
+        /////////////////////////////////////////////////////////v7+//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+/7y8vP8BAQH/AAAA/zMzM//9/f3/////////
+        //////////////39/f80NDT/AAAA/wICAv+8vLz//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7//v7+/+jo6P8lJSX/AAAA/wEB
+        Af+Dg4P//v7+///////////////////////+/v7/g4OD/wEBAf8AAAD/JCQk/+rq6v/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//f39/+np
+        6f89PT3/AAAA/wAAAP8AAAD/y8vL//7+/v///////////////////////////8vLy/8AAAD/AAAA/wAA
+        AP86Ojr/6enp////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//f39/8jIyP8oKCj/AAAA/wEBAf8sLCz/DQ0N//j4+P/+/v7//v7+//7+/v//////////////
+        ///39/f/Dg4O/ywsLP8CAgL/AAAA/ykpKf/IyMj//v7+//7+/v////////////7+/v/+/v7/////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/9/f3/5+fn/29vb/8HBwf/AAAA/wEBAf9NTU3/2NjY/ysrK//+/v7///////7+
+        /v/+/v7//////////////////f39/ysrK//Y2Nj/TU1N/wEBAf8AAAD/BgYG/25ubv/o6Oj//f39//7+
+        /v/+/v7//v7+/////////////v7+//7+/v/+/v7//v7+/////////////v7+//7+/v/+/v7/////////
+        ///+/v7//v7+//7+/v//////////////////////////////////////////////////////////////
+        //////////////////////////////39/f/q6ur/fHx8/xAQEP8BAQH/AgIC/xISEv8qKir/9vb2//T0
+        9P86Ojr//v7+///////+/v7//v7+//////////////////39/f85OTn/8/Pz//X19f8qKir/ExMT/wEB
+        Af8AAAD/EBAQ/3x8fP/q6ur//v7+//7+/v////////////7+/v/+/v7//v7+//7+/v////////////7+
+        /v/+/v7//v7+//////////////////7+/v/+/v7/////////////////////////////////////////
+        ///////////////////////////////////+/v7//f39//Ly8v+CgoL/EhIS/wICAv8BAQH/CAgI/62t
+        rf+rq6v/cXFx//7+/v/9/f3/QUFB//39/f/+/v7////////////////////////////9/f3/QUFB//39
+        /f/+/v7/cXFx/6urq/+tra3/CAgI/wEBAf8CAgL/ExMT/4KCgv/x8fH//f39////////////////////
+        ///////////////////+/v7//v7+//7+/v//////////////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//f39/7S0tP8iIiL/AQEB/y4u
+        Lv9mZmb/AgIC/2ZmZv/9/f3/3t7e/7a2tv/+/v7//f39/4uLi//8/Pz//v7+////////////////////
+        /////////Pz8/4uLi//9/f3//v7+/7e3t//e3t7//f39/2ZmZv8CAgL/ZmZm/y4uLv8CAgL/IiIi/7Oz
+        s//9/f3//v7+//7+/v///////////////////////v7+//7+/v/+/v7/////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/+vr6/3t7
+        e/8FBQX/ExMT/6Kiov/5+fn/ZWVl/wQEBP/U1NT//v7+//7+/v/+/v7//v7+//7+/v/9/f3//f39////
+        //////////////////////////////7+/v/9/f3//v7+//7+/v/+/v7//v7+///////U1NT/BAQE/2Vl
+        Zf/5+fn/oqKi/xISEv8FBQX/enp6//r6+v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7/+/v7/2xsbP8CAgL/BQUF/8HBwf/9/f3/9/f3/xYWFv83Nzf//f39////////////////////
+        ///+/v7//v7+////////////////////////////////////////////////////////////////////
+        /////////Pz8/zg4OP8YGBj/+Pj4//7+/v/BwcH/BwcH/wMDA/9sbGz//Pz8//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////f39/5WVlf8RERH/YWFh/1JSUv/+/v7//v7+/9LS0v8BAQH/fn5+//39
+        /f//////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////9+fn7/AgIC/9LS0v///////v7+/1NTU/9iYmL/ExMT/5SU
+        lP/9/f3///////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+/////////////////////////////////9/f3/8VFRX/vLy8/5aWlv+Ojo7//v7+//7+
+        /v+qqqr/AQEB/6qqqv/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////qamp/wEBAf+rq6v///////7+
+        /v+Ojo7/lpaW/7y8vP8WFhb/39/f//39/f//////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v////////////////////////////39/f9oaGj/dnZ2//z8
+        /P+cnJz/n5+f////////////lZWV/wAAAP+4uLj/////////////////////////////////////////
+        /////////////////////////////////////////////////////////////////////////////7e3
+        t/8AAAD/lpaW///////+/v7/n5+f/5ycnP/9/f3/dnZ2/2hoaP/9/f3/////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7/////////////////////////
+        ///9/f3/Xl5e/+rq6v/+/v7/sbGx/5eXl////////////5OTk/8BAQH/oKCg//39/f//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////+hoaH/AQEB/5OTk//+/v7//v7+/5aWlv+wsLD//v7+/+np6f9eXl7//f39////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v//////////////
+        /////////////////////////v7+//39/f/9/f3//v7+/+3t7f/Z2dn///////////+enp7/Hh4e/11d
+        Xf/9/f3///////7+/v/+/v7//v7+////////////////////////////////////////////////////
+        ///////////////////////////////////9/f3/XV1d/x4eHv+fn5///v7+//7+/v/Z2dn/7e3t//7+
+        /v/+/v7//f39//7+/v///////////////////////////////////////////////////////v7+//7+
+        /v/+/v7//v7+//7+/v/+/v7////////////////////////////////////////////+/v7//v7+////
+        ////////t7e3/3R0dP9LS0v/0dHR//7+/v/+/v7//v7+//7+/v//////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7/0dHR/0tLS/9zc3P/t7e3////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        /////////////////////////////9ra2v9ra2v/5+fn/1RUVP/c3Nz//v7+////////////////////
+        //////////////////////////////////////////////////////////////7+/v/9/f3/3Nzc/1RU
+        VP/o6Oj/a2tr/9ra2v//////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ///////////////////////////////////////////////////4+Pj/XV1d//z8/P/r6+v/bGxs/9HR
+        0f//////////////////////////////////////////////////////////////////////////////
+        ///+/v7/0dHR/2tra//r6+v//f39/1xcXP/4+Pj/////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+//7+
+        /v///////////////////////////////////////////////////////////////////////v7+/19f
+        X//8/Pz///////7+/v/8/Pz/////////////////////////////////////////////////////////
+        /////////////////////////v7+//z8/P/8/Pz//v7+//v7+/9gYGD//f39////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7///////////////////////////////////////7+/v/+/v7//v7+////
+        //////////////7+/v+4uLj/+fn5///////+/v7//v7+////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v/5+fn/t7e3//39
+        /f//////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7//v7+//7+/v/////////////////+/v7//v7+//7+/v//////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7/////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7/////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7/////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//7+/v//////////////////////////////////////////////
+        ////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+</value>
+  </data>
+</root>

+ 99 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Program.cs

@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace ServiceWrapper
+{
+    static class Program
+    {
+        [DllImport("kernel32")]
+        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
+
+        [DllImport("kernel32")]
+        private static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);
+
+        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
+        private static extern uint GetPrivateProfileSection(string lpAppName, IntPtr lpReturnedString, uint nSize, string lpFileName);
+
+        private static string ReadString(string section, string key, string def, string filePath)
+        {
+            StringBuilder temp = new StringBuilder(1024);
+
+            try
+            {
+                GetPrivateProfileString(section, key, def, temp, 1024, filePath);
+            }
+            catch
+            { }
+            return temp.ToString();
+        }
+        /// <summary>
+        /// 根据section取所有key
+        /// </summary>
+        /// <param name="section"></param>
+        /// <param name="filePath"></param>
+        /// <returns></returns>
+        public static string[] ReadIniAllKeys(string section, string filePath)
+        {
+            UInt32 MAX_BUFFER = 32767;
+
+            string[] items = new string[0];
+
+            IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER * sizeof(char));
+
+            UInt32 bytesReturned = GetPrivateProfileSection(section, pReturnedString, MAX_BUFFER, filePath);
+
+            if (!(bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
+            {
+                string returnedString = Marshal.PtrToStringAuto(pReturnedString, (int)bytesReturned);
+
+                items = returnedString.Split(new char[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
+            }
+
+            Marshal.FreeCoTaskMem(pReturnedString);
+
+            return items;
+        }
+
+        /// <summary>
+        /// 根据section,key取值
+        /// </summary>
+        /// <param name="section"></param>
+        /// <param name="keys"></param>
+        /// <param name="filePath">ini文件路径</param>
+        /// <returns></returns>
+        public static string ReadIniKeys(string section, string keys, string filePath)
+        {
+            return ReadString(section, keys, "", filePath);
+        }
+
+        /// <summary>
+        /// 保存ini
+        /// </summary>
+        /// <param name="section"></param>
+        /// <param name="key"></param>
+        /// <param name="value"></param>
+        /// <param name="filePath">ini文件路径</param>
+        public static void WriteIniKeys(string section, string key, string value, string filePath)
+        {
+            WritePrivateProfileString(section, key, value, filePath);
+        }
+
+        /// <summary>
+        /// 应用程序的主入口点。
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            PublicVariable.frontEndAddress = ReadIniKeys("serverAddress", "frontEndAddress", "./config.ini");
+            PublicVariable.backEndAddress = ReadIniKeys("serverAddress", "backEndAddress", "./config.ini");
+            Application.Run(new Start());
+        }
+    }
+}

+ 36 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("ServiceWrapper")]
+[assembly: AssemblyDescription("服务包装手动版")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("浙江大学")]
+[assembly: AssemblyProduct("服务包装器")]
+[assembly: AssemblyCopyright("Copyright ©  2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("8ff781cb-5c33-4c3f-872d-1fe0e114a8d0")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 63 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Properties/Resources.Designer.cs

@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本:4.0.30319.42000
+//
+//     对此文件的更改可能会导致不正确的行为,并且如果
+//     重新生成代码,这些更改将会丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace ServiceWrapper.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   一个强类型的资源类,用于查找本地化的字符串等。
+    /// </summary>
+    // 此类是由 StronglyTypedResourceBuilder
+    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+    // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+    // (以 /str 作为命令选项),或重新生成 VS 项目。
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   返回此类使用的缓存的 ResourceManager 实例。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ServiceWrapper.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   重写当前线程的 CurrentUICulture 属性
+        ///   重写当前线程的 CurrentUICulture 属性。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 26 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Properties/Settings.Designer.cs

@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本:4.0.30319.42000
+//
+//     对此文件的更改可能会导致不正确的行为,并且如果
+//     重新生成代码,这些更改将会丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace ServiceWrapper.Properties {
+    
+    
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+        
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+        
+        public static Settings Default {
+            get {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 32 - 0
ServiceWrapperEntry/ServiceWrapperEntry/PublicVariable.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using OpenQA.Selenium;
+using OpenQA.Selenium.Chrome;
+using OpenQA.Selenium.Interactions;
+using OpenQA.Selenium.Internal;
+using OpenQA.Selenium.Support;
+using Fleck;
+using Newtonsoft.Json;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+namespace ServiceWrapper
+{
+    class PublicVariable
+    {
+        public static bool isInitialized = false;
+        public static double ratio = 0.5; //上面流程图窗口所占的大小比率
+        public static Start start = null;
+        public static Flow fr = null;
+        public static Process chrome = null;
+        public static string frontEndAddress = "http://183.129.170.180:8041/frontEnd";
+        public static string backEndAddress = "http://183.129.170.180:8041";
+    }
+}

+ 179 - 0
ServiceWrapperEntry/ServiceWrapperEntry/ServiceWrapperEntry.csproj

@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.props" Condition="Exists('..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.props')" />
+  <Import Project="..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.props" Condition="Exists('..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.props')" />
+  <Import Project="..\packages\cef.redist.x86.79.1.35\build\cef.redist.x86.props" Condition="Exists('..\packages\cef.redist.x86.79.1.35\build\cef.redist.x86.props')" />
+  <Import Project="..\packages\cef.redist.x64.79.1.35\build\cef.redist.x64.props" Condition="Exists('..\packages\cef.redist.x64.79.1.35\build\cef.redist.x64.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{8FF781CB-5C33-4C3F-872D-1FE0E114A8D0}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>ServiceWrapper</RootNamespace>
+    <AssemblyName>ServiceWrapper</AssemblyName>
+    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>true</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <LangVersion>7.3</LangVersion>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>true</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationIcon>favicon.ico</ApplicationIcon>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Fleck, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Fleck.1.1.0\lib\net45\Fleck.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WebDriver, Version=3.141.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\Selenium.WebDriver.3.141.0\lib\net45\WebDriver.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Class1.cs" />
+    <Compile Include="Flow.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Flow.Designer.cs">
+      <DependentUpon>Flow.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="PublicVariable.cs" />
+    <Compile Include="Start.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Start.Designer.cs">
+      <DependentUpon>Start.cs</DependentUpon>
+    </Compile>
+    <EmbeddedResource Include="Flow.resx">
+      <DependentUpon>Flow.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <EmbeddedResource Include="Start.resx">
+      <DependentUpon>Start.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="favicon.ico" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4.7.2 %28x86 和 x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\cef.redist.x64.79.1.35\build\cef.redist.x64.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x64.79.1.35\build\cef.redist.x64.props'))" />
+    <Error Condition="!Exists('..\packages\cef.redist.x86.79.1.35\build\cef.redist.x86.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\cef.redist.x86.79.1.35\build\cef.redist.x86.props'))" />
+    <Error Condition="!Exists('..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.props'))" />
+    <Error Condition="!Exists('..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.targets'))" />
+    <Error Condition="!Exists('..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.props'))" />
+    <Error Condition="!Exists('..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.targets'))" />
+  </Target>
+  <Import Project="..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.79.1.350\build\CefSharp.Common.targets')" />
+  <Import Project="..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.targets" Condition="Exists('..\packages\CefSharp.WinForms.79.1.350\build\CefSharp.WinForms.targets')" />
+</Project>

+ 13 - 0
ServiceWrapperEntry/ServiceWrapperEntry/ServiceWrapperEntry.csproj.user

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <PublishUrlHistory>publish\</PublishUrlHistory>
+    <InstallUrlHistory />
+    <SupportUrlHistory />
+    <UpdateUrlHistory />
+    <BootstrapperUrlHistory />
+    <ErrorReportUrlHistory />
+    <FallbackCulture>zh-CN</FallbackCulture>
+    <VerifyUploadedFiles>false</VerifyUploadedFiles>
+  </PropertyGroup>
+</Project>

+ 107 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Start.Designer.cs

@@ -0,0 +1,107 @@
+namespace ServiceWrapper
+{
+    partial class Start
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Start));
+            this.button1 = new System.Windows.Forms.Button();
+            this.label1 = new System.Windows.Forms.Label();
+            this.State = new System.Windows.Forms.Label();
+            this.button2 = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // button1
+            // 
+            this.button1.Location = new System.Drawing.Point(60, 66);
+            this.button1.Margin = new System.Windows.Forms.Padding(4);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(196, 75);
+            this.button1.TabIndex = 1;
+            this.button1.Text = "包装/修改/查看服务";
+            this.button1.UseVisualStyleBackColor = true;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(15, 29);
+            this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(88, 16);
+            this.label1.TabIndex = 2;
+            this.label1.Text = "程序状态:";
+            // 
+            // State
+            // 
+            this.State.AutoSize = true;
+            this.State.Location = new System.Drawing.Point(102, 29);
+            this.State.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
+            this.State.Name = "State";
+            this.State.Size = new System.Drawing.Size(200, 16);
+            this.State.TabIndex = 3;
+            this.State.Text = "请点击相应操作按钮使用。";
+            // 
+            // button2
+            // 
+            this.button2.Location = new System.Drawing.Point(60, 163);
+            this.button2.Margin = new System.Windows.Forms.Padding(4);
+            this.button2.Name = "button2";
+            this.button2.Size = new System.Drawing.Size(196, 75);
+            this.button2.TabIndex = 4;
+            this.button2.Text = "查看/调用/删除服务";
+            this.button2.UseVisualStyleBackColor = true;
+            this.button2.Click += new System.EventHandler(this.button2_Click);
+            // 
+            // Start
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(340, 260);
+            this.Controls.Add(this.button2);
+            this.Controls.Add(this.State);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.button1);
+            this.Font = new System.Drawing.Font("宋体", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
+            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            this.Margin = new System.Windows.Forms.Padding(4);
+            this.MaximizeBox = false;
+            this.Name = "Start";
+            this.Text = "面向Web资源的服务封装系统";
+            this.Load += new System.EventHandler(this.Start_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.Label State;
+        private System.Windows.Forms.Button button2;
+    }
+}

+ 256 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Start.cs

@@ -0,0 +1,256 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using OpenQA.Selenium;
+using OpenQA.Selenium.Chrome;
+using OpenQA.Selenium.Interactions;
+using OpenQA.Selenium.Internal;
+using OpenQA.Selenium.Support;
+using Fleck;
+using Newtonsoft.Json;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Threading;
+
+namespace ServiceWrapper
+{
+    public partial class Start : Form
+    {
+        public static IWebDriver browser;
+        public static IWebSocketConnection socket_start; //输入网址页面的socket
+        public static IWebSocketConnection socket_window; //正式使用的窗口的socket
+        public static IWebSocketConnection socket_flowchart; //流程图的socket
+        public static WebSocketServer server;
+        public static IntPtr chromeId;
+        public static string[] links;
+        public Flow fr;
+        public string serviceListUrl = PublicVariable.frontEndAddress + "/serviceList.html?backEndAddressServiceWrapper=" + PublicVariable.backEndAddress;
+
+        [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "MoveWindow")]
+        public static extern bool MoveWindow(System.IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetForegroundWindow();
+        [System.Runtime.InteropServices.DllImport("user32.dll")]
+        public static extern int SetForegroundWindow(IntPtr hwnd);
+
+        [DllImport("user32", EntryPoint = "GetWindowThreadProcessId")]
+        private static extern int GetWindowThreadProcessId(IntPtr hwnd, out int pid);
+
+        [DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CharSet = CharSet.Auto)]
+        private static extern int SendMessage(IntPtr hwnd, uint wMsg, int wParam, int lParam);
+        [DllImport("user32.dll")]
+        private extern static bool SwapMouseButton(bool fSwap);
+        [DllImport("user32.dll", SetLastError = true)]
+        static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
+
+        [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
+        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
+
+        const int WM_SYSCOMMAND = 0x0112;
+        const int SC_CLOSE = 0xF060;
+        const int SC_MINIMIZE = 0xF020;
+        const int SC_MAXIMIZE = 0xF030;
+        const int SC_RESTORE = 0xF120;
+
+        public Start()
+        {
+            InitializeComponent();
+            PublicVariable.start = this;
+        }
+
+        private void Start_Load(object sender, EventArgs e)
+        {
+            //string title = (string)Scripts().ExecuteScript("return document.title");
+            server = new WebSocketServer("ws://0.0.0.0:8084");
+            server.Start(socke =>
+            {
+                socke.OnOpen = () =>
+                {
+                    BeginInvoke(new ConnectionChange(ModifyState), new object[] { "与浏览器连接已建立,请使用。" });
+                };
+                socke.OnClose = () =>
+                {
+                    //BeginInvoke(new ConnectionChange(ModifyState), new object[] { "与浏览器连接已断开。" });
+                };
+                socke.OnMessage = message =>
+                {
+
+                    Msg msg = JsonConvert.DeserializeObject<Msg>(message);//result为上面的Json数据
+                                                                          //处理连接操作
+                    if (msg.type == 0)//如果是第一次连接操作,设定socket
+                    {
+                        if (msg.message.id == 0)
+                        {
+                            socket_window = socke;
+                            Console.WriteLine("Socket Window Connected.");
+                        }
+                        else if (msg.message.id == 1)
+                        {
+                            socket_start = socke;
+                            Console.WriteLine("Socket Start Connected.");
+                        }
+                        else
+                        {
+                            socket_flowchart = socke;
+                            Console.WriteLine("Socket Flowchart Connected.");
+                            //发送打开网页指令
+                            //FlowMessage fmsg = JsonConvert.DeserializeObject<FlowMessage>("{\"type\":0,\"data\":{\"option\":1,\"parameters\":{\"url\":\"https://www.baidu.com\"}}}");
+                            //fmsg.data.parameters.url = links[0];
+                            //string json = JsonConvert.SerializeObject(fmsg);
+                            //socket_flowchart.Send(json);
+                        }
+                    }
+                    else //其他情况放在进程外处理
+                    {
+                        try
+                        {
+                            BeginInvoke(new GetMessage(HandleEvent), new object[] { message });
+                        }
+                        catch (Exception)
+                        {
+
+                            throw;
+                        }
+                    }
+
+                };
+            });
+            try
+            {
+                SendKeys.Send("+");
+                SendKeys.Send("+"); //测试是否能正常使用输入模块
+            }
+            catch (Exception)
+            {
+                MessageBox.Show("输入模块初始化失败,请退出360之类的安全软件!");
+                Application.Exit();
+            }
+        }
+
+        delegate void ConnectionChange(object input);//委托
+        delegate void GetMessage(object input);
+
+        //正式处理程序入口
+        public void HandleEvent(object input)
+        {
+            
+            Msg msg = JsonConvert.DeserializeObject<Msg>(input.ToString());//result为上面的Json数据
+            if (msg.type == 1) //开始的时候输入网址
+            {
+                chromeId = GetForegroundWindow(); //记录下所在浏览器的进程Id号
+                Console.WriteLine(chromeId);
+                Console.WriteLine();
+                //links = msg.message.links.Split(new string[] { "\n" }, StringSplitOptions.None);
+                //List<string> list = links.ToList();
+                //int l = links.Length;
+                //if (links[l - 1].Length == 0)//如果最后一行是空行则删掉
+                //{
+                //    list.RemoveAt(l - 1);
+                //}
+                //links = list.ToArray();
+                //if (browser != null)
+                //{
+                //    browser.Navigate().GoToUrl(links[0]);
+                //}
+                int width = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size.Width;
+                int height = System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Size.Height;
+                SendMessage(chromeId, WM_SYSCOMMAND, SC_RESTORE, 0); // 最大化
+                MoveWindow(chromeId, 0, Convert.ToInt32(height * PublicVariable.ratio) - 120, width, 120 + Convert.ToInt32(height * (1.0 - PublicVariable.ratio)), true);
+                if(fr!=null)
+                {
+                    if (msg.message.id != -1) //读取服务流程,不是新增的时候
+                    {
+                        fr.chromeBrowser.Load(Flow.flowChartUrl + msg.message.id.ToString() + "&backEndAddressServiceWrapper=" + PublicVariable.backEndAddress);
+                    }
+                    //SwapMouseButton(true);
+                    fr.Show();
+                }
+                Hide();
+                //SwitchToThisWindow(chromeId,true);
+                //ShowWindow(System.UIntPtr(browser.CurrentWindowHandle),2);
+                SetForegroundWindow(Start.chromeId); //打开流程图窗口后将chrome窗口显示到最前方
+                SetForegroundWindow(Handle); //打开流程图窗口后将chrome窗口显示到最前方
+                SetForegroundWindow(Start.chromeId); //打开流程图窗口后将chrome窗口显示到最前方
+                //MouseHelper.SetCursorPos(400, Convert.ToInt32(height * PublicVariable.ratio) - 110);
+                //MouseHelper.mouse_event(MouseHelper.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
+                //Thread.Sleep(50);
+                //MouseHelper.mouse_event(MouseHelper.MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
+            }
+            else if (msg.type == 2)
+            {
+                try
+                {
+                    SendKeys.Send(msg.message.keyboardStr);
+                    SendKeys.Send("+");
+                    SendKeys.Send("+"); //两个shift是为了防止有人按用中文输入法输入了英文按了回车,这样切换两次输入法就可以达到效果
+                }
+                catch (Exception)
+                {
+                    MessageBox.Show("输入失败,请退出360之类的安全软件!");
+                }
+               
+            }
+            else if (msg.type == 3)
+            {
+                if (msg.from == 0)
+                {
+                    socket_flowchart.Send(msg.message.pipe); //直接把消息转接
+                }
+                else
+                {
+                    socket_window.Send(msg.message.pipe);
+                }
+            }
+            else if (msg.type == 5)
+            {
+                string FileName = Application.StartupPath + @"/Chrome/ServiceWrapper_ExcuteStage.exe"; //启动的应用程序名称
+                string arguments = msg.message.id.ToString() + " " + PublicVariable.backEndAddress;
+                Process.Start(FileName, arguments); //启动执行程序
+            }
+        }
+
+        public void ModifyState(object input)
+        {
+            State.Text = (string)input;
+        }
+
+
+        public static IJavaScriptExecutor Scripts()
+        {
+            return (IJavaScriptExecutor)browser;
+        }
+
+        private void button1_Click(object sender, EventArgs e)
+        {
+            fr = new Flow(); //先创造流程图界面,暂时隐藏不显示
+            fr.Show();
+            fr.Hide();
+            State.Text = "加载中……";
+            ChromeOptions options = new ChromeOptions();
+            options.AddExtension(Application.StartupPath + @"/ServiceWrapper.crx");
+            browser = new ChromeDriver(Application.StartupPath +@"/Chrome", options);
+            browser.Navigate().GoToUrl(serviceListUrl); //默认可以修改服务
+            //ProcessStartInfo startInfo = new ProcessStartInfo();
+            //startInfo.FileName = Application.StartupPath + @"/Chrome/chrome.exe"; //启动的应用程序名称
+            //SwapMouseButton(false);//此时此刻的鼠标应该是默认状态
+            //PublicVariable.chrome =  Process.Start(startInfo);
+            //browser.Navigate().GoToUrl("file:///Start.html");
+        }
+
+        private void button2_Click(object sender, EventArgs e)
+        {
+            Flow fr2 = new Flow(serviceListUrl+"&type=1"); //加载的页面不可增加和修改服务
+            fr2.closedriver = false;
+            fr2.WindowState = FormWindowState.Maximized; //最大化窗口
+            fr2.Show();
+            Hide();
+        }
+    }
+}

+ 408 - 0
ServiceWrapperEntry/ServiceWrapperEntry/Start.resx

@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA
+        AAD/////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7//v7+///////+/v7//v7+////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////v7+//7+/v/+/v7/////////
+        /////////////////////////v7+//7+/v//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+///////+/v7//v7+//////////////////7+/v/+/v7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////+/v7//v7+/////////////v7+//7+/v/+/v7////////////+/v7//v7+//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+////
+        /////////v7+//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v//////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//7+/v/+/v7////////////////////////////+/v7/+vr6/5eX
+        l/+YmJj/+vr6//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7/////////////////////////
+        ///9/f3/4uLi/0lJSf8AAAD/AAAA/0lJSf/j4+P//f39////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////9/f3/ubm5/xkZGf8BAQH/AAAA/wAAAP8BAQH/GRkZ/7m5uf/+/v7//v7+////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////9/f3/kpKS/wYGBv8AAAD/AAAA/wAAAP8AAAD/AAAA/wEB
+        Af8GBgb/kpKS//7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////9/f3/hoaG/wICAv8AAAD/AAAA/wAA
+        AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wICAv+FhYX//f39////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/q6ur/wQE
+        BP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC/6ysrP/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7/9PT0/x8fH/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEB
+        Af8dHR3/9fX1////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+/7W1tf8AAAD/AAAA/wICAv8aGhr/AwMD/wAAAP8AAAD/AAAA/wAA
+        AP8EBAT/Ghoa/wICAv8AAAD/AAAA/7a2tv//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v+RkZH/AAAA/wAAAP8gICD/+/v7/9fX
+        1/9UVFT/AgIC/wICAv9VVVX/2NjY//v7+/8fHx//AAAA/wAAAP+SkpL/////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/mpqa/wAA
+        AP8AAAD/Nzc3//7+/v/+/v7/ysrK/8TExP/Dw8P/ycnJ//7+/v/9/f3/ODg4/wAAAP8AAAD/mpqa////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+/8PDw/8AAAD/AAAA/zU1Nf/+/v7//v7+/83Nzf+Wlpb/lpaW/87Ozv/+/v7//f39/zU1
+        Nf8AAAD/AAAA/8PDw///////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////7+/v/19fX/EBAQ/wAAAP8YGBj/4uLi/6mpqf8tLS3/AgIC/wEB
+        Af8tLS3/qqqq/+Hh4f8YGBj/AAAA/xAQEP/19fX/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////v7+//7+/v/+/v7//v7+/1lZWf8AAAD/AQEB/wMD
+        A/8DAwP/Li4u/2xsbP9vb2//NDQ0/wICAv8DAwP/AAAA/wAAAP9ZWVn//f39////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/////////
+        //+0tLT/AAAA/wAAAP8JCQn/np6e/+/v7/+1tbX/srKy/+7u7v+qqqr/DAwM/wAAAP8BAQH/tLS0////
+        //////////////7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+////////////+Pj4/x4eHv8CAgL/mJiY/8XFxf8fHx//AQEB/wAAAP8aGhr/vr6+/6Wl
+        pf8BAQH/HR0d//j4+P/////////////////+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v99fX3/LS0t/+bm5v8YGBj/AAAA/wAA
+        AP8AAAD/AAAA/xQUFP/j4+P/MjIy/319ff/9/f3/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/3t7e/4GB
+        gf+BgYH/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/enp6/4WFhf/e3t7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////39/f/n5+f/MzMz/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/zIyMv/o6Oj//f39////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+////
+        ///////////////////////////////////+/v7/7+/v/wcHB/8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA
+        AP8HBwf/8fHx//7+/v//////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v///////////////////////////////////////f39/9jY2P+IiIj/fX19/zEx
+        Mf8ICAj/CAgI/y4uLv99fX3/iIiI/9nZ2f/+/v7/////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////Hx
+        8f9mZmb/KSkp/zY2Nv+ioqL/QUFB/z09Pf+kpKT/PDw8/ygoKP9oaGj/8fHx//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+//7+/v+CgoL/BwcH/wcHB/8BAQH/DQ0N/7Gxsf+rq6v/Dg4O/wEBAf8GBgb/BwcH/4OD
+        g//9/f3//v7+////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+//7+/v/+/v7//v7+//j4+P/29vb/LCws/wcHB/8HBwf/AAAA/wMDA/9lZWX/Y2Nj/wAA
+        AP8AAAD/BgYG/wcHB/8sLCz/9fX1//f39//+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//Pz8//X19f/vr6+/4iIiP8yMjL/srKy/wEBAf8GBgb/BAQE/wEB
+        Af8nJyf/aGho/2FhYf8lJSX/AQEB/wcHB/8HBwf/AQEB/7Kysv80NDT/iIiI/729vf/X19f/8vLy//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////6Ojo/1RUVP8FBQX/AAAA/wAAAP8AAAD/AgIC/6Cg
+        oP/V1dX/rq6u/62trf+rq6v/ioqK/05OTv9QUFD/kJCQ/7CwsP+pqan/rq6u/9XV1f+fn5//AwMD/wAA
+        AP8AAAD/AAAA/wYGBv9UVFT/6enp//7+/v//////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////+vr6/z8/P/8BAQH/AAAA/wAA
+        AP8AAAD/AAAA/wcHB/+vr6//+fn5/xQUFP8ICAj/CAgI/wcHB/8JCQn/CAgI/wcHB/8HBwf/CAgI/xQU
+        FP/4+Pj/sLCw/wYGBv8AAAD/AAAA/wAAAP8AAAD/AAAA/0BAQP/6+vr/////////////////////////
+        /////////////////////////v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+/6am
+        pv8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAf+Li4v//v7+//z8/P++vr7/v7+//4ODg/95eXn/2NjY/9LS
+        0v9ycnL/eXl5/8DAwP+9vb3//Pz8//39/f+Li4v/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/p6en//7+
+        /v////////////////////////////////////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+
+        /v//////////////////////////////////////////////////////////////////////////////
+        /////////v7+//z8/P86Ojr/AAAA/wAAAP8AAAD/AAAA/wEBAf9QUFD/+/v7//7+/v/q6ur/GBgY/wkJ
+        Cf+ampr//f39//7+/v/+/v7//f39/5mZmf8ICAj/GBgY/+vr6//+/v7/+vr6/09PT/8BAQH/AAAA/wAA
+        AP8AAAD/AAAA/zo6Ov/8/Pz/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////7+/v/c3Nz/BQUF/wAAAP8AAAD/AAAA/wgICP9nZ2f/8vLy//7+
+        /v/+/v7/pqam/wAAAP8BAQH/m5ub//7+/v////////////////+ampr/AAAA/wEBAf+mpqb//v7+//7+
+        /v/y8vL/Z2dn/wgICP8BAQH/AAAA/wAAAP8EBAT/3Nzc////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7/+fn5/93d3f/Gxsb/vLy8/8nJ
+        yf/v7+///f39//7+/v///////f39/0RERP8AAAD/AgIC/+Dg4P//////////////////////39/f/wEB
+        Af8AAAD/Q0ND//39/f/+/v7//v7+//39/f/v7+//ycnJ/729vf/Gxsb/3Nzc//n5+f//////////////
+        /////////////////////////////////////////////////////////v7+//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+/7y8vP8BAQH/AAAA/zMzM//9/f3/////////
+        //////////////39/f80NDT/AAAA/wICAv+8vLz//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7//v7+/+jo6P8lJSX/AAAA/wEB
+        Af+Dg4P//v7+///////////////////////+/v7/g4OD/wEBAf8AAAD/JCQk/+rq6v/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//f39/+np
+        6f89PT3/AAAA/wAAAP8AAAD/y8vL//7+/v///////////////////////////8vLy/8AAAD/AAAA/wAA
+        AP86Ojr/6enp////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//f39/8jIyP8oKCj/AAAA/wEBAf8sLCz/DQ0N//j4+P/+/v7//v7+//7+/v//////////////
+        ///39/f/Dg4O/ywsLP8CAgL/AAAA/ykpKf/IyMj//v7+//7+/v////////////7+/v/+/v7/////////
+        //////////////////////////////////////////////////////////////7+/v/+/v7/////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/9/f3/5+fn/29vb/8HBwf/AAAA/wEBAf9NTU3/2NjY/ysrK//+/v7///////7+
+        /v/+/v7//////////////////f39/ysrK//Y2Nj/TU1N/wEBAf8AAAD/BgYG/25ubv/o6Oj//f39//7+
+        /v/+/v7//v7+/////////////v7+//7+/v/+/v7//v7+/////////////v7+//7+/v/+/v7/////////
+        ///+/v7//v7+//7+/v//////////////////////////////////////////////////////////////
+        //////////////////////////////39/f/q6ur/fHx8/xAQEP8BAQH/AgIC/xISEv8qKir/9vb2//T0
+        9P86Ojr//v7+///////+/v7//v7+//////////////////39/f85OTn/8/Pz//X19f8qKir/ExMT/wEB
+        Af8AAAD/EBAQ/3x8fP/q6ur//v7+//7+/v////////////7+/v/+/v7//v7+//7+/v////////////7+
+        /v/+/v7//v7+//////////////////7+/v/+/v7/////////////////////////////////////////
+        ///////////////////////////////////+/v7//f39//Ly8v+CgoL/EhIS/wICAv8BAQH/CAgI/62t
+        rf+rq6v/cXFx//7+/v/9/f3/QUFB//39/f/+/v7////////////////////////////9/f3/QUFB//39
+        /f/+/v7/cXFx/6urq/+tra3/CAgI/wEBAf8CAgL/ExMT/4KCgv/x8fH//f39////////////////////
+        ///////////////////+/v7//v7+//7+/v//////////////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//f39/7S0tP8iIiL/AQEB/y4u
+        Lv9mZmb/AgIC/2ZmZv/9/f3/3t7e/7a2tv/+/v7//f39/4uLi//8/Pz//v7+////////////////////
+        /////////Pz8/4uLi//9/f3//v7+/7e3t//e3t7//f39/2ZmZv8CAgL/ZmZm/y4uLv8CAgL/IiIi/7Oz
+        s//9/f3//v7+//7+/v///////////////////////v7+//7+/v/+/v7/////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7/+vr6/3t7
+        e/8FBQX/ExMT/6Kiov/5+fn/ZWVl/wQEBP/U1NT//v7+//7+/v/+/v7//v7+//7+/v/9/f3//f39////
+        //////////////////////////////7+/v/9/f3//v7+//7+/v/+/v7//v7+///////U1NT/BAQE/2Vl
+        Zf/5+fn/oqKi/xISEv8FBQX/enp6//r6+v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7/+/v7/2xsbP8CAgL/BQUF/8HBwf/9/f3/9/f3/xYWFv83Nzf//f39////////////////////
+        ///+/v7//v7+////////////////////////////////////////////////////////////////////
+        /////////Pz8/zg4OP8YGBj/+Pj4//7+/v/BwcH/BwcH/wMDA/9sbGz//Pz8//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////f39/5WVlf8RERH/YWFh/1JSUv/+/v7//v7+/9LS0v8BAQH/fn5+//39
+        /f//////////////////////////////////////////////////////////////////////////////
+        //////////////////////////////////9+fn7/AgIC/9LS0v///////v7+/1NTU/9iYmL/ExMT/5SU
+        lP/9/f3///////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+/////////////////////////////////9/f3/8VFRX/vLy8/5aWlv+Ojo7//v7+//7+
+        /v+qqqr/AQEB/6qqqv/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////qamp/wEBAf+rq6v///////7+
+        /v+Ojo7/lpaW/7y8vP8WFhb/39/f//39/f//////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v////////////////////////////39/f9oaGj/dnZ2//z8
+        /P+cnJz/n5+f////////////lZWV/wAAAP+4uLj/////////////////////////////////////////
+        /////////////////////////////////////////////////////////////////////////////7e3
+        t/8AAAD/lpaW///////+/v7/n5+f/5ycnP/9/f3/dnZ2/2hoaP/9/f3/////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7/////////////////////////
+        ///9/f3/Xl5e/+rq6v/+/v7/sbGx/5eXl////////////5OTk/8BAQH/oKCg//39/f//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////////+hoaH/AQEB/5OTk//+/v7//v7+/5aWlv+wsLD//v7+/+np6f9eXl7//f39////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v//////////////
+        /////////////////////////v7+//39/f/9/f3//v7+/+3t7f/Z2dn///////////+enp7/Hh4e/11d
+        Xf/9/f3///////7+/v/+/v7//v7+////////////////////////////////////////////////////
+        ///////////////////////////////////9/f3/XV1d/x4eHv+fn5///v7+//7+/v/Z2dn/7e3t//7+
+        /v/+/v7//f39//7+/v///////////////////////////////////////////////////////v7+//7+
+        /v/+/v7//v7+//7+/v/+/v7////////////////////////////////////////////+/v7//v7+////
+        ////////t7e3/3R0dP9LS0v/0dHR//7+/v/+/v7//v7+//7+/v//////////////////////////////
+        //////////////////////////////////////////////7+/v/+/v7/0dHR/0tLS/9zc3P/t7e3////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        /////////////////////////////9ra2v9ra2v/5+fn/1RUVP/c3Nz//v7+////////////////////
+        //////////////////////////////////////////////////////////////7+/v/9/f3/3Nzc/1RU
+        VP/o6Oj/a2tr/9ra2v//////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+////////////////////
+        ///////////////////////////////////////////////////4+Pj/XV1d//z8/P/r6+v/bGxs/9HR
+        0f//////////////////////////////////////////////////////////////////////////////
+        ///+/v7/0dHR/2tra//r6+v//f39/1xcXP/4+Pj/////////////////////////////////////////
+        ///////////////////////////////////////////////////////////////////+/v7//v7+//7+
+        /v///////////////////////////////////////////////////////////////////////v7+/19f
+        X//8/Pz///////7+/v/8/Pz/////////////////////////////////////////////////////////
+        /////////////////////////v7+//z8/P/8/Pz//v7+//v7+/9gYGD//f39////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7///////////////////////////////////////7+/v/+/v7//v7+////
+        //////////////7+/v+4uLj/+fn5///////+/v7//v7+////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v/5+fn/t7e3//39
+        /f//////////////////////////////////////////////////////////////////////////////
+        /////////////////////////////////////////////////////////v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7//v7+//7+/v/////////////////+/v7//v7+//7+/v//////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7/////////////////////////////////////////////////////////
+        //////////////////////////////////////////////////////////////////////////////7+
+        /v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v//////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////////////////////+/v7//v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7/////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////v7+//7+/v/+/v7/////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        //////////////7+/v/+/v7//v7+//7+/v/+/v7//v7+////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ///+/v7//v7+////////////////////////////////////////////////////////////////////
+        ///////////////////////////////////+/v7//v7+//7+/v/+/v7/////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        ////////////////////////////////////////////////////////////////////////////////
+        /////////////////////////v7+//7+/v//////////////////////////////////////////////
+        ////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+</value>
+  </data>
+</root>

+ 2 - 0
ServiceWrapperEntry/ServiceWrapperEntry/bin/x64/Debug/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

BIN
ServiceWrapperEntry/ServiceWrapperEntry/favicon.ico


+ 10 - 0
ServiceWrapperEntry/ServiceWrapperEntry/packages.config

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="cef.redist.x64" version="79.1.35" targetFramework="net472" />
+  <package id="cef.redist.x86" version="79.1.35" targetFramework="net472" />
+  <package id="CefSharp.Common" version="79.1.350" targetFramework="net472" />
+  <package id="CefSharp.WinForms" version="79.1.350" targetFramework="net472" />
+  <package id="Fleck" version="1.1.0" targetFramework="net472" />
+  <package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
+  <package id="Selenium.WebDriver" version="3.141.0" targetFramework="net472" />
+</packages>

BIN
media/Picture.png


BIN
media/Picture1.png


BIN
media/Picture10.png


BIN
media/Picture11.png


BIN
media/Picture12.png


BIN
media/Picture13.png


BIN
media/Picture14.png


BIN
media/Picture15.png


BIN
media/Picture16.png


BIN
media/Picture17.png


BIN
media/Picture18.png


BIN
media/Picture2.png


BIN
media/Picture4.png


BIN
media/Picture5.png


BIN
media/Picture6.png


BIN
media/Picture7.png


BIN
media/Picture8.png


BIN
media/Picture9.png


BIN
media/Picture90.png


BIN
media/Picture91.png