my_form.vue 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. <template>
  2. <view>
  3. <view class="requiredFieldOnly-head" v-if="requiredFieldOnly">
  4. <view class="label"> 基本信息 </view>
  5. <view class="content">
  6. 仅显示必填信息<text style="padding: 0 2.5px" />
  7. <u-switch activeColor="#C40C24" v-model="unShowAll" />
  8. </view>
  9. </view>
  10. <slot name="head" />
  11. <block v-for="(item, index) in list" :key="item.key">
  12. <block v-if="item.isMust || !unShowAll">
  13. <!-- 文本输入 -->
  14. <view
  15. class="input-box"
  16. v-if="item.type == 'text'"
  17. :style="{
  18. marginTop: tovw(item.marginTop || 0),
  19. opacity: item.disabled ? 0.7 : 1,
  20. }"
  21. @click="focusLabel = item.label"
  22. >
  23. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  24. <view class="label">
  25. <text class="must" v-if="item.isMust">*</text>
  26. {{ item.label }}:
  27. </view>
  28. <view class="content-box" style="flex: 1">
  29. <view
  30. class="content"
  31. style="display: flex; flex: 1; box-sizing: border-box"
  32. >
  33. <input
  34. v-if="item.inputmode == 'number'"
  35. type="number"
  36. :disabled="item.disabled"
  37. placeholder-style="color: #BBBBBB;font-family: Source Han Sans SC, Source Han Sans SC;"
  38. :focus="focusLabel == item.label"
  39. :placeholder="item.placeholder || '请填写' + item.label"
  40. :value="item.value"
  41. style="flex: 1"
  42. @input="onInput($event, index)"
  43. :maxlength="item.maxlength || '499'"
  44. confirm-type="done"
  45. />
  46. <input
  47. v-else-if="item.inputmode == 'digit'"
  48. type="digit"
  49. :disabled="item.disabled"
  50. placeholder-style="color: #BBBBBB;font-family: Source Han Sans SC, Source Han Sans SC;"
  51. :focus="focusLabel == item.label"
  52. :placeholder="item.placeholder || '请填写' + item.label"
  53. :value="item.value"
  54. style="flex: 1"
  55. @input="onInput($event, index)"
  56. :maxlength="item.maxlength || '499'"
  57. confirm-type="done"
  58. />
  59. <textarea
  60. v-else
  61. :disabled="item.disabled"
  62. placeholder-style="color: #BBBBBB;font-family: Source Han Sans SC, Source Han Sans SC;"
  63. auto-height
  64. type="text"
  65. :focus="focusLabel == item.label"
  66. :placeholder="item.placeholder || '请填写' + item.label"
  67. :value="item.value"
  68. style="flex: 1; width: 0; box-sizing: border-box"
  69. @input="onInput($event, index)"
  70. :maxlength="item.maxlength || '499'"
  71. confirm-type="done"
  72. />
  73. <icon
  74. v-if="item.value && !item.disabled"
  75. class="icon"
  76. type="clear"
  77. size="3.733vw"
  78. @click="onClearInput(index)"
  79. />
  80. <view style="margin-left: 6px" v-if="item.getPhoneNumber">
  81. <u-button
  82. color="#C30D23"
  83. size="small"
  84. open-type="getPhoneNumber"
  85. @click.stop=""
  86. @getphonenumber="butGetphonenumber($event, index)"
  87. >
  88. 获取微信
  89. <text
  90. class="iconfont icon-dianhua-hui"
  91. style="font-size: 12px; margin-left: 3px"
  92. />
  93. </u-button>
  94. </view>
  95. </view>
  96. <view v-if="item.errText" class="err-text">
  97. <icon
  98. class="icon"
  99. color="#E3041F"
  100. type="clear"
  101. size="2.733vw"
  102. />
  103. {{ item.errText }}
  104. </view>
  105. </view>
  106. </view>
  107. </view>
  108. <!-- 文本域 -->
  109. <view class="textarea-box" v-else-if="item.type == 'textarea'">
  110. <textarea
  111. class="textarea"
  112. :class="item.unBorBot ? '' : 'borBot'"
  113. :disabled="item.disabled"
  114. placeholder-style="color: #BBBBBB;font-family: Source Han Sans SC, Source Han Sans SC;"
  115. type="text"
  116. :placeholder="item.placeholder || '请填写' + item.label"
  117. :value="item.value"
  118. @input="onInput($event, index)"
  119. :maxlength="item.maxlength || '499'"
  120. confirm-type="done"
  121. />
  122. </view>
  123. <!-- 显示标题文本域 参考意见反馈 -->
  124. <view
  125. class="textarea-box2"
  126. v-else-if="item.type == 'textarea2'"
  127. :style="{ marginTop: tovw(item.marginTop || 0) }"
  128. >
  129. <view class="label">
  130. <text class="must" v-if="item.isMust">*</text>
  131. {{ item.label }}:
  132. </view>
  133. <textarea
  134. class="textarea"
  135. :class="item.unBorBot ? '' : 'borBot'"
  136. :disabled="item.disabled"
  137. placeholder-style="color: #BBBBBB;font-family: Source Han Sans SC, Source Han Sans SC;"
  138. type="text"
  139. :placeholder="item.placeholder || '请填写' + item.label"
  140. :value="item.value"
  141. @input="onInput($event, index)"
  142. :maxlength="item.maxlength || '499'"
  143. confirm-type="done"
  144. />
  145. </view>
  146. <!-- 自定义选项分类 -->
  147. <view
  148. class="custom-class-box"
  149. v-else-if="item.type == 'customClass'"
  150. :style="{ marginTop: tovw(item.marginTop || 0) }"
  151. >
  152. <view class="head">
  153. <view class="label">
  154. <text class="must" style="color: #e3041f" v-if="item.isMust"
  155. >*</text
  156. >
  157. {{ item.label }}
  158. </view>
  159. <view class="state">
  160. {{ item.isMultipleChoice ? "可多选" : "仅单选" }}
  161. </view>
  162. </view>
  163. <view class="options">
  164. <view
  165. class="option"
  166. :class="
  167. item.isMultipleChoice
  168. ? item.value.includes(option.value)
  169. ? 'active'
  170. : ''
  171. : item.value == option.value
  172. ? 'active'
  173. : ''
  174. "
  175. v-for="option in item.list"
  176. :key="option.value"
  177. hover-class="navigator-hover"
  178. @click="changOptions(option.value, index)"
  179. >
  180. {{ option.remarks }}
  181. </view>
  182. </view>
  183. </view>
  184. <!-- 选择所在地区 -->
  185. <picker
  186. class="region"
  187. @change="selectRegion($event, index)"
  188. mode="region"
  189. :disabled="item.disabled"
  190. :value="item.value"
  191. v-else-if="item.type == 'region'"
  192. :style="{
  193. marginTop: tovw(item.marginTop || 0),
  194. opacity: item.disabled ? 0.7 : 1,
  195. }"
  196. >
  197. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  198. <view class="label">
  199. <text class="must" v-if="item.isMust">*</text>
  200. {{ item.label }}:
  201. </view>
  202. <view class="content-box">
  203. <view class="value" v-if="item.value.length">
  204. {{ item.value.join(",") }}
  205. </view>
  206. <view v-else class="placeholder" hover-class="none">
  207. {{ item.placeholder || "请选择" + item.label }}
  208. </view>
  209. <view
  210. v-if="!item.disabled"
  211. class="iconfont icon-a-wodetiaozhuan"
  212. />
  213. </view>
  214. </view>
  215. </picker>
  216. <!-- 日期 -->
  217. <picker
  218. class="region"
  219. @change="selectRegion($event, index)"
  220. mode="date"
  221. :disabled="item.disabled"
  222. :value="item.value"
  223. v-else-if="item.type == 'date'"
  224. :style="{
  225. marginTop: tovw(item.marginTop || 0),
  226. opacity: item.disabled ? 0.7 : 1,
  227. }"
  228. >
  229. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  230. <view class="label">
  231. <text class="must" v-if="item.isMust">*</text>
  232. {{ item.label }}:
  233. </view>
  234. <view class="content-box">
  235. <view class="value" v-if="item.value">
  236. {{ item.value }}
  237. </view>
  238. <view v-else class="placeholder" hover-class="none">
  239. {{ item.placeholder || "请选择" + item.label }}
  240. </view>
  241. <view
  242. v-if="!item.disabled"
  243. class="iconfont icon-a-wodetiaozhuan"
  244. />
  245. </view>
  246. </view>
  247. </picker>
  248. <!-- 上传附件 -->
  249. <view
  250. class="custom-class-box"
  251. v-else-if="item.type == 'upload'"
  252. :style="{ marginTop: tovw(item.marginTop || 0) }"
  253. >
  254. <view class="head">
  255. <view class="label">
  256. <text class="must" v-if="item.isMust">*</text>
  257. {{ item.label }}
  258. </view>
  259. <view class="state">
  260. {{ item.placeholder }}
  261. </view>
  262. </view>
  263. <view class="content">
  264. <view
  265. class="file-box"
  266. v-for="file in item.value"
  267. :key="file.attachmentid"
  268. >
  269. <image
  270. class="image"
  271. v-if="file.fileType == 'image'"
  272. :src="file.url"
  273. mode="aspectFill"
  274. lazy-load="true"
  275. @click="previewImg(file)"
  276. />
  277. <video
  278. v-else-if="file.fileType == 'video'"
  279. class="video"
  280. :poster="file.subfiles[0].url"
  281. :src="file.url"
  282. />
  283. <image
  284. class="delete"
  285. @click.stop="deleteFile(file, index)"
  286. src="https://yossys06593.obs.cn-east-3.myhuaweicloud.com:443/202404241713944430197B47af9b2f.png"
  287. mode="widthFix"
  288. />
  289. </view>
  290. <My_upload
  291. v-if="item.allowUpload"
  292. :showLoading="false"
  293. :maxCount="item.maxCount || 99"
  294. :accept="item.accept"
  295. @uploadCallback="uploadCallback($event, index)"
  296. @onLoading="onUploadLoading($event, index)"
  297. >
  298. <view
  299. class="upload-box"
  300. v-if="
  301. item.maxCount
  302. ? item.value.length != item.maxCount
  303. : item.value.length != 99
  304. "
  305. hover-class="navigator-hover"
  306. >
  307. <u-loading-icon v-if="item.loading" />
  308. <text v-else class="iconfont icon-xiazai" />
  309. <text style="margin-left: 5px">上传</text>
  310. </view>
  311. </My_upload>
  312. </view>
  313. </view>
  314. <!-- 开关 -->
  315. <view class="region" v-else-if="item.type == 'switch'">
  316. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  317. <view class="label">
  318. <text class="must" v-if="item.isMust">*</text>
  319. {{ item.label }}:
  320. </view>
  321. <view class="content-box">
  322. <view />
  323. <u-switch
  324. activeColor="#70D95D"
  325. v-model="item.value"
  326. :disabled="item.disabled"
  327. @change="switchChange($event, index)"
  328. />
  329. </view>
  330. </view>
  331. </view>
  332. <!-- 性别 -->
  333. <view class="region" v-else-if="item.type == 'sex'">
  334. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  335. <view class="label">
  336. <text class="must" v-if="item.isMust">*</text>
  337. {{ item.label }}:
  338. </view>
  339. <u-radio-group
  340. v-model="item.value"
  341. placement="row"
  342. @change="groupChange($event, index)"
  343. >
  344. <u-radio
  345. :customStyle="{ marginRight: tovw(60) }"
  346. label="男"
  347. name="男"
  348. />
  349. <u-radio label="女" name="女" />
  350. </u-radio-group>
  351. </view>
  352. </view>
  353. <!-- 单选 -->
  354. <view class="region" v-else-if="item.type == 'radio'">
  355. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  356. <view class="label">
  357. <text class="must" v-if="item.isMust">*</text>
  358. {{ item.label }}:
  359. </view>
  360. <u-radio-group
  361. v-model="item.value"
  362. :placement="item.placement || 'row'"
  363. @change="groupChange($event, index)"
  364. >
  365. <u-radio
  366. v-for="option in item.options"
  367. :customStyle="{
  368. marginRight: tovw(
  369. option.marginRight || item.marginRight || 0
  370. ),
  371. marginTop: tovw(option.marginTop || item.marginTop || 0),
  372. }"
  373. :key="option.label"
  374. :label="option.label"
  375. :name="option.name"
  376. />
  377. </u-radio-group>
  378. </view>
  379. </view>
  380. <!-- 路由选择器 -->
  381. <view
  382. class="region"
  383. v-else-if="item.type == 'route'"
  384. :style="{
  385. marginTop: tovw(item.marginTop || 0),
  386. opacity: item.disabled ? 0.7 : 1,
  387. }"
  388. @click="item.disabled ? '' : toRoute(item, index)"
  389. >
  390. <view class="box" :class="item.unBorBot ? '' : 'borBot'">
  391. <view class="label">
  392. <text class="must" v-if="item.isMust">*</text>
  393. {{ item.label }}:
  394. </view>
  395. <view class="content-box">
  396. <view class="value" v-if="item.showValue.length">
  397. {{ item.showValue.join(",") }}
  398. </view>
  399. <view v-else class="placeholder" hover-class="none">
  400. {{ item.placeholder || "请选择" + item.label }}
  401. </view>
  402. <view
  403. v-if="!item.disabled"
  404. class="iconfont icon-a-wodetiaozhuan"
  405. />
  406. </view>
  407. </view>
  408. </view>
  409. <!-- 标签 -->
  410. <view
  411. class="tag-box custom-class-box"
  412. v-else-if="item.type == 'tag'"
  413. :style="{ marginTop: tovw(item.marginTop || 0) }"
  414. >
  415. <text class="label">{{ item.label }}</text>
  416. <view class="tag-list">
  417. <view class="tag" v-for="tag in item.value" :key="tag">
  418. <text>{{ tag }}</text>
  419. <view @click="delTag(tag, index)" class="del">x</view>
  420. </view>
  421. <view>
  422. <u-modal
  423. :title="item.label"
  424. :show="showTagModal"
  425. style="flex: 0 !important"
  426. confirmColor="#C30D23"
  427. ref="uModal"
  428. showCancelButton
  429. :asyncClose="false"
  430. @confirm="addTagSend(index)"
  431. @cancel="showTagModal = false"
  432. >
  433. <view class="slot-content">
  434. <view
  435. v-if="item.errText"
  436. class="err-text"
  437. style="margin-bottom: 10px"
  438. >
  439. <icon
  440. class="icon"
  441. color="#E3041F"
  442. type="clear"
  443. size="2.733vw"
  444. />
  445. {{ item.errText }}
  446. </view>
  447. <u--input
  448. :maxlength="item.maxlength ? item.maxlength : '99999'"
  449. :focus="showUModal"
  450. @input="onTagInput($event, index)"
  451. :placeholder="item.placeholder || '请输入'"
  452. v-model="tagValue"
  453. border="bottom"
  454. clearable
  455. />
  456. </view>
  457. </u-modal>
  458. <view class="add-tag" @click="showTagModal = true">+ 添加</view>
  459. </view>
  460. </view>
  461. </view>
  462. </block>
  463. </block>
  464. </view>
  465. </template>
  466. <script>
  467. import { formattedFiles, viewImage } from "../utils/settleFiles.js";
  468. export default {
  469. name: "my_form",
  470. props: {
  471. form: {
  472. type: Array,
  473. default: [],
  474. },
  475. isUncomplete: {
  476. type: Function,
  477. },
  478. onUploading: {
  479. type: Function,
  480. },
  481. requiredFieldOnly: {
  482. type: Boolean,
  483. },
  484. isShowAll: {
  485. type: Function,
  486. },
  487. interrupt: {
  488. type: Function,
  489. },
  490. },
  491. data() {
  492. return {
  493. list: [],
  494. focusLabel: "",
  495. unShowAll: false,
  496. showTagModal: false,
  497. tagValue: "",
  498. };
  499. },
  500. watch: {
  501. form: {
  502. handler: function (newVal) {
  503. if (newVal) {
  504. this.list = JSON.parse(JSON.stringify(newVal));
  505. setTimeout(() => {
  506. this.verify();
  507. }, 200);
  508. }
  509. },
  510. immediate: true,
  511. },
  512. unShowAll: function (newVal) {
  513. this.$emit("isShowAll", newVal);
  514. },
  515. },
  516. async created() {
  517. /* let list = [{
  518. key: "name",
  519. type: "text",
  520. label: "标题",
  521. isMust: true,//是否必填
  522. value: "",
  523. inputmode:"", //https://uniapp.dcloud.net.cn/component/input.html#type
  524. marginTop: 10,
  525. verify:[],
  526. }, {
  527. key: "Class",
  528. type: "customClass",
  529. label: "标题",
  530. isMust: false,//是否必填
  531. isMultipleChoice: true,//是否多选
  532. value: [],// 多选[] 单选 ""
  533. isMust: true,//是否必填
  534. list: await this.getCustomClass('picturespace'),
  535. marginTop: 10
  536. },{
  537. key: "attachmentids",
  538. type: "upload",
  539. label: "图片/视频",
  540. accept:"all",
  541. placeholder: "可上传多个视频或图片",
  542. ownertable: "temporary",
  543. ownerid: 999,
  544. usetype: 'default',
  545. allowUpload: true,
  546. allowDelete: true,
  547. value:[],
  548. marginTop: 10
  549. }, {
  550. key: "region",
  551. type: "region",
  552. label: "所在地区",
  553. isMust: true,//是否必填
  554. value: [],
  555. }, {
  556. key: "address",
  557. type: "textarea",
  558. label: "详细地址",
  559. isMust: true,//是否必填
  560. value: '',
  561. }, {
  562. key: "isdefault",
  563. type: "switch",
  564. label: "设为默认地址",
  565. isMust: false,//是否必填
  566. value: false,
  567. isNum: true,
  568. unBorBot: true
  569. }] */
  570. },
  571. methods: {
  572. delTag(tag, index) {
  573. let item = this.list[index];
  574. console.log(tag);
  575. item.value.splice(item.value.indexOf(tag), 1);
  576. this.$set(this.list[index], "value", item.value);
  577. },
  578. addTagSend(index) {
  579. let item = this.list[index];
  580. if (!item.errText) {
  581. item.value.push(this.tagValue);
  582. this.$set(this.list[index], "value", item.value);
  583. this.tagValue = "";
  584. this.showTagModal = false;
  585. }
  586. },
  587. toRoute(item, index) {
  588. let url = item.path;
  589. if (item.showValue.length) {
  590. let obj = JSON.stringify({
  591. value: item.value,
  592. showValue: item.showValue,
  593. });
  594. url +=
  595. (url.indexOf("?") == -1
  596. ? "?alreadySelecteds="
  597. : "&alreadySelecteds=") + obj;
  598. }
  599. uni.navigateTo({
  600. url,
  601. });
  602. this.$Http.routeSelected = function (selected) {
  603. this.$emit("interrupt", item, selected, index);
  604. delete this.$Http.routeSelected;
  605. }.bind(this);
  606. },
  607. onTagInput(e, index) {
  608. let item = this.list[index];
  609. item.errText = "";
  610. if (item.verify && item.verify.length && this.tagValue != "") {
  611. let err = item.verify.find(
  612. (r) => !new RegExp(r.reg).test(this.tagValue)
  613. );
  614. if (err) this.$set(this.list[index], "errText", err.errText);
  615. }
  616. this.verify();
  617. },
  618. butGetphonenumber(e, index) {
  619. if (e.detail.code) {
  620. this.$Http
  621. .basic({
  622. id: 20240520110702,
  623. content: {
  624. systemclient: getApp().globalData.systemclient,
  625. code: e.detail.code,
  626. },
  627. })
  628. .then((res) => {
  629. console.log("获取手机号", res);
  630. if (this.cutoff(res.msg)) return;
  631. this.$set(this.list[index], "value", res.data.phoneNumber);
  632. this.verify();
  633. });
  634. }
  635. },
  636. onInput(e, index) {
  637. let item = this.list[index];
  638. item.errText = "";
  639. this.$set(this.list[index], "value", e.detail.value);
  640. if (item.verify && item.verify.length && item.value != "") {
  641. let err = item.verify.find((r) => !new RegExp(r.reg).test(item.value));
  642. if (err) this.$set(this.list[index], "errText", err.errText);
  643. }
  644. this.verify();
  645. },
  646. setItem(index, item, back = false) {
  647. this.$set(this.list, index, item);
  648. this.verify();
  649. if (back) uni.navigateBack();
  650. },
  651. setValue(index, value, back = false) {
  652. this.$set(this.list[index], "value", value);
  653. this.verify();
  654. if (back) uni.navigateBack();
  655. },
  656. onClearInput(index) {
  657. let item = this.list[index];
  658. item.errText = "";
  659. this.$set(this.list[index], "value", "");
  660. this.verify();
  661. },
  662. switchChange(e, index) {
  663. this.$set(this.list[index], "value", e);
  664. this.verify();
  665. },
  666. changOptions(value, index) {
  667. let item = this.list[index];
  668. if (item.isMultipleChoice) {
  669. let i = -1;
  670. try {
  671. i = item.value.findIndex((v) => v == value);
  672. } catch (error) {}
  673. if (i == -1) {
  674. item.value.push(value);
  675. } else {
  676. item.value.splice(i, 1);
  677. }
  678. this.$set(this.list[index], "value", item.value);
  679. } else {
  680. this.$set(this.list[index], "value", value);
  681. }
  682. this.verify();
  683. },
  684. verify() {
  685. let list = this.list.filter((v) => v.isMust);
  686. let Uncomplete = false;
  687. if (list.length)
  688. Uncomplete = list.some((v) => {
  689. let res = false;
  690. if (v.type == "customClass") {
  691. if (v.isMultipleChoice) {
  692. res = v.value.length == 0;
  693. } else {
  694. res = v.value == "";
  695. }
  696. } else if (v.type == "upload") {
  697. res = v.value.length == 0;
  698. } else if (v.type == "text") {
  699. res = v.value == "";
  700. if (v.errText) res = true;
  701. } else if (v.type == "route") {
  702. res = v.showValue.length == 0;
  703. } else {
  704. res = v.value == "";
  705. }
  706. return res;
  707. });
  708. if (!Uncomplete)
  709. Uncomplete = this.list.filter((v) => !v.isMust).some((v) => v.errText);
  710. this.$emit("isUncomplete", Uncomplete);
  711. },
  712. previewImg(item) {
  713. viewImage(item.url);
  714. },
  715. uploadCallback(attachmentids, index) {
  716. let item = this.list[index];
  717. this.$Http
  718. .basic({
  719. classname: "system.attachment.Attachment",
  720. method: "createFileLink",
  721. content: {
  722. ownertable: item.ownertable,
  723. ownerid: item.ownerid,
  724. usetype: item.usetype,
  725. attachmentids,
  726. },
  727. })
  728. .then((res) => {
  729. console.log("绑定附件", res);
  730. if (this.cutoff(res.msg)) return;
  731. res.data = formattedFiles(res.data);
  732. item.value.push(res.data[0]);
  733. //临时文件
  734. if (res.data[0].ownertable == "temporary")
  735. try {
  736. item.temporarys.push(attachmentids[0]);
  737. } catch (error) {
  738. item.temporarys = [attachmentids[0]];
  739. }
  740. this.$set(this.list[index], "value", item.value);
  741. this.verify();
  742. });
  743. },
  744. deleteFiles() {
  745. this.list.forEach((v) => {
  746. if (v.type == "upload") {
  747. let linksids = v.value
  748. .filter((v) => v.ownertable == "temporary")
  749. .map((v) => v.linksid);
  750. if (linksids.length)
  751. this.$Http
  752. .basic({
  753. classname: "system.attachment.Attachment",
  754. method: "deleteFileLink",
  755. content: {
  756. linksids,
  757. },
  758. })
  759. .then((res) => {
  760. console.log("处理删除附件", res);
  761. if (this.cutoff(res.msg)) return;
  762. });
  763. }
  764. });
  765. },
  766. onUploadLoading(e, index) {
  767. this.$set(this.list[index], "loading", e);
  768. this.$emit("onUploading", e);
  769. },
  770. groupChange(e, index) {
  771. this.$set(this.list[index], "loading", e);
  772. this.verify();
  773. },
  774. selectRegion({ detail }, index) {
  775. this.$set(this.list[index], "value", detail.value);
  776. this.verify();
  777. },
  778. deleteFile(flie, index) {
  779. let item = this.list[index];
  780. item.value = item.value.filter(
  781. (v) => v.attachmentid != flie.attachmentid
  782. );
  783. //临时文件
  784. if (flie.ownertable == "temporary") {
  785. item.temporarys = item.temporarys.filter((v) => v != flie.attachmentid);
  786. this.$Http
  787. .basic({
  788. classname: "system.attachment.Attachment",
  789. method: "deleteFileLink",
  790. content: {
  791. linksids: [flie.linksid],
  792. },
  793. })
  794. .then((res) => {
  795. console.log("处理删除附件", res);
  796. if (this.cutoff(res.msg)) return;
  797. });
  798. } else {
  799. try {
  800. item.linksids.push(flie.linksid);
  801. } catch (error) {
  802. item.linksids = [flie.linksid];
  803. }
  804. }
  805. this.$set(this.list[index], "value", item.value);
  806. this.verify();
  807. },
  808. submit() {
  809. return new Promise((resolve, reject) => {
  810. let res = {};
  811. this.list.forEach((v) => {
  812. if (v.type == "upload") {
  813. res.files = {
  814. temporarys: [],
  815. linksids: [],
  816. };
  817. try {
  818. res.files.temporarys = v.temporarys || [];
  819. } catch (error) {}
  820. try {
  821. res.files.linksids = v.linksids || [];
  822. } catch (error) {}
  823. } else if (v.type == "region") {
  824. if (v.value.length) {
  825. res.province = v.value[0];
  826. res.city = v.value[1];
  827. res.county = v.value[2];
  828. } else {
  829. res.province = "";
  830. res.city = "";
  831. res.county = "";
  832. }
  833. } else if (v.type == "switch") {
  834. if (v.isNum) {
  835. res[v.key] = v.value ? 1 : 0;
  836. } else {
  837. res[v.key] = v.value;
  838. }
  839. } else if (v.type == "route") {
  840. if (v.isRadio) {
  841. const routeValue =
  842. typeof v.value.length == "number"
  843. ? v.value.length
  844. ? v.value[0]
  845. : ""
  846. : v.value || {};
  847. if (v.keys) {
  848. v.keys.forEach((e) => {
  849. res[e] = routeValue ? routeValue[e] || "" : "";
  850. });
  851. } else {
  852. res[v.key] = {
  853. name: v.showValue[0] || "",
  854. value: routeValue,
  855. };
  856. }
  857. } else {
  858. res[v.key] = {
  859. name: v.showValue || [],
  860. value: v.value || [],
  861. };
  862. }
  863. } else {
  864. try {
  865. res[v.key] = v.value.trim();
  866. } catch (error) {
  867. res[v.key] = v.value;
  868. }
  869. }
  870. });
  871. resolve(res);
  872. });
  873. },
  874. },
  875. };
  876. </script>
  877. <style lang="scss">
  878. .requiredFieldOnly-head {
  879. display: flex;
  880. align-items: center;
  881. justify-content: space-between;
  882. width: 100vw;
  883. height: 45px;
  884. background: #f7f7f7;
  885. padding: 0 10px;
  886. box-sizing: border-box;
  887. .label {
  888. font-family: PingFang SC, PingFang SC;
  889. font-weight: bold;
  890. font-size: 15px;
  891. color: #333333;
  892. line-height: 22px;
  893. }
  894. .content {
  895. display: flex;
  896. align-items: center;
  897. font-family: PingFang SC, PingFang SC;
  898. font-size: 14px;
  899. color: #999999;
  900. }
  901. }
  902. .borBot {
  903. border-bottom: 1px #dddddd solid;
  904. }
  905. .custom-class-box {
  906. width: 100%;
  907. background: #fff;
  908. padding: 15px 0 15px 10px;
  909. box-sizing: border-box;
  910. .head {
  911. width: 355px;
  912. height: 20px;
  913. display: flex;
  914. justify-content: space-between;
  915. align-items: flex-end;
  916. .label {
  917. font-size: 14px;
  918. color: #333333;
  919. line-height: 20px;
  920. }
  921. .state {
  922. font-family: Source Han Sans SC, Source Han Sans SC;
  923. font-size: 12px;
  924. color: #999999;
  925. }
  926. }
  927. .options {
  928. display: flex;
  929. flex-wrap: wrap;
  930. .option {
  931. padding: 6px 10px;
  932. text-align: center;
  933. min-width: 81px;
  934. font-family: PingFang SC, PingFang SC;
  935. font-size: 14px;
  936. color: #333333;
  937. border-radius: 5px;
  938. background: #f2f2f2;
  939. margin-top: 10px;
  940. margin-right: 10px;
  941. box-sizing: border-box;
  942. }
  943. .active {
  944. background: #c30d23;
  945. color: #fff;
  946. }
  947. }
  948. .content {
  949. .file-box {
  950. position: relative;
  951. width: 355px;
  952. height: 240px;
  953. margin-top: 10px;
  954. .video,
  955. .image {
  956. width: 355px;
  957. height: 240px;
  958. border-radius: 5px;
  959. }
  960. .delete {
  961. position: absolute;
  962. width: 30px;
  963. top: 0;
  964. right: 0;
  965. z-index: 1;
  966. }
  967. }
  968. .upload-box {
  969. display: flex;
  970. justify-content: center;
  971. align-items: center;
  972. width: 355px;
  973. height: 45px;
  974. background: #ffffff;
  975. border-radius: 5px;
  976. border: 1px dashed #c30d23;
  977. font-family: Source Han Sans SC, Source Han Sans SC;
  978. font-size: 14px;
  979. color: #c30d23;
  980. margin-top: 10px;
  981. }
  982. }
  983. }
  984. .textarea-box {
  985. width: 100%;
  986. .textarea {
  987. width: 355px;
  988. height: 160px;
  989. padding: 15px 10px;
  990. box-sizing: border-box;
  991. margin: 0 auto;
  992. }
  993. }
  994. .textarea-box2 {
  995. width: 100%;
  996. display: flex;
  997. flex-direction: column;
  998. background: #ffffff;
  999. padding: 15px 0 15px 10px;
  1000. .label {
  1001. width: 100px;
  1002. margin-right: 10px;
  1003. line-height: 20px;
  1004. font-family: Source Han Sans SC, Source Han Sans SC;
  1005. font-size: 14px;
  1006. color: #666666;
  1007. flex-shrink: 0;
  1008. .must {
  1009. color: #e3041f;
  1010. margin-right: 5px;
  1011. }
  1012. }
  1013. .textarea {
  1014. width: 355px;
  1015. height: 160px;
  1016. padding: 15px 10px;
  1017. box-sizing: border-box;
  1018. margin: 0 auto;
  1019. }
  1020. }
  1021. .input-box {
  1022. width: 100vw;
  1023. background: #fff;
  1024. box-sizing: border-box;
  1025. padding-left: 10px;
  1026. .box {
  1027. display: flex;
  1028. width: 100%;
  1029. min-height: 54.4px;
  1030. padding: 15px 0;
  1031. box-sizing: border-box;
  1032. align-items: center;
  1033. }
  1034. .label {
  1035. width: 100px;
  1036. margin-right: 10px;
  1037. line-height: 20px;
  1038. font-family: Source Han Sans SC, Source Han Sans SC;
  1039. font-size: 14px;
  1040. color: #666666;
  1041. flex-shrink: 0;
  1042. .must {
  1043. color: #e3041f;
  1044. margin-right: 5px;
  1045. }
  1046. }
  1047. .content-box {
  1048. padding-right: 10px;
  1049. .content {
  1050. flex: 1;
  1051. display: flex;
  1052. align-items: center;
  1053. box-sizing: border-box;
  1054. .icon {
  1055. padding: 5px;
  1056. }
  1057. }
  1058. .err-text {
  1059. font-size: 12px;
  1060. color: #e3041f;
  1061. margin-bottom: -12px;
  1062. .icon {
  1063. margin-right: 2px;
  1064. }
  1065. }
  1066. }
  1067. }
  1068. .region {
  1069. width: 100vw;
  1070. background: #fff;
  1071. box-sizing: border-box;
  1072. padding: 15px 0 0 10px;
  1073. .box {
  1074. display: flex;
  1075. padding-bottom: 15px;
  1076. padding-right: 10px;
  1077. box-sizing: border-box;
  1078. .label {
  1079. width: 100px;
  1080. margin-right: 10px;
  1081. line-height: 20px;
  1082. font-family: Source Han Sans SC, Source Han Sans SC;
  1083. font-size: 14px;
  1084. color: #666666;
  1085. flex-shrink: 0;
  1086. .must {
  1087. color: #e3041f;
  1088. margin-right: 5px;
  1089. }
  1090. }
  1091. .content-box {
  1092. flex: 1;
  1093. display: flex;
  1094. align-items: center;
  1095. justify-content: space-between;
  1096. height: 20px;
  1097. line-height: 20px;
  1098. .placeholder {
  1099. font-family: Source Han Sans SC, Source Han Sans SC;
  1100. font-size: 14px;
  1101. color: #bbbbbb;
  1102. }
  1103. }
  1104. }
  1105. }
  1106. .tag-box {
  1107. .label {
  1108. width: 100px;
  1109. margin-right: 10px;
  1110. line-height: 20px;
  1111. font-family: Source Han Sans SC, Source Han Sans SC;
  1112. font-size: 14px;
  1113. color: #666666;
  1114. flex-shrink: 0;
  1115. .must {
  1116. color: #e3041f;
  1117. margin-right: 5px;
  1118. }
  1119. }
  1120. .tag-list {
  1121. display: flex;
  1122. align-content: center;
  1123. align-items: center;
  1124. flex-wrap: wrap;
  1125. font-family: PingFang SC, PingFang SC;
  1126. margin-top: 10px;
  1127. .err-text {
  1128. font-size: 12px;
  1129. color: #e3041f;
  1130. margin-bottom: -12px;
  1131. .icon {
  1132. margin-right: 2px;
  1133. }
  1134. }
  1135. .tag {
  1136. padding: 6px 10px;
  1137. background: #f2f2f2;
  1138. border-radius: 5px 5px 5px 5px;
  1139. margin-right: 10px;
  1140. margin-bottom: 10px;
  1141. font-weight: 400;
  1142. font-size: 14px;
  1143. color: #333333;
  1144. display: flex;
  1145. align-items: center;
  1146. align-content: center;
  1147. text-align: center;
  1148. &:last-child {
  1149. margin-right: 0 !important;
  1150. }
  1151. .del {
  1152. margin-left: 10px;
  1153. padding: 2px;
  1154. }
  1155. }
  1156. .add-tag {
  1157. border-radius: 5px 5px 5px 5px;
  1158. border: 1px dashed #c30d23;
  1159. padding: 6px 20px;
  1160. color: #c30d23;
  1161. font-weight: 400;
  1162. margin-bottom: 10px;
  1163. font-size: 14px;
  1164. }
  1165. }
  1166. }
  1167. </style>