guest_form.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. <template>
  2. <view class="bg-white" style="min-height: 100vh;">
  3. <view class="content" v-if="!loading">
  4. <view class="padding-20 bg-white" v-if="!this.islock&&description">
  5. <u-alert-tips type="warning" :description="description"></u-alert-tips>
  6. </view>
  7. <view class="card">
  8. <view class="form">
  9. <view class="flex">
  10. <view class="need">*</view>
  11. <view>访问区域</view>
  12. </view>
  13. <view class="bg-gray padding-20 ">
  14. <input disabled type="text" v-model="data.guestPosition" />
  15. </view>
  16. </view>
  17. <view class="form">
  18. <view class="flex">
  19. <view class="need">*</view>
  20. <view>访问日期</view>
  21. </view>
  22. <view class="bg-gray padding-20 ">
  23. <ruiDatePicker v-if="$isNotEmpty(data.interviewTime)" :start="guestAuthorize.beginDate"
  24. :end="guestAuthorize.endDate" fields="second" @change="timeConfirm"
  25. :value="data.interviewTime">
  26. </ruiDatePicker>
  27. </view>
  28. <view class="text-sm text-right text-orange" style="padding-top: 8rpx;">
  29. <text>有效时间:{{guestAuthorize.beginDate}} 至 {{guestAuthorize.endDate}}</text>
  30. </view>
  31. </view>
  32. <view class="form">
  33. <view class="flex">
  34. <view class="need">*</view>
  35. <view>接待人</view>
  36. </view>
  37. <view class="bg-gray padding-20 ">
  38. <input :disabled="isDisabled" type="text" placeholder="请填写接待人" v-model="data.userName" />
  39. </view>
  40. </view>
  41. <view class="form">
  42. <view class="flex">
  43. <view class="need">*</view>
  44. <view>您的姓名:</view>
  45. </view>
  46. <view class="bg-gray padding-20 ">
  47. <input :disabled="isDisabled" type="text" placeholder="请填写您的姓名" v-model="data.guestName" />
  48. </view>
  49. </view>
  50. <view class="form ">
  51. <view class="flex">
  52. <view class="need">*</view>
  53. <view>您的联系方式</view>
  54. </view>
  55. <view class="bg-gray padding-20 flex justify-between " style="box-sizing: border-box;">
  56. <input maxlength="11" type="number" placeholder="请获取您的联系方式" v-model="data.guestTel" />
  57. <button :disabled="isDisabled" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber"
  58. class="light sm cu-btn bg-blue radius">
  59. 获取手机号
  60. </button>
  61. </view>
  62. </view>
  63. <view class="form ">
  64. <view class="flex">
  65. <view>您的身份证号</view>
  66. </view>
  67. <view class="bg-gray padding-20 ">
  68. <input :disabled="isDisabled" placeholder="请输入您的身份证号(选填)" v-model="data.guestIdcard" />
  69. </view>
  70. </view>
  71. </view>
  72. <view class="card ">
  73. <view class="form" style="height: 320rpx;">
  74. <view class="flex">
  75. <view class="need">*</view>
  76. <view>来访目的</view>
  77. </view>
  78. <view class="bg-gray padding-10">
  79. <textarea :disabled="isDisabled" v-model="data.guestReason" maxlength="100"
  80. style="width: 100%;height: 270rpx;line-height: 50rpx;" placeholder="请填写来访原因"></textarea>
  81. <view class="text-right text-df text-gray padding-top-10">
  82. {{data.guestReason.length}} / 100
  83. </view>
  84. </view>
  85. </view>
  86. </view>
  87. <view class="bg-white" style="height: 160rpx;"></view>
  88. <view v-if="!islock&&auditStatus==null" style="z-index: 999;" class=" footer-fixed" @click="submit">
  89. <view class="cu-btn flex text-lg bg-red-btn" style="padding: 46rpx 0;">
  90. 确定提交
  91. </view>
  92. </view>
  93. <view @click="again" v-if="!islock&&auditStatus==2" style="z-index: 999;" class=" footer-fixed">
  94. <view class="cu-btn flex text-lg bg-red" style="padding: 46rpx 0;">
  95. 重新填表
  96. </view>
  97. </view>
  98. <view v-if="islock" style="z-index: 999;" class=" footer-fixed">
  99. <view class="cu-btn flex text-lg bg-gray" style="padding: 46rpx 0;">
  100. 已锁定
  101. </view>
  102. </view>
  103. </view>
  104. <view v-else style="position: absolute;top: 40%;left: 50%;transform: translate(-50%,-50%);">
  105. <u-loading mode="flower" size="80"></u-loading>
  106. </view>
  107. <!--弹窗-->
  108. <view class="modal-mask" v-if="showModal"></view>
  109. <view class="modal-dialog" v-if="showModal">
  110. <view class="modal-title">提示</view>
  111. <view class="modal-content">
  112. <view class="modal-input">
  113. <text class="password">填写成功,请转发给好友审核</text>
  114. </view>
  115. </view>
  116. <view class="modal-footer">
  117. <button class="btn-confirm" @click="showModal=false;getAuthRecords()"
  118. data-status="confirm">暂不转发</button>
  119. <button class="btn-cancel" open-type="share" data-status="cancel">立即转发</button>
  120. </view>
  121. </view>
  122. <!-- 刷新 -->
  123. <view v-if="auditStatus==0" @click="reload" class="cuIcon cu-btn "
  124. style="width: 80rpx;height: 80rpx;background-color: rgba(0,0,0,.2);color: #FFFFFF;position: fixed;bottom: 40%;right: 20rpx;z-index: 9;">
  125. <u-loading mode="flower" size="50" color="#fff" :show="isReload"></u-loading>
  126. <text class="cuIcon-refresh rotateCenter" v-if="!isReload" style="font-size: 50rpx;"></text>
  127. </view>
  128. <u-toast ref="uToast"></u-toast>
  129. </view>
  130. </template>
  131. <script>
  132. var app = getApp()
  133. var that;
  134. import ruiDatePicker from '@/comps/rattenking-dtpicker/rattenking-dtpicker.vue';
  135. export default {
  136. components: {
  137. ruiDatePicker
  138. },
  139. data() {
  140. return {
  141. guestRecordId:'',
  142. loading: false,
  143. isReload: false,
  144. timeValue: '',
  145. guestAuthorize: {},
  146. //0新增表单操作,1修改表单操作
  147. operaType: 0,
  148. id: '', //授权记录的id
  149. doorNeedAudit: 0, //该授权开门是否需要审核
  150. memberId: '', //业主的 memberId,用来获取设备列表
  151. residentialId: '', //小区id,用来获取设备列表
  152. openId: '',
  153. sessionKey: '',
  154. showModal: false,
  155. //查询出来的审核状态
  156. auditStatus: null,
  157. islock: false,
  158. //审核不通过重新修改时的旧数据
  159. oldData: {},
  160. //提交的数据
  161. data: {
  162. userId: '',
  163. //授权记录的表id
  164. guestAuthId: '',
  165. //被访者区域
  166. guestPosition: '',
  167. //来访日期
  168. interviewTime: '',
  169. beginTime: '',
  170. endTime: '',
  171. //接待人
  172. userName: '',
  173. //来访者姓名
  174. guestName: '',
  175. //来访者联系方式
  176. guestTel: '',
  177. //来访者身份证号
  178. guestIdcard: '',
  179. //来访原因
  180. guestReason: '',
  181. //审核状态
  182. auditStatus: 0,
  183. //登记来源小程序
  184. registerSource: 1
  185. },
  186. //添加访客记录后,将访客记录id分享给好友审核
  187. shareId: '',
  188. }
  189. },
  190. computed: {
  191. isDisabled: {
  192. get() {
  193. if (this.auditStatus == null) {
  194. if (this.islock) {
  195. return true
  196. } else {
  197. return false
  198. }
  199. } else {
  200. return true
  201. }
  202. }
  203. },
  204. description() {
  205. if (this.auditStatus == 0) {
  206. return '待审核,请通知被访者进入小程序审核'
  207. }
  208. if (this.auditStatus == 2) {
  209. if (this.$isNotEmpty(this.data.opinion)) {
  210. return `审核失败:${this.data.opinion}`
  211. } else {
  212. return `审核失败:请点击重新填表`
  213. }
  214. }
  215. return false
  216. }
  217. },
  218. onShareAppMessage: function(ops) {
  219. this.showModal = false
  220. this.getAuthRecords()
  221. return {
  222. title: "我是" + this.data.guestName + ",我正在填表申请开门,请审核",
  223. path: "/pages/record/record?id=" + this.shareId
  224. };
  225. },
  226. async onLoad(options) {
  227. this.loading = true
  228. that = this
  229. if (!this.$isEmpty(options.scene)) {
  230. let scene = decodeURIComponent(options.scene).split(",")
  231. //从小程序二维码进入
  232. options.id = scene[0]
  233. options.doorNeedAudit = scene[1]
  234. options.memberId = scene[2]
  235. }
  236. //附带的页面参数id为空,则锁定页面
  237. if (this.$isEmpty(options.id)) {
  238. uni.showModal({
  239. showCancel: false,
  240. content: "系统错误,已锁定",
  241. success: (res) => {
  242. if (res.confirm) {
  243. that.islock = true
  244. }
  245. }
  246. })
  247. this.loading = false
  248. return
  249. }
  250. this.id = options.id
  251. this.doorNeedAudit = options.doorNeedAudit
  252. this.memberId = options.memberId
  253. this.data.userId = this.memberId
  254. this.data.guestAuthId = this.id
  255. await this.getAuthRecords()
  256. setTimeout(() => {
  257. this.loading = false
  258. }, 200)
  259. },
  260. methods: {
  261. again() {
  262. this.auditStatus = null;
  263. this.operaType = 1;
  264. this.oldData = this.$u.deepClone(this.data)
  265. this.$forceUpdate()
  266. },
  267. async reload() {
  268. this.isReload = true
  269. await this.getAuthRecords()
  270. this.isReload = false
  271. },
  272. getPhoneNumber(e) {
  273. let that = this
  274. if (e.detail.errMsg == "getPhoneNumber:ok") {
  275. let params = {
  276. sessionKey: that.sessionKey,
  277. encryptedData: e.detail.encryptedData,
  278. iv: e.detail.iv
  279. }
  280. this.$http.getOpenData(params).then(res => {
  281. this.data.guestTel = res.data.purePhoneNumber
  282. })
  283. } else {
  284. this.$refs.uToast.show({
  285. title: '获取手机号失败!',
  286. position: "top",
  287. type: 'error',
  288. })
  289. return
  290. }
  291. },
  292. /**
  293. * 跳转到设备列表
  294. */
  295. jumpOpenDoor() {
  296. let params = {
  297. memberId: this.memberId,
  298. residentialId: this.residentialId,
  299. guestTel: this.data.guestTel,
  300. guestRecordId:this.guestRecordId
  301. }
  302. uni.redirectTo({
  303. url: "/pages/guest/open_door" + this.$u.queryParams(params)
  304. })
  305. },
  306. timeConfirm(e) {
  307. this.data.interviewTime = e
  308. },
  309. getTime(value) {
  310. let date = typeof(value) == 'string' ? value.replace(/\-/g, '/') : value
  311. return new Date(date).getTime()
  312. },
  313. /**
  314. * 先通过id查询授权记录表查看该授权是否过期
  315. * 过期了就不能进行接下来的操作,提示访客联系业主重新授权
  316. * 没有过期就判断审核配置,配置了不需要审核表单就直接跳到设备列表,
  317. * 需要审核就通过授权记录的id和openid查询访客记录表,查询到记录就直接跳到设备列表
  318. * 查不到记录就填表
  319. */
  320. async getAuthRecords() {
  321. let params = {
  322. id: this.id
  323. }
  324. let res = await this.$http.guestAuthorizeDetail(params)
  325. if (this.$isEmpty(res.data.data)) {
  326. this.$dialog.showModal('没有该授权记录,或者授权记录已被撤销', false).then(() => {
  327. this.islock = true
  328. })
  329. return
  330. }
  331. //授权详情
  332. let guestAuthorize = res.data.data
  333. this.guestAuthorize = guestAuthorize
  334. this.data.beginTime = this.guestAuthorize.beginDate
  335. this.data.interviewTime = this.guestAuthorize.beginDate
  336. that.residentialId = guestAuthorize.residentialId
  337. //授权结束时间
  338. that.data.endTime = guestAuthorize.endDate
  339. let endDate = that.$commonDate(guestAuthorize.endDate).getTime()
  340. //当前时间
  341. let now = new Date().getTime()
  342. //判断授权是否过期
  343. if (now > endDate) {
  344. uni.showModal({
  345. title: "提示",
  346. content: "授权已过期,请联系被访者重新授权",
  347. showCancel: false,
  348. success: (res) => {
  349. if (res.confirm) {
  350. that.islock = true
  351. }
  352. }
  353. })
  354. return
  355. }
  356. // 授权没有过期
  357. //通过openid,授权记录id查询访客记录表
  358. let guestRes = await this.getGuestRecords()
  359. if (this.$isEmpty(guestRes.data.data)) {
  360. that.data.guestPosition = guestAuthorize.residentialName + "," +
  361. guestAuthorize.buildingName + "," + guestAuthorize.unitName + "," +
  362. guestAuthorize.roomName
  363. //没有记录,就填表
  364. that.data.userName = guestAuthorize.userName
  365. that.data.residentialId = guestAuthorize.residentialId
  366. that.data.residentialName = guestAuthorize.residentialName
  367. return
  368. }
  369. //有记录,就判断审核状态
  370. this.data=guestRes.data.data[0]
  371. this.guestRecordId=this.data.id
  372. this.data.guestPosition = that.data.residentialName + "," +
  373. that.data.buildingName + "," + that.data.unitName + "," +
  374. that.data.roomName
  375. that.auditStatus = that.data.auditStatus
  376. if (that.auditStatus == 1) {
  377. //审核通过。跳转到设备列表
  378. that.jumpOpenDoor()
  379. }
  380. },
  381. /**
  382. * 通过openid和授权记录id和审核通过的状态查看访客记录表
  383. */
  384. async getGuestRecords() {
  385. let jsCode = await new Promise((resolve, reject) => {
  386. uni.login({
  387. provider: 'weixin',
  388. success: res => {
  389. resolve(res.code);
  390. },
  391. fail: err => {
  392. reject(err);
  393. }
  394. })
  395. })
  396. let params = {
  397. js_code: jsCode,
  398. name: 'community',
  399. app_type: 1
  400. };
  401. // let operation = 'miniprogram/getOpenid'; //发起请求
  402. let res = await this.$http.getOpenid(params);
  403. that.sessionKey = res.data.session_key
  404. this.openId = res.data.openid
  405. //获取成功
  406. let guestParams = {
  407. guestAuthId: this.id,
  408. openId: this.openId
  409. }
  410. let guestRes = await this.$http.guestRecordsList(guestParams)
  411. return guestRes
  412. },
  413. submit() {
  414. let that = this
  415. if (this.$isEmpty(this.data.guestPosition)) {
  416. uni.showModal({
  417. title: "提示",
  418. content: "系统错误",
  419. showCancel: false,
  420. success: (res) => {
  421. if (res.confirm) {
  422. that.islock = true
  423. }
  424. }
  425. })
  426. return
  427. }
  428. if (this.$isEmpty(this.data.interviewTime)) {
  429. this.$refs.uToast.show({
  430. title: '请选择访问日期',
  431. position: "top",
  432. type: 'error',
  433. })
  434. return
  435. }
  436. if (this.$isEmpty(this.data.userName)) {
  437. this.$refs.uToast.show({
  438. title: '请填写接待人姓名',
  439. position: "top",
  440. type: 'error',
  441. })
  442. return
  443. }
  444. if (this.$isEmpty(this.data.guestName)) {
  445. this.$refs.uToast.show({
  446. title: '请填写您的姓名',
  447. position: "top",
  448. type: 'error',
  449. })
  450. return
  451. }
  452. if (this.$isEmpty(this.data.guestTel)) {
  453. this.$refs.uToast.show({
  454. title: '请填写联系方式',
  455. position: "top",
  456. type: 'error',
  457. })
  458. return
  459. }
  460. if (!this.$u.test.mobile(this.data.guestTel)) {
  461. this.$refs.uToast.show({
  462. title: '联系方式不正确',
  463. position: "top",
  464. type: 'error',
  465. })
  466. return
  467. }
  468. if (this.$isNotEmpty(this.data.guestIdcard) && !this.$u.test.idCard(this.data.guestIdcard)) {
  469. this.$refs.uToast.show({
  470. title: '身份证号不正确',
  471. position: "top",
  472. type: 'error',
  473. })
  474. return
  475. }
  476. if (this.$isEmpty(this.data.guestReason)) {
  477. this.$refs.uToast.show({
  478. title: '请填写来访目的',
  479. position: "top",
  480. type: 'error',
  481. })
  482. return
  483. }
  484. this.data.openId = this.openId
  485. let operation = ''
  486. if (this.operaType == 0) {
  487. //新增
  488. if (this.doorNeedAudit == 0) {
  489. //1不需要审核,直接审核通过
  490. this.data.auditStatus = 1
  491. }
  492. } else {
  493. //修改
  494. this.data.auditStatus = 0
  495. }
  496. this.$http.guestRecordsSubmit(this.data).then(res => {
  497. if (res.data.success) {
  498. if (this.doorNeedAudit == 0) {
  499. //不需要审核,直接跳转到设备列表页
  500. this.jumpOpenDoor()
  501. } else {
  502. this.$dialog.showModal('提交成功,请通知被访者审核', false).then(() => {
  503. this.getAuthRecords()
  504. })
  505. // this.shareId = res.data.guestRecordId
  506. // this.showModal = true
  507. }
  508. } else {
  509. this.$refs.uToast.show({
  510. title: '操作失败',
  511. position: "top",
  512. type: 'error',
  513. })
  514. }
  515. })
  516. }
  517. }
  518. }
  519. </script>
  520. <style lang="scss" scoped>
  521. .bg-gray {
  522. background-color: #f7f7f7;
  523. }
  524. .card {
  525. box-sizing: border-box;
  526. background-color: #FFFFFF;
  527. }
  528. .bg-red {
  529. background-color: #e54d42;
  530. color: #FFFFFF;
  531. }
  532. .card .form {
  533. padding: 20rpx 40rpx;
  534. }
  535. .need {
  536. font-size: 38rpx;
  537. font-weight: 800;
  538. color: #ff0000;
  539. padding-right: 10rpx;
  540. }
  541. .modal-mask {
  542. width: 100%;
  543. height: 100%;
  544. position: fixed;
  545. top: 0;
  546. left: 0;
  547. background: #000;
  548. opacity: 0.5;
  549. overflow: hidden;
  550. z-index: 9000;
  551. color: #fff;
  552. }
  553. .modal-dialog {
  554. width: 540rpx;
  555. overflow: hidden;
  556. position: fixed;
  557. top: 45%;
  558. left: 0;
  559. z-index: 9999;
  560. background: #f9f9f9;
  561. margin: -180rpx 105rpx;
  562. border-radius: 36rpx;
  563. }
  564. .modal-title {
  565. padding-top: 50rpx;
  566. font-size: 36rpx;
  567. color: #030303;
  568. text-align: center;
  569. }
  570. .modal-content {
  571. padding: 60rpx 0;
  572. }
  573. .modal-input {
  574. display: flex;
  575. font-size: 30rpx;
  576. }
  577. .password {
  578. width: 100%;
  579. height: 80rpx;
  580. font-size: 30rpx;
  581. line-height: 80rpx;
  582. padding: 0 20rpx;
  583. box-sizing: border-box;
  584. color: #606266;
  585. text-align: center;
  586. }
  587. input-holder {
  588. color: #666;
  589. font-size: 28rpx;
  590. }
  591. .modal-footer {
  592. display: flex;
  593. flex-direction: row;
  594. height: 86rpx;
  595. border-top: 1px solid #dedede;
  596. font-size: 34rpx;
  597. line-height: 86rpx;
  598. }
  599. .modal-footer button::after {
  600. border: none;
  601. }
  602. .modal-footer .btn-cancel {
  603. width: 50%;
  604. color: #2a7fff;
  605. text-align: center;
  606. border-radius: 0;
  607. }
  608. .modal-footer .btn-confirm {
  609. width: 50%;
  610. color: #666;
  611. border-right: 1px solid #dedede;
  612. text-align: center;
  613. }
  614. </style>