WebQn.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. <template>
  2. <div>
  3. <!-- page title -->
  4. <div v-if="showHello">
  5. <mt-header type="default" title="问卷调查-问候语" fixed></mt-header>
  6. </div>
  7. <div v-else-if="stage == 1">
  8. <mt-header title="问卷调查-问卷题目" fixed>
  9. <mt-button v-if="questionHEAD!=0" icon="back" slot="left" @click="onPreTap">返回</mt-button>
  10. </mt-header>
  11. </div>
  12. <div v-else-if="stage == 2">
  13. <mt-header title="问卷调查-结束语" fixed></mt-header>
  14. <p>
  15. <img src="static/ending-image.jpeg" style="width: 100%;" />
  16. </p>
  17. </div>
  18. <!-- 问候语 -->
  19. <div v-if="showHello">
  20. <p style="margin: 80px 0;">{{questionaire.info.hello}}</p>
  21. <mt-button type="primary" @click="start" class="button-bottom">继续</mt-button>
  22. </div>
  23. <!-- 问卷题目 -->
  24. <div rows="auto * auto" v-else-if="stage==1">
  25. <!-- 题目问题 -->
  26. <div style="margin:20px 0 40px 0">
  27. <!-- <Progress :value="questionHEAD" :maxValue="questionaire.questions.length" /> -->
  28. <mt-progress :value="percent" :bar-height="5" style="margin-top: -30px;"></mt-progress>
  29. <div>
  30. <span class="h3">{{questionHEAD + 1}}、</span>
  31. <span class="h3" style="margin-left: 5;">[</span>
  32. <span class="h3">{{questionType}}</span>
  33. <span class="h3">{{multipleTip}}</span>
  34. <span class="h3" style="margin-right: 5;">]</span>
  35. </div>
  36. <p class="h3">{{questionBody}}</p>
  37. <span class="h3">{{questionRemark}}</span>
  38. </div>
  39. <mt-radio
  40. style="display: inline-block;"
  41. v-if="questionType == '单选题'"
  42. v-model="selectedSingle"
  43. :options="questionOptions"
  44. @change="onOptionSelected"
  45. ></mt-radio>
  46. <mt-checklist
  47. style="display: inline-block;"
  48. v-else-if="questionType == '多选题'"
  49. v-model="selectedMultiple"
  50. :options="questionOptions"
  51. @change="onOptionSelected"
  52. ></mt-checklist>
  53. <textarea
  54. v-model="answerValue"
  55. placeholder="请在此输入答案"
  56. v-else-if="questionType == '开放题'"
  57. style="width: 96%;height: 160px;"
  58. />
  59. <mt-button
  60. type="primary"
  61. @click="onQuestionConfirm"
  62. class="button-bottom"
  63. v-show="nextBtnVisible"
  64. >继续</mt-button>
  65. </div>
  66. <!-- <div rows="* auto" v-else class="margin">
  67. <Label class="body" :text="questionaire.info.bye" textWrap="true" verticalAlignment="top" />
  68. <Button text="继续" @tap="onFinishTap" row="1" />
  69. </div>-->
  70. <div v-else-if="stage == 2">
  71. <p style="margin: 80px 0;">{{questionaire.info.bye}}</p>
  72. </div>
  73. </div>
  74. </template>
  75. <script>
  76. import axios from "axios";
  77. import dateFormat from "../dateFormat.js";
  78. import indicatorBiz from "../indicatorBiz.js";
  79. import Vue from "vue";
  80. // CREATED(0, "已创建"),
  81. // CLICKED(1, "已点击"),
  82. // STARTED(2, "已开始"),
  83. // COMPLETE(3, "已完成");
  84. export default {
  85. name: "WebQn",
  86. data: function() {
  87. return {
  88. showHello: true,
  89. webQuestionaire: {},
  90. questionaire: { info: {} },
  91. questionHEAD: 0,
  92. answerSheet: {
  93. // questionaireId: this.questionaire.info.id,
  94. questionaireId: 0,
  95. sheetName: "",
  96. status: 0,
  97. startTime: null,
  98. endTime: null,
  99. locationLong: this.long,
  100. locationLat: this.lat
  101. },
  102. answers: {},
  103. answerValue: "",
  104. answerNote: {},
  105. selectedSingle: "",
  106. selectedMultiple: [],
  107. recorder: null,
  108. isRecording: false,
  109. indicators: {},
  110. historyStack: [],
  111. nextBtnVisible: true,
  112. webQnUrl: "",
  113. lastCheckList: [],
  114. // 选择题选中开放式选项的开放回答值
  115. selectedOpenList: []
  116. };
  117. },
  118. mounted: function() {
  119. let id = this.getParam("id");
  120. if (!id) {
  121. alert("无效的问卷地址");
  122. return;
  123. }
  124. this.webQnUrl = this.$baseUrl + "/web-qn/" + id;
  125. console.log("webQnUrl", this.webQnUrl);
  126. axios.get(this.webQnUrl + "/judge").then(response => {
  127. console.log("open way:", response.data);
  128. this.openWay = response.data;
  129. if (response.data == "Project") {
  130. console.log("匿名方式问卷打开");
  131. let qnDataUrl = this.webQnUrl + "/complete-info-incognito";
  132. console.log("qnDataUrl:", qnDataUrl);
  133. axios.get(qnDataUrl).then(r => {
  134. this.questionaire = r.data;
  135. this.webQuestionaire = { status: 1 };
  136. // this.webQuestionaire = webQnResponse.data;
  137. // this.questionaire.info = r.data.info;
  138. console.log("匿名方式问卷内容:", this.questionaire);
  139. });
  140. } else {
  141. console.log("登录方式问卷打开");
  142. axios.get(this.webQnUrl).then(webQnResponse => {
  143. let qnId = webQnResponse.data.qnId;
  144. let qnDataUrl = this.webQnUrl + "/complete-info";
  145. console.log("qnDataUrl", qnDataUrl);
  146. axios.get(qnDataUrl).then(r => {
  147. this.questionaire = r.data;
  148. this.webQuestionaire = webQnResponse.data;
  149. // this.questionaire.info = r.data.info;
  150. console.log("登录方式问卷内容", this.questionaire);
  151. });
  152. });
  153. }
  154. // 获取最新的配额
  155. // let $this = this;
  156. // axios.get(`${this.$baseUrl}/questionaire/${this.questionaire.info.id}/indicator`).then(function (response) {
  157. // // $this.indicators = response.data
  158. // for (let i = 0; i < response.data.length; i++) {
  159. // $this.indicators[response.data[i].id] = response.data[i];
  160. // }
  161. // });
  162. // // 将本次运行写入数据库
  163. // if (this.questionaire.info.status >= 3) {
  164. // this.insertAnswerSheet();
  165. // }
  166. // this.onQuestionLoaded();
  167. });
  168. let time = new Date();
  169. this.answerSheet.startTime = dateFormat.formatDate(
  170. "yyyy-MM-dd HH:mm:ss",
  171. time
  172. );
  173. this.answerSheet.sheetName = this.generateSheetName(time);
  174. },
  175. computed: {
  176. stage() {
  177. if (this.webQuestionaire.status == 3) {
  178. // 显示结束语
  179. return 2;
  180. } else if (this.webQuestionaire.status == 2) {
  181. // 显示题目
  182. return 1;
  183. } else {
  184. // 显示问候语
  185. return 0;
  186. }
  187. },
  188. // pageTitle() {
  189. // console.log('compute page title');
  190. // let title = '';
  191. // switch (this.stage) {
  192. // case 0:
  193. // title = "问候语";
  194. // break;
  195. // case 1: title = "问卷内容";
  196. // break;
  197. // case 2: title = "问卷已结束";
  198. // break;
  199. // }
  200. // if (this.isRecording) {
  201. // return `${title}(录音中...)`
  202. // } else {
  203. // return title;
  204. // }
  205. // },
  206. currentQuestion() {
  207. return this.questionaire.questions[this.questionHEAD];
  208. },
  209. percent() {
  210. let perc =
  211. ((this.questionHEAD + 1) / this.questionaire.questions.length) * 100;
  212. console.log("percent", perc);
  213. return perc;
  214. },
  215. questionType() {
  216. let type = this.currentQuestion.type;
  217. if (type == 1) {
  218. if (
  219. this.currentQuestion.minOptions == 1 &&
  220. this.currentQuestion.maxOptions == 1
  221. ) {
  222. return "单选题";
  223. } else {
  224. return "多选题";
  225. }
  226. } else if (type == 3) {
  227. return "排序题";
  228. } else if (type == 4) {
  229. return "开放题";
  230. }
  231. },
  232. multipleTip() {
  233. let type = this.currentQuestion.type;
  234. if (type == 1) {
  235. if (this.currentQuestion.maxOptions > 1) {
  236. return (
  237. "(" +
  238. this.currentQuestion.minOptions +
  239. "-" +
  240. this.currentQuestion.maxOptions +
  241. "个)"
  242. );
  243. }
  244. }
  245. return "";
  246. },
  247. questionBody() {
  248. // 处理${ID}的情况
  249. return this.replaceDollarId(this.currentQuestion.body);
  250. },
  251. questionRemark() {
  252. // 处理${ID}的情况
  253. return this.replaceDollarId(this.currentQuestion.remark);
  254. },
  255. upperDatasourceQuestion() {
  256. console.log("call upperDatasourceQuestion");
  257. // 获取上一级的数据源所在的题目id(同一个id,但列数小1的题目)
  258. if (!this.currentQuestion.datasourceId) {
  259. return 0;
  260. } else {
  261. let dsId = this.currentQuestion.datasourceId;
  262. let dsColumn = this.currentQuestion.datasourceColumn;
  263. for (let i = 0; i < this.questionHEAD; i++) {
  264. if (
  265. this.questionaire.questions[i].datasourceId == dsId &&
  266. this.questionaire.questions[i].datasourceColumn == dsColumn - 1
  267. ) {
  268. return this.questionaire.questions[i].id;
  269. }
  270. }
  271. return 0;
  272. }
  273. },
  274. questionOptions() {
  275. console.log("call questionOptions");
  276. let opts = [];
  277. let openList = this.selectedOpenList;
  278. if (this.upperDatasourceQuestion == 0) {
  279. opts = this.currentQuestion.options;
  280. } else {
  281. let dsId = this.currentQuestion.datasourceId;
  282. let dsColumn = this.currentQuestion.datasourceColumn;
  283. let targetOptionId = this.answers[this.upperDatasourceQuestion].answer;
  284. let dsFilter = this.findOptionContent(
  285. this.upperDatasourceQuestion,
  286. targetOptionId
  287. );
  288. let subDataColumn = [];
  289. let datasource = null;
  290. for (let i in this.questionaire.datasource) {
  291. if (this.questionaire.datasource[i].id == dsId) {
  292. datasource = this.questionaire.datasource[i];
  293. break;
  294. }
  295. }
  296. if (!datasource) {
  297. return this.currentQuestion.options;
  298. }
  299. for (let i in datasource.contentList) {
  300. if (datasource.contentList[i]["c" + (dsColumn - 1)] == dsFilter) {
  301. subDataColumn.push(datasource.contentList[i]["c" + dsColumn]);
  302. }
  303. }
  304. let subOptions = [];
  305. for (let i in this.currentQuestion.options) {
  306. if (
  307. this.currentQuestion.options[i].datasourceId == 0 ||
  308. subDataColumn.indexOf(
  309. this.currentQuestion.options[i].optionContent
  310. ) >= 0
  311. ) {
  312. subOptions.push(this.currentQuestion.options[i]);
  313. }
  314. }
  315. opts = subOptions;
  316. }
  317. // 组装成 mt-radio 或 mt-checklist 组件需要的格式
  318. for (var index = 0; index < opts.length; index++) {
  319. // let label = `${i + 1}、${opts[i].optionContent}`;
  320. let label = `${opts[index].optionContent}`;
  321. for (var openIndex = 0; openIndex < openList.length; openIndex++) {
  322. if (
  323. openList[openIndex] &&
  324. openList[openIndex].selectedIndex == index &&
  325. opts[index].open &&
  326. openList[openIndex].selectedValue
  327. ) {
  328. label = label + "(" + openList[openIndex].selectedValue + ")";
  329. }
  330. }
  331. let value = index.toString();
  332. Vue.set(opts[index], "label", label);
  333. Vue.set(opts[index], "value", value);
  334. }
  335. return opts;
  336. }
  337. },
  338. watch: {
  339. questionHEAD() {
  340. //换题后返回页面顶部
  341. console.log("before scroll", document.documentElement.scrollTop);
  342. document.documentElement.scrollTop = 0;
  343. console.log("after scroll", document.documentElement.scrollTop);
  344. }
  345. },
  346. methods: {
  347. getParam: function(name) {
  348. if (
  349. (name = new RegExp("[?&]" + encodeURIComponent(name) + "=([^&]*)").exec(
  350. location.search
  351. ))
  352. )
  353. return decodeURIComponent(name[1]);
  354. },
  355. // backEventHandler(args) {
  356. // console.log('activityBackPressedEvent......')
  357. // debugger;
  358. // if (this.stage < 2) {
  359. // args.cancel = true;
  360. // this.onQuitTap();
  361. // } else if (this.stage == 2) {
  362. // args.cancel = true;
  363. // this.onFinishTap();
  364. // }
  365. // },
  366. start() {
  367. if (this.stage < 2) {
  368. if (this.openWay == "Project") {
  369. // 匿名方式打开
  370. this.webQuestionaire.status = 2;
  371. } else {
  372. // 登录状态打开方式
  373. this.webQuestionaire.status = 2;
  374. axios
  375. .put(this.webQnUrl, { status: 2 })
  376. .then(() => console.log("update status success"));
  377. }
  378. }
  379. this.showHello = false;
  380. },
  381. getUserName() {
  382. if (this.openWay == "Project") {
  383. // 匿名方式打开
  384. return "incognito";
  385. } else {
  386. // 登录状态打开方式
  387. return this.webQuestionaire.phoneNumber;
  388. }
  389. },
  390. getOrgCode() {
  391. let orgCode = "webqn";
  392. return orgCode;
  393. },
  394. generateSheetName(time) {
  395. let orgCode = this.getOrgCode();
  396. let userName = this.getUserName();
  397. return `${orgCode}-${dateFormat.formatDate(
  398. "yyyyMMddHHmmss",
  399. time
  400. )}-${userName}`;
  401. },
  402. replaceDollarId(body) {
  403. // 处理${ID}的情况
  404. let regex = /\$\{(\d+)\}/m;
  405. let match = regex.exec(body);
  406. while (match && match[0]) {
  407. let targetQuestionId = match[1];
  408. let targetOptionId = this.answers[targetQuestionId].answer;
  409. let targetOptionContent = this.findOptionContent(
  410. targetQuestionId,
  411. targetOptionId
  412. );
  413. body = body.replace(match[0], targetOptionContent);
  414. match = regex.exec(body);
  415. }
  416. return body;
  417. },
  418. onQuitTap() {
  419. confirm({
  420. title: "请确认",
  421. message: "确定要结束问卷吗?",
  422. okButtonText: "确定",
  423. cancelButtonText: "取消"
  424. }).then(result => {
  425. if (result) {
  426. // 中途拒访
  427. this.finishQuestionaire(2);
  428. }
  429. });
  430. },
  431. onPreTap() {
  432. let lastIndex = this.historyStack.pop();
  433. this.questionHEAD = lastIndex;
  434. this.selectedOpenList.length = 0;
  435. this.onQuestionLoaded(true);
  436. },
  437. onListItemTap(event) {
  438. let selectedOpt = event.item;
  439. selectedOpt.isSelected = !selectedOpt.isSelected;
  440. console.log(
  441. "onListItemTap",
  442. `select option: ${selectedOpt.optionContent}, selected? ${selectedOpt.isSelected}`
  443. );
  444. this.onOptionChange(selectedOpt);
  445. },
  446. onOptionSelected(index) {
  447. console.log("option changed : ", typeof index);
  448. let _type = typeof index;
  449. let selectedOpt = null;
  450. if (_type == "object") {
  451. // 多选
  452. let isUnselect = this.lastCheckList.length > index.length;
  453. if (isUnselect) {
  454. let selSet = new Set(index);
  455. let lastSet = new Set(this.lastCheckList);
  456. let unselectSet = new Set([...lastSet].filter(x => !selSet.has(x)));
  457. let unselectItem = Array.from(unselectSet)[0];
  458. for (
  459. var oIndex = 0;
  460. oIndex < this.selectedOpenList.length;
  461. oIndex++
  462. ) {
  463. if (this.selectedOpenList[oIndex].selectedIndex == unselectItem) {
  464. this.selectedOpenList.splice(oIndex, 1);
  465. }
  466. }
  467. }
  468. if (!isUnselect) {
  469. let lastIndex = index[index.length - 1];
  470. selectedOpt = this.questionOptions[lastIndex];
  471. }
  472. // 将本次选项写入this.lastCheckList
  473. this.lastCheckList.length = 0;
  474. for (let i = 0; i < index.length; i++) {
  475. this.lastCheckList.push(index[i]);
  476. }
  477. if (isUnselect) {
  478. return;
  479. }
  480. } else if (_type == "string") {
  481. selectedOpt = this.questionOptions[index];
  482. this.selectedOpenList.splice(0, 1);
  483. }
  484. // 处理开放选项
  485. if (selectedOpt.open) {
  486. this.$prompt(selectedOpt.openOptionTips, "请填写", {
  487. confirmButtonText: "确定",
  488. cancelButtonText: "取消",
  489. customClass: "select-open-dialog",
  490. inputType: "textarea"
  491. }).then(({ value }) => {
  492. console.log(`Dialog value: ${value}, `);
  493. this.$set(this.selectedOpenList, this.selectedOpenList.length, {
  494. selectedIndex: selectedOpt.value,
  495. selectedId: selectedOpt.id,
  496. selectedValue: value
  497. });
  498. this.answerNote[selectedOpt.id] = value;
  499. });
  500. }
  501. },
  502. autoSelect() {
  503. // 后退或者继续时,如果下一道题已经填写过,则自动加载答案
  504. let lastQuestionId = this.questionaire.questions[this.questionHEAD].id;
  505. let lastAnswer = this.answers[lastQuestionId];
  506. if (
  507. this.questionaire.questions[this.questionHEAD].type == 1 &&
  508. this.questionaire.questions[this.questionHEAD].maxOptions == 1
  509. ) {
  510. // 返回的是单选题
  511. for (var i in this.questionOptions) {
  512. if (this.questionOptions[i].id == lastAnswer.answer) {
  513. this.selectedSingle = i;
  514. if (lastAnswer.answerNote) {
  515. // 如果有开放选项内容,再添加内容
  516. this.$set(this.selectedOpenList, this.selectedOpenList.length, {
  517. selectedIndex: i,
  518. selectedId: lastAnswer.answer,
  519. selectedValue: lastAnswer.answerNote
  520. });
  521. }
  522. break;
  523. }
  524. }
  525. } else if (
  526. this.questionaire.questions[this.questionHEAD].type == 1 &&
  527. this.questionaire.questions[this.questionHEAD].maxOptions > 1
  528. ) {
  529. // 返回的是多选题
  530. let idList = lastAnswer.answer.split(",");
  531. let lastAnswerNote = JSON.parse(lastAnswer.answerNote);
  532. for (var idIndex in idList) {
  533. for (var i in this.questionOptions) {
  534. if (this.questionOptions[i].id == idList[idIndex]) {
  535. if (idList[idIndex] in lastAnswerNote) {
  536. let optId = idList[idIndex];
  537. // let optNote = lastAnswerNote. optId;
  538. this.$set(this.selectedOpenList, this.selectedOpenList.length, {
  539. selectedIndex: i,
  540. selectedId: idList[idIndex],
  541. selectedValue: lastAnswerNote[optId]
  542. });
  543. }
  544. this.selectedMultiple.push(i);
  545. break;
  546. }
  547. }
  548. }
  549. } else {
  550. this.answerValue = lastAnswer.answer;
  551. }
  552. // if (this.currentQuestion.type == 1 && lastAnswer.answerNote) {
  553. // this.answerNote[lastAnswer.answer] = lastAnswer.answerNote;
  554. // }
  555. },
  556. onQuestionLoaded(isBack) {
  557. console.log("call onQuestionLoaded");
  558. if (isBack) {
  559. this.autoSelect();
  560. // delete this.answers[lastQuestionId];
  561. } else {
  562. let curQuestionId = this.questionaire.questions[this.questionHEAD].id;
  563. let curAnswer = this.answers[curQuestionId];
  564. if (curAnswer) {
  565. this.autoSelect();
  566. } else {
  567. this.answerValue = "";
  568. this.answerNote = {};
  569. this.selectedSingle = "";
  570. this.selectedMultiple = [];
  571. }
  572. }
  573. // 根据题目类型,动态展示对应的答题方式
  574. // ---- 已在页面绑定中体现了
  575. // 处理${ID}的情况
  576. // ---- 已在computed questionBody()中处理
  577. // 处理数据源绑定(如果绑定了数据源并且上一列已经选中,则根据上一列的结果筛选选项)
  578. // ---- 已在computed questionOptions()中处理
  579. // 如果某选项会跳转到结束问卷,则提示出来
  580. // ---- 已在页面绑定中体现了
  581. },
  582. findOptionContent(targetQuestionId, targetOptionId) {
  583. for (let i in this.questionaire.questions) {
  584. if (this.questionaire.questions[i].id == targetQuestionId) {
  585. console.log("target qeustion", this.questionaire.questions[i].body);
  586. for (let j in this.questionaire.questions[i].options) {
  587. if (
  588. this.questionaire.questions[i].options[j].id == targetOptionId
  589. ) {
  590. console.log(
  591. "target option",
  592. this.questionaire.questions[i].options[j].optionContent
  593. );
  594. return this.questionaire.questions[i].options[j].optionContent;
  595. }
  596. }
  597. }
  598. }
  599. },
  600. onQuestionConfirm() {
  601. console.log("onQuestionConfirm...");
  602. // let selections = [];
  603. let selectionIds = [];
  604. let questionId = this.questionaire.questions[this.questionHEAD].id;
  605. if (this.currentQuestion.type == 1) {
  606. if (this.questionType == "单选题") {
  607. if (this.selectedSingle) {
  608. selectionIds.pushNoRepeat(
  609. this.questionOptions[this.selectedSingle].id
  610. );
  611. }
  612. } else {
  613. for (let i = 0; i < this.selectedMultiple.length; i++) {
  614. selectionIds.pushNoRepeat(
  615. this.questionOptions[this.selectedMultiple[i]].id
  616. );
  617. }
  618. }
  619. console.log("selectionIds", selectionIds);
  620. if (
  621. this.currentQuestion.maxOptions &&
  622. this.currentQuestion.maxOptions < selectionIds.length
  623. ) {
  624. alert(`最多可选中${this.currentQuestion.maxOptions}项`);
  625. return;
  626. }
  627. if (
  628. this.currentQuestion.minOptions &&
  629. this.currentQuestion.minOptions > selectionIds.length
  630. ) {
  631. alert(`最少需选中${this.currentQuestion.minOptions}项`);
  632. return;
  633. }
  634. // 判断选择题中的开放回答是否填写
  635. let optionList = this.questionaire.questions[this.questionHEAD].options;
  636. for (let selIndex in selectionIds) {
  637. for (let optIndex in optionList) {
  638. if (
  639. selectionIds[selIndex] == optionList[optIndex].id &&
  640. optionList[optIndex].open
  641. ) {
  642. // selectionIds[selIndex] 是选中的开放性答案的id,判断其有没有对应填写的开放回答
  643. let isPass = false;
  644. for (let oIndex in this.selectedOpenList) {
  645. if (
  646. this.selectedOpenList[oIndex].selectedId ==
  647. selectionIds[selIndex] &&
  648. this.selectedOpenList[oIndex].selectedValue
  649. ) {
  650. isPass = true;
  651. }
  652. }
  653. if (!isPass) {
  654. alert("请填写开放性选项答案");
  655. return;
  656. }
  657. }
  658. }
  659. }
  660. // 确定答案
  661. // this.answers[questionId] = selectionIds.join(',');
  662. this.answers[questionId] = {
  663. questionId: questionId,
  664. answer: selectionIds.join(",")
  665. };
  666. if (
  667. this.currentQuestion.maxOptions == 1 &&
  668. this.selectedOpenList.length > 0
  669. ) {
  670. this.answers[
  671. questionId
  672. ].answerNote = this.selectedOpenList[0].selectedValue;
  673. } else if (this.currentQuestion.maxOptions > 1) {
  674. let answerNoteObj = {};
  675. for (let index in selectionIds) {
  676. let selectedId = selectionIds[index];
  677. for (var sIndex in this.selectedOpenList) {
  678. if (this.selectedOpenList[sIndex].selectedId == selectedId) {
  679. answerNoteObj[selectedId] = this.selectedOpenList[
  680. sIndex
  681. ].selectedValue;
  682. break;
  683. }
  684. }
  685. }
  686. this.answers[questionId].answerNote = JSON.stringify(answerNoteObj);
  687. }
  688. this.selectedOpenList.length = 0;
  689. // 判断是否配额不足
  690. let isIndicartorOut = indicatorBiz.isIndicartorOut(
  691. this.currentQuestion,
  692. this.indicators,
  693. this.answers
  694. );
  695. if (isIndicartorOut) {
  696. // 配额不足,跳转至结束
  697. this.finishQuestionaire(4);
  698. return;
  699. }
  700. // 判断是否需要跳题以及是否需要结束问卷
  701. let hopToQuestionId = 0;
  702. if (
  703. this.currentQuestion.type == 1 &&
  704. this.currentQuestion.maxOptions == 1
  705. ) {
  706. for (let i in this.questionOptions) {
  707. let opt = this.questionOptions[i];
  708. if (opt.id == selectionIds[0] && opt.redirectTo != 0) {
  709. hopToQuestionId = opt.redirectTo;
  710. break;
  711. }
  712. }
  713. }
  714. console.log("hop to question", hopToQuestionId);
  715. if (hopToQuestionId == -2) {
  716. // 甄别不过,跳转至结束
  717. this.finishQuestionaire(3);
  718. return;
  719. } else if (hopToQuestionId == -1) {
  720. // 正常结束
  721. this.finishQuestionaire(1);
  722. return;
  723. } else if (hopToQuestionId > 0) {
  724. // 跳转到某道题
  725. // for (let i in this.questionaire.questions) {
  726. for (let i = 0; i < this.questionaire.questions.length; i++) {
  727. if (this.questionaire.questions[i].id == hopToQuestionId) {
  728. this.questionHEAD = i;
  729. this.onQuestionLoaded();
  730. return;
  731. }
  732. }
  733. }
  734. } else if (this.currentQuestion.type == 3) {
  735. // 排序题
  736. } else if (this.currentQuestion.type == 4) {
  737. // 开放题
  738. if (this.currentQuestion.required && !this.answerValue) {
  739. alert("此项必填");
  740. return;
  741. }
  742. this.answers[questionId] = {
  743. questionId: questionId,
  744. answer: this.answerValue
  745. };
  746. }
  747. if (this.questionHEAD == this.questionaire.questions.length - 1) {
  748. // 所有题目都回答完了,问卷正常结束
  749. this.finishQuestionaire(1);
  750. return;
  751. } else {
  752. // 进入下一道题
  753. this.historyStack.push(this.questionHEAD);
  754. this.questionHEAD++;
  755. }
  756. this.onQuestionLoaded();
  757. },
  758. finishQuestionaire(status) {
  759. if (this.questionaire.info.status >= 3) {
  760. this.answerSheet.status = status;
  761. this.answerSheet.endTime = dateFormat.formatDate(
  762. "yyyy-MM-dd HH:mm:ss",
  763. new Date()
  764. );
  765. let arr = [];
  766. for (let i in this.answers) {
  767. arr.push(this.answers[i]);
  768. }
  769. // 持久化answerSheet数据
  770. // this.updateAnswerSheetData(JSON.stringify(arr));
  771. axios
  772. .post(this.webQnUrl, {
  773. sheet: this.answerSheet,
  774. answers: arr
  775. })
  776. .then(() => {
  777. // this.updateAnswerSheetDataUploaded(true);
  778. // alert('问卷结果已提交');
  779. this.webQuestionaire.status = 3;
  780. });
  781. }
  782. },
  783. onFinishTap() {
  784. if (app.android) {
  785. app.android.off(
  786. app.AndroidApplication.activityBackPressedEvent,
  787. this.backEventHandler
  788. );
  789. console.log("backEventHandler off");
  790. }
  791. if (this.isRecord) {
  792. this.recorder.stop().catch(ex => {
  793. console.log("recorder stop failed", ex);
  794. this.isRecording = false;
  795. });
  796. }
  797. this.$modal.close();
  798. },
  799. insertAnswerSheet() {
  800. this.$db.execSQL(
  801. "insert into answer_sheet values(?,?,?,?,?,?,?,?,?,?,?,?)",
  802. [
  803. this.answerSheet.sheetName,
  804. this.answerSheet.questionaireId,
  805. this.answerSheet.status,
  806. this.answerSheet.startTime,
  807. null,
  808. this.answerSheet.locationLong,
  809. this.answerSheet.locationLat,
  810. null,
  811. 0,
  812. this.isRecord ? 1 : 0,
  813. 0,
  814. this.getUserName()
  815. ],
  816. function(err) {
  817. if (err) {
  818. console.error("insertAnswerSheet error", err);
  819. }
  820. }
  821. );
  822. }
  823. // updateAnswerSheetData(answerJson) {
  824. // this.$db.execSQL('update answer_sheet set endTime = ?, answerJson = ?, status = ? where sheetName = ?',
  825. // [
  826. // this.answerSheet.endTime,
  827. // answerJson,
  828. // this.answerSheet.status,
  829. // this.answerSheet.sheetName,
  830. // ], function (err) {
  831. // if (err) {
  832. // console.error('updateAnswerSheetData error', err)
  833. // }
  834. // })
  835. // },
  836. // updateAnswerSheetDataUploaded(isDataUploaded) {
  837. // this.$db.execSQL('update answer_sheet set dataUploaded = ? where sheetName = ?',
  838. // [
  839. // isDataUploaded ? 1 : 0,
  840. // this.answerSheet.sheetName,
  841. // ], function (err) {
  842. // if (err) {
  843. // console.error('updateAnswerSheetDataUploaded error', err)
  844. // }
  845. // })
  846. // }
  847. }
  848. };
  849. </script>
  850. <style scoped>
  851. .button-bottom {
  852. width: 96%;
  853. /* position: absolute; */
  854. /* left: 2%; */
  855. /* bottom: 2%; */
  856. margin-top: 40px;
  857. margin-left: 2%;
  858. }
  859. </style>
  860. <style>
  861. .select-open-dialog {
  862. width: 50%;
  863. }
  864. .select-open-dialog textarea {
  865. height: 100px;
  866. }
  867. .mint-cell {
  868. display: inherit;
  869. }
  870. /* 取消选择框上下线 */
  871. .mint-cell-wrapper {
  872. background-image: none;
  873. }
  874. .mint-cell:last-child {
  875. background-image: none;
  876. }
  877. /* .mint-radio-input:checked + .mint-radio-core {
  878. background-color: #e80413;
  879. border-color: #e80413;
  880. } */
  881. </style>