satisfactionQuestions.vue 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. <template>
  2. <view class="container">
  3. <scroll-view
  4. class="scroll_view"
  5. scroll-y
  6. scroll-with-animation
  7. scroll-anchoring
  8. :scroll-into-view="point"
  9. >
  10. <view class="top_bg_box">
  11. <image mode="widthFix" :src="icon.satisfaction.ques_top_bg"></image>
  12. <view class="ques_introduce displayFlexCol">
  13. <text>{{ quesList.SubjectTitle }}</text>
  14. <text>{{ quesList.Remark }}</text>
  15. </view>
  16. </view>
  17. <view class="main_box">
  18. <view class="mask_form" v-if="complete"></view>
  19. <block v-for="(item, index) in quesList.QuestionList" :key="index">
  20. <view
  21. class="ques_item_box"
  22. :id="'p' + index"
  23. :class="item.QuestType == 'SubTitle' ? 'sub_title' : ''"
  24. >
  25. <view class="ques_title_box">
  26. <text class="mustQuest_tag" wx:if="{{item.MustQuest}}">*</text>
  27. <text v-if="item.QuestType != 'SubTitle'">{{ item.Sort }}.{{ item.Question }}</text>
  28. <text v-if="item.QuestType == 'SubTitle'">{{ item.Num }}、{{ item.Question }}</text>
  29. </view>
  30. <!-- 填空题 -->
  31. <view
  32. class="ques_options align_items_left displayFlexCol"
  33. v-if="item.QuestType == 'Input'"
  34. >
  35. <text class="input_label">{{ item.Question }}:</text>
  36. <view class="textarea_box">
  37. <textarea
  38. auto-height
  39. :data-index="index"
  40. :placeholder="'最多输入' + item.RuleInfo.MaxLength + '个字'"
  41. :maxlength="item.RuleInfo.MaxLength"
  42. :value="item.AnswerList"
  43. @blur="setVal"
  44. />
  45. </view>
  46. </view>
  47. <!-- 矩阵填空题 -->
  48. <view
  49. class="ques_options align_items_left displayFlexCol"
  50. v-if="item.QuestType == 'MatrixInput'"
  51. >
  52. <block
  53. v-for="(childItem, childIndex) in item.MatrixQuestionList"
  54. :key="`MatrixInput-${index}-${childIndex}`"
  55. >
  56. <view class="matrix_input_box margin_bottom_10 displayFlexRow">
  57. <text>{{ childItem.Question }}:</text>
  58. <view class="textarea_box matrix_textarea_box">
  59. <textarea
  60. auto-height
  61. :data-index="index"
  62. :data-childindex="childIndex"
  63. :placeholder="'最多输入' + childItem.RuleInfo.MaxLength + '个字'"
  64. :maxlength="childItem.RuleInfo.MaxLength"
  65. :value="childItem.AnswerList"
  66. @input="setVal"
  67. />
  68. </view>
  69. </view>
  70. </block>
  71. </view>
  72. <!-- 单选/多选题 -->
  73. <view
  74. class="ques_options displayFlexCol"
  75. v-if="item.QuestType == 'Radio' || item.QuestType == 'Checkbox'"
  76. >
  77. <block
  78. v-for="(childItem, childIndex) in item.QuestionItemList"
  79. :key="`Checkbox-${index}-${childIndex}`"
  80. >
  81. <text
  82. class="choice_item"
  83. :class="fn.answer(item, childItem.ItemId) ? 'active_option' : ''"
  84. :data-index="index"
  85. :data-childindex="childIndex"
  86. @click="choiceOption"
  87. >
  88. {{ childItem.ItemName }}
  89. </text>
  90. </block>
  91. </view>
  92. <!-- 选择题 -->
  93. <view class="ques_options displayFlexCol" v-if="item.QuestType == 'Select'">
  94. <picker
  95. class="picker_box"
  96. range-key="ItemName"
  97. :range="item.QuestionItemList"
  98. :data-index="index"
  99. :value="item.AnswerList"
  100. @change="bindPickerChange"
  101. >
  102. <view class="picker displayFlexRow">
  103. <text>{{ item.QuestionItemList[item.AnswerList].ItemName }}</text>
  104. <image :src="icon.satisfaction.right" mode="" />
  105. </view>
  106. </picker>
  107. </view>
  108. <!-- 矩阵单选题/矩阵多选题/矩阵量表 -->
  109. <view
  110. class="ques_options matrix_border displayFlexCol"
  111. v-if="
  112. item.QuestType == 'MatrixRadio' ||
  113. item.QuestType == 'MatrixCheckbox' ||
  114. item.QuestType == 'MatrixScale'
  115. "
  116. >
  117. <view class="matrix_options matrix_options_title displayFlexRow">
  118. <block
  119. v-for="(childItem, childIndex) in item.MatrixQuestionList[0].QuestionItemList"
  120. :key="`${item.QuestType}0-${index}-${childIndex}`"
  121. >
  122. <text
  123. :style="{
  124. width: fn.getWidth(item.MatrixQuestionList[0].QuestionItemList.length) + '%',
  125. }"
  126. >
  127. {{ childItem.ItemName }}
  128. </text>
  129. </block>
  130. </view>
  131. <block
  132. v-for="(childItem, childIndex) in item.MatrixQuestionList"
  133. :key="`${item.QuestType}-${index}-${childIndex}`"
  134. >
  135. <view class="matrix_icon_box displayFlexCol">
  136. <text
  137. :style="{
  138. width: fn.getWidth(item.MatrixQuestionList[0].QuestionItemList.length) + '%',
  139. }"
  140. >{{ childItem.Question }}</text
  141. >
  142. <view class="matrix_options displayFlexBetween">
  143. <block
  144. v-for="(sunItem, sunIndex) in childItem.QuestionItemList"
  145. :key="`${item.QuestType}-${index}-${childIndex}-${sunIndex}`"
  146. >
  147. <view
  148. class="displayFlexRow"
  149. :data-index="index"
  150. :data-childindex="childIndex"
  151. :data-sunindex="sunIndex"
  152. @click="choiceMatrixOption"
  153. >
  154. <!-- 矩阵单选/矩阵量表 -->
  155. <image
  156. :src="
  157. fn.answer(childItem, sunItem.ItemId)
  158. ? icon.satisfaction.circle_active
  159. : icon.satisfaction.circle
  160. "
  161. mode=""
  162. v-if="item.QuestType == 'MatrixRadio' || item.QuestType == 'MatrixScale'"
  163. />
  164. <!-- 矩阵多选 -->
  165. <image
  166. :src="
  167. fn.answer(childItem, sunItem.ItemId)
  168. ? icon.satisfaction.checkBox_circle_active
  169. : icon.satisfaction.checkBox_circle
  170. "
  171. mode=""
  172. v-if="item.QuestType == 'MatrixCheckbox'"
  173. />
  174. </view>
  175. </block>
  176. </view>
  177. </view>
  178. </block>
  179. </view>
  180. <!-- 上传文件题 -->
  181. <view class="ques_options displayFlexCol" v-if="item.QuestType == 'UploadImage'">
  182. <view class="img_list displayFlexRow">
  183. <image
  184. class="add_img"
  185. mode=""
  186. :src="icon.satisfaction.add"
  187. :data-index="index"
  188. @click="choiceFile"
  189. />
  190. <block
  191. v-for="(imgItem, imgIndex) in item.AnswerList"
  192. :key="`UploadImage-${index}-${imgIndex}`"
  193. >
  194. <view class="add_img">
  195. <image class="item_img" :src="imgItem" mode="" />
  196. <image
  197. class="cha_img"
  198. :src="icon.satisfaction.cha_green"
  199. mode=""
  200. :data-index="index"
  201. :data-imgitem="imgItem"
  202. @click="closeImg"
  203. />
  204. </view>
  205. </block>
  206. </view>
  207. <view class="add_img_tips p_flexStart">
  208. <text>限制:</text>
  209. <text> 仅支持图片上传、</text>
  210. <text>
  211. 大小不超过{{ item.RuleInfo.FileSize }}M数量不超过{{ item.RuleInfo.FileCount }}个
  212. </text>
  213. </view>
  214. </view>
  215. <!-- 量表题 -->
  216. <view class="ques_options displayFlexRow" v-if="item.QuestType == 'Scale'">
  217. <block
  218. v-for="(childItem, childIndex) in item.QuestionItemList"
  219. :key="`Scale-${index}-${childIndex}`"
  220. >
  221. <view
  222. class="options_item_box displayFlexCol"
  223. :data-index="index"
  224. :data-childindex="childIndex"
  225. @click="choiceOption"
  226. >
  227. <text>{{ childItem.ItemName }}</text>
  228. <image
  229. :src="
  230. fn.answer(item, childItem.ItemId)
  231. ? icon.satisfaction.circle_active
  232. : icon.satisfaction.circle
  233. "
  234. mode=""
  235. />
  236. </view>
  237. </block>
  238. </view>
  239. </view>
  240. </block>
  241. </view>
  242. </scroll-view>
  243. <view class="yjfl" @click="yjfk">
  244. <image :src="icon.satisfaction.yjfk" alt="" style="width: 140rpx; height: 140rpx" />
  245. <view class="title"> 意见反馈 </view>
  246. </view>
  247. <view class="footer_box displayFlexRow">
  248. <text :class="complete ? 'backgroundCustom_D9' : ''" @click="submit">提交</text>
  249. </view>
  250. <!-- 是否实名弹窗 -->
  251. <view class="modal_wrap" v-if="showModal_Anonymous">
  252. <view class="modal_box">
  253. <view class="modal_tit">是否实名填写</view>
  254. <view class="modal_con">
  255. <view class="modal_box_b1" @click="isAnonymous(1)">实名填写</view>
  256. <view class="modal_box_b1" @click="isAnonymous(2)">匿名填写</view>
  257. </view>
  258. </view>
  259. </view>
  260. <!-- 是否实名弹窗 -->
  261. <view class="modal_wrap" v-if="showModal_User">
  262. <view class="modal_box">
  263. <view class="modal_tit">请选择答卷人</view>
  264. <view class="modal_con">
  265. <view class="modal_user_item" v-if="currentUser.memberName" @click="goSelMember">
  266. <view>
  267. <view>
  268. <text class="modal_t1">{{ currentUser.memberName }}</text>
  269. <text class="modal_t2">
  270. {{ currentUser.sex == 1 ? '男' : currentUser.sex == 2 ? '女' : '未知' }} |
  271. {{ currentUser.age }}岁
  272. </text>
  273. </view>
  274. <view class="modal_t3">{{ currentUser.mobile }}</view>
  275. </view>
  276. <image class="modal_user_right_img" :src="icon.satisfaction.right"></image>
  277. </view>
  278. <view class="modal_user_item" wx:else @click="goSelMember">
  279. <view>点击选择答卷人</view>
  280. <image class="modal_user_right_img" :src="icon.satisfaction.right"></image>
  281. </view>
  282. <view class="modal_btn_wrap displayFlexBetween" v-if="currentUser.memberName">
  283. <view class="modal_btn modal_btn1" @click="goBack">取消</view>
  284. <view class="modal_btn modal_btn2" @click="confirmMember">确定</view>
  285. </view>
  286. </view>
  287. </view>
  288. </view>
  289. </view>
  290. </template>
  291. <script lang="ts" setup>
  292. import { reactive, ref } from 'vue';
  293. import { useOnLoad } from '@/hook';
  294. import { useDomain } from '@kasite/uni-app-base';
  295. import { mapGetters } from '@kasite/uni-app-base/store/hook';
  296. import {
  297. QuerySubjectListToChannelTask_V3,
  298. QuerySubjectInfoById_V3,
  299. UploadZxFile,
  300. CommitAnswer_V3,
  301. } from '../../service';
  302. import icon from '@/utils/icon';
  303. import { common } from '@/utils';
  304. import fn from './fn';
  305. const app = getApp();
  306. let time = null;
  307. const iconUrl = ref(icon)
  308. const currentUser = ref({} as any);
  309. const taskId = ref('');
  310. const objType = ref('3'); // 3门诊 4住院
  311. const quesList = ref({} as any);
  312. const imgList = ref([]);
  313. const point = ref('');
  314. const complete = ref(false);
  315. const anonymousType = ref(0);
  316. const showModal_Anonymous = ref(false); // 是否实名填写弹窗显示
  317. const showModal_User = ref(false); // 实名用户选择弹窗显示
  318. let quesAnswers = reactive({
  319. MemberId: '',
  320. TaskId: '-1',
  321. SysAppId: 'visit',
  322. SubjectId: '',
  323. UserAgent: '',
  324. IP: '',
  325. Location: '',
  326. Mobile: '',
  327. UserName: '',
  328. Sex: '',
  329. Age: '',
  330. ThirdPartyId: '',
  331. AnswerUseTime: 0,
  332. PushDept: '',
  333. PushDeptName: '',
  334. BedNo: '',
  335. HospitalNo: '',
  336. CardNo: '',
  337. AnswerList: [],
  338. });
  339. const { getCurrentUser } = mapGetters({
  340. getCurrentUser: 'getCurrentUser',
  341. });
  342. const main = async (options) => {
  343. currentUser.value = getCurrentUser();
  344. const params = {
  345. SubjectId: options.subjectId,
  346. TaskId: options.taskId,
  347. };
  348. const resp = await QuerySubjectListToChannelTask_V3(params);
  349. if (!common.isEmpty(resp)) {
  350. objType.value = resp[0].GroupType;
  351. //匿名有3种传参 ""(空) "true" "false" 转换字符串为布尔值
  352. let anonymous =
  353. resp[0].Anonymous === 'false'
  354. ? false
  355. : resp[0].Anonymous === 'true'
  356. ? true
  357. : resp[0].Anonymous || '';
  358. // type 1实名 2:匿名 3自行选择
  359. anonymousType.value = anonymous === '' ? 3 : anonymous === false ? 1 : 2;
  360. showModal_Anonymous.value = anonymous == 3 ? true : false;
  361. taskId.value = options.taskId;
  362. quesAnswers.SubjectId = options.subjectId;
  363. //如果不是执行选择直接调用对应填写按钮
  364. if (anonymous != 3) {
  365. isAnonymous(anonymous);
  366. }
  367. querySubjectInfoById_V3();
  368. // 开始计算答卷时间
  369. getSec();
  370. } else {
  371. common.showModal('该任务已失效', () => {
  372. common.goToUrl(`/pages/business/tabbar/homePage/homePage`, { skipWay: 'reLaunch' });
  373. });
  374. return;
  375. }
  376. };
  377. /** 实名/匿名 */
  378. const isAnonymous = (type) => {
  379. //实名
  380. if (type == 1) {
  381. showModal_Anonymous.value = false;
  382. showModal_User.value = true;
  383. }
  384. //匿名
  385. else {
  386. currentUser.value = {};
  387. showModal_Anonymous.value = false;
  388. }
  389. };
  390. /** 问卷详情 */
  391. const querySubjectInfoById_V3 = async () => {
  392. const resp = await QuerySubjectInfoById_V3({
  393. SubjectId: quesAnswers.SubjectId,
  394. });
  395. if (common.isNotEmpty(resp)) {
  396. if (resp[0].Status != 0) {
  397. common.showModal('该问卷已失效', () => {
  398. common.navigateBack(1);
  399. });
  400. return;
  401. }
  402. if (resp[0].State != 1) {
  403. common.showModal('该问卷未发布', () => {
  404. common.navigateBack(1);
  405. });
  406. return;
  407. }
  408. // 提交答案数据模版
  409. quesAnswers.PushDept = resp[0].DeptId;
  410. quesAnswers.PushDeptName = resp[0].PushDeptName;
  411. resp[0].QuestionList.forEach((item, index) => {
  412. item.AnswerList = [];
  413. item.MustQuest = item.MustQuest == 'false' ? false : true;
  414. item.RuleInfo = item.RuleInfo != '' ? JSON.parse(item.RuleInfo) : '';
  415. // 多选框
  416. if (item.QuestType == 'Select') {
  417. item.AnswerList = 0;
  418. }
  419. if (common.isNotEmpty(item.MatrixQuestionList)) {
  420. item.MatrixQuestionList.forEach((childItem) => {
  421. childItem.AnswerList = [];
  422. childItem.RuleInfo = childItem.RuleInfo != '' ? JSON.parse(childItem.RuleInfo) : '';
  423. // 答案列表模版
  424. let answerItem = {
  425. Answer: [],
  426. Blank: index,
  427. QuestId: childItem.QuestId,
  428. QuestType: item.QuestType,
  429. MustQuest: item.MustQuest,
  430. };
  431. quesAnswers.AnswerList.push(answerItem);
  432. if (common.isNotEmpty(childItem.QuestionItemList)) {
  433. childItem.QuestionItemList.forEach((sunItem) => {
  434. sunItem.Check = false;
  435. });
  436. }
  437. });
  438. } else {
  439. // 答案列表模版
  440. let answerItem = {
  441. Answer: [],
  442. Blank: index,
  443. QuestId: item.QuestId,
  444. QuestType: item.QuestType,
  445. MustQuest: item.MustQuest,
  446. };
  447. quesAnswers.AnswerList.push(answerItem);
  448. }
  449. });
  450. resp[0].QuestionList = bySort(resp[0].QuestionList);
  451. quesList.value = resp[0];
  452. console.log(quesList.value);
  453. }
  454. };
  455. /** 计算答题时间 */
  456. const getSec = () => {
  457. time = setTimeout(() => {
  458. let answerUseTime = quesAnswers.AnswerUseTime;
  459. answerUseTime++;
  460. quesAnswers.AnswerUseTime = answerUseTime;
  461. getSec();
  462. }, 1000);
  463. };
  464. /** 根据子标题排序 */
  465. const bySort = (list: any[]) => {
  466. let find = 0;
  467. let sort = 0;
  468. let item = {} as any;
  469. for (var t = 0; t < list.length; t++) {
  470. item = list[t];
  471. //子标题
  472. if (item.QuestType == 'SubTitle') {
  473. //将子标题底下的题目从1开始排
  474. sort = 0;
  475. //判断是出现的第几个子标题
  476. //num是子标题的排序
  477. item.Num = toChinesNum(find + 1);
  478. find++;
  479. } else {
  480. //sort是子标题底下的排序
  481. item.Sort = sort + 1;
  482. sort++;
  483. }
  484. item.SortNum = t;
  485. if (common.isNotEmpty(item.QuestionItemList)) {
  486. item.QuestionItemList.forEach((childItem, childIndex) => {
  487. childItem.SortNum = childIndex;
  488. if (common.isNotEmpty(childItem.QuestionItem)) {
  489. childItem.QuestionItem.forEach((sunItem, sunIndex) => {
  490. sunItem.SortNum = sunIndex;
  491. });
  492. }
  493. });
  494. }
  495. }
  496. return list;
  497. };
  498. /** 汉字顺序 */
  499. const toChinesNum = (num) => {
  500. var changeNum = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'],
  501. newNum = '',
  502. arr = num.toString().split('');
  503. arr[0] = parseInt(arr[0]) - 1;
  504. if (arr[0] == -1 && arr.length == 1) {
  505. return '零';
  506. }
  507. if (arr.length > 1) {
  508. arr[1] = parseInt(arr[1]) - 1;
  509. if (!arr[0]) {
  510. newNum = !arr[0] && arr[1] == -1 ? changeNum[9] : changeNum[9] + changeNum[arr[1]];
  511. } else {
  512. newNum = changeNum[arr[0]] + changeNum[9] + (changeNum[arr[1]] ? changeNum[arr[1]] : '');
  513. }
  514. } else {
  515. newNum = changeNum[arr[0]];
  516. }
  517. return newNum;
  518. };
  519. /** 单选/多选/量表 */
  520. const choiceOption = (e) => {
  521. let index = e.currentTarget.dataset.index;
  522. let childIndex = e.currentTarget.dataset.childindex;
  523. let answerIndex = 0;
  524. let questionList = quesList.value.QuestionList;
  525. let answerList = quesAnswers.AnswerList;
  526. answerList.forEach((itm, ind) => {
  527. if (itm.QuestId == questionList[index].QuestId) {
  528. answerIndex = ind;
  529. }
  530. });
  531. // 单选/量表
  532. if (questionList[index].QuestType == 'Radio' || questionList[index].QuestType == 'Scale') {
  533. if (
  534. questionList[index].AnswerList[0] != questionList[index].QuestionItemList[childIndex].ItemId
  535. ) {
  536. questionList[index].AnswerList = [];
  537. questionList[index].AnswerList.push(questionList[index].QuestionItemList[childIndex].ItemId);
  538. }
  539. answerList[answerIndex].Answer = questionList[index].QuestionItemList[childIndex].ItemId;
  540. }
  541. // 多选
  542. else if (questionList[index].QuestType == 'Checkbox') {
  543. let flag = false;
  544. questionList[index].AnswerList.forEach((item) => {
  545. if (item == questionList[index].QuestionItemList[childIndex].ItemId) {
  546. flag = true;
  547. }
  548. });
  549. if (flag) {
  550. questionList[index].AnswerList = questionList[index].AnswerList.filter((item) => {
  551. return item != questionList[index].QuestionItemList[childIndex].ItemId;
  552. });
  553. answerList[answerIndex].Answer = answerList[answerIndex].Answer.filter((fiItem) => {
  554. return fiItem != questionList[index].QuestionItemList[childIndex].ItemId;
  555. });
  556. } else {
  557. if (questionList[index].RuleInfo.MaxLength < questionList[index].AnswerList.length + 1) {
  558. common.showModal('最多选择' + questionList[index].RuleInfo.MaxLength + '项');
  559. return;
  560. }
  561. questionList[index].AnswerList.push(questionList[index].QuestionItemList[childIndex].ItemId);
  562. answerList[answerIndex].Answer.push(questionList[index].QuestionItemList[childIndex].ItemId);
  563. }
  564. }
  565. quesList.value.QuestionList = questionList;
  566. quesAnswers.AnswerList = answerList;
  567. };
  568. /** 选择题 */
  569. const bindPickerChange = (e) => {
  570. let index = e.currentTarget.dataset.index;
  571. let val = e.detail.value;
  572. let questionList = quesList.value.QuestionList;
  573. let answerList = quesAnswers.AnswerList;
  574. let answerIndex = 0;
  575. answerList.forEach((itm, ind) => {
  576. if (itm.QuestId == questionList[index].QuestId) {
  577. answerIndex = ind;
  578. }
  579. });
  580. questionList[index].AnswerList = val;
  581. answerList[answerIndex].Answer = questionList[index].QuestionItemList[val].ItemId;
  582. quesList.value.QuestionList = questionList;
  583. quesAnswers.AnswerList = answerList;
  584. };
  585. /** 矩阵单选 */
  586. const choiceMatrixOption = (e) => {
  587. let index = e.currentTarget.dataset.index;
  588. let childIndex = e.currentTarget.dataset.childindex;
  589. let sunIndex = e.currentTarget.dataset.sunindex;
  590. let questionList = quesList.value.QuestionList;
  591. let answerList = quesAnswers.AnswerList;
  592. let answerIndex = 0;
  593. answerList.forEach((itm, ind) => {
  594. if (itm.QuestId == questionList[index].MatrixQuestionList[childIndex].QuestId) {
  595. answerIndex = ind;
  596. }
  597. });
  598. // 矩阵单选/矩阵量表
  599. if (
  600. questionList[index].QuestType == 'MatrixRadio' ||
  601. questionList[index].QuestType == 'MatrixScale'
  602. ) {
  603. if (
  604. questionList[index].MatrixQuestionList[childIndex].AnswerList[0] !=
  605. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  606. ) {
  607. questionList[index].MatrixQuestionList[childIndex].AnswerList = [];
  608. questionList[index].MatrixQuestionList[childIndex].AnswerList.push(
  609. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  610. );
  611. }
  612. answerList[answerIndex].Answer =
  613. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId;
  614. }
  615. // 矩阵多选
  616. else if (questionList[index].QuestType == 'MatrixCheckbox') {
  617. let flag = false;
  618. questionList[index].MatrixQuestionList[childIndex].AnswerList.forEach((item) => {
  619. if (
  620. item == questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  621. ) {
  622. flag = true;
  623. }
  624. });
  625. if (flag) {
  626. questionList[index].MatrixQuestionList[childIndex].AnswerList = questionList[
  627. index
  628. ].MatrixQuestionList[childIndex].AnswerList.filter((item) => {
  629. return (
  630. item !=
  631. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  632. );
  633. });
  634. answerList[answerIndex].Answer = answerList[answerIndex].Answer.filter((fiItem) => {
  635. return (
  636. fiItem !=
  637. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  638. );
  639. });
  640. } else {
  641. questionList[index].MatrixQuestionList[childIndex].AnswerList.push(
  642. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  643. );
  644. answerList[answerIndex].Answer.push(
  645. questionList[index].MatrixQuestionList[childIndex].QuestionItemList[sunIndex].ItemId
  646. );
  647. }
  648. }
  649. quesList.value.QuestionList = questionList;
  650. quesAnswers.AnswerList = answerList;
  651. };
  652. /** 选择文件 */
  653. const choiceFile = (e) => {
  654. let index = e.currentTarget.dataset.index;
  655. let questionList = quesList.value.QuestionList;
  656. let answerList = quesAnswers.AnswerList;
  657. let answerIndex = 0;
  658. answerList.forEach((itm, ind) => {
  659. if (itm.QuestId == questionList[index].QuestId) {
  660. answerIndex = ind;
  661. }
  662. });
  663. if (answerList[answerIndex].Answer.length >= questionList[index].RuleInfo.FileCount) {
  664. common.showModal('最多上传' + questionList[index].RuleInfo.FileCount + '张图片');
  665. return;
  666. }
  667. uni.chooseMedia({
  668. count: questionList[index].RuleInfo.FileCount,
  669. mediaType: ['image'],
  670. sourceType: ['album', 'camera'],
  671. sizeType: ['compressed'],
  672. async success(res) {
  673. uni.showLoading({
  674. title: '上传中。。。',
  675. });
  676. for (var i = 0; i < res.tempFiles.length; i++) {
  677. let m = 1024 * 1024;
  678. if (res.tempFiles[i].size < m) {
  679. let imgUrl = (await uploadFile(
  680. res.tempFiles[i].tempFilePath,
  681. questionList[index].RuleInfo.FileCount,
  682. answerList[answerIndex].Answer
  683. )) as string;
  684. if (common.isNotEmpty(imgUrl)) {
  685. imgUrl =
  686. imgUrl.indexOf('http') > -1 ? imgUrl : useDomain() + imgUrl.replace(/\\/g, '/');
  687. answerList[answerIndex].Answer.push(imgUrl);
  688. questionList[index].AnswerList = answerList[answerIndex].Answer;
  689. quesList.value.QuestionList = questionList;
  690. quesAnswers.AnswerList = answerList;
  691. if (res.tempFiles.length - 1 == i) {
  692. uni.hideLoading();
  693. }
  694. }
  695. } else {
  696. uni.hideLoading();
  697. common.showModal('文件不得大于' + questionList[index].RuleInfo.FileSize + 'M');
  698. return;
  699. }
  700. }
  701. },
  702. });
  703. };
  704. /** 上传文件 */
  705. const uploadFile = (imgItem, fileCount, imgList) => {
  706. return new Promise((resolve, reject) => {
  707. if (imgList.length >= fileCount) {
  708. uni.hideLoading();
  709. common.showModal('最多上传' + fileCount + '张图片');
  710. return;
  711. }
  712. // 将图片上传至服务器
  713. uni.uploadFile({
  714. url: UploadZxFile,
  715. filePath: imgItem,
  716. name: 'newsFile',
  717. formData: {
  718. user: 'test',
  719. },
  720. header: {
  721. token: uni.getStorageSync('token'),
  722. },
  723. data: {},
  724. success(res) {
  725. const data = JSON.parse(res.data);
  726. if (data.RespCode == '10000') {
  727. resolve(data.url);
  728. } else {
  729. common.showModal(data.msg);
  730. }
  731. },
  732. });
  733. });
  734. };
  735. /** 删除图片 */
  736. const closeImg = (e) => {
  737. let index = e.currentTarget.dataset.index;
  738. let imgItem = e.currentTarget.dataset.imgitem;
  739. let questionList = quesList.value.QuestionList;
  740. let answerList = quesAnswers.AnswerList;
  741. let answerIndex = 0;
  742. answerList.forEach((itm, ind) => {
  743. if (itm.QuestId == questionList[index].QuestId) {
  744. answerIndex = ind;
  745. }
  746. });
  747. answerList[answerIndex].Answer = answerList[answerIndex].Answer.filter((item) => {
  748. return item != imgItem;
  749. });
  750. questionList[index].AnswerList = answerList[answerIndex].Answer;
  751. quesList.value.QuestionList = questionList;
  752. quesAnswers.AnswerList = answerList;
  753. };
  754. /** 获取input值 */
  755. const setVal = (e) => {
  756. let index = e.currentTarget.dataset.index;
  757. let childIndex = e.currentTarget.dataset.childindex;
  758. let questionList = quesList.value.QuestionList;
  759. let answerList = quesAnswers.AnswerList;
  760. let answerIndex = 0;
  761. // 矩阵填空题
  762. if (questionList[index].QuestType == 'MatrixInput') {
  763. if (
  764. questionList[index].MatrixQuestionList[childIndex].AnswerList.length ==
  765. questionList[index].MatrixQuestionList[childIndex].RuleInfo.MaxLength
  766. ) {
  767. common.showToast(
  768. '最多输入' + questionList[index].MatrixQuestionList[childIndex].RuleInfo.MaxLength + '个字'
  769. );
  770. return;
  771. }
  772. answerList.forEach((itm, ind) => {
  773. if (itm.QuestId == questionList[index].MatrixQuestionList[childIndex].QuestId) {
  774. answerIndex = ind;
  775. }
  776. });
  777. questionList[index].MatrixQuestionList[childIndex].AnswerList = e.detail.value;
  778. }
  779. // 填空题
  780. else {
  781. if (questionList[index].RuleInfo.DataType != '无') {
  782. let dataTypeOptions = questionList[index].RuleInfo.DataTypeOptions;
  783. for (var i = 0; i < dataTypeOptions.length; i++) {
  784. if (questionList[index].RuleInfo.DataType == dataTypeOptions[i].Value) {
  785. const regRule = dataTypeOptions[i].Rule;
  786. let reg = null;
  787. if (regRule.startsWith('/') && regRule.endsWith('/')) {
  788. reg = new RegExp(regRule.slice(1, -1));
  789. } else {
  790. reg = new RegExp(regRule);
  791. }
  792. if (!reg.test(e.detail.value)) {
  793. common.showModal('请输入' + dataTypeOptions[i].Text);
  794. questionList[index].AnswerList = '';
  795. answerList[answerIndex].Answer = '';
  796. this.setData({
  797. 'quesList.QuestionList': questionList,
  798. 'quesAnswers.AnswerList': answerList,
  799. });
  800. return;
  801. }
  802. }
  803. }
  804. }
  805. if (questionList[index].AnswerList.length == questionList[index].RuleInfo.MaxLength) {
  806. common.showToast('最多输入' + questionList[index].RuleInfo.MaxLength + '个字');
  807. return;
  808. }
  809. answerList.forEach((itm, ind) => {
  810. if (itm.QuestId == questionList[index].QuestId) {
  811. answerIndex = ind;
  812. }
  813. });
  814. questionList[index].AnswerList = e.detail.value;
  815. }
  816. answerList[answerIndex].Answer = e.detail.value;
  817. quesList.value.QuestionList = questionList;
  818. quesAnswers.AnswerList = answerList;
  819. };
  820. /** 提交 */
  821. const submit = async () => {
  822. uni.showLoading();
  823. await common.sleep(1000);
  824. if (complete.value) return;
  825. const answers = { ...quesAnswers } as any;
  826. for (var i = 0; i < answers.AnswerList.length; i++) {
  827. let item = answers.AnswerList[i];
  828. if (item.MustQuest && common.isEmpty(item.Answer)) {
  829. common.showToast('存在未填写的问卷');
  830. point.value = 'p' + item.Blank;
  831. return;
  832. }
  833. }
  834. answers.AnswerList.forEach((item) => {
  835. if (typeof item.Answer == 'object') {
  836. item.Answer = item.Answer.join();
  837. }
  838. });
  839. answers.AnswerList = JSON.stringify(quesAnswers.AnswerList);
  840. quesAnswers.IP = (await getIP()).cip;
  841. quesAnswers.Location = (await getIP()).cname;
  842. quesAnswers.UserAgent = app.globalData.smallPro_systemInfo;
  843. quesAnswers.Mobile = currentUser.value.mobile;
  844. quesAnswers.UserName = currentUser.value.memberName;
  845. quesAnswers.MemberId = currentUser.value.memberId;
  846. quesAnswers.Sex = currentUser.value.sex;
  847. quesAnswers.Age = currentUser.value.age;
  848. quesAnswers.ThirdPartyId = currentUser.value.memberId || uni.getStorageSync('openid');
  849. quesAnswers.BedNo = '';
  850. quesAnswers.HospitalNo = objType.value == '4' ? currentUser.value.cardNo : '';
  851. quesAnswers.CardNo = objType.value == '3' ? currentUser.value.cardNo : '';
  852. quesAnswers.TaskId = taskId.value;
  853. let res = await CommitAnswer_V3(quesAnswers);
  854. clearTimeout(time);
  855. if (common.isNotEmpty(res)) {
  856. common.showModal('提交成功!', () => {
  857. common.navigateBack(1);
  858. });
  859. }
  860. };
  861. /** 获取IP */
  862. const getIP = () => {
  863. return new Promise((resolve, reject) => {
  864. uni.request({
  865. url: 'https://pv.sohu.com/cityjson?ie=utf-8',
  866. success: (res: any) => {
  867. const result = res.data.substring(res.data.indexOf('{'), res.data.lastIndexOf('}') + 1);
  868. const obj = JSON.parse(result);
  869. resolve(obj);
  870. },
  871. });
  872. }) as Promise<any>;
  873. };
  874. const goBack = () => {
  875. uni.navigateBack({
  876. delta: 1,
  877. });
  878. };
  879. const yjfk = () => {};
  880. const goSelMember = () => {};
  881. const confirmMember = () => {};
  882. useOnLoad((options) => {
  883. main(options);
  884. });
  885. </script>
  886. <style lang="scss" scoped>
  887. .align_items_left {
  888. align-items: flex-start;
  889. }
  890. .active_option {
  891. background: #18ba89 !important;
  892. color: white !important;
  893. }
  894. .mask_form {
  895. width: 100%;
  896. height: 100%;
  897. position: absolute;
  898. top: 0;
  899. left: 0;
  900. z-index: 100;
  901. }
  902. .container {
  903. overflow: hidden;
  904. }
  905. .scroll_view {
  906. height: 100%;
  907. }
  908. .top_bg_box {
  909. position: relative;
  910. image {
  911. width: 100%;
  912. height: 456rpx;
  913. position: absolute;
  914. top: 0;
  915. left: 0;
  916. z-index: 1;
  917. }
  918. .ques_introduce {
  919. padding: 46rpx 52rpx 0 52rpx;
  920. box-sizing: border-box;
  921. position: absolute;
  922. top: 0;
  923. left: 0;
  924. z-index: 2;
  925. text:nth-child(1) {
  926. font-size: 36rpx;
  927. font-weight: bold;
  928. color: white;
  929. margin-bottom: 20rpx;
  930. }
  931. text:nth-child(2) {
  932. line-height: 45rpx;
  933. font-size: 28rpx;
  934. color: white;
  935. }
  936. }
  937. }
  938. .main_box {
  939. padding: 470rpx 30rpx 190rpx 30rpx;
  940. box-sizing: border-box;
  941. position: relative;
  942. z-index: 2;
  943. }
  944. .ques_item_box {
  945. padding: 30rpx;
  946. box-sizing: border-box;
  947. background: white;
  948. border-radius: 20rpx;
  949. margin-bottom: 32rpx;
  950. > .ques_title_box > text {
  951. line-height: 50rpx;
  952. font-size: 36rpx;
  953. font-weight: bold;
  954. color: #1c1c1c;
  955. }
  956. .mustQuest_tag {
  957. color: #dc2828;
  958. }
  959. }
  960. .ques_options {
  961. margin-top: 34rpx;
  962. }
  963. .choice_item {
  964. width: 100%;
  965. line-height: 80rpx;
  966. font-size: 30rpx;
  967. color: #686868;
  968. text-align: center;
  969. margin-bottom: 16rpx;
  970. border-radius: 10rpx;
  971. background: #f8f8fa;
  972. &:last-child {
  973. margin-bottom: 0;
  974. }
  975. }
  976. .input_label {
  977. line-height: 40rpx;
  978. font-size: 32rpx;
  979. color: #474747;
  980. }
  981. .textarea_box {
  982. width: 100%;
  983. padding: 20rpx;
  984. box-sizing: border-box;
  985. border-radius: 10rpx;
  986. background: #f8f8fa;
  987. margin-top: 22rpx;
  988. textarea {
  989. width: 100%;
  990. }
  991. }
  992. .matrix_textarea_box {
  993. width: 70%;
  994. }
  995. .picker_box {
  996. width: 100%;
  997. }
  998. .picker {
  999. width: 100%;
  1000. height: 80rpx;
  1001. padding: 22rpx;
  1002. box-sizing: border-box;
  1003. background: #f9f9f9;
  1004. border-radius: 20rpx;
  1005. justify-content: space-between;
  1006. text {
  1007. white-space: nowrap;
  1008. font-size: 28rpx;
  1009. color: #686868;
  1010. }
  1011. image {
  1012. width: 12rpx;
  1013. height: 24rpx;
  1014. }
  1015. }
  1016. .matrix_options {
  1017. width: 100%;
  1018. margin-bottom: 34rpx;
  1019. justify-content: space-between;
  1020. text {
  1021. font-size: 30rpx;
  1022. color: #1c1c1c;
  1023. text-align: center;
  1024. padding: 20rpx;
  1025. box-sizing: border-box;
  1026. word-wrap: break-word;
  1027. word-break: break-all;
  1028. }
  1029. }
  1030. .matrix_border {
  1031. border: 1px solid #f0f0f0;
  1032. }
  1033. .matrix_options_title {
  1034. background: #f5f5f5;
  1035. }
  1036. .matrix_icon_box {
  1037. width: 100%;
  1038. align-items: flex-start;
  1039. text {
  1040. font-size: 30rpx;
  1041. color: #1c1c1c;
  1042. margin-bottom: 36rpx;
  1043. padding: 0 20rpx;
  1044. box-sizing: border-box;
  1045. }
  1046. image {
  1047. width: 40rpx;
  1048. height: 40rpx;
  1049. }
  1050. }
  1051. .sub_title {
  1052. background: none;
  1053. }
  1054. .img_list {
  1055. width: 100%;
  1056. margin-bottom: 24rpx;
  1057. justify-content: flex-start;
  1058. flex-wrap: wrap;
  1059. .item_img {
  1060. width: 100%;
  1061. height: 100%;
  1062. }
  1063. }
  1064. .add_img {
  1065. width: 32%;
  1066. height: 200rpx;
  1067. margin-right: 2%;
  1068. margin-bottom: 3%;
  1069. position: relative;
  1070. &:nth-child(3n) {
  1071. margin-right: 0;
  1072. }
  1073. }
  1074. .add_img_tips {
  1075. width: 100%;
  1076. text {
  1077. font-size: 30rpx;
  1078. color: #474747;
  1079. }
  1080. }
  1081. .cha_img {
  1082. width: 50rpx;
  1083. height: 50rpx;
  1084. position: absolute;
  1085. top: -15rpx;
  1086. right: -5rpx;
  1087. }
  1088. .options_item_box {
  1089. width: 100%;
  1090. padding: 0 10rpx;
  1091. box-sizing: border-box;
  1092. margin-bottom: 20rpx;
  1093. justify-content: space-between;
  1094. text {
  1095. font-size: 28rpx;
  1096. color: #686868;
  1097. word-wrap: break-word;
  1098. word-break: break-all;
  1099. }
  1100. image {
  1101. width: 40rpx;
  1102. height: 40rpx;
  1103. margin: 20rpx 0;
  1104. }
  1105. }
  1106. .matrix_input_box {
  1107. width: 100%;
  1108. text {
  1109. width: 30%;
  1110. white-space: nowrap;
  1111. }
  1112. input {
  1113. width: 70%;
  1114. }
  1115. }
  1116. .footer_box {
  1117. width: 100%;
  1118. padding: 30rpx 30rpx 60rpx 30rpx;
  1119. box-sizing: border-box;
  1120. background: white;
  1121. position: fixed;
  1122. bottom: 0;
  1123. left: 0;
  1124. z-index: 10;
  1125. text {
  1126. width: 100%;
  1127. line-height: 88rpx;
  1128. font-size: 36rpx;
  1129. color: white;
  1130. text-align: center;
  1131. border-radius: 88rpx;
  1132. background: #18ba89;
  1133. display: block;
  1134. }
  1135. }
  1136. .modal_wrap {
  1137. width: 100%;
  1138. height: 100%;
  1139. background-color: rgba(0, 0, 0, 0.6);
  1140. position: fixed;
  1141. left: 0;
  1142. top: 0;
  1143. z-index: 99;
  1144. display: flex;
  1145. align-items: center;
  1146. justify-content: center;
  1147. }
  1148. .modal_box {
  1149. width: 600rpx;
  1150. max-height: 600rpx;
  1151. background-color: #fff;
  1152. border-radius: 5px;
  1153. padding: 40rpx 40rpx 60rpx;
  1154. }
  1155. .modal_tit {
  1156. text-align: center;
  1157. font-size: 30rpx;
  1158. }
  1159. .modal_box_b1 {
  1160. background-color: #f2f2f2;
  1161. border-radius: 5px;
  1162. line-height: 80rpx;
  1163. margin-top: 40rpx;
  1164. /* padding-left: 40rpx; */
  1165. text-align: center;
  1166. }
  1167. .modal_user_item {
  1168. background: #f2f2f2;
  1169. padding: 30rpx;
  1170. margin-top: 40rpx;
  1171. position: relative;
  1172. }
  1173. .modal_user_right_img {
  1174. width: 12rpx;
  1175. height: 21rpx;
  1176. position: absolute;
  1177. right: 30rpx;
  1178. top: 0;
  1179. bottom: 0;
  1180. margin: auto 0;
  1181. }
  1182. .modal_t1 {
  1183. font-weight: bold;
  1184. display: inline-block;
  1185. margin-right: 20rpx;
  1186. font-size: 32rpx;
  1187. }
  1188. .modal_t3 {
  1189. margin-top: 20rpx;
  1190. }
  1191. .modal_btn {
  1192. width: 46%;
  1193. line-height: 75rpx;
  1194. text-align: center;
  1195. border-radius: 50rpx;
  1196. margin-top: 40rpx;
  1197. }
  1198. .modal_btn1 {
  1199. background: #aaaaaa;
  1200. color: #fff;
  1201. }
  1202. .modal_btn2 {
  1203. background: #61c88f;
  1204. color: #fff;
  1205. }
  1206. .yjfl {
  1207. position: fixed;
  1208. bottom: 340rpx;
  1209. right: 0;
  1210. z-index: 100;
  1211. width: 160rpx;
  1212. text-align: center;
  1213. .title {
  1214. color: #fff;
  1215. position: absolute;
  1216. bottom: 10rpx;
  1217. right: 4rpx;
  1218. width: 100%;
  1219. text-align: center;
  1220. font-size: 24rpx;
  1221. }
  1222. }
  1223. </style>