鸿宇研学生前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
15 KiB

  1. <template>
  2. <view>
  3. <uv-popup ref="popup" mode="bottom" bgColor="none" >
  4. <view class="popup__view">
  5. <view class="flex header">
  6. <view class="title">{{ title }}</view>
  7. <button class="btn" @click="close">关闭</button>
  8. </view>
  9. <view class="form">
  10. <uv-form
  11. ref="form"
  12. :model="form"
  13. :rules="rules"
  14. errorType="toast"
  15. >
  16. <view class="form-item">
  17. <uv-form-item prop="name" :customStyle="formItemStyle">
  18. <view class="form-item-label">
  19. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  20. 姓名
  21. </view>
  22. <view class="form-item-content">
  23. <formInput v-model="form.name"></formInput>
  24. </view>
  25. </uv-form-item>
  26. </view>
  27. <view class="form-item">
  28. <uv-form-item prop="idNo" :customStyle="formItemStyle">
  29. <view class="form-item-label">
  30. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  31. 身份证号
  32. </view>
  33. <view class="form-item-content">
  34. <formInput v-model="form.idNo"></formInput>
  35. </view>
  36. </uv-form-item>
  37. </view>
  38. <view class="form-item">
  39. <uv-form-item prop="type" :customStyle="formItemStyle">
  40. <view class="form-item-label">
  41. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  42. 类型
  43. </view>
  44. <view class="form-item-content">
  45. <uv-radio-group v-model="form.type"
  46. iconColor="#00A9FF"
  47. iconSize="36rpx"
  48. size="36rpx"
  49. labelColor="#181818"
  50. labelSize="26rpx"
  51. >
  52. <uv-radio
  53. v-for="(item, index) in typeOptions"
  54. :key="index"
  55. :label="item.label"
  56. :name="item.value"
  57. :customStyle="{ flex: 1 }"
  58. ></uv-radio>
  59. </uv-radio-group>
  60. </view>
  61. </uv-form-item>
  62. </view>
  63. <view class="form-item">
  64. <uv-form-item prop="gender" :customStyle="formItemStyle">
  65. <view class="form-item-label">
  66. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  67. 性别
  68. </view>
  69. <view class="form-item-content">
  70. <uv-radio-group v-model="form.gender"
  71. iconColor="#00A9FF"
  72. iconSize="36rpx"
  73. size="36rpx"
  74. labelColor="#181818"
  75. labelSize="26rpx"
  76. >
  77. <uv-radio
  78. v-for="(item, index) in genderOptions"
  79. :key="index"
  80. :label="item.label"
  81. :name="item.value"
  82. :customStyle="{ flex: 1 }"
  83. ></uv-radio>
  84. </uv-radio-group>
  85. </view>
  86. </uv-form-item>
  87. </view>
  88. <view class="form-item">
  89. <uv-form-item prop="phone" :customStyle="formItemStyle">
  90. <view class="form-item-label">
  91. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  92. 手机号
  93. </view>
  94. <view class="form-item-content">
  95. <formInput v-model="form.phone"></formInput>
  96. </view>
  97. </uv-form-item>
  98. </view>
  99. <view class="form-item">
  100. <uv-form-item prop="wx" :customStyle="formItemStyle">
  101. <view class="form-item-label">微信号</view>
  102. <view class="form-item-content">
  103. <formInput v-model="form.wx"></formInput>
  104. </view>
  105. </uv-form-item>
  106. </view>
  107. <view class="form-item">
  108. <uv-form-item prop="school" :customStyle="formItemStyle">
  109. <view class="form-item-label">学校</view>
  110. <view class="form-item-content">
  111. <formInput v-model="form.school"></formInput>
  112. </view>
  113. </uv-form-item>
  114. </view>
  115. <view class="form-item">
  116. <uv-form-item prop="grade" :customStyle="formItemStyle">
  117. <view class="form-item-label">年级</view>
  118. <view class="form-item-content">
  119. <formInput v-model="form.grade"></formInput>
  120. </view>
  121. </uv-form-item>
  122. </view>
  123. <view class="form-item">
  124. <uv-form-item prop="age" :customStyle="formItemStyle">
  125. <view class="form-item-label">年龄</view>
  126. <view class="form-item-content">
  127. <formInput v-model="form.age"></formInput>
  128. </view>
  129. </uv-form-item>
  130. </view>
  131. <view class="form-item">
  132. <uv-form-item prop="remark" :customStyle="formItemStyle">
  133. <view class="form-item-label">特殊需求饮食/健康等备注</view>
  134. <view class="form-item-content">
  135. <formInput v-model="form.remark"></formInput>
  136. </view>
  137. </uv-form-item>
  138. </view>
  139. <view class="form-item">
  140. <uv-form-item prop="emergencyContact" :customStyle="formItemStyle">
  141. <view class="form-item-label">
  142. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  143. 紧急联系人
  144. </view>
  145. <view class="form-item-content">
  146. <formInput v-model="form.emergencyContact"></formInput>
  147. </view>
  148. </uv-form-item>
  149. </view>
  150. <view class="form-item">
  151. <uv-form-item prop="guardiancontact" :customStyle="formItemStyle">
  152. <view class="form-item-label">
  153. <image class="icon" src="@/static/image/icon-require.png" mode="widthFix"></image>
  154. 监护人联系方式
  155. </view>
  156. <view class="form-item-content">
  157. <formInput v-model="form.guardiancontact"></formInput>
  158. </view>
  159. </uv-form-item>
  160. </view>
  161. </uv-form>
  162. </view>
  163. <view class="footer">
  164. <view class="agreement">
  165. <view>
  166. <uv-checkbox-group
  167. v-model="checkboxValue"
  168. shape="circle"
  169. >
  170. <uv-checkbox
  171. size="40rpx"
  172. icon-size="40rpx"
  173. activeColor="#00A9FF"
  174. :name="1"
  175. ></uv-checkbox>
  176. </uv-checkbox-group>
  177. </view>
  178. <view class="desc">
  179. 我已阅读并同意
  180. <!-- todo: 替换配置项key -->
  181. <text class="highlight" @click="$refs.modal.open('config_agreement', '服务协议')">服务协议</text>
  182. <!-- todo: 替换配置项key -->
  183. <text class="highlight" @click="$refs.modal.open('config_privacy', '隐私政策')">隐私政策</text>
  184. </view>
  185. </view>
  186. <view class="bar">
  187. <button class="flex btn" @click="onSave">保存</button>
  188. </view>
  189. </view>
  190. </view>
  191. </uv-popup>
  192. <agreementModal ref="modal" @confirm="onConfirmAgreement"></agreementModal>
  193. </view>
  194. </template>
  195. <script>
  196. import formInput from '@/pages_order/components/formInput.vue'
  197. import agreementModal from '@/pages_order/components/agreementModal.vue'
  198. export default {
  199. components: {
  200. formInput,
  201. agreementModal,
  202. },
  203. data() {
  204. return {
  205. id: null,
  206. title: null,
  207. form: {
  208. name: null,
  209. idNo: null,
  210. type: 0,
  211. gender: 0,
  212. phone: null,
  213. wx: null,
  214. school: null,
  215. grade: null,
  216. age: null,
  217. remark: null,
  218. emergencyContact: null,
  219. guardiancontact: null,
  220. },
  221. rules: {
  222. 'name': {
  223. type: 'string',
  224. required: true,
  225. message: '请输入姓名',
  226. },
  227. 'idNo': {
  228. type: 'string',
  229. required: true,
  230. message: '请输入身份证号',
  231. },
  232. 'type': {
  233. type: 'string',
  234. required: true,
  235. message: '请选择类型',
  236. },
  237. 'gender': {
  238. type: 'string',
  239. required: true,
  240. message: '请选择性别',
  241. },
  242. 'phone': {
  243. type: 'string',
  244. required: true,
  245. message: '请输入手机号',
  246. },
  247. 'emergencyContact': {
  248. type: 'string',
  249. required: true,
  250. message: '请输入紧急联系人联系方式',
  251. },
  252. 'guardiancontact': {
  253. type: 'string',
  254. required: true,
  255. message: '请输入监护人联系方式',
  256. },
  257. },
  258. formItemStyle: { padding: 0 },
  259. // todo: check
  260. typeOptions: [
  261. {
  262. id: '001',
  263. label: '成人',
  264. value: '0',
  265. },
  266. {
  267. id: '002',
  268. label: '青少年',
  269. value: '1',
  270. },
  271. {
  272. id: '003',
  273. label: '儿童',
  274. value: '2',
  275. },
  276. ],
  277. genderOptions: [
  278. {
  279. id: '001',
  280. label: '男',
  281. value: '0',
  282. },
  283. {
  284. id: '002',
  285. label: '女',
  286. value: '1',
  287. },
  288. ],
  289. checkboxValue: [],
  290. }
  291. },
  292. methods: {
  293. async fetchTravelerDetail(id) {
  294. try {
  295. // todo: fetch
  296. } catch (err) {
  297. }
  298. },
  299. open(id) {
  300. if (id) {
  301. this.id = id
  302. this.title = '编辑出行人'
  303. this.fetchTravelerDetail(id)
  304. } else {
  305. this.id = null
  306. this.title = '添加出行人'
  307. this.form = {
  308. name: null,
  309. idNo: null,
  310. type: 0,
  311. gender: 0,
  312. phone: null,
  313. wx: null,
  314. school: null,
  315. grade: null,
  316. age: null,
  317. remark: null,
  318. emergencyContact: null,
  319. guardiancontact: null,
  320. }
  321. }
  322. this.$refs.popup.open()
  323. },
  324. close() {
  325. this.$refs.popup.close()
  326. },
  327. onConfirmAgreement(confirm) {
  328. if (confirm) {
  329. this.checkboxValue = [1]
  330. } else {
  331. this.checkboxValue = []
  332. }
  333. },
  334. async onSave() {
  335. if(!this.checkboxValue.length){
  336. return uni.showToast({
  337. title: '请先同意《服务协议》和《隐私政策》',
  338. icon:'none'
  339. })
  340. }
  341. try {
  342. await this.$refs.form.validate()
  343. const {
  344. } = this.form
  345. const params = {
  346. }
  347. if (this.id) {
  348. params.id = this.id
  349. // todo: fetch
  350. // await this.$fetch('updateAddress', params)
  351. uni.showToast({
  352. icon: 'success',
  353. title: '修改出行人成功',
  354. });
  355. } else {
  356. // todo: fetch
  357. // await this.$fetch('addAddress', params)
  358. uni.showToast({
  359. icon: 'success',
  360. title: '添加出行人成功',
  361. });
  362. }
  363. this.$emit('submitted')
  364. this.close()
  365. } catch (err) {
  366. console.log('onSave err', err)
  367. }
  368. },
  369. },
  370. }
  371. </script>
  372. <style lang="scss" scoped>
  373. .popup__view {
  374. width: 100vw;
  375. display: flex;
  376. flex-direction: column;
  377. box-sizing: border-box;
  378. background: #FFFFFF;
  379. border-top-left-radius: 32rpx;
  380. border-top-right-radius: 32rpx;
  381. }
  382. .header {
  383. position: relative;
  384. width: 100%;
  385. padding: 24rpx 0;
  386. box-sizing: border-box;
  387. border-bottom: 2rpx solid #EEEEEE;
  388. .title {
  389. font-family: PingFang SC;
  390. font-weight: 500;
  391. font-size: 34rpx;
  392. line-height: 1.4;
  393. color: #181818;
  394. }
  395. .btn {
  396. font-family: PingFang SC;
  397. font-weight: 500;
  398. font-size: 32rpx;
  399. line-height: 1.4;
  400. color: #8B8B8B;
  401. position: absolute;
  402. top: 26rpx;
  403. left: 40rpx;
  404. }
  405. }
  406. .form {
  407. max-height: 75vh;
  408. padding: 32rpx 40rpx;
  409. box-sizing: border-box;
  410. overflow-y: auto;
  411. &-item {
  412. padding: 8rpx 0 6rpx 0;
  413. & + & {
  414. padding-top: 24rpx;
  415. border-top: 2rpx solid #EEEEEE;
  416. }
  417. &-label {
  418. margin-bottom: 14rpx;
  419. display: flex;
  420. align-items: center;
  421. font-family: PingFang SC;
  422. font-weight: 400;
  423. font-size: 26rpx;
  424. line-height: 1.4;
  425. color: #181818;
  426. .icon {
  427. margin-right: 8rpx;
  428. width: 16rpx;
  429. height: auto;
  430. }
  431. }
  432. &-content {
  433. .placeholder {
  434. color: #C6C6C6;
  435. font-size: 32rpx;
  436. font-weight: 400;
  437. }
  438. .region {
  439. min-height: 44rpx;
  440. justify-content: flex-start;
  441. }
  442. }
  443. }
  444. }
  445. .footer {
  446. width: 100%;
  447. .agreement {
  448. display: flex;
  449. padding: 16rpx 40rpx;
  450. background: #E9F8FF;
  451. box-sizing: border-box;
  452. /deep/ .uv-checkbox-group {
  453. flex: none;
  454. }
  455. .desc {
  456. flex: 1;
  457. font-family: PingFang SC;
  458. font-size: 24rpx;
  459. font-weight: 400;
  460. line-height: 40rpx;
  461. color: #8B8B8B;
  462. }
  463. .highlight {
  464. color: $uni-color;
  465. }
  466. }
  467. .bar {
  468. width: 100%;
  469. padding: 32rpx 40rpx;
  470. box-sizing: border-box;
  471. border-top: 2rpx solid #F1F1F1;
  472. }
  473. .btn {
  474. width: 100%;
  475. padding: 14rpx 0;
  476. box-sizing: border-box;
  477. font-family: PingFang SC;
  478. font-weight: 500;
  479. font-size: 36rpx;
  480. line-height: 1.4;
  481. color: #FFFFFF;
  482. background-image: linear-gradient(to right, #21FEEC, #019AF9);
  483. border: 2rpx solid #00A9FF;
  484. border-radius: 41rpx;
  485. }
  486. }
  487. </style>