MessageAnalyse.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <style lang="scss">
  2. .content {
  3. // height: 80vh;
  4. }
  5. // 新
  6. .item {
  7. font-size: 14px;
  8. margin-bottom: 20px;
  9. .item-title {
  10. margin-bottom: 10px;
  11. color: #606266;
  12. .title-num {
  13. display: inline-block;
  14. // width:50px;
  15. font-weight: bold;
  16. }
  17. .title-header {
  18. // font-weight: 600;
  19. }
  20. .title-type {
  21. margin-left: 10px;
  22. }
  23. .title-download {
  24. color: #409eff;
  25. cursor: pointer;
  26. }
  27. }
  28. .item-content {
  29. // margin-left:60px;
  30. display: flex;
  31. .el-table {
  32. flex: 1.5;
  33. }
  34. div {
  35. flex: 1;
  36. }
  37. }
  38. }
  39. </style>
  40. <template>
  41. <section>
  42. <p><span>信息管理></span>问卷统计</p>
  43. <div class="content">
  44. <div class="download-all" style="display: inline-block; float: right">
  45. <el-button
  46. type="primary"
  47. icon="el-icon-download"
  48. size="mini"
  49. @click="downloadAll"
  50. >导出excel</el-button
  51. >
  52. </div>
  53. <div class="item" v-for="(item, index) in results" :key="index">
  54. <div class="item-title">
  55. <span class="title-num">第{{ index + 1 }}题:</span>
  56. <span class="title-header">{{ item.label }}</span>
  57. <span class="title-type">{{ item.type | getType }}</span>
  58. <span class="title-download" @click="downloadItem(item)"
  59. >导出Excel</span
  60. >
  61. </div>
  62. <!-- <div
  63. class="item-content"
  64. v-if="item.type == 'input' || item.type == 'textarea'"
  65. >
  66. 【答案】:<span v-for="(item1, index) in item.result" :key="index"
  67. >{{ item1 }}{{ index == item.result.length - 1 ? "" : "、" }}</span
  68. >
  69. </div> -->
  70. <div
  71. class="item-content"
  72. v-if="item.type == 'input' || item.type == 'textarea'"
  73. >
  74. 【答案】:<el-button
  75. type="primary"
  76. size="mini"
  77. @click="showItemResult(item)"
  78. >查看详情</el-button
  79. >
  80. </div>
  81. <div class="item-content" v-if="item.type == 'image'">
  82. 【答案】:<el-button
  83. type="primary"
  84. size="mini"
  85. @click="showItemResult(item)"
  86. >查看详情</el-button
  87. >
  88. </div>
  89. <div
  90. class="item-content"
  91. v-if="item.type == 'radio' || item.type == 'checkbox'"
  92. >
  93. <el-table :data="item.items" border>
  94. <el-table-column prop="label" label="选项"> </el-table-column>
  95. <el-table-column prop="times" label="次数"> </el-table-column>
  96. <el-table-column prop="sale" label="比例">
  97. <template slot-scope="scope">
  98. <el-progress :percentage="scope.row.sale"></el-progress>
  99. </template>
  100. </el-table-column>
  101. </el-table>
  102. <div
  103. :id="`chartPie${index}`"
  104. style="width: 500px; height: 250px"
  105. ></div>
  106. <div
  107. :id="`chartBar${index}`"
  108. style="width: 500px; height: 250px"
  109. ></div>
  110. </div>
  111. </div>
  112. </div>
  113. <!-- 查看答题详情 -->
  114. <el-dialog
  115. :title="dialogTitle"
  116. :close-on-click-modal="false"
  117. :visible.sync="dialogVisible"
  118. >
  119. <div class="content">
  120. <div class="filter">
  121. <el-form
  122. size="small"
  123. label-width="70px"
  124. :inline="true"
  125. label-position="left"
  126. >
  127. <el-form-item label="">
  128. <el-input
  129. clearable
  130. placeholder="请输入标题"
  131. v-model="form.name"
  132. @clear="search"
  133. @keyup.enter.native="search"
  134. ></el-input>
  135. </el-form-item>
  136. <el-form-item>
  137. <el-button type="primary" @click="search">搜索</el-button>
  138. </el-form-item>
  139. <el-form-item style="float: right">
  140. <el-button
  141. type="primary"
  142. icon="el-icon-download"
  143. size="mini"
  144. @click="downloadItem(cur_item)"
  145. >导出excel</el-button
  146. >
  147. </el-form-item>
  148. </el-form>
  149. </div>
  150. <el-table
  151. class="table"
  152. :data="analyseDataList"
  153. height="50vh"
  154. border
  155. v-loading="loading"
  156. default-expand-all
  157. row-key="id"
  158. style="width: 100%"
  159. >
  160. <el-table-column label="序号" type="index" width="50" align="center">
  161. </el-table-column>
  162. <template v-for="(item, key) in this.headers">
  163. <el-table-column
  164. v-if="curItemType=='image'"
  165. :key="key"
  166. :prop="item"
  167. :label="item"
  168. >
  169. <template slot-scope="scope">
  170. <img :src="url" alt="" v-for="(url,iindex) in scope.row[item]" :key="iindex" width="80" height="60">
  171. </template>
  172. </el-table-column>
  173. <el-table-column
  174. v-else
  175. :key="key"
  176. :prop="item"
  177. :label="item"
  178. >
  179. </el-table-column>
  180. </template>
  181. </el-table>
  182. <Page
  183. ref="pageButton"
  184. :current="form.page"
  185. :page_size="form.page_size"
  186. :total="total"
  187. @pageChange="gopage"
  188. />
  189. </div>
  190. </el-dialog>
  191. </section>
  192. </template>
  193. <script>
  194. import Page from "../../components/Page";
  195. import echarts from "echarts";
  196. export default {
  197. components: {
  198. Page,
  199. },
  200. data() {
  201. return {
  202. // checked: [],
  203. curItemType:'',
  204. form: {},
  205. total: 1,
  206. loading: false,
  207. results: [],
  208. dialogTitle: "",
  209. dialogVisible: false,
  210. analyseDataList: [],
  211. headers: [],
  212. cur_item: null,
  213. };
  214. },
  215. filters: {
  216. getType(val) {
  217. if ((val == "input") | (val == "textarea")) {
  218. return "【填空题】";
  219. } else if (val == "radio") {
  220. return "【单选题】";
  221. } else if (val == "checkbox") {
  222. return "【多选题】";
  223. }
  224. },
  225. },
  226. methods: {
  227. gopage(size) {
  228. if (size) {
  229. this.form.page_size = size;
  230. }
  231. this.form.page = this.$refs.pageButton.page;
  232. this.showItemResult();
  233. },
  234. downloadAll() {
  235. let message_id = this.$route.query.id;
  236. let type = this.$route.query.type;
  237. this.$api
  238. .downloadAnalyseAll({ message_id: message_id, type: type })
  239. .then((res) => {
  240. var elink = document.createElement("a");
  241. let blob = new Blob([res.data], {
  242. type: "application/vnd.ms-excel,charset=UTF-8",
  243. });
  244. let objUrl = URL.createObjectURL(blob);
  245. let file_name = decodeURIComponent(
  246. res.headers["content-disposition"].split("=")[1]
  247. );
  248. console.log(file_name);
  249. elink.download = file_name;
  250. elink.style.display = "none";
  251. elink.href = objUrl;
  252. document.body.appendChild(elink);
  253. elink.click();
  254. document.body.removeChild(elink);
  255. this.download_loading = false;
  256. });
  257. },
  258. downloadItem(item) {
  259. let message_id = this.$route.query.id;
  260. let type = this.$route.query.type;
  261. this.$api
  262. .downloadAnalyseItem({
  263. message_id: message_id,
  264. type: type,
  265. item: item.label,
  266. })
  267. .then((res) => {
  268. var elink = document.createElement("a");
  269. let blob = new Blob([res.data], {
  270. type: "application/vnd.ms-excel,charset=UTF-8",
  271. });
  272. let objUrl = URL.createObjectURL(blob);
  273. let file_name = decodeURIComponent(
  274. res.headers["content-disposition"].split("=")[1]
  275. );
  276. console.log(file_name);
  277. elink.download = file_name;
  278. elink.style.display = "none";
  279. elink.href = objUrl;
  280. document.body.appendChild(elink);
  281. elink.click();
  282. document.body.removeChild(elink);
  283. this.download_loading = false;
  284. });
  285. },
  286. showItemResult(item) {
  287. this.curItemType = item.type
  288. this.dialogTitle = '"' + item.label + '"答案详情';
  289. let message_id = this.$route.query.id;
  290. let type = this.$route.query.type;
  291. var parm = this.form;
  292. parm.message_id = message_id;
  293. parm.type = type;
  294. parm.item = item.label;
  295. this.$api.showAnalyseItem(parm).then((res) => {
  296. let data = res.data.data;
  297. this.headers = Object.keys(data[0]);
  298. this.analyseDataList = data;
  299. });
  300. this.dialogVisible = true;
  301. this.cur_item = item;
  302. },
  303. search() {
  304. let item = this.cur_item;
  305. let parm = this.form;
  306. let message_id = this.$route.query.id;
  307. let type = this.$route.query.type;
  308. parm.message_id = message_id;
  309. parm.type = type;
  310. parm.item = item.label;
  311. this.$api.showAnalyseItem(parm).then((res) => {
  312. let data = res.data.data;
  313. this.headers = Object.keys(data[0]);
  314. this.analyseDataList = data;
  315. });
  316. },
  317. getData() {
  318. let message_id = this.$route.query.id;
  319. let type = this.$route.query.type;
  320. this.$api
  321. .getMessageSurveyQuestionAnalyse({ id: message_id, type: type })
  322. .then((res) => {
  323. this.results = res.data.data;
  324. this.results.forEach((item, index) => {
  325. this.$nextTick(function () {
  326. this.getEcharts(item, index);
  327. });
  328. });
  329. });
  330. },
  331. getEcharts(item, index) {
  332. var myChart = this.$echarts.init(
  333. document.getElementById(`chartBar${index}`)
  334. );
  335. var myChart1 = this.$echarts.init(
  336. document.getElementById(`chartPie${index}`)
  337. );
  338. let dataPie = [];
  339. let dataBarX = [];
  340. let dataBarY = [];
  341. let colors = [
  342. "#9379ff",
  343. "#62A2FF",
  344. "#FFD053",
  345. "#FF9F41",
  346. "#FF542C",
  347. "#FE8463",
  348. "#9BCA63",
  349. "#FAD860",
  350. "#F3A43B",
  351. "#60C0DD",
  352. "#D7504B",
  353. "#C6E579",
  354. "#F4E001",
  355. "#F0805A",
  356. "#26C0C0",
  357. ];
  358. let pieColors = [];
  359. item.items.forEach((item, index) => {
  360. dataPie.push({
  361. name: item.label,
  362. value: item.times,
  363. color: colors[index],
  364. itemStyle: {
  365. normal: {
  366. label: {
  367. show: true,
  368. color: colors[index],
  369. },
  370. labelLine: {
  371. show: true,
  372. color: colors[index],
  373. },
  374. },
  375. },
  376. });
  377. dataBarX.push(item.label);
  378. dataBarY.push({
  379. sale: item.sale,
  380. value: item.times,
  381. itemStyle: { color: colors[index] },
  382. });
  383. });
  384. dataPie = dataPie.filter(function (x) {
  385. if (x.value == 0) {
  386. return false;
  387. }
  388. return true;
  389. });
  390. dataPie.forEach((item, index) => {
  391. pieColors.push(item.color);
  392. });
  393. let option = {
  394. title: {
  395. subtext: "填报次数",
  396. },
  397. color: ["#5066FF"],
  398. tooltip: {
  399. trigger: "axis",
  400. axisPointer: {
  401. // 坐标轴指示器,坐标轴触发有效
  402. type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
  403. },
  404. },
  405. grid: {
  406. left: "2%",
  407. right: "4%",
  408. bottom: "3%",
  409. // top:'0px',
  410. containLabel: true,
  411. },
  412. xAxis: [
  413. {
  414. type: "category",
  415. data: dataBarX,
  416. axisTick: {
  417. alignWithLabel: true,
  418. },
  419. axisLine: {
  420. lineStyle: {
  421. color: "#D4D8EE",
  422. width: 2,
  423. type: "dotted",
  424. },
  425. },
  426. axisLabel: {
  427. // formatter:function(val) {
  428. // console.log(val,"")
  429. // return '中国科' //对每个标签处理后的结果(通过js字符串方法处理)
  430. // },
  431. formatter: function (value, index) {
  432. // 10 6 这些你自定义就行
  433. var v = value.substring(0, 6) + "...";
  434. return value.length > 10 ? v : value;
  435. },
  436. // x轴字体颜色
  437. textStyle: {
  438. color: "#999999",
  439. // lineHeight: 20,
  440. fontSize: 12,
  441. },
  442. align: "center",
  443. // padding:[10,0 ,0,-40],
  444. },
  445. },
  446. ],
  447. yAxis: [
  448. {
  449. type: "value",
  450. boundaryGap: ["0%", "20%"],
  451. axisTick: {
  452. show: false,
  453. },
  454. minInterval: 1,
  455. axisLine: {
  456. show: false,
  457. },
  458. axisLabel: {
  459. show: true,
  460. textStyle: {
  461. color: "#666666", //更改坐标轴文字颜色
  462. fontSize: 14, //更改坐标轴文字大小
  463. },
  464. },
  465. splitLine: {
  466. show: true,
  467. lineStyle: {
  468. type: "dashed",
  469. },
  470. },
  471. // data:['0' , '100' , '200' , '300,400]
  472. },
  473. ],
  474. series: [
  475. {
  476. name: "次数",
  477. type: "bar",
  478. barWidth: "30px",
  479. data: dataBarY,
  480. itemStyle: {
  481. //柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
  482. normal: {
  483. //柱形图圆角,初始化效果
  484. barBorderRadius: [10, 10, 10, 10],
  485. label: {
  486. show: true,
  487. position: "top",
  488. formatter: function (v) {
  489. return v.data.sale ? v.data.sale + "%" : "0%";
  490. },
  491. },
  492. },
  493. },
  494. },
  495. ],
  496. };
  497. let option1 = {
  498. // backgroundColor: '#dddddd',
  499. // title: {
  500. // text: 'Customized Pie',
  501. // left: 'center',
  502. // top: 20,
  503. // textStyle: {
  504. // color: '#ccc'
  505. // }
  506. // },
  507. color: pieColors,
  508. tooltip: {
  509. trigger: "item",
  510. formatter: "{a} <br/>{b} : {c} ({d}%)",
  511. },
  512. series: [
  513. {
  514. name: "访问来源",
  515. type: "pie",
  516. radius: "65%",
  517. // center: ['50%', '50%'],
  518. data: dataPie.sort(function (a, b) {
  519. return a.value - b.value;
  520. }),
  521. // roseType: 'radius',
  522. // label: {
  523. // color: "rgba(102, 102, 102,1)",
  524. // fontSize: 14,
  525. // },
  526. // labelLine: {
  527. // // show:false,
  528. // lineStyle: {
  529. // color: "rgba(000, 000, 000, 0.1)",
  530. // },
  531. // smooth: 0.2,
  532. // length: 20,
  533. // length2: 8,
  534. // },
  535. // itemStyle: {
  536. // // color: '#c23531',
  537. // // shadowBlur: 200,
  538. // // shadowColor: 'rgba(0, 0, 0, 0.5)'
  539. // normal:{
  540. // label:{
  541. // show: function(val){
  542. // console.log(val,222222222)
  543. // return false
  544. // },
  545. // },
  546. // labelLine: {
  547. // show: true
  548. // }
  549. // }
  550. // },
  551. data: dataPie.sort(function (a, b) {
  552. return a.value - b.value;
  553. }),
  554. animationType: "scale",
  555. animationEasing: "elasticOut",
  556. animationDelay: function (idx) {
  557. return Math.random() * 200;
  558. },
  559. },
  560. ],
  561. };
  562. myChart.setOption(option);
  563. myChart1.setOption(option1);
  564. },
  565. },
  566. mounted() {
  567. this.results.forEach((item, index) => {
  568. this.$nextTick(function () {
  569. this.getEcharts(item, index);
  570. });
  571. });
  572. },
  573. created() {
  574. this.getData();
  575. },
  576. };
  577. </script>