Selaa lähdekoodia

Merge branch 'feature_调研宝0324' of zhangs/surveyMaker into develop

wangs 5 vuotta sitten
vanhempi
commit
59aab5fa98

+ 417 - 11
package-lock.json

@@ -4,6 +4,182 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@antv/adjust": {
+      "version": "0.2.2",
+      "resolved": "http://r.cnpmjs.org/@antv/adjust/download/@antv/adjust-0.2.2.tgz",
+      "integrity": "sha1-Vp/5NyE9FKgDsX8FTL4dsGgFxQg=",
+      "requires": {
+        "@antv/util": "~2.0.0",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/attr": {
+      "version": "0.3.2",
+      "resolved": "http://r.cnpmjs.org/@antv/attr/download/@antv/attr-0.3.2.tgz",
+      "integrity": "sha1-5YZrZIcMYvOpwluKYfZUuiv9oFE=",
+      "requires": {
+        "@antv/color-util": "^2.0.1",
+        "@antv/util": "~2.0.0",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/color-util": {
+      "version": "2.0.4",
+      "resolved": "http://r.cnpmjs.org/@antv/color-util/download/@antv/color-util-2.0.4.tgz",
+      "integrity": "sha1-Q+JlA8zZRV0sFCdYxwGLI0sxw+o=",
+      "requires": {
+        "@antv/util": "^2.0.7",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/component": {
+      "version": "0.5.6",
+      "resolved": "http://r.cnpmjs.org/@antv/component/download/@antv/component-0.5.6.tgz",
+      "integrity": "sha1-UMJt2N5NBCSRIIuYlXclS036e1o=",
+      "requires": {
+        "@antv/dom-util": "~2.0.1",
+        "@antv/g-base": "~0.4.0",
+        "@antv/matrix-util": "~2.0.4",
+        "@antv/path-util": "~2.0.7",
+        "@antv/scale": "~0.3.1",
+        "@antv/util": "~2.0.0",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/coord": {
+      "version": "0.2.6",
+      "resolved": "http://r.cnpmjs.org/@antv/coord/download/@antv/coord-0.2.6.tgz",
+      "integrity": "sha1-qrux0y4PQEtjlUZQ0hGmk7cPEQM=",
+      "requires": {
+        "@antv/matrix-util": "~2.0.1-beta.1",
+        "@antv/util": "~2.0.3",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/dom-util": {
+      "version": "2.0.2",
+      "resolved": "http://r.cnpmjs.org/@antv/dom-util/download/@antv/dom-util-2.0.2.tgz",
+      "integrity": "sha1-THsKGV4CflVXBDWmglzsVt+wtZA=",
+      "requires": {
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/event-emitter": {
+      "version": "0.1.2",
+      "resolved": "http://r.cnpmjs.org/@antv/event-emitter/download/@antv/event-emitter-0.1.2.tgz",
+      "integrity": "sha1-oXt8uG5tBxiA3Gv7IydW+IYk7Lw="
+    },
+    "@antv/g-base": {
+      "version": "0.4.0",
+      "resolved": "http://r.cnpmjs.org/@antv/g-base/download/@antv/g-base-0.4.0.tgz",
+      "integrity": "sha1-n9hc6rMnotwYSsEuzT+rFCKzph8=",
+      "requires": {
+        "@antv/event-emitter": "^0.1.1",
+        "@antv/g-math": "^0.1.1",
+        "@antv/matrix-util": "^2.0.4",
+        "@antv/path-util": "~2.0.5",
+        "@antv/util": "~2.0.0",
+        "@types/d3-timer": "^1.0.9",
+        "d3-ease": "^1.0.5",
+        "d3-interpolate": "^1.3.2",
+        "d3-timer": "^1.0.9"
+      }
+    },
+    "@antv/g-canvas": {
+      "version": "0.4.2",
+      "resolved": "http://r.cnpmjs.org/@antv/g-canvas/download/@antv/g-canvas-0.4.2.tgz",
+      "integrity": "sha1-OGUjVsKp0SYOdggjD4EgkjRSaNU=",
+      "requires": {
+        "@antv/g-base": "^0.4.0",
+        "@antv/g-math": "^0.1.1",
+        "@antv/gl-matrix": "~2.7.1",
+        "@antv/path-util": "~2.0.5",
+        "@antv/util": "~2.0.0"
+      }
+    },
+    "@antv/g-math": {
+      "version": "0.1.1",
+      "resolved": "http://r.cnpmjs.org/@antv/g-math/download/@antv/g-math-0.1.1.tgz",
+      "integrity": "sha1-OgDsYHs0xMXeK4rSUGmyXB9ZYmo=",
+      "requires": {
+        "@antv/gl-matrix": "~2.7.1",
+        "@antv/util": "~2.0.0"
+      }
+    },
+    "@antv/g-svg": {
+      "version": "0.4.0",
+      "resolved": "http://r.cnpmjs.org/@antv/g-svg/download/@antv/g-svg-0.4.0.tgz",
+      "integrity": "sha1-Pf0TQjp6FiwTfAvb6ekxclJr3i8=",
+      "requires": {
+        "@antv/g-base": "^0.4.0",
+        "@antv/g-math": "^0.1.1",
+        "@antv/util": "~2.0.0",
+        "detect-browser": "^4.6.0"
+      }
+    },
+    "@antv/g2": {
+      "version": "4.0.5",
+      "resolved": "http://r.cnpmjs.org/@antv/g2/download/@antv/g2-4.0.5.tgz",
+      "integrity": "sha1-m7UpZQ6CNmw8/oISe0tNXh/MUu8=",
+      "requires": {
+        "@antv/adjust": "^0.2.1",
+        "@antv/attr": "^0.3.1",
+        "@antv/color-util": "^2.0.2",
+        "@antv/component": "^0.5.0",
+        "@antv/coord": "^0.2.6",
+        "@antv/event-emitter": "~0.1.0",
+        "@antv/g-base": "^0.4.0",
+        "@antv/g-canvas": "^0.4.0",
+        "@antv/g-svg": "^0.4.0",
+        "@antv/matrix-util": "^2.0.4",
+        "@antv/path-util": "^2.0.3",
+        "@antv/scale": "^0.3.1",
+        "@antv/util": "~2.0.5",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/gl-matrix": {
+      "version": "2.7.1",
+      "resolved": "http://r.cnpmjs.org/@antv/gl-matrix/download/@antv/gl-matrix-2.7.1.tgz",
+      "integrity": "sha1-rLjjf3qz3wE0WrpDcteUK+QuuhQ="
+    },
+    "@antv/matrix-util": {
+      "version": "2.0.5",
+      "resolved": "http://r.cnpmjs.org/@antv/matrix-util/download/@antv/matrix-util-2.0.5.tgz",
+      "integrity": "sha1-b8hRlWyngQo4B3j0hbC/4vc4eBs=",
+      "requires": {
+        "@antv/gl-matrix": "^2.7.1",
+        "@antv/util": "^2.0.7",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/path-util": {
+      "version": "2.0.7",
+      "resolved": "http://r.cnpmjs.org/@antv/path-util/download/@antv/path-util-2.0.7.tgz",
+      "integrity": "sha1-eacCyeadU+8JqEjJAbi+klspb9I=",
+      "requires": {
+        "@antv/util": "^2.0.7",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/scale": {
+      "version": "0.3.1",
+      "resolved": "http://r.cnpmjs.org/@antv/scale/download/@antv/scale-0.3.1.tgz",
+      "integrity": "sha1-8QiFgnXKjCfXrz6zdXq3PyY2KZw=",
+      "requires": {
+        "@antv/util": "~2.0.3",
+        "fecha": "~3.0.3",
+        "tslib": "^1.10.0"
+      }
+    },
+    "@antv/util": {
+      "version": "2.0.7",
+      "resolved": "http://r.cnpmjs.org/@antv/util/download/@antv/util-2.0.7.tgz",
+      "integrity": "sha1-uWRmvKfUFDwg3OSFOWzZe1+rchQ=",
+      "requires": {
+        "tslib": "^1.10.0"
+      }
+    },
     "@gulp-sourcemaps/map-sources": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz",
@@ -60,6 +236,11 @@
         "commander": "*"
       }
     },
+    "@types/d3-timer": {
+      "version": "1.0.9",
+      "resolved": "http://r.cnpmjs.org/@types/d3-timer/download/@types/d3-timer-1.0.9.tgz",
+      "integrity": "sha1-rtG94M8Ykg0z9dRIOdc945NjP9M="
+    },
     "@types/node": {
       "version": "10.9.4",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-10.9.4.tgz",
@@ -85,6 +266,11 @@
         "through": ">=2.2.7 <3"
       }
     },
+    "abab": {
+      "version": "1.0.4",
+      "resolved": "http://r.cnpmjs.org/abab/download/abab-1.0.4.tgz",
+      "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4="
+    },
     "abbrev": {
       "version": "1.0.9",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
@@ -113,6 +299,21 @@
         "acorn": "^5.0.0"
       }
     },
+    "acorn-globals": {
+      "version": "1.0.9",
+      "resolved": "http://r.cnpmjs.org/acorn-globals/download/acorn-globals-1.0.9.tgz",
+      "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=",
+      "requires": {
+        "acorn": "^2.1.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "2.7.0",
+          "resolved": "http://r.cnpmjs.org/acorn/download/acorn-2.7.0.tgz",
+          "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc="
+        }
+      }
+    },
     "acorn-jsx": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
@@ -331,6 +532,11 @@
       "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
       "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
     },
+    "array-equal": {
+      "version": "1.0.0",
+      "resolved": "http://r.cnpmjs.org/array-equal/download/array-equal-1.0.0.tgz",
+      "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
+    },
     "array-find-index": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -1569,6 +1775,7 @@
       "version": "2.10.1",
       "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
       "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
+      "optional": true,
       "requires": {
         "hoek": "2.x.x"
       }
@@ -1996,6 +2203,24 @@
       "integrity": "sha512-7uo4mQgSWK9lmGKpuXhW1HYfOOF3le+coG/h0Op/AAEvjOuVO9mQQo4EW2WrtOZgxgnLIxVVr57aKT8G5woFoQ==",
       "dev": true
     },
+    "canvg": {
+      "version": "1.5.3",
+      "resolved": "http://r.cnpmjs.org/canvg/download/canvg-1.5.3.tgz",
+      "integrity": "sha1-qtF5FfMzaL+OuAsl0SnjrpIt3F8=",
+      "requires": {
+        "jsdom": "^8.1.0",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^1.4.1",
+        "xmldom": "^0.1.22"
+      },
+      "dependencies": {
+        "stackblur-canvas": {
+          "version": "1.4.1",
+          "resolved": "http://r.cnpmjs.org/stackblur-canvas/download/stackblur-canvas-1.4.1.tgz",
+          "integrity": "sha1-hJqm+UsnL/JvZHH6QTDtH35HlVs="
+        }
+      }
+    },
     "caseless": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -2805,11 +3030,18 @@
       "dev": true
     },
     "css-line-break": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.0.1.tgz",
-      "integrity": "sha1-GfIGOjPpX7KDG4ZEbAuAwYivRQo=",
+      "version": "1.1.1",
+      "resolved": "http://r.cnpmjs.org/css-line-break/download/css-line-break-1.1.1.tgz",
+      "integrity": "sha1-1em90peEAJnrBQPHMQ/TSSegJu8=",
       "requires": {
-        "base64-arraybuffer": "^0.1.5"
+        "base64-arraybuffer": "^0.2.0"
+      },
+      "dependencies": {
+        "base64-arraybuffer": {
+          "version": "0.2.0",
+          "resolved": "http://r.cnpmjs.org/base64-arraybuffer/download/base64-arraybuffer-0.2.0.tgz",
+          "integrity": "sha1-S5RPrAGRqlkHr+LYyZnMxXzoD0U="
+        }
       }
     },
     "css-loader": {
@@ -2949,6 +3181,19 @@
         }
       }
     },
+    "cssom": {
+      "version": "0.3.8",
+      "resolved": "http://r.cnpmjs.org/cssom/download/cssom-0.3.8.tgz",
+      "integrity": "sha1-nxJ29bK0Y/IRTT8sdSUK+MGjb0o="
+    },
+    "cssstyle": {
+      "version": "0.2.37",
+      "resolved": "http://r.cnpmjs.org/cssstyle/download/cssstyle-0.2.37.tgz",
+      "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
+      "requires": {
+        "cssom": "0.3.x"
+      }
+    },
     "currently-unhandled": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -2972,6 +3217,29 @@
         "es5-ext": "^0.10.9"
       }
     },
+    "d3-color": {
+      "version": "1.4.0",
+      "resolved": "http://r.cnpmjs.org/d3-color/download/d3-color-1.4.0.tgz",
+      "integrity": "sha1-icRamV7Xc7EzFPBkYN8m1gug7K8="
+    },
+    "d3-ease": {
+      "version": "1.0.6",
+      "resolved": "http://r.cnpmjs.org/d3-ease/download/d3-ease-1.0.6.tgz",
+      "integrity": "sha1-69ttoi36wKIiIvLU2gb2bEFqDsA="
+    },
+    "d3-interpolate": {
+      "version": "1.4.0",
+      "resolved": "http://r.cnpmjs.org/d3-interpolate/download/d3-interpolate-1.4.0.tgz",
+      "integrity": "sha1-Um554tgNqjg/ngwcHH3MDwWD6Yc=",
+      "requires": {
+        "d3-color": "1"
+      }
+    },
+    "d3-timer": {
+      "version": "1.0.10",
+      "resolved": "http://r.cnpmjs.org/d3-timer/download/d3-timer-1.0.10.tgz",
+      "integrity": "sha1-3+dripF0iDGxO22ceT/71QjdneU="
+    },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -3181,6 +3449,11 @@
       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
     },
+    "detect-browser": {
+      "version": "4.8.0",
+      "resolved": "http://r.cnpmjs.org/detect-browser/download/detect-browser-4.8.0.tgz",
+      "integrity": "sha1-HXO9iMF76GaQGVDOCqrh7QYJAsY="
+    },
     "detect-indent": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
@@ -4365,6 +4638,11 @@
         "pend": "~1.2.0"
       }
     },
+    "fecha": {
+      "version": "3.0.3",
+      "resolved": "http://r.cnpmjs.org/fecha/download/fecha-3.0.3.tgz",
+      "integrity": "sha1-+rvUFkl2SaQsJNNL+nJrV5IDoeI="
+    },
     "figures": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
@@ -4394,6 +4672,10 @@
         "loader-utils": "~0.2.5"
       }
     },
+    "file-saver": {
+      "version": "github:eligrey/FileSaver.js#e865e37af9f9947ddcced76b549e27dc45c1cb2e",
+      "from": "github:eligrey/FileSaver.js#1.3.8"
+    },
     "file-type": {
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
@@ -6021,11 +6303,11 @@
       }
     },
     "html2canvas": {
-      "version": "1.0.0-alpha.12",
-      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-alpha.12.tgz",
-      "integrity": "sha1-OxmS48mz9WBjw1/WIElPN+uohRM=",
+      "version": "1.0.0-rc.5",
+      "resolved": "http://r.cnpmjs.org/html2canvas/download/html2canvas-1.0.0-rc.5.tgz",
+      "integrity": "sha1-TuPKyfbiCg+gwvNab5nJYK5+xME=",
       "requires": {
-        "css-line-break": "1.0.1"
+        "css-line-break": "1.1.1"
       }
     },
     "htmlescape": {
@@ -6846,6 +7128,42 @@
       "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
       "optional": true
     },
+    "jsdom": {
+      "version": "8.5.0",
+      "resolved": "http://r.cnpmjs.org/jsdom/download/jsdom-8.5.0.tgz",
+      "integrity": "sha1-1Nj12/J2hjW2KmKCO5R89wcevJg=",
+      "requires": {
+        "abab": "^1.0.0",
+        "acorn": "^2.4.0",
+        "acorn-globals": "^1.0.4",
+        "array-equal": "^1.0.0",
+        "cssom": ">= 0.3.0 < 0.4.0",
+        "cssstyle": ">= 0.2.34 < 0.3.0",
+        "escodegen": "^1.6.1",
+        "iconv-lite": "^0.4.13",
+        "nwmatcher": ">= 1.3.7 < 2.0.0",
+        "parse5": "^1.5.1",
+        "request": "^2.55.0",
+        "sax": "^1.1.4",
+        "symbol-tree": ">= 3.1.0 < 4.0.0",
+        "tough-cookie": "^2.2.0",
+        "webidl-conversions": "^3.0.1",
+        "whatwg-url": "^2.0.1",
+        "xml-name-validator": ">= 2.0.1 < 3.0.0"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "2.7.0",
+          "resolved": "http://r.cnpmjs.org/acorn/download/acorn-2.7.0.tgz",
+          "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc="
+        },
+        "parse5": {
+          "version": "1.5.1",
+          "resolved": "http://r.cnpmjs.org/parse5/download/parse5-1.5.1.tgz",
+          "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ="
+        }
+      }
+    },
     "jsesc": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
@@ -6941,6 +7259,42 @@
       "resolved": "https://registry.npmjs.org/jspack/-/jspack-0.0.4.tgz",
       "integrity": "sha1-Mt01x/3LPjRWwY+7fvntC8YjgXc="
     },
+    "jspdf": {
+      "version": "1.5.3",
+      "resolved": "http://r.cnpmjs.org/jspdf/download/jspdf-1.5.3.tgz",
+      "integrity": "sha1-WhLAEUed76vvVzXeVckTBg7SGfI=",
+      "requires": {
+        "canvg": "1.5.3",
+        "file-saver": "github:eligrey/FileSaver.js#1.3.8",
+        "html2canvas": "1.0.0-alpha.12",
+        "omggif": "1.0.7",
+        "promise-polyfill": "8.1.0",
+        "stackblur-canvas": "2.2.0"
+      },
+      "dependencies": {
+        "css-line-break": {
+          "version": "1.0.1",
+          "resolved": "http://r.cnpmjs.org/css-line-break/download/css-line-break-1.0.1.tgz",
+          "integrity": "sha1-GfIGOjPpX7KDG4ZEbAuAwYivRQo=",
+          "requires": {
+            "base64-arraybuffer": "^0.1.5"
+          }
+        },
+        "html2canvas": {
+          "version": "1.0.0-alpha.12",
+          "resolved": "http://r.cnpmjs.org/html2canvas/download/html2canvas-1.0.0-alpha.12.tgz",
+          "integrity": "sha1-OxmS48mz9WBjw1/WIElPN+uohRM=",
+          "requires": {
+            "css-line-break": "1.0.1"
+          }
+        },
+        "promise-polyfill": {
+          "version": "8.1.0",
+          "resolved": "http://r.cnpmjs.org/promise-polyfill/download/promise-polyfill-8.1.0.tgz",
+          "integrity": "sha1-MAWdpU0TWM6QWsWB8ofhhK7fmV0="
+        }
+      }
+    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -9160,6 +9514,11 @@
       "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
     },
+    "nwmatcher": {
+      "version": "1.4.4",
+      "resolved": "http://r.cnpmjs.org/nwmatcher/download/nwmatcher-1.4.4.tgz",
+      "integrity": "sha1-IoVjHzSpXw0Dlc2QDJbtObWPNG4="
+    },
     "oauth-sign": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
@@ -9192,6 +9551,11 @@
         "is-extendable": "^0.1.1"
       }
     },
+    "omggif": {
+      "version": "1.0.7",
+      "resolved": "http://r.cnpmjs.org/omggif/download/omggif-1.0.7.tgz",
+      "integrity": "sha1-WdLuywJj3oRjWz/riHwMmXPx5J0="
+    },
     "on-finished": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
@@ -11108,6 +11472,11 @@
         "onetime": "^1.0.0"
       }
     },
+    "rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "http://r.cnpmjs.org/rgbcolor/download/rgbcolor-1.0.1.tgz",
+      "integrity": "sha1-1lBezbMEplldom+ktDMHMGd1lF0="
+    },
     "right-align": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
@@ -11313,8 +11682,7 @@
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
-      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-      "dev": true
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
     },
     "scss-tokenizer": {
       "version": "0.2.3",
@@ -11868,6 +12236,11 @@
         }
       }
     },
+    "stackblur-canvas": {
+      "version": "2.2.0",
+      "resolved": "http://r.cnpmjs.org/stackblur-canvas/download/stackblur-canvas-2.2.0.tgz",
+      "integrity": "sha1-ysxZJKB0Sz4YPrLmwdhVnBoXwm4="
+    },
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
@@ -12163,6 +12536,11 @@
         }
       }
     },
+    "symbol-tree": {
+      "version": "3.2.4",
+      "resolved": "http://r.cnpmjs.org/symbol-tree/download/symbol-tree-3.2.4.tgz",
+      "integrity": "sha1-QwY30ki6d+B4iDlR+5qg7tfGP6I="
+    },
     "syntax-error": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
@@ -12430,11 +12808,15 @@
       "version": "2.3.4",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
       "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
-      "optional": true,
       "requires": {
         "punycode": "^1.4.1"
       }
     },
+    "tr46": {
+      "version": "0.0.3",
+      "resolved": "http://r.cnpmjs.org/tr46/download/tr46-0.0.3.tgz",
+      "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+    },
     "trim-newlines": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@@ -12480,6 +12862,11 @@
         }
       }
     },
+    "tslib": {
+      "version": "1.11.1",
+      "resolved": "http://r.cnpmjs.org/tslib/download/tslib-1.11.1.tgz",
+      "integrity": "sha1-6xXRKIJ/vuKEFUnhcfRe0zisfjU="
+    },
     "tty-browserify": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
@@ -13207,6 +13594,11 @@
         "argparse": "^1.0.6"
       }
     },
+    "webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "http://r.cnpmjs.org/webidl-conversions/download/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+    },
     "webpack": {
       "version": "1.15.0",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.15.0.tgz",
@@ -13423,6 +13815,15 @@
         }
       }
     },
+    "whatwg-url": {
+      "version": "2.0.1",
+      "resolved": "http://r.cnpmjs.org/whatwg-url/download/whatwg-url-2.0.1.tgz",
+      "integrity": "sha1-U5ayBD8CDub3BNnEXqhRnnJN5lk=",
+      "requires": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
     "whet.extend": {
       "version": "0.9.9",
       "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
@@ -13510,6 +13911,11 @@
       "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=",
       "dev": true
     },
+    "xml-name-validator": {
+      "version": "2.0.1",
+      "resolved": "http://r.cnpmjs.org/xml-name-validator/download/xml-name-validator-2.0.1.tgz",
+      "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU="
+    },
     "xmldom": {
       "version": "0.1.27",
       "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",

+ 3 - 1
package.json

@@ -12,6 +12,7 @@
     "uat": "cross-env NODE_ENV=uat node build/build.js"
   },
   "dependencies": {
+    "@antv/g2": "^4.0.5",
     "acorn": "^5.1.1",
     "animate.css": "^3.5.2",
     "art-template": "^3.0.3",
@@ -36,12 +37,13 @@
     "formidable": "^1.2.1",
     "github-markdown-css": "^2.4.1",
     "hbs": "~4.0.1",
-    "html2canvas": "^1.0.0-alpha.12",
+    "html2canvas": "^1.0.0-rc.5",
     "iconv-lite": "~ 0.4.4",
     "install.js": "^1.0.1",
     "jquery": "^3.3.1",
     "jsonwebtoken": "^7.1.9",
     "jspack": "~ 0.0.3",
+    "jspdf": "^1.5.3",
     "less-middleware": "~2.2.0",
     "lodash": "~ 2.4",
     "lrz": "^4.9.40",

+ 0 - 1
src/api/editor.js

@@ -48,7 +48,6 @@ const cncTestDetail = (data) => {
 const createTest = (data) => {
   return http.post('/testTheme/createTest', data)
 }
-
 module.exports = {
   houseList, cncTestDetail, createTest,
   getUserThemeList, saveTheme, updateTheme, uploadPic, uploadPsd, getPageByThemeId, getPicListByThemeId, delTheme, cncTestcaseList

+ 13 - 1
src/api/test.js

@@ -23,6 +23,18 @@ const exportExcelPath = (param) => {
   return http.post('/excel/exportExcelPath', param)
 }
 
+const answerData = (data) => {
+  return http.post('/analyse/answerData', data)
+}
+const saveAnalyseBag = (data) => {
+  return http.post('/analyse/saveAnalyseBag', data)
+}
+const condition = (data) => {
+  return http.post('/analyse/condition', data)
+}
+const crossAnalyse = (data) => {
+  return http.post('/analyse/crossAnalyse', data)
+}
 module.exports = {
-  testList, deleteTest, copyTest, queryTestTheme, exportExcelPath
+  testList, deleteTest, copyTest, queryTestTheme, exportExcelPath, answerData, saveAnalyseBag, condition, crossAnalyse
 }

+ 73 - 0
src/components/HeaderData.vue

@@ -0,0 +1,73 @@
+<template>
+  <div class="header">
+    <div class="tag">
+      <div class="left">
+        <span @click="home" style="cursor: pointer;">首页</span> > 数据
+      </div>
+      <div class="right">
+        <div class="operational-data" @click="handleExport">下载PDF</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {};
+  },
+  methods: {
+    home() {
+      this.$router.push({ path: "/" });
+    },
+    handleExport() {
+      this.$parent.goToPreviewPage();
+    }
+  }
+};
+</script>
+
+<style lang="less" scoped>
+.header {
+  z-index: 1;
+  position: fixed;
+  top: 0px;
+  width: 100%;
+  height: 60px;
+  box-shadow: 0 2px 8px 0 rgba(62, 67, 116, 0.1);
+  border-bottom: 0;
+  display: flex;
+  flex-direction: row;
+  justify-content: center;
+  align-items: center;
+  padding: 0px 50px;
+  .tag {
+    max-width: 1180px;
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    font-size: 14px;
+    font-family: Helvetica;
+    color: rgba(51, 51, 51, 1);
+    line-height: 17px;
+  }
+  .right {
+    display: flex;
+    flex-direction: row;
+    .operational-data {
+      width: 88px;
+      height: 30px;
+      font-size: 12px;
+      font-family: STYuanti-SC-Regular, STYuanti-SC;
+      font-weight: 400;
+      color: rgba(255, 255, 255, 1);
+      background: rgba(78, 93, 255, 1);
+      border-radius: 15px;
+      line-height: 30px;
+      text-align: center;
+      cursor: pointer;
+    }
+  }
+}
+</style>

+ 4 - 16
src/components/HeaderEdit.vue

@@ -7,21 +7,11 @@
     </div>
     <div class="tools">
       <div class="next_return">
-        <div
-          class="return"
-          title="撤销"
-          @click="revocation"
-          :style="`opacity:${operationList.length>1?'1':'.3'}`"
-        >
+        <div class="return" title="撤销" @click="revocation" :style="`opacity:${operationList.length>1?'1':'.3'}`">
           <img class="retutn_icon" src="../assets/images/button_return.png" alt />
           <span>撤销</span>
         </div>
-        <div
-          class="return"
-          title="恢复"
-          @click="recover"
-          :style="`opacity:${nextList.length>0?'1':'.3'}`"
-        >
+        <div class="return" title="恢复" @click="recover" :style="`opacity:${nextList.length>0?'1':'.3'}`">
           <img class="retutn_icon" src="../assets/images/button_next.png" alt />
           <span>恢复</span>
         </div>
@@ -37,11 +27,9 @@
           <img class="size" @click="zoom(false)" src="../assets/images/subtraction.png"></img>
           <div class="zoom-num">
             <span
-              style="font-size:14px;font-family:MicrosoftYaHei;color:rgba(100,107,129,1);line-height:19px"
-            >{{zoomNum*100}}%</span>
+              style="font-size:14px;font-family:MicrosoftYaHei;color:rgba(100,107,129,1);line-height:19px">{{zoomNum*100}}%</span>
             <span
-              style="font-size:14px;font-family:MicrosoftYaHei;color:rgba(100,107,129,1);line-height:19px;"
-            >缩放</span>
+              style="font-size:14px;font-family:MicrosoftYaHei;color:rgba(100,107,129,1);line-height:19px;">缩放</span>
           </div>
           <img class="size" @click="zoom(true)" src="../assets/images/add.png"></img>
         </div>

+ 6 - 2
src/components/HeaderMain.vue

@@ -3,7 +3,7 @@
     <div class="logo" @click="home">
       <img class="logo-img" src="../assets/images/diaoyanbao-log.png" alt="">调研宝</div>
     <div class="right">
-      <div class="operational-data">去“看板”查看测试运营数据</div>
+      <div class="operational-data" @click="testData">查看数据</div>
       <el-dropdown placement="bottom" trigger="click">
         <div class="userinfo">用户名 <i class="el-icon-caret-bottom"></i></div>
         <el-dropdown-menu slot="dropdown">
@@ -23,6 +23,9 @@ export default {
   methods: {
     home() {
       this.$router.push({ path: "/" });
+    },
+    testData() {
+      this.$router.push({ path: "/testData" });
     }
   }
 };
@@ -58,7 +61,7 @@ export default {
     display: flex;
     flex-direction: row;
     .operational-data {
-      width: 240px;
+      width: 119px;
       height: 34px;
       background: #e6edff;
       border-radius: 17px;
@@ -67,6 +70,7 @@ export default {
       line-height: 34px;
       text-align: center;
       margin-right: 46px;
+      cursor: pointer;
     }
     .userinfo {
       width: 132px;

+ 81 - 0
src/components/HistogramHorizontal.vue

@@ -0,0 +1,81 @@
+<!-- 水平方向的柱状图 -->
+<template>
+  <div :id="chartId"></div>
+</template>
+<script>
+import { Chart } from "@antv/g2";
+import superHorizontal from "./SuperComponent";
+export default {
+  name: "chart",
+  data() {
+    return {
+      ...superHorizontal.rootComponent.data(),
+      chart: null
+    };
+  },
+  props: superHorizontal.rootComponent.props,
+  mounted() {
+    this.drawChart();
+  },
+  watch: {
+    chartData: function(val) {
+      this.chart.changeData(val); // 动态更新数据
+    }
+  },
+  methods: {
+    drawChart: function() {
+      // Step 1: 创建 Chart 对象
+      this.chart = new Chart({
+        container: this.chartId, // 指定图表容器 ID
+        autoFit: true,
+        height: 400
+      });
+
+      this.chart.data(this.chartData);
+      this.chart.scale({
+        sold: {
+          max: 100,
+          min: 0,
+          alias: "占该题总答题人数百分比"
+        }
+      });
+      this.chart.axis("sold", {
+        label: null,
+        title: {
+          offset: 30,
+          style: {
+            fontSize: 12,
+            fontWeight: 300
+          }
+        }
+      });
+      this.chart.legend(false);
+      this.chart.coordinate().transpose();
+      this.chart
+        .interval()
+        .position("genre*sold")
+        .label("sold", {
+          style: {
+            fill: "#8d8d8d"
+          },
+          offset: 10,
+          content: originData => {
+            return originData.sold + "%";
+          }
+        })
+        .tooltip("genre*sold", (genre, sold) => {
+          return {
+            name: genre,
+            value: sold + "%"
+          };
+        });
+
+      this.chart.interaction("active-region");
+      this.chart.render();
+    }
+  }
+};
+</script>
+
+<style scoped>
+</style>

+ 82 - 0
src/components/HistogramHorizontals.vue

@@ -0,0 +1,82 @@
+<!-- 水平方向的柱状图 -->
+<template>
+  <div :id="chartId"></div>
+</template>
+<script>
+import { Chart } from "@antv/g2";
+import superHorizontal from "./SuperComponent";
+export default {
+  name: "chart",
+  data() {
+    return {
+      ...superHorizontal.rootComponent.data(),
+      chart: null
+    };
+  },
+  props: superHorizontal.rootComponent.props,
+  mounted() {
+    this.drawChart();
+  },
+  watch: {
+    chartData: function(val) {
+      this.chart.changeData(val); // 动态更新数据
+    }
+  },
+  methods: {
+    drawChart: function() {
+      // Step 1: 创建 Chart 对象
+      this.chart = new Chart({
+        container: this.chartId,
+        autoFit: true,
+        height: 500
+      });
+      this.chart.data(this.chartData);
+
+      this.chart.axis("time", {
+        tickLine: null
+      });
+
+      this.chart.legend({
+        position: "bottom"
+      });
+
+      this.chart.tooltip({
+        shared: true,
+        showMarkers: false
+      });
+      this.chart.interaction("active-region");
+
+      this.chart
+        .interval()
+        .adjust("stack")
+        .position("time*value")
+        .color("type", ["#F3CC1C", "#1890ff", "#6190FF", "#36CFAA"])
+        .tooltip("type*value*total", (type, value, total) => {
+          return {
+            name: type,
+            value: value + " (" + total + "%)"
+          };
+        })
+        .label("value", val => {
+          if (val < 10) {
+            return null;
+          }
+          return {
+            position: "middle",
+            offset: 0,
+            content: originData => {
+              return originData.total + "%";
+            },
+            style: {
+              stroke: "#fff"
+            }
+          };
+        });
+      this.chart.render();
+    }
+  }
+};
+</script>
+
+<style scoped>
+</style>

+ 22 - 0
src/components/SuperComponent.js

@@ -0,0 +1,22 @@
+const rootComponent = {
+  data() {
+    return {
+      chart: null
+    }
+  },
+  props: {
+    chartData: {
+      type: Array,
+      default: function () {
+        return {
+          data: []
+        }
+      }
+    },
+    id: String,
+    chartId: String
+  }
+}
+export default {
+  rootComponent
+}

+ 2 - 0
src/main.js

@@ -21,6 +21,8 @@ Vue.use(VueRouter)
 Vue.use(Vuex)
 Vue.use(ElementUI)
 
+import htmlToPdf from './util/htmlToPdf' // 路径仅为示例
+Vue.use(htmlToPdf)
 // 全局样式
 import 'normalize.css'
 import 'element-ui/lib/theme-chalk/index.css'

+ 8 - 0
src/routers.js

@@ -45,6 +45,14 @@ const router = new Router({
     path: '/cncTestLists',
     name: "cncTestLists",
     component: require('./views/cnctestlists/cncTestLists.vue')
+  }, {
+    path: '/testData',
+    name: "testData",
+    component: require('./views/testData/testData.vue')
+  }, {
+    path: '/previewPage',
+    name: "previewPage",
+    component: require('./views/previewPage/previewPage.vue')
   }]
 })
 router.beforeEach((to, from, next) => {

+ 1 - 1
src/util/appConst.js

@@ -9,7 +9,7 @@ if (process.env.NODE_ENV === 'test') {
   QINIU_DOMAIN = 'https://gatewaytest.elab-plus.com'
   DIAOYANBAO_PATH = 'http://h5test.elab-plus.com/diaoyanbao/#/preview?mgid='
 } else if (process.env.NODE_ENV === 'development') {//开发
-  BACKEND_DOMAIN = 'http://192.168.0.16:5318'
+  BACKEND_DOMAIN = 'http://43.254.221.77:5555/elab-diaoyanbao'
   DIAOYANBAO_PATH = 'http://192.168.4.249:8080/#/preview?mgid='
   QINIU_DOMAIN = 'https://gatewaytest.elab-plus.com'
   // BACKEND_DOMAIN = 'http://gatewaytest.elab-plus.com/elab-diaoyanbao'

+ 38 - 0
src/util/htmlToPdf.js

@@ -0,0 +1,38 @@
+// 导出页面为PDF格式
+import html2Canvas from 'html2canvas'
+import JsPDF from 'jspdf'
+export default {
+  install(Vue, options) {
+    Vue.prototype.$appName = 'My App';
+    Vue.prototype.$getPdf = function () {
+      let title = this.htmlTitle
+      html2Canvas(document.querySelector('#pdfDom'), {
+        allowTaint: true
+      }).then(function (canvas) {
+        let contentWidth = canvas.width
+        let contentHeight = canvas.height
+        let pageHeight = contentWidth / 592.28 * 841.89
+        let leftHeight = contentHeight
+        let position = 0
+        const imgWidth = 595.28
+        let imgHeight = 592.28 / contentWidth * contentHeight
+        let pageData = canvas.toDataURL('image/jpeg', 1.0)
+        let PDF = new JsPDF('', 'pt', 'a4')
+        if (leftHeight < pageHeight) {
+          PDF.addImage(pageData, 'JPEG', 0, 10, imgWidth, imgHeight)
+        } else {
+          while (leftHeight > 0) {
+            PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
+            leftHeight -= pageHeight
+            position -= 841.89
+            if (leftHeight > 0) {
+              PDF.addPage()
+            }
+          }
+        }
+        PDF.save(title + '.pdf')
+      }
+      )
+    }
+  }
+}

+ 20 - 1
src/util/time.js

@@ -31,6 +31,25 @@ const dateStr = (date) => {
     return date.getFullYear() + "/" + (date.getMonth() + 1) + "/" + date.getDate();
   }
 }
+
+
+
+const getNowFormatDate = () => {
+  var date = new Date();
+  var year = date.getFullYear();
+  var month = date.getMonth() + 1;
+  var strDate = date.getDate();
+  if (month >= 1 && month <= 9) {
+    month = '0' + month;
+  }
+  if (strDate >= 0 && strDate <= 9) {
+    strDate = '0' + strDate;
+  }
+  var currentdate = year + '-' + month + '-' + strDate + ":" + date.getHours() + ":" + date.getMinutes();
+
+  console.log("XXXXXX", currentdate);
+  return currentdate;
+}
 export default {
-  dateStr
+  dateStr, getNowFormatDate
 }

+ 27 - 86
src/views/h5editor/overview.vue

@@ -2,18 +2,10 @@
   <div class="overview">
     <!-- 顶部tag -->
     <div class="preview-tag">
-      <div
-        class="page-tag-btn tagPage"
-        :class="{ active: viewState === 0 }"
-        @click="function () { viewState = 0 }"
-      >
+      <div class="page-tag-btn tagPage" :class="{ active: viewState === 0 }" @click="function () { viewState = 0 }">
         <div class="page-tag-btn-tip">页面</div>
       </div>
-      <div
-        class="page-tag-btn tagElement"
-        :class="{ active: viewState === 1 }"
-        @click="function () { viewState = 1 }"
-      >
+      <div class="page-tag-btn tagElement" :class="{ active: viewState === 1 }" @click="function () { viewState = 1 }">
         <div class="page-tag-btn-tip">元素</div>
       </div>
     </div>
@@ -25,21 +17,12 @@
           <div class="page_preview_tag_title">封面</div>
           <div class="item-page" v-for="(page,index) in pages" v-show="index==0">
             <span>1</span>
-            <div
-              class="page"
-              :class="{ active: page === editingPage }"
+            <div class="page" :class="{ active: page === editingPage }"
               :style="{ width: 70 + 4 + 'px', height: (70 / canvasWidth) * canvasHeight + 4 + 'px' }"
-              @click="setEditingPage(page,0)"
-              @click.right="rightEvent()"
-            >
-              <Page
-                :isOverView="true"
-                class="content"
-                :hideFoot="true"
+              @click="setEditingPage(page,0)" @click.right="rightEvent()">
+              <Page :isOverView="true" class="content" :hideFoot="true"
                 :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', transform: 'scale(' + 70 / canvasWidth +')',backgroundColor: bodyBackgroundColor }"
-                :elements="page.elements"
-                type="see"
-              />
+                :elements="page.elements" type="see" />
             </div>
           </div>
         </li>
@@ -48,27 +31,15 @@
           <div class="page_preview_tag_title">题目</div>
           <div class="item-page" v-for="(page,index) in pages" v-show="isShow(index)">
             <span>{{index + 1 }}</span>
-            <div
-              class="page"
-              :class="{ active: page === editingPage }"
+            <div class="page" :class="{ active: page === editingPage }"
               :style="{ width: 70 + 4 + 'px', height: (70 / canvasWidth) * canvasHeight + 4 + 'px' }"
-              @click="setEditingPage(page,index)"
-            >
-              <Page
-                :isOverView="true"
-                class="content"
-                :hideFoot="true"
+              @click="setEditingPage(page,index)">
+              <Page :isOverView="true" class="content" :hideFoot="true"
                 :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', transform: 'scale(' + 70 / canvasWidth +')',backgroundColor: bodyBackgroundColor }"
-                :elements="page.elements"
-                type="see"
-              />
+                :elements="page.elements" type="see" />
             </div>
-            <el-dropdown
-              placement="bottom"
-              trigger="click"
-              class="operation"
-              @command="command=>operationCommand(command, page, index)"
-            >
+            <el-dropdown placement="bottom" trigger="click" class="operation"
+              @command="command=>operationCommand(command, page, index)">
               <div class="operation_img"></div>
               <el-dropdown-menu slot="dropdown">
                 <el-dropdown-item command="insertBottom">向下插入新页面</el-dropdown-item>
@@ -84,27 +55,15 @@
           <div class="page_preview_tag_title">结论</div>
           <div class="item-page" v-for="(page,index) in pages" v-show="isShowResult(index)">
             <span>{{index + 1}}</span>
-            <div
-              class="page"
-              :class="{ active: page === editingPage }"
+            <div class="page" :class="{ active: page === editingPage }"
               :style="{ width: 70 + 4 + 'px', height: (70 / canvasWidth) * canvasHeight + 4 + 'px' }"
-              @click="setEditingPage(page,index)"
-            >
-              <Page
-                :isOverView="true"
-                class="content"
-                :hideFoot="true"
+              @click="setEditingPage(page,index)">
+              <Page :isOverView="true" class="content" :hideFoot="true"
                 :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', transform: 'scale(' + 70 / canvasWidth +')',backgroundColor: bodyBackgroundColor }"
-                :elements="page.elements"
-                type="see"
-              />
+                :elements="page.elements" type="see" />
             </div>
-            <el-dropdown
-              placement="bottom"
-              trigger="click"
-              class="operation"
-              @command="command=>operationCommand(command, page, index)"
-            >
+            <el-dropdown placement="bottom" trigger="click" class="operation"
+              @command="command=>operationCommand(command, page, index)">
               <div class="operation_img"></div>
               <el-dropdown-menu slot="dropdown">
                 <el-dropdown-item command="del">删除</el-dropdown-item>
@@ -116,31 +75,18 @@
       </ul>
     </div>
     <!-- 图层 -->
-    <div
-      class="list custom-scrollbar"
-      style="z-index: 2;"
-      v-show="viewState === 1"
-      :class="{ dragging: dragState === 1 }"
-    >
+    <div class="list custom-scrollbar" style="z-index: 2;" v-show="viewState === 1"
+      :class="{ dragging: dragState === 1 }">
       <ul>
         <li v-for="(layer, index) in layersNoBg" :key="index">
-          <div
-            class="layer"
-            :class="{ active: editingLayer === layer}"
-            @mousedown="moveLayer($event,layer)"
-          >
+          <div class="layer" :class="{ active: editingLayer === layer}" @mousedown="moveLayer($event,layer)">
             <span class="thumb" :style="{ backgroundImage: 'url(' + layer.imgSrc + ')' }"></span>
             {{ layer.type }}
           </div>
         </li>
       </ul>
-      <div
-        v-for="(layer, index) in layersBg"
-        :key="index"
-        class="layer"
-        :class="{ active: editingLayer === layer}"
-        @click="setEditingLayer(layer)"
-      >
+      <div v-for="(layer, index) in layersBg" :key="index" class="layer" :class="{ active: editingLayer === layer}"
+        @click="setEditingLayer(layer)">
         <span class="thumb" :style="{ backgroundImage: 'url(' + layer.imgSrc + ')' }"></span>
         {{ layer.type }}
       </div>
@@ -154,14 +100,8 @@
       <el-collapse-transition>
         <div v-show="showTopic">
           <div class="topic-group">
-            <el-checkbox
-              v-model="item.isChecked"
-              v-for="(item, index) in questionList"
-              :label="item.name"
-              :key="index"
-              @change="checked=>selectCheckbox(checked,item,index)"
-              :disabled="isDisabled(index)"
-            ></el-checkbox>
+            <el-checkbox v-model="item.isChecked" v-for="(item, index) in questionList" :label="item.name" :key="index"
+              @change="checked=>selectCheckbox(checked,item,index)" :disabled="isDisabled(index)"></el-checkbox>
           </div>
         </div>
       </el-collapse-transition>
@@ -260,7 +200,7 @@ export default {
         this.$store.state.editor.editorTheme.bodyBackgroundColor ||
         "rgba(255,255,255,0)";
       if (isTop) {
-        var position = index ;
+        var position = index;
       } else {
         var position = index + 1;
       }
@@ -764,6 +704,7 @@ export default {
     margin-left: 10px;
     border: 2px solid rgba(255, 255, 255, 1);
     background: #fff;
+    padding: 0px;
     &.active {
       border-color: rgba(78, 93, 255, 1);
       box-shadow: 0px 2px 4px 0px rgba(78, 93, 255, 1);

+ 91 - 0
src/views/previewPage/previewPage.html

@@ -0,0 +1,91 @@
+<div class="content">
+  <div @click="xxxxx" class="dowload"> 下载到本地 </div>
+  <div id="pdfDom" class="pdfContent">
+    <div class="pHeader">
+      <div class="projectTitle">项目答题数据</div>
+      <div class="testList"> <span v-for="(item, index) in options" :key="index">【{{item.label}}】</span></div>
+      <div class="tip">截止到{{currentDate}},问卷共{{answerData.answerJoin || 0}}人参与,完成全部题目的有{{answerData.answerAll || 0}}人。
+      </div>
+    </div>
+    <div class="filterResult" v-if="filterStr">已为您筛选出【{{filterStr}}】共{{answerData.answerCondition}}人,此条件下的用户题目答题情况如下:
+    </div>
+    <div v-if="!isCrossAnalyse">
+      <!-- 答题统计->表格 -->
+      <div class="result" v-if="isShowTable">
+        <div class="resultItem" v-for="(item, index) in answerData.questionList" :key="index">
+          <div class="testLable"
+            v-if="index == 0 || answerData.questionList[index-1].belongTestOrder != answerData.questionList[index].belongTestOrder">
+            测试{{item.belongTestOrder}}:{{item.lable}}</div>
+          <div class="resultTitle"><img v-if="item.isFilter" style="width: 32px;height: 17px;margin-right: 5px;"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E6%9D%A1%E4%BB%B6%E6%A0%87%E8%AE%B0@2x.png" alt="">
+            题目{{index+1}}:{{item.content}}[{{item.chooseType == '1'? '单选':'多选'}}]<span
+              v-if="item.testOrderList.length">(包含测试<span v-for="(testOrder,textIndex) in item.testOrderList"
+                :key="index">{{testOrder}}<span
+                  v-if="textIndex!=(item.testOrderList.length-1)">、</span></span>中的数据)</span></div>
+          <div class="resultTable">
+            <div class="tableHeader">
+              <div class="option">选项</div>
+              <div class="numbers">答题人数</div>
+              <div class="percent">占该题总答题人数百分比</div>
+            </div>
+            <div class="tableRow" v-for="(optionItem, optionIndex) in item.optionList" :key="optionIndex">
+              <div class="option">{{optionItem.content}}</div>
+              <div class="numbers">{{optionItem.answerCount}}</div>
+              <div class="percent">
+                <div style="width: 100%;">
+                  <el-progress
+                    :percentage="parseInt(item.answerTotal==0?0:((optionItem.answerCount/item.answerTotal)*100).toFixed(0))"
+                    color="#4E5DFF" :stroke-width="8">
+                  </el-progress>
+                </div>
+              </div>
+            </div>
+            <div class="tableRow">
+              <div class="option">总计</div>
+              <div class="numbers">{{item.answerTotal}}</div>
+              <div class="percent">_ _</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="chart" v-if="!isShowTable">
+        <div class="chartItem" v-for="(item, index) in chartData" :key="index">
+          <div class="chartTitle"><span v-if="item.isFilter"
+              class="filterTag">条件</span>题目{{index+1}}:{{item.content}}[{{item.chooseType == '1'? '单选':'多选'}}]<span
+              v-if="item.testOrderList.length">(包含测试<span v-for="(testOrder,textIndex) in item.testOrderList"
+                :key="index">{{testOrder}}<span
+                  v-if="textIndex!=(item.testOrderList.length-1)">、</span></span>中的数据)</span>
+          </div>
+          <div class="chartData">
+            <HistogramHorizontal :id="'c1'" :chartId="'c'+item.questionId" :chart-data="item.data">
+            </HistogramHorizontal>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="isCrossAnalyse" class="crossAnalyse">
+      <div class="crossAnalyseTable" v-for="(item, index) in crossAnalyse" :key="index">
+        <div class="crossAnalyseTitle">题目{{index+1}}:{{item.name}}</div>
+        <div class="crossAnalyseChart">
+          <HistogramHorizontals :id="'c2'" :chartId="'caaaaa'+index" :chart-data="item.data">
+          </HistogramHorizontals>
+        </div>
+        <div class="table">
+          <div class="caTable">
+            <div class="headerRow" style="width: 100px;">X\Y</div>
+            <div class="headerRow" v-for="(item1,index1) in item.table[0].title" :key="index1" v-if="index1"
+              :style="`width:${740/(item.table[0].title.length-1 || 1)}px`">{{item1}}</div>
+            <div class="headerRow" style="width: 100px;">总计(人次)</div>
+          </div>
+          <div class="caTable" v-for="(items,indexs) in item.table" :key="indexs">
+            <div class="tabkeRow" style="width: 100px;">{{items.name}}</div>
+            <div class="tabkeRow" v-for="(item0,index0) in items.value" :key="index0" v-if="index0"
+              :style="`width:${740/(items.value.length-1 || 1)}px`">
+              {{item0}} ({{items.value[0]==0?0:((item0 / items.value[0]) * 100).toFixed(0)}}%)</div>
+            <div class="tabkeRow" style="width: 100px;">{{items.value[0]}}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 40 - 0
src/views/previewPage/previewPage.js

@@ -0,0 +1,40 @@
+import timeFormat from '../../util/time'
+import HistogramHorizontal from "../../components/HistogramHorizontal";
+import HistogramHorizontals from "../../components/HistogramHorizontals";
+export default {
+  components: {
+    HistogramHorizontal, HistogramHorizontals
+  },
+
+  data() {
+    return {
+      currentDate: null,
+      answerData: null,
+      chartData: null,
+      options: null,
+      filterStr: null,
+      isShowTable: null,
+      isCrossAnalyse: null,
+      crossAnalyse: null,
+    }
+  },
+  created() {
+    this.chartData = this.$route.params.chartData
+    this.currentDate = this.$route.params.currentDate
+    this.answerData = this.$route.params.answerData
+    this.options = this.$route.params.options
+    this.filterStr = this.$route.params.filterStr
+    this.isShowTable = this.$route.params.isShowTable
+    this.isCrossAnalyse = this.$route.params.isCrossAnalyse
+    this.crossAnalyse = this.$route.params.crossAnalyse
+    console.log("xXXXX", this.$route.params);
+
+    const routerParams = this.$route.query.filterStr;
+    console.log("接受的pdf的值:", routerParams);
+  },
+  methods: {
+    xxxxx() {
+      this.$getPdf('exportBox', '测试截屏');
+    }
+  },
+}

+ 361 - 0
src/views/previewPage/previewPage.scss

@@ -0,0 +1,361 @@
+.content {
+  background: #edeff7;
+  padding: 0px;
+}
+.dowload {
+  width:100px;
+  height:30px;
+  background:rgba(78,93,255,1);
+  border-radius:15px;
+  font-size:12px;
+  font-family:STYuanti-SC-Regular,STYuanti-SC;
+  font-weight:400;
+  color:rgba(255,255,255,1);
+  line-height:30px;
+  text-align: center;
+  margin: 0 auto;
+  cursor: pointer;
+  position: fixed;
+  top: 20px;
+  right: 20px;
+}
+.pdfContent {
+  width: 1180px;
+  margin: 0 auto;
+  background: white;
+  .pHeader{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    border-bottom: 1px solid #E8E8E8;
+    .projectTitle {
+      margin-top: 86px;
+      margin-bottom: 16px;
+      font-size:36px;
+      font-family:PingFangSC-Medium,PingFang SC;
+      font-weight:500;
+      color:rgba(51,51,51,1);
+      line-height:50px;
+    }
+    .testList {
+      font-size:18px;
+      font-family:PingFangSC-Regular,PingFang SC;
+      font-weight:400;
+      color:rgba(51,51,51,1);
+      line-height:25px;
+    }
+    .tip {
+      font-size:18px;
+      font-family:PingFangSC-Medium,PingFang SC;
+      font-weight:500;
+      color:rgba(51,51,51,1);
+      line-height:25px;
+      margin-bottom: 23px;
+    }
+  }
+  .filterResult {
+    width: 960px;
+    margin: 0 auto;
+    font-size:14px;
+    font-family:PingFangSC-Regular,PingFang SC;
+    font-weight:400;
+    color:rgba(51,51,51,1);
+    line-height:20px;
+    border-bottom: 1px dashed #E8E8E8;
+    padding-top: 23px;
+    padding-bottom: 15px;
+  }
+  .result {
+    margin-top: 30px;
+    padding: 0px 120px;
+    box-sizing: border-box;
+    .resultItem {
+      margin-top: 36px;
+      padding-bottom: 20px;
+      border-bottom:1px dashed rgba(202,204,210,1);
+      .testLable {
+        font-size:18px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(78,93,255,1);
+        line-height:25px;
+        margin-bottom: 10px;
+        padding-bottom: 10px;
+        width: 100%;
+        border-bottom: 1px dashed #E8E8E8;
+      }
+      .resultTitle {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        font-size:18px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:25px;
+      }
+      .resultTable {
+
+        border-radius:4px;
+        border:1px solid rgba(232,232,232,1);
+        margin-top: 8px;
+      }
+      .tableHeader {
+        display: flex;
+        flex-direction: row;
+        height: 32px;
+        background:rgba(250,250,250,1);
+        border-radius:4px 0px 0px 0px;
+        font-size:14px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(0,0,0,0.85);
+        line-height:21px;
+        align-items:flex-end;
+        .option {
+         flex-grow: 2;
+         padding-left: 25px;
+         box-sizing: border-box;
+        }
+        .numbers {
+          width:236px;
+          height: 100%;
+          padding-top: 8px;
+          padding-left: 25px;
+          box-sizing: border-box;
+          border-left:1px solid rgba(232,232,232,1);
+          border-right:1px solid rgba(232,232,232,1);
+        }
+        .percent {
+          width: 408px;
+          padding-left: 25px;
+          box-sizing: border-box;
+        }
+      }
+      .tableRow {
+        display: flex;
+        flex-direction: row;
+        min-height: 32px;
+        font-size:14px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(0,0,0,0.65);
+        line-height:21px;
+        .option {
+         flex-grow: 2;
+         height: 100%;
+         padding-top: 8px;
+         padding-left: 25px;
+         box-sizing: border-box;
+         border-top:1px solid rgba(232,232,232,1);
+        padding: 8px 15px;
+        }
+        .numbers {
+          width:236px;
+          min-height: 100%;
+          padding: 0px 15px;
+          padding-left: 25px;
+          box-sizing: border-box;
+          border-left:1px solid rgba(232,232,232,1);
+          border-right:1px solid rgba(232,232,232,1);
+          border-top:1px solid rgba(232,232,232,1);
+          flex-shrink: 0;
+          display: flex;
+          align-items: center;
+        }
+        .percent {
+          width: 408px;
+          min-height: 100%;
+          padding-left: 25px;
+          box-sizing: border-box;
+          border-top:1px solid rgba(232,232,232,1);
+          flex-shrink: 0;
+          display: flex;
+          align-items: center;
+        }
+      }
+    }
+  }
+  .chart {
+    display: flex;
+    flex-direction: column;
+    margin-top: 30px;
+    padding: 0px 120px;
+    box-sizing: border-box;
+    .chartItem {
+      display: flex;
+      flex-direction: column;
+      .chartTitle {
+        font-size:18px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:25px;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        .filterTag{
+          display: block;
+          width: 32px;
+          height: 16px;
+          background:rgba(255,106,106,1);
+          border-radius:8px;
+          font-size:12px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(255,255,255,1);
+          line-height:16px;
+          text-align: center;
+          margin-right: 5px;
+        }
+      }
+      .chartData {
+        width: 100%;
+        margin: 10px 0px;
+      }
+    }
+  }
+  .crossAnalyse {
+    width: 100%;
+    background: white;
+    border-radius:6px;
+    padding: 24px 120px;
+    box-sizing: border-box;
+    .crossFilter{
+      background:rgba(250,250,250,1);
+      border-radius:6px;
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      flex-wrap:wrap;
+      .xyFilter {
+        width: 360px;
+        .el-cascader {
+          width: 320px;
+          background:rgba(241,241,241,1);
+          line-height: 30px;
+          font-size:14px;
+          color:rgba(51,51,51,1);
+          .el-input__inner {
+            height: 30px;
+            line-height: 30px;
+            background:rgba(241,241,241,1);
+          }
+          .el-input__icon {
+            line-height: 30px;
+          }
+        }
+        .addfilter{
+          width:320px;
+          height:30px;
+          border:1px dashed rgba(202,204,210,1);
+          margin-top: 8px;
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+          cursor: pointer;
+          .addfilterIcon {
+            width: 74px;
+            height: 18px;
+          }
+        }
+      }
+      .crossFilterTitle {
+        font-size:14px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:20px;
+      }
+      .crossFilterSubTitle {
+        font-size:12px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(51,51,51,1);
+        line-height:20px;
+      }
+      .analyse {
+        width: 100%;
+        margin: 16px 0px;
+        display: flex;
+        flex-direction: row;
+        .startAnalyse {
+          margin-left: 90px;
+          width:80px;
+          height:28px;
+          background:rgba(78,93,255,1);
+          border-radius:14px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(255,255,255,1);
+          line-height:28px;
+          text-align: center;
+          cursor: pointer;
+        }
+        .analyseTip {
+          font-size:12px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(255,0,0,1);
+          line-height:28px;
+          margin-left: 8px;
+        }
+      }
+    }
+    .crossAnalyseTable {
+      .crossAnalyseTitle {
+        font-size:18px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:25px;
+        margin-top: 32px;
+      }
+      .crossAnalyseChart {
+        width: 100%;
+        margin: 8px 0px;
+      }
+      .table{
+        border-radius:4px;
+        border-top:1px solid rgba(232,232,232,1); 
+        border-left:1px solid rgba(232,232,232,1); 
+      }
+      .caTable {
+        display: flex;
+        flex-direction: row;
+        .headerRow {
+          background:rgba(250,250,250,1);
+          border-radius:4px 0px 0px 0px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(0,0,0,0.85);
+          line-height:21px;
+          align-items:flex-end;
+          padding-top: 8px;
+          padding-bottom: 12px;
+          box-sizing: border-box;
+          border-bottom: 1px solid #E8E8E8;
+          border-right: 1px solid #E8E8E8;
+        }
+        .tabkeRow {
+          font-size:14px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(0,0,0,0.65);
+          line-height:21px;
+          align-items:flex-end;
+          padding-top: 8px;
+          padding-bottom: 1px;
+          padding-left: 5px;
+          box-sizing: border-box;
+          border-bottom: 1px solid #E8E8E8;
+          border-right: 1px solid #E8E8E8;
+        }
+        
+      }
+    }
+  }
+}

+ 7 - 0
src/views/previewPage/previewPage.vue

@@ -0,0 +1,7 @@
+<template src='./previewPage.html'>
+</template>
+<script src="./previewPage.js">
+</script>
+<style lang="scss">
+@import "./previewPage.scss";
+</style>

+ 228 - 0
src/views/testData/testData.html

@@ -0,0 +1,228 @@
+<div class="page" style="overflow:auto">
+  <!-- 头部 -->
+  <HeaderData></HeaderData>
+  <!-- 题目筛选 -->
+  <div class="testData">
+    <div class="testList">
+      <div class="testProject">
+        <el-dropdown trigger="click" @command="projectCommand">
+          <el-button type="primary">{{ownHouseName}} <i class="el-icon-caret-bottom icon-right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item>全部</el-dropdown-item>
+            <el-dropdown-item v-for="(item,index) in houseList" :key="item.houseId" :command="item">
+              {{item.houseName}}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </div>
+      <div class="testItem">
+        <div class="itemArrow"><i class="el-icon-arrow-left"></i></div>
+        <div class="testContent">
+          <div class="testTopic" :class="{testTopicSel:item.isSelected}" v-for="(item,index) in dataList"
+            :key="item.created">
+            <div id></div>
+            <div style="display: -webkit-box;
+            -webkit-box-orient: vertical;
+            -webkit-line-clamp: 3;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            word-break: break-all;
+            word-wrap: break-word;">{{index+1}}.{{item.title}}</div>
+            <img v-if="item.isSelected" class="testSel" src="
+              https://dm.static.elab-plus.com/diaoyanbao/%E5%A4%9A%E9%80%89-%E9%80%89%E4%B8%AD@2x.png" alt=""
+              @click="changeTest(item)">
+            <img v-if="!item.isSelected" class="testSel"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E5%A4%9A%E9%80%89-%E6%9C%AA%E9%80%89@2x.png" alt=""
+              @click="changeTest(item)">
+          </div>
+        </div>
+        <div class="itemArrow"><i class="el-icon-arrow-right"></i></div>
+      </div>
+    </div>
+    <div class="testTip">
+      <div v-if="!isCrossAnalyse"><span
+          v-if="currentDate">截止到{{currentDate}},问卷共{{answerData.answerJoin || 0}}人参与,完成全部题目的有{{answerData.answerAll || 0}}人。</span>
+      </div>
+      <div v-if="isCrossAnalyse" style="display: flex;align-items:center;">
+        <div class="analyseBag">
+          <div class="analyseBagTitle">
+            <el-dropdown trigger="click" @command="analyseCommand">
+              <el-button type="primary">{{analyseCommandSel}}<i class="el-icon-caret-bottom icon-right"></i>
+              </el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item command="-1">全部</el-dropdown-item>
+                <el-dropdown-item command="0">数据包</el-dropdown-item>
+                <el-dropdown-item command="1">区域</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </div>
+          <div class="analyseBagList">
+            <el-cascader v-model="analyseValue" :options="analyseOptions"
+              :props="{ checkStrictly: analyseCommandSel== '区域' ? true : false }"
+              @change="handleAnalyseChange(analyseValue)">
+            </el-cascader>
+          </div>
+        </div>
+        <div class="addBag" @click="isCrossAnalyse=false"><i class="el-icon-circle-plus-outline"></i><span> 新建数据包</span>
+        </div>
+      </div>
+      <div class="switchItem">
+        <div class="switch" :class="{ switchSelected: !isCrossAnalyse}" @click="isCrossAnalyse=false">答题统计</div>
+        <div class="switch" :class="{ switchSelected: isCrossAnalyse}" @click="isCrossAnalyse=true">交叉分析</div>
+      </div>
+    </div>
+    <div class="answer" v-if="!isCrossAnalyse">
+      <div class="filter">
+        <img v-if="isFilter" class="filterIcon"
+          src="https://dm.static.elab-plus.com/diaoyanbao/%E5%8F%96%E6%B6%88%E7%AD%9B%E9%80%89%E6%8C%89%E9%92%AE@2x.png"
+          alt="" @click="isFilter=false">
+        <img v-if="!isFilter" class="filterIcon"
+          src="https://dm.static.elab-plus.com/diaoyanbao/%E7%AD%9B%E9%80%89%E6%8C%89%E9%92%AE@2x.png" alt=""
+          @click="isFilter=true">
+        <div class="rightFilter">
+          <div class="rightFilterItem" :class="{ rightFilterItemSel: !isShowTable}" @click="isShowTable=false">图形</div>
+          <div class="rightFilterItem" :class="{ rightFilterItemSel: isShowTable}" @click="isShowTable=true">表格</div>
+        </div>
+      </div>
+      <div class="filterContent" v-if="isFilter">
+        <div class="filterView">
+          <div class="filterItem" v-for="(items, indexs) in filterList" :key="indexs">
+            <div class="filterTitle"><span v-if="indexs==0">选择条件</span></div>
+            <div class="filterAnswer">
+              <el-cascader v-model="value[indexs]" :options="options" @change="handleChange(value[indexs],indexs)">
+              </el-cascader>
+            </div>
+            <div class="filterReply" v-if="questionListSel[indexs]">
+              <el-checkbox-group v-model="checkList[indexs]">
+                <el-checkbox v-for="(item, index) in questionListSel[indexs].optionList" :label="item.content"
+                  :key="index" @change="checked=>changequestionChild(checked,item, indexs)">
+                </el-checkbox>
+              </el-checkbox-group>
+            </div>
+            <div class="filterDel" @click="delFilter(indexs)"><i class="el-icon-delete"></i>
+            </div>
+          </div>
+          <div class="addfilter" @click="addFilter">
+            <img class="addfilterIcon"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E6%B7%BB%E5%8A%A0%E6%9D%A1%E4%BB%B6%E6%8C%89%E9%92%AE@2x.png"
+              alt="">
+          </div>
+          <div class="filterSave">
+            <div class="saveLocation" @click="getAnswerData">筛选</div>
+            <div class="saveOnLine" @click="saveOnLine">保存此筛选条件作为数据包</div>
+          </div>
+        </div>
+        <div class="filterResult">已为您筛选出【{{filterStr}}】共{{answerData.answerCondition}}人,此条件下的用户题目答题情况如下:</div>
+      </div>
+      <!-- 答题统计->表格 -->
+      <div class="result" v-if="isShowTable">
+        <div class="resultItem" v-for="(item, index) in answerData.questionList" :key="index">
+          <div class="testLable"
+            v-if="index == 0 || answerData.questionList[index-1].belongTestOrder != answerData.questionList[index].belongTestOrder">
+            测试{{item.belongTestOrder}}:{{item.lable}}</div>
+          <div class="resultTitle"><img v-if="item.isFilter" style="width: 32px;height: 17px;margin-right: 5px;"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E6%9D%A1%E4%BB%B6%E6%A0%87%E8%AE%B0@2x.png" alt="">
+            题目{{index+1}}:{{item.content}}[{{item.chooseType == '1'? '单选':'多选'}}]<span
+              v-if="item.testOrderList.length">(包含测试<span v-for="(testOrder,textIndex) in item.testOrderList"
+                :key="index">{{testOrder}}<span
+                  v-if="textIndex!=(item.testOrderList.length-1)">、</span></span>中的数据)</span></div>
+          <div class="resultTable">
+            <div class="tableHeader">
+              <div class="option">选项</div>
+              <div class="numbers">答题人数</div>
+              <div class="percent">占该题总答题人数百分比</div>
+            </div>
+            <div class="tableRow" v-for="(optionItem, optionIndex) in item.optionList" :key="optionIndex">
+              <div class="option">{{optionItem.content}}</div>
+              <div class="numbers">{{optionItem.answerCount}}</div>
+              <div class="percent">
+                <div style="width: 100%;">
+                  <el-progress
+                    :percentage="parseInt(item.answerTotal==0?0:((optionItem.answerCount/item.answerTotal)*100).toFixed(0))"
+                    color="#4E5DFF" :stroke-width="8">
+                  </el-progress>
+                </div>
+              </div>
+            </div>
+            <div class="tableRow">
+              <div class="option">总计</div>
+              <div class="numbers">{{item.answerTotal}}</div>
+              <div class="percent">_ _</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 答题统计->图形 -->
+      <div class="chart" v-if="!isShowTable">
+        <div class="chartItem" v-for="(item, index) in chartData" :key="index">
+          <div class="chartTitle">题目{{index+1}}:{{item.content}}[{{item.chooseType == '1'? '单选':'多选'}}]<span
+              v-if="item.testOrderList.length">(包含测试<span v-for="(testOrder,textIndex) in item.testOrderList"
+                :key="index">{{testOrder}}<span
+                  v-if="textIndex!=(item.testOrderList.length-1)">、</span></span>中的数据)</span>
+          </div>
+          <div class="chartData">
+            <HistogramHorizontal :id="'c1'" :chartId="'c'+item.questionId" :chart-data="item.data">
+            </HistogramHorizontal>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div v-if="isCrossAnalyse" class="crossAnalyse">
+      <div class="crossFilter">
+        <div class="xyFilter">
+          <div><span class="crossFilterTitle">自变量 X</span><span
+              class="crossFilterSubTitle">(一般为样本属性,例如性别,年龄等。限2题)</span></div>
+          <div style="margin-top: 8px;" v-for="(items, indexs) in filterXList" :key="indexs">
+            <el-cascader v-model="optionsXValue[indexs]" :options="optionsX"
+              @change="handleChangeX(optionsXValue[indexs],indexs)">
+            </el-cascader>
+          </div>
+          <div class="addfilter" @click="addfilterX" v-if="filterXList.length<2">
+            <img class="addfilterIcon"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E6%B7%BB%E5%8A%A0%E6%9D%A1%E4%BB%B6%E6%8C%89%E9%92%AE@2x.png"
+              alt="">
+          </div>
+        </div>
+        <div class="xyFilter" style="margin-left: 40px;">
+          <div><span class="crossFilterTitle">因变量 Y</span><span class="crossFilterSubTitle">(您要分析的目标题目)</span></div>
+          <div style="margin-top: 8px;" v-for="(items, indexs) in filterYList" :key="indexs">
+            <el-cascader v-model="optionsYValue[indexs]" :options="optionsY"
+              @change="handleChangeY(optionsYValue[indexs],indexs)">
+            </el-cascader>
+          </div>
+          <div class="addfilter" @click="addfilterY">
+            <img class="addfilterIcon"
+              src="https://dm.static.elab-plus.com/diaoyanbao/%E6%B7%BB%E5%8A%A0%E6%9D%A1%E4%BB%B6%E6%8C%89%E9%92%AE@2x.png"
+              alt="">
+          </div>
+        </div>
+        <div class="analyse">
+          <div class="startAnalyse" @click="getCrossAnalyse">开始分析</div>
+          <div class="analyseTip">*不可选择同样的题目</div>
+        </div>
+      </div>
+      <div class="crossAnalyseTable" v-for="(item, index) in crossAnalyse" :key="index">
+        <div class="crossAnalyseTitle">题目{{index+1}}:{{item.name}}</div>
+        <div class="crossAnalyseChart">
+          <HistogramHorizontals :id="'c2'" :chartId="'caaaaa'+index" :chart-data="item.data">
+          </HistogramHorizontals>
+        </div>
+        <div class="table">
+          <div class="caTable">
+            <div class="headerRow" style="width: 100px;">X\Y</div>
+            <div class="headerRow" v-for="(item1,index1) in item.table[0].title" :key="index1" v-if="index1"
+              :style="`width:${740/(item.table[0].title.length-1 || 1)}px`">{{item1}}</div>
+            <div class="headerRow" style="width: 100px;">总计(人次)</div>
+          </div>
+          <div class="caTable" v-for="(items,indexs) in item.table" :key="indexs">
+            <div class="tabkeRow" style="width: 100px;">{{items.name}}</div>
+            <div class="tabkeRow" v-for="(item0,index0) in items.value" :key="index0" v-if="index0"
+              :style="`width:${740/(items.value.length-1 || 1)}px`">
+              {{item0}} ({{items.value[0]==0?0:((item0 / items.value[0]) * 100).toFixed(0)}}%)</div>
+            <div class="tabkeRow" style="width: 100px;">{{items.value[0]}}</div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 745 - 0
src/views/testData/testData.js

@@ -0,0 +1,745 @@
+import HeaderData from "../../components/HeaderData";
+import HistogramHorizontal from "../../components/HistogramHorizontal";
+import HistogramHorizontals from "../../components/HistogramHorizontals";
+import api from '../../api/test'
+import editorApi from '../../api/editor'
+import timeFormat from '../../util/time'
+import { format } from "util";
+export default {
+  components: {
+    HeaderData, HistogramHorizontal, HistogramHorizontals
+  },
+  data() {
+    return {
+      isCopy: false,
+      houseList: [],
+      ownHouseName: "所属项目",
+      dataList: [],
+      isFilter: false,
+      isShowTable: true,
+      checkList: [[]],
+      data: [],
+      value: [],
+      oldValue: [],
+      options: [],
+      questionList: [],
+      questionListSel: [],
+      filterList: [""],
+      questionChilds: [],
+      answerData: [],
+      currentDate: null,
+      filterStr: "",
+      chartData: [],
+      isCrossAnalyse: false,
+      condition: [],
+      analyseCommandSel: "全部",
+      analyseOptions: [],
+      analyseValue: [],
+      crossAnalyse: [],
+      optionsX: [],
+      optionsXValue: [],
+      optionsXOldValue: [],
+      optionsY: [],
+      optionsYValue: [],
+      optionsYOldValue: [],
+
+      filterXList: [""],
+      filterYList: [""],
+      selectedDataList: [],
+    }
+  },
+  watch: {
+    answerData: function (val) {
+      var questionList = val.questionList;
+      this.chartData = []
+      for (var i = 0; i < questionList.length; i++) {
+        var question = questionList[i];
+        var data = []
+        var optionList = question.optionList;
+        for (var j = 0; j < optionList.length; j++) {
+          var sold = question.answerTotal == 0 ? 0 : ((optionList[j].answerCount / question.answerTotal) * 100).toFixed(0)
+          data.push({ genre: optionList[j].content, sold: parseInt(sold) })
+        }
+        var conditionQuestion = { data: data, ...question }
+        this.chartData.push(conditionQuestion);
+      }
+    },
+    analyseCommandSel: function (val) {
+      this.analyseOptions = [];
+      this.analyseValue = [];
+      if (val == "全部") {
+
+      } else if (val == "数据包") {
+        var bagList = this.condition.bagList;
+        for (var i = 0; i < bagList.length; i++) {
+          this.analyseOptions.push({ value: bagList[i].analyseBagId, label: bagList[i].title, disabled: false })
+        }
+      } else {
+        var locationList = this.condition.locationList;
+        let locationTemp = []
+        for (var i = 0; i < locationList.length; i++) {
+          var item = locationList[i]
+          if (item.city == "") {
+            item.city = item.province;
+          }
+          locationTemp.push(item)
+        }
+        locationList = locationTemp;
+        let result = Object.values(locationList.reduce((m, n) => {
+          if (!m[n.province]) {
+            m[n.province] = { value: n.province, children: [] }
+          }
+          m[n.province].children.push(n)
+          return m
+        }, {}))
+        console.log("XXXX:result:", result)
+        var arr = []
+        for (var i = 0; i < result.length; i++) {
+
+          var list = result[i].children;
+          let results = Object.values(list.reduce((m, n) => {
+            if (!m[n.city]) {
+              m[n.city] = { value: n.city, label: n.city, children: [] }
+            }
+            m[n.city].children.push({ value: n.district, label: n.district })
+            return m
+          }, {}))
+          arr.push({ value: result[i].value, label: result[i].value, children: results })
+        }
+
+        this.analyseOptions = arr;
+      }
+    },
+    options: function (val) {
+      if (val) {
+        this.getCondition();
+      }
+    }
+  },
+  created() {
+    this.houseList = [];
+    editorApi.houseList().then((res) => {
+      if (res.success) {
+        this.houseList = res.list;
+      }
+    });
+    this.getTestList();
+  },
+  methods: {
+    async changeTest(item) {
+      console.log("XXXXXX1", item);
+      var list = []
+      for (var i = 0; i < this.dataList.length; i++) {
+        var element = this.dataList[i]
+        if (item._id == element._id) {
+          element.isSelected = !element.isSelected;
+        }
+        list.push(element)
+      }
+      console.log("XXXxXXX", list);
+      this.dataList = list;
+
+      this.analyseOptions = [];
+      this.analyseValue = [];
+
+      this.answerData = [];
+      this.options = []
+      this.questionList = []
+      var testThemesList = [];
+      for (var i = 0; i < this.dataList.length; i++) {
+        var element = this.dataList[i]
+        if (element.isSelected) {
+          this.getCNCTestDetail(element)
+          testThemesList.push(element);
+        }
+      }
+      this.getCNCTestDetails(testThemesList);
+
+      this.optionsX = []
+      for (var i = 0; i < this.dataList.length; i++) {
+        var element = this.dataList[i]
+        if (element.isSelected) {
+          this.getCNCTestDetailX(element)
+        }
+      }
+
+      this.optionsY = []
+      for (var i = 0; i < this.dataList.length; i++) {
+        var element = this.dataList[i]
+        if (element.isSelected) {
+          this.getCNCTestDetailY(element)
+        }
+      }
+    },
+    async getCondition() {
+      var testThemesIdList = [];
+      for (var i = 0; i < this.options.length; i++) {
+        var element = this.options[i]
+        testThemesIdList.push(element.id);
+      }
+      let data = {
+        testThemesIdList: testThemesIdList
+      }
+      api.condition(data).then((res) => {
+        if (res.success) {
+          console.log("success", res.single);
+          this.condition = res.single;
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    async getCNCTestDetails(testThemesList) {
+      this.currentDate = timeFormat.getNowFormatDate();
+      var testThemesIdList = [];
+      for (var i = 0; i < testThemesList.length; i++) {
+        var element = testThemesList[i]
+        testThemesIdList.push(element._id);
+      }
+      let data = {
+        testThemesIdList: testThemesIdList
+      }
+      api.answerData(data).then((res) => {
+        if (res.success) {
+          console.log("success", res);
+          var answerData = res.single;
+          for (var i = 0; i < answerData.questionList.length; i++) {
+            var element = answerData.questionList[i]
+            if (element.belongTestOrder <= testThemesIdList.length) {
+              element.lable = testThemesList[element.belongTestOrder - 1].title;
+            }
+          }
+          console.log("answerData", answerData);
+          this.answerData = answerData;
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    async getCNCTestDetail(item) {
+      let data = {
+        testThemesIdList: [item._id]
+      }
+      api.answerData(data).then((res) => {
+        if (res.success) {
+          console.log("success", res);
+          var questionList = res.single.questionList;
+          var children = []
+          for (var i = 0; i < questionList.length; i++) {
+            var question = questionList[i];
+            var disabled = false;
+            const found = this.value.find(element => element[1] == question.questionId);
+            if (found) {
+              disabled = true
+            }
+            children.push({ value: question.questionId, label: question.content, disabled: disabled })
+          }
+          var element = { value: item._id, label: item.title, children: children, id: item._id };
+          this.options.push(element);
+          this.questionList.push(questionList);
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    async getCNCTestDetailX(item) {
+      let data = {
+        testThemesIdList: [item._id]
+      }
+      api.answerData(data).then((res) => {
+        if (res.success) {
+          console.log("success", res);
+          var questionList = res.single.questionList;
+          var children = []
+          for (var i = 0; i < questionList.length; i++) {
+            var question = questionList[i];
+            var disabled = false;
+
+            const foundX = this.optionsXValue.find(element => element[1] == question.questionId);
+            if (foundX) {
+              disabled = true
+            }
+            const foundY = this.optionsYValue.find(element => element[1] == question.questionId);
+            if (foundY) {
+              disabled = true
+            }
+            children.push({ value: question.questionId, label: question.content, disabled: disabled })
+          }
+          var element = { value: item._id, label: item.title, children: children, id: item._id };
+          this.optionsX.push(element);
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    async getCNCTestDetailY(item) {
+      let data = {
+        testThemesIdList: [item._id]
+      }
+      api.answerData(data).then((res) => {
+        if (res.success) {
+          console.log("success", res);
+          var questionList = res.single.questionList;
+          var children = []
+          for (var i = 0; i < questionList.length; i++) {
+            var question = questionList[i];
+            var disabled = false;
+
+            const foundX = this.optionsXValue.find(element => element[1] == question.questionId);
+            if (foundX) {
+              disabled = true
+            }
+            const foundY = this.optionsYValue.find(element => element[1] == question.questionId);
+            if (foundY) {
+              disabled = true
+            }
+            children.push({ value: question.questionId, label: question.content, disabled: disabled })
+          }
+          var element = { value: item._id, label: item.title, children: children, id: item._id };
+          this.optionsY.push(element);
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    handleChange(value, index) {
+      console.log(value, index, this.oldValue);
+      for (var i = 0; i < this.questionList.length; i++) {
+        var questionList = this.questionList[i]
+        for (var j = 0; j < questionList.length; j++) {
+          if (value[1] == questionList[j].questionId) {
+            if (this.oldValue.length >= index + 1) {
+              console.log("XXXXXXXXXXXXX");
+              this.setOptionsDisabled(this.oldValue[index], false);
+            }
+            this.questionListSel[index] = questionList[j];
+          }
+        }
+      }
+      this.setOptionsDisabled(value, true);
+
+      this.value[index] = value;
+      this.oldValue[index] = value;
+      this.checkList.splice(index, 1, []);
+      this.questionChilds.splice(index, 1, []);
+    },
+    handleChangeX(value, index) {
+      console.log("handleChangeX", value, index, this.optionsXOldValue);
+      for (var i = 0; i < this.questionList.length; i++) {
+        if (value[1] == this.questionList[i].questionId) {
+          if (this.optionsXOldValue.length >= index + 1) {
+            console.log("XXXXXXXXXXXXX");
+            this.setOptionsDisabledXY(this.optionsXOldValue[index], false, 0);
+            this.setOptionsDisabledXY(this.optionsYOldValue[index], false, 1);
+          }
+        }
+      }
+
+      this.setOptionsDisabledXY(value, true, 1);
+      this.setOptionsDisabledXY(value, true, 0);
+
+      this.optionsXValue[index] = value;
+      this.optionsXOldValue[index] = value;
+    },
+    handleChangeY(value, index) {
+      console.log("handleChangeX", value, index, this.optionsYOldValue);
+      for (var i = 0; i < this.questionList.length; i++) {
+        var questionList = this.questionList[i];
+        for (var j = 0; j < questionList.length; j++) {
+          if (value[1] == questionList[j].questionId) {
+            if (this.optionsYOldValue.length >= index + 1) {
+              this.setOptionsDisabledXY(this.optionsYOldValue[index], false, 1);
+              this.setOptionsDisabledXY(this.optionsYOldValue[index], false, 0);
+            }
+          }
+        }
+      }
+      this.setOptionsDisabledXY(value, true, 1);
+      this.setOptionsDisabledXY(value, true, 0);
+
+      this.optionsYValue[index] = value;
+      this.optionsYOldValue[index] = value;
+    },
+    addfilterX() {
+      this.filterXList.push('');
+    },
+    addfilterY() {
+      this.filterYList.push('');
+    },
+    handleAnalyseChange(value) {
+      console.log(value);
+    },
+    setOptionsDisabledXY(value, disabled, type = 0) {
+      var newOptions = [];
+      console.log("XXXXXXX", value)
+      var options = type == 0 ? this.optionsX : this.optionsY;
+      for (var i = 0; i < options.length; i++) {
+        var item = options[i];
+        if (item.value == value[0]) {
+          for (var j = 0; j < options[i].children.length; j++) {
+            var children = []
+            var element = options[i].children[j];
+            if (element.value == value[1]) {
+              element.disabled = disabled
+            }
+            children.push(element)
+          }
+        }
+        newOptions.push(item)
+      }
+      if (type == 0) {
+        this.optionsX = newOptions;
+      } else {
+        this.optionsY = newOptions;
+      }
+
+    },
+    setOptionsDisabled(value, disabled) {
+      var newOptions = [];
+      console.log("XXXXXXX", value)
+      for (var i = 0; i < this.options.length; i++) {
+        var item = this.options[i];
+        if (item.value == value[0]) {
+          for (var j = 0; j < this.options[i].children.length; j++) {
+            var children = []
+            var element = this.options[i].children[j];
+            if (element.value == value[1]) {
+              element.disabled = disabled
+            }
+            children.push(element)
+          }
+        }
+        newOptions.push(item)
+      }
+      this.options = newOptions;
+    },
+    addFilter() {
+      this.filterList.push('');
+      this.checkList.push([]);
+    },
+    delFilter(index) {
+      if (this.value[index]) {
+        this.setOptionsDisabled(this.value[index], false);
+      }
+
+      this.filterList.splice(index, 1);
+      this.value.splice(index, 1);
+
+      this.questionListSel.splice(index, 1);
+      this.questionChilds.splice(index, 1);
+      this.checkList.splice(index, 1);
+    },
+    projectCommand(command) {
+      if (this.houseList.indexOf(command) == -1) {
+        console.log("不存在");
+        this.ownHouseName = "所属项目";
+      } else {
+        console.log("存在", command.houseName);
+        this.ownHouseName = command.houseName;
+      }
+      this.getTestList();
+    },
+    analyseCommand(command) {
+      console.log("XXXXXXX", command)
+      if (command == -1) {
+        this.analyseCommandSel = "全部";
+      } else if (command == 0) {
+        this.analyseCommandSel = "数据包";
+      } else {
+        this.analyseCommandSel = "区域";
+      }
+      // this.getTestList();
+    },
+    changequestionChild(checked, value, index) {
+      console.log("XXXXXX", value, index, checked);
+
+      var arr = this.questionChilds;
+      if (this.questionChilds.length <= index) { // 没有
+        if (checked) {
+          console.log("选中");
+          for (var i = 0; i < this.filterList.length; i++) {
+            if (i < index) {
+              if (this.questionChilds.length < index) {
+                this.questionChilds.push([]);
+              }
+            }
+          }
+          this.questionChilds.push([value]);
+        } else {
+          console.log("取消选中")
+        }
+      } else { // 有
+        console.log("有")
+        var questionList = this.questionChilds[index];
+        if (checked) {
+          questionList.push(value)
+        } else {
+          var arr = questionList;
+          for (var i = 0; i < questionList.length; i++) {
+            var option = questionList[i];
+            if (option.optionId == value.optionId) {
+              arr.splice(i, 1);
+            }
+          }
+          questionList = arr;
+        }
+        this.questionChilds[index] = questionList;
+      }
+
+    },
+    getTestList() {
+
+      let data = {
+        "orderType": "",
+        "ownHouseName": this.ownHouseName == "所属项目" ? '' : this.ownHouseName,
+        "pageNo": 1,
+        "pageSize": 100,
+        "houseAnswerStatus": ""
+      }
+      api.testList(data).then((res) => {
+        if (res.success) {
+          this.total = res.pageModel.total;
+          this.dataList = [];
+          this.dataList.push(...res.pageModel.resultSet);
+          this.dataList.forEach(element => {
+            element.isSelected = false
+          });
+          console.log("success", this.dataList, res.pageModel);
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    async getAnswerData() {
+      this.filterStr = "";
+
+      var conditionQuestionList = [];
+      var testThemesIdList = [];
+      for (var i = 0; i < this.questionChilds.length; i++) {
+        var question = this.questionChilds[i];
+        var value = this.value[i];
+        var optionList = [];
+        for (var j = 0; j < question.length; j++) {
+          optionList.push({ optionId: question[j].optionId })
+          this.filterStr += question[j].content + "/";
+        }
+        var conditionQuestion = { questionId: value[1], optionList: optionList }
+        conditionQuestionList.push(conditionQuestion);
+      }
+
+      for (var i = 0; i < this.options.length; i++) {
+        testThemesIdList.push(this.options[i].id);
+      }
+      this.filterStr = this.filterStr.substr(0, this.filterStr.length - 1)
+      let data = {
+        conditionQuestionList: conditionQuestionList,
+        testThemesIdList: testThemesIdList
+      }
+      api.answerData(data).then((res) => {
+        if (res.success) {
+          console.log("success", res);
+          var answerData = res.single;
+          for (var i = 0; i < answerData.questionList.length; i++) {
+            var element = answerData.questionList[i]
+            console.log("found", found);
+            if (element.belongTestOrder <= this.options.length) {
+              element.lable = this.options[element.belongTestOrder - 1].label;
+            }
+
+            const found = conditionQuestionList.find(element => element.questionId == element.questionId);
+            if (found) {
+              if (found.questionId == element.questionId) {
+                element.isFilter = true
+              } else {
+                element.isFilter = false
+              }
+            }
+          }
+          console.log("answerData", answerData);
+          this.answerData = answerData;
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    saveOnLine() {
+      var checkList = [];
+
+      for (var i = 0; i < this.questionChilds.length; i++) {
+        var question = this.questionChilds[i]
+        for (var j = 0; j < question.length; j++) {
+          var option = question[j];
+          var questionObj = this.questionListSel[i];
+          checkList.push({ subOptionContent: option.content, subOptionId: option.optionId, subQuestionContent: questionObj.content, subQuestionId: questionObj.questionId })
+        }
+      }
+
+      console.log("编辑数据包", checkList);
+      this.$prompt("请数据包名称", "提保存筛选条件作为数据包", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/,
+        inputErrorMessage: "数据包名称不为空",
+        inputValue: this.title
+      })
+        .then(({ value }) => {
+          let param = {
+            checkList: checkList,
+            analyseBagTitle: value,
+            operator: "admin"
+          };
+          api.saveAnalyseBag(param).then(res => {
+            if (res.success) {
+              this.$message.success("保存成功");
+            } else {
+              this.$message.error("数据加载失败,请重试");
+            }
+          });
+        })
+        .catch(() => { });
+    },
+    async getCrossAnalyse() {
+
+      var analyseBagIdList = [];
+      var province = ""
+      var city = ""
+      var district = ""
+
+      if (this.analyseCommandSel == "数据包") {
+        if (this.analyseValue.length > 0) {
+          analyseBagIdList.push(this.analyseValue[0])
+        }
+      } else if (this.analyseCommandSel == "区域") {
+        if (this.analyseValue.length > 0) {
+          province = this.analyseValue[0]
+        } else if (this.analyseValue.length > 1) {
+          city = this.analyseValue[1]
+        } else if (this.analyseValue.length > 2) {
+          district = this.analyseValue[2]
+        }
+      }
+      var testThemesIdList = [];
+      for (var i = 0; i < this.options.length; i++) {
+        testThemesIdList.push(this.options[i].id);
+      }
+      var xlist = [];
+      var ylist = [];
+      for (var i = 0; i < this.questionList.length; i++) {
+        var item = this.questionList[i];
+        for (var j = 0; j < item.length; j++) {
+          for (var m = 0; m < this.optionsXValue.length; m++) {
+            var element = this.optionsXValue[m];
+            if (item[j].questionId == element[1]) {
+              xlist.push(item[j]);
+            }
+          }
+          for (var n = 0; n < this.optionsYValue.length; n++) {
+            var element = this.optionsYValue[n];
+            if (item[j].questionId == element[1]) {
+              ylist.push(item[j]);
+            }
+          }
+        }
+      }
+
+      let data = {
+        province: province,
+        city: city,
+        district: district,
+        analyseBagIdList: analyseBagIdList,
+        testThemesIdList: testThemesIdList,
+        xlist: xlist,
+        ylist: ylist
+      }
+      console.log("XXXXXX", data);
+      api.crossAnalyse(data).then((res) => {
+        if (res.success) {
+          console.log("success", res.list);
+          var crossAnalyse = res.list;
+          this.crossAnalyse = []
+          var result = [];
+          var rowArr = [];
+          for (var n = 0; n < crossAnalyse.length; n++) {
+            var arrs = []
+            var crossResult = crossAnalyse[n].crossResult;
+            console.log("XXXXX", Object.keys(crossResult), Object.values(crossResult))
+            rowArr = Object.keys(crossResult);
+            var values = Object.values(crossResult)
+            for (var m = 0; m < values.length; m++) {
+              console.log("SSSSS", Object.keys(values[m]), Object.values(values[m]))
+              arrs.push({ name: Object.keys(values[m]), value: Object.values(values[m]) })
+            }
+            result.push(arrs);
+          }
+
+          // console.log("AAAAAA", result);
+
+          for (var x = 0; x < result.length; x++) {
+            var qqq = result[x];
+            var sss = [];
+            for (var q = 0; q < qqq.length; q++) {
+              sss.push({ name: rowArr[q], title: qqq[q].name, value: qqq[q].value })
+            }
+            this.crossAnalyse.push({ table: sss, data: [], question: null, name: null });
+          }
+          // console.log("SSSSS", this.crossAnalyse);
+
+          for (var x = 0; x < this.crossAnalyse.length; x++) {
+            var data = [];
+            var top = this.crossAnalyse[x].table;
+            for (var y = 0; y < top.length; y++) {
+              var one = top[y].value;
+              // console.log("one", top[y].name)
+              var total = 0;
+              for (var z = 0; z < one.length; z++) {
+                var two = one[z];
+                var p = total == 0 ? 0 : ((two / total) * 100).toFixed(0)
+                if (top[y].title[z] != "total") {
+                  data.push({ time: top[y].name, type: top[y].title[z], value: two, total: p })
+                } else {
+                  total = two
+                }
+              }
+            }
+
+            this.crossAnalyse[x].data = data;
+            this.crossAnalyse[x].question = data;
+
+            const found = this.optionsY.find(element => element.id == this.optionsYValue[x][0]);
+            // console.log("XXXXXXXXXfound", found);
+            if (found) {
+              const children = found.children.find(element => element.value == this.optionsYValue[x][1]);
+              // console.log("XXXXXXXXXchildren", children);
+              if (children) {
+                this.crossAnalyse[x].name = children.label
+              }
+            }
+
+          }
+          console.log("data", this.crossAnalyse);
+
+        } else {
+          console.log("error");
+        }
+      });
+    },
+    goToPreviewPage() {
+
+      this.$router.push({
+        name: 'previewPage',
+        params: {
+          chartData: this.chartData,
+          answerData: this.answerData,
+          currentDate: this.currentDate,
+          options: this.options,
+          filterStr: this.filterStr,
+          isShowTable: this.isShowTable,
+          isCrossAnalyse: this.isCrossAnalyse,
+          crossAnalyse: this.crossAnalyse
+        }
+      })
+    }
+
+
+  },
+}

+ 622 - 0
src/views/testData/testData.scss

@@ -0,0 +1,622 @@
+.page {
+  padding: 60px 0px;
+  width: 100%;
+  height: 100%;
+  background: rgba(237,239,247,1);
+}
+.testData {
+  width: 1180px;  
+  margin: 0 auto;
+  display: flex;
+  flex-direction: column;
+  .testList {
+    width: 100%;
+    height: 148px;
+    background: white;
+    margin-top: 16px;
+    border-radius:6px;
+    .testProject {
+      margin-top: 16px;
+      margin-left: 135px;
+      .el-button{
+        padding: 7px 20px;
+        position: relative
+      }
+      .el-button--primary{
+        width: 144px;
+        height: 32px;
+        border-radius: 17px;
+        font-size: 14px;
+        color: #4E5DFF;
+        background:rgba(245,248,255,1);
+        border-color: #fff;
+      }
+      .el-button--primary:focus,.el-button--primary:hover {
+        background: #4E5DFF;
+        border-color: #4E5DFF;
+        color: #fff;
+      }
+    }
+    .testItem {
+      width: calc(100% - 200px);
+      height: 84px;
+      display: flex;
+      flex-direction: row;
+      margin-left: 100px;
+      margin-top: 16px;
+      .itemArrow {
+        width: 30px;
+        height: 100%;
+        margin-top: 20px;
+        cursor: pointer;
+        font-size: 30px;
+        color: #999999;
+      }
+      .testContent {
+        flex-grow: 2;
+        display: flex;
+        flex-direction: row;
+        overflow-x: auto;
+        .testTopic {
+          width: 145px;
+          height: 68px;
+          margin:0px 5px;
+          flex-shrink: 0;
+          background:rgba(237,237,237,1);
+          border-radius:2px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(100,107,129,1);
+          line-height:20px;
+          padding: 5px;
+          box-sizing: border-box;
+          position: relative;
+          .testSel {
+            position: absolute;
+            bottom: 2px;
+            right: 2px;
+            width: 16px;
+            height: 16px;
+            cursor: pointer;
+          }
+        }
+        .testTopicSel {
+          background:rgba(78,93,255,1);
+          color:rgba(255,255,255,1);
+        }
+      }
+    }
+  }
+  .testTip {
+    width: 100%;
+    height: 80px;
+    line-height: 80px;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    font-size:18px;
+    font-family:PingFangSC-Medium,PingFang SC;
+    font-weight:500;
+    color:rgba(51,51,51,1);
+    .switchItem {
+      display: flex;
+      flex-direction: row;
+      height: 40px;
+      background:rgba(255,255,255,1);
+      border-radius:20px;
+      .switch {
+        width: 80px;
+        height: 40px;
+        line-height: 40px;
+        background:rgba(255,255,255,1);
+        border-radius:20px;
+        text-align: center;
+        font-size:14px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(78,93,255,1);
+        cursor: pointer;
+      }
+      .switchSelected {
+        color:rgba(255,255,255,1);
+        background:rgba(78,93,255,1);
+      }
+    }
+    .analyseBag {
+      display: flex;
+      flex-direction: row;
+      width:340px;
+      height:34px;
+      background:rgba(255,255,255,1);
+      border-radius:17px;
+      .analyseBagTitle {
+        width:64px;
+        height:34px;
+        border-radius:17px;
+        text-align: center;
+        font-size:14px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(255,255,255,1);
+        line-height:34px;
+        .el-button{
+          padding: 7px 0px;
+          position: relative
+        }
+        .el-button--primary{
+          width:64px;
+          height:34px;
+          border-radius: 17px;
+          font-size: 14px;
+          color: #fff;
+          background: #4E5DFF;
+          border-color: #fff;
+        }
+        .el-button--primary:focus,.el-button--primary:hover {
+          background: #4E5DFF;
+          border-color: #4E5DFF;
+          color: #fff;
+        }
+      }
+      .analyseBagList {
+        height: 34px;
+        margin-top: -24px;
+        .el-cascader {
+          width: 260px;
+          background:rgba(241,241,241,1);
+          line-height: 34px;
+          font-size:14px;
+          color:rgba(51,51,51,1);
+          .el-input__inner {
+            height: 34px;
+            line-height: 34px;
+            background:rgba(255,255,255,1);
+            border: 0px;
+          }
+          .el-input__icon {
+            line-height: 34px;
+          }
+        }
+      }
+    }
+    .addBag {
+      font-size:12px;
+      font-family:PingFangSC-Regular,PingFang SC;
+      font-weight:400;
+      color:rgba(100,107,129,1);
+      line-height:17px;
+      cursor: pointer;
+      padding-left: 10px;
+    }
+  }
+  .answer {
+    width: 100%;
+    background: white;
+    border-radius:6px;
+    padding: 24px 120px;
+    box-sizing: border-box;
+    .filter {
+      width: 100%;
+      height: 40px;
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      .filterIcon {
+        width: 100px;
+        height: 40px;
+        cursor: pointer;
+      }
+      .rightFilter {
+        display: flex;
+        flex-direction: row;
+        .rightFilterItem {
+          width: 48px;
+          height: 24px;
+          font-size:12px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(153,160,182,1);
+          line-height:24px;
+          border-radius:14px;
+          border:1px solid rgba(153,160,182,1);
+          text-align: center;
+          margin: 0px 4px;
+          cursor: pointer;
+        }
+        .rightFilterItemSel {
+          color:rgba(78,93,255,1);
+          border:1px solid rgba(78,93,255,1);
+        }
+      }
+    }
+    .filterContent {
+      width: 100%;
+      .filterView {
+        background:rgba(250,250,250,1);
+        border-radius:6px;
+        padding: 24px 16px;
+      }
+      .filterItem {
+        width: 100%;
+        margin: 4px 0px;
+        display: flex;
+        flex-direction: row;
+        box-sizing: border-box;
+        .filterTitle {
+          margin-top: 5px;
+          margin-left: 8px;
+          font-size:14px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(51,51,51,1);
+          line-height:20px;
+          flex-shrink: 0;
+          width: 57px;
+        }
+        .filterAnswer {
+          margin-left: 10px;
+          flex-shrink: 0;
+          margin-right: 10px;
+          .el-cascader {
+            width: 320px;
+            background:rgba(241,241,241,1);
+            line-height: 30px;
+            font-size:14px;
+            color:rgba(51,51,51,1);
+            .el-input__inner {
+              height: 30px;
+              line-height: 30px;
+              background:rgba(241,241,241,1);
+            }
+            .el-input__icon {
+              line-height: 30px;
+            }
+          }
+        }
+        .filterReply {
+          display: flex;
+          align-items:center;
+        }
+      }
+      .addfilter{
+        width:320px;
+        height:30px;
+        border:1px dashed rgba(202,204,210,1);
+        margin-left: 74px;
+        margin-top: 8px;
+        display: flex;
+        flex-direction: row;
+        justify-content: center;
+        align-items: center;
+        cursor: pointer;
+        .addfilterIcon {
+          width: 74px;
+          height: 18px;
+        }
+      }
+      .filterDel {
+        cursor: pointer;
+        display: flex;
+        align-items:center;
+        color: #646B81;
+        margin-left: 10px;
+      }
+      .filterSave {
+        height: 28px;
+        margin-left: 74px;
+        margin-top: 16px;
+        display: flex;
+        text-align: center;
+        .saveLocation {
+          width:80px;
+          height:28px;
+          background:rgba(78,93,255,1);
+          border-radius:14px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(255,255,255,1);
+          line-height:28px;
+          cursor: pointer;
+        }
+        .saveOnLine {
+          margin-left: 16px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(78,93,255,1);
+          line-height:28px;
+          width:200px;
+          height:28px;
+          border-radius:14px;
+          border:1px solid rgba(78,93,255,1);
+          cursor: pointer;
+        }
+      }
+      .filterResult {
+        font-size:14px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(51,51,51,1);
+        line-height:20px;
+        border-bottom: 1px dashed #E8E8E8;
+        padding-top: 4px;
+        padding-bottom: 15px;
+      }
+    }
+    .result {
+      .resultItem {
+        margin-top: 36px;
+        padding-bottom: 20px;
+        border-bottom:1px dashed rgba(202,204,210,1);
+        .testLable {
+          font-size:18px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(78,93,255,1);
+          line-height:25px;
+          margin-bottom: 10px;
+          padding-bottom: 10px;
+          width: 100%;
+          border-bottom: 1px dashed #E8E8E8;
+        }
+        .resultTitle {
+          display: flex;
+          flex-direction: row;
+          align-items: center;
+          font-size:18px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(51,51,51,1);
+          line-height:25px;
+        }
+        .resultTable {
+
+          border-radius:4px;
+          border:1px solid rgba(232,232,232,1);
+          margin-top: 8px;
+        }
+        .tableHeader {
+          display: flex;
+          flex-direction: row;
+          height: 32px;
+          background:rgba(250,250,250,1);
+          border-radius:4px 0px 0px 0px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(0,0,0,0.85);
+          line-height:21px;
+          align-items:flex-end;
+          .option {
+           flex-grow: 2;
+           padding-left: 25px;
+           box-sizing: border-box;
+          }
+          .numbers {
+            width:236px;
+            height: 100%;
+            padding-top: 8px;
+            padding-left: 25px;
+            box-sizing: border-box;
+            border-left:1px solid rgba(232,232,232,1);
+            border-right:1px solid rgba(232,232,232,1);
+          }
+          .percent {
+            width: 408px;
+            padding-left: 25px;
+            box-sizing: border-box;
+          }
+        }
+        .tableRow {
+          display: flex;
+          flex-direction: row;
+          min-height: 32px;
+          font-size:14px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(0,0,0,0.65);
+          line-height:21px;
+          .option {
+           flex-grow: 2;
+           height: 100%;
+           padding-top: 8px;
+           padding-left: 25px;
+           box-sizing: border-box;
+           border-top:1px solid rgba(232,232,232,1);
+          padding: 8px 15px;
+          }
+          .numbers {
+            width:236px;
+            min-height: 100%;
+            padding: 0px 15px;
+            padding-left: 25px;
+            box-sizing: border-box;
+            border-left:1px solid rgba(232,232,232,1);
+            border-right:1px solid rgba(232,232,232,1);
+            border-top:1px solid rgba(232,232,232,1);
+            flex-shrink: 0;
+            display: flex;
+            align-items: center;
+          }
+          .percent {
+            width: 408px;
+            min-height: 100%;
+            padding-left: 25px;
+            box-sizing: border-box;
+            border-top:1px solid rgba(232,232,232,1);
+            flex-shrink: 0;
+            display: flex;
+            align-items: center;
+          }
+        }
+      }
+    }
+    .chart {
+      display: flex;
+      flex-direction: column;
+      margin-top: 30px;
+      .chartItem {
+        display: flex;
+        flex-direction: column;
+        .chartTitle {
+          font-size:18px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(51,51,51,1);
+          line-height:25px;
+        }
+        .chartData {
+          width: 100%;
+          margin: 10px 0px;
+        }
+      }
+    }
+    
+  }
+  .crossAnalyse {
+    width: 100%;
+    background: white;
+    border-radius:6px;
+    padding: 24px 120px;
+    box-sizing: border-box;
+    .crossFilter{
+      background:rgba(250,250,250,1);
+      border-radius:6px;
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+      flex-wrap:wrap;
+      .xyFilter {
+        width: 360px;
+        .el-cascader {
+          width: 320px;
+          background:rgba(241,241,241,1);
+          line-height: 30px;
+          font-size:14px;
+          color:rgba(51,51,51,1);
+          .el-input__inner {
+            height: 30px;
+            line-height: 30px;
+            background:rgba(241,241,241,1);
+          }
+          .el-input__icon {
+            line-height: 30px;
+          }
+        }
+        .addfilter{
+          width:320px;
+          height:30px;
+          border:1px dashed rgba(202,204,210,1);
+          margin-top: 8px;
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          align-items: center;
+          cursor: pointer;
+          .addfilterIcon {
+            width: 74px;
+            height: 18px;
+          }
+        }
+      }
+      .crossFilterTitle {
+        font-size:14px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:20px;
+      }
+      .crossFilterSubTitle {
+        font-size:12px;
+        font-family:PingFangSC-Regular,PingFang SC;
+        font-weight:400;
+        color:rgba(51,51,51,1);
+        line-height:20px;
+      }
+      .analyse {
+        width: 100%;
+        margin: 16px 0px;
+        display: flex;
+        flex-direction: row;
+        .startAnalyse {
+          margin-left: 90px;
+          width:80px;
+          height:28px;
+          background:rgba(78,93,255,1);
+          border-radius:14px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(255,255,255,1);
+          line-height:28px;
+          text-align: center;
+          cursor: pointer;
+        }
+        .analyseTip {
+          font-size:12px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(255,0,0,1);
+          line-height:28px;
+          margin-left: 8px;
+        }
+      }
+    }
+    .crossAnalyseTable {
+      .crossAnalyseTitle {
+        font-size:18px;
+        font-family:PingFangSC-Medium,PingFang SC;
+        font-weight:500;
+        color:rgba(51,51,51,1);
+        line-height:25px;
+        margin-top: 32px;
+      }
+      .crossAnalyseChart {
+        width: 100%;
+        margin: 8px 0px;
+      }
+      .table{
+        border-radius:4px;
+        border-top:1px solid rgba(232,232,232,1); 
+        border-left:1px solid rgba(232,232,232,1); 
+      }
+      .caTable {
+        display: flex;
+        flex-direction: row;
+        .headerRow {
+          background:rgba(250,250,250,1);
+          border-radius:4px 0px 0px 0px;
+          font-size:14px;
+          font-family:PingFangSC-Medium,PingFang SC;
+          font-weight:500;
+          color:rgba(0,0,0,0.85);
+          line-height:21px;
+          align-items:flex-end;
+          padding-top: 8px;
+          padding-bottom: 12px;
+          box-sizing: border-box;
+          border-bottom: 1px solid #E8E8E8;
+          border-right: 1px solid #E8E8E8;
+        }
+        .tabkeRow {
+          font-size:14px;
+          font-family:PingFangSC-Regular,PingFang SC;
+          font-weight:400;
+          color:rgba(0,0,0,0.65);
+          line-height:21px;
+          align-items:flex-end;
+          padding-top: 8px;
+          padding-bottom: 1px;
+          padding-left: 5px;
+          box-sizing: border-box;
+          border-bottom: 1px solid #E8E8E8;
+          border-right: 1px solid #E8E8E8;
+        }
+        
+      }
+    }
+  }
+}

+ 7 - 0
src/views/testData/testData.vue

@@ -0,0 +1,7 @@
+<template src='./testData.html'>
+</template>
+<script src="./testData.js">
+</script>
+<style lang="scss">
+@import "./testData.scss";
+</style>