add.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. <template>
  2. <div class="visit-add">
  3. <nav-bar></nav-bar>
  4. <div class="page-container">
  5. <!-- 基本信息 -->
  6. <div class="card">
  7. <van-panel >
  8. <template #header>
  9. <van-cell title="介绍信信息"></van-cell>
  10. </template>
  11. <div class="panel-box">
  12. <select-cell
  13. title="介绍信类型"
  14. is-row
  15. :prop="prop"
  16. v-model="visitType"
  17. :data-list="typeList"
  18. @change="changeType"
  19. required>
  20. </select-cell>
  21. <van-field
  22. label="介绍信编号"
  23. :required="visitType == 2"
  24. v-model="formData.letterNo"
  25. placeholder="请输入"
  26. :maxlength="15"/>
  27. <van-field
  28. label="出入事由"
  29. required
  30. rows="1"
  31. autosize
  32. type="textarea"
  33. v-model="formData.reasons"
  34. placeholder="请输入"
  35. show-word-limit
  36. :maxlength="100"/>
  37. <date-cell
  38. v-if="visitType=='2'"
  39. is-row
  40. :required="visitType == 2"
  41. v-model="formData.startTime"
  42. title="开具日期">
  43. </date-cell>
  44. <van-cell
  45. v-else
  46. is-row
  47. v-model="formData.startTime"
  48. title="开具日期">
  49. </van-cell>
  50. <van-cell
  51. title="有效天数"
  52. :required="visitType == 2">
  53. <van-stepper :disabled="visitType == 3" integer :min="1" :max="356" v-model="formData.effectiveDays" step="1" />
  54. </van-cell>
  55. <!-- <select-cell-->
  56. <!-- :required="visitType == 2"-->
  57. <!-- title="有效天数"-->
  58. <!-- is-row-->
  59. <!-- :label="formData.effectiveDays"-->
  60. <!-- is-link-->
  61. <!-- @click="showCalendar">-->
  62. <!-- </select-cell>-->
  63. <div class="upload-box">
  64. <span :class="{'required':visitType == 2}">上传介绍信</span>
  65. <van-cell>
  66. <uploader :maxCount="5" v-model="formData.letterFile"/>
  67. </van-cell>
  68. </div>
  69. <van-field
  70. v-model="formData.description"
  71. rows="1"
  72. autosize
  73. :maxlength="200"
  74. label="备注信息"
  75. type="textarea"
  76. show-word-limit
  77. placeholder="请输入"/>
  78. <van-cell required title="添加人员">
  79. <template #right-icon>
  80. <div class="flex-box">
  81. <van-button type="info" size="mini" @click="openPicker">点击添加</van-button>
  82. </div>
  83. </template>
  84. </van-cell>
  85. </div>
  86. </van-panel>
  87. </div>
  88. <!-- 人员列表 -->
  89. <div class="card" v-for="(v,i) in pList" :key="v.uuid">
  90. <van-swipe-cell>
  91. <div class="goods-card">
  92. <div class="card-img-box" @click="preView(v.imgFile)">
  93. <img :src="imgUrl(v.imgFile[0].imgPath)" alt="">
  94. </div>
  95. <div class="card-cell-box">
  96. <van-cell title="申请单位" :value="v.companyName"></van-cell>
  97. <van-cell title="出入人员" :value="v.userName"></van-cell>
  98. <van-cell title="证件类型" :value="getDictLabel(v.idType,'letter_id_type')"></van-cell>
  99. <van-cell title="证件号码" :value="v.idCard"></van-cell>
  100. </div>
  101. </div>
  102. <template #left>
  103. <van-button style="height: 100%;" square text="编辑" type="info" @click="editPerson(v,i)" class="delete-button" />
  104. </template>
  105. <template #right>
  106. <van-button style="height: 100%;" square text="删除" type="danger" @click="deletePerson(v,i)" class="delete-button" />
  107. </template>
  108. </van-swipe-cell>
  109. </div>
  110. <div class="big-btn-box" >
  111. <van-button type="info" size="large" @click="onSubmit">提交</van-button>
  112. </div>
  113. </div>
  114. <!-- <van-calendar-->
  115. <!-- v-model="showCalendar"-->
  116. <!-- :allow-same-day="true"-->
  117. <!-- type="range"-->
  118. <!-- :show-confirm="false"-->
  119. <!-- @confirm="onConfirm"/>-->
  120. <calendar-picker ref="CalendarPicker" @change="getDate"></calendar-picker>
  121. <org-picker
  122. :show="showPicker"
  123. @cancel="cancelPicker"
  124. @confirm="changeOrg">
  125. </org-picker>
  126. <!-- 添加人员弹窗 -->
  127. <van-popup
  128. class="add-picker"
  129. v-model="showAddPicker"
  130. :close-on-click-overlay="false"
  131. position="top">
  132. <!-- 添加人员信息 -->
  133. <div class="card" >
  134. <!-- <van-cell title="人员信息">-->
  135. <!-- <template #right-icon>-->
  136. <!-- <van-button type="info" v-if="isAdd" icon="plus" size="mini" @click="onAdd">添加</van-button>-->
  137. <!-- <van-button type="info" v-else icon="edit" size="mini" @click="onEdit">确认</van-button>-->
  138. <!-- </template>-->
  139. <!-- </van-cell>-->
  140. <div class="panel-box">
  141. <van-form validate-first @failed="onFailed">
  142. <van-field
  143. required
  144. v-model="personnel.companyName"
  145. rows="1"
  146. autosize
  147. :maxlength="20"
  148. label="申请单位"
  149. :rules="[{ pattern:/^(.+)$/, message: '请输入' }]"
  150. placeholder="请输入"/>
  151. <van-field
  152. required
  153. v-model="personnel.userName"
  154. rows="1"
  155. autosize
  156. :maxlength="20"
  157. label="出入人员"
  158. :rules="[{ pattern:/^(.+)$/, message: '请输入' }]"
  159. placeholder="请输入"/>
  160. <select-cell
  161. title="证件类型"
  162. is-row
  163. v-model="personnel.idType"
  164. :data-list="getDictItem('letter_id_type')"
  165. required>
  166. </select-cell>
  167. <van-field
  168. required
  169. v-model="personnel.idCard"
  170. rows="1"
  171. autosize
  172. :maxlength="20"
  173. label="证件号码"
  174. placeholder="请输入"/>
  175. </van-form>
  176. <div class="upload-box" >
  177. <span class="required">{{personnel.idType==0?'证件正反面':'上传证件照'}}</span>
  178. <van-cell>
  179. <uploader :maxCount="2" v-model="personnel.imgFile"/>
  180. </van-cell>
  181. </div>
  182. <p class="tip-text" >注:证件号码将作为唯一识别码</p>
  183. </div>
  184. <div class="header-line">
  185. <div class="cancel" @click="onCancel">取消</div>
  186. <!-- <div class="title">添加人员</div>-->
  187. <div v-if="isAdd" class="sure" @click="onAdd">添加</div>
  188. <div v-else class="sure" @click="onEdit">确定</div>
  189. </div>
  190. </div>
  191. </van-popup>
  192. </div>
  193. </template>
  194. <script>
  195. import SelectCell from "@/components/selectCell/index.vue";
  196. import DateCell from "@/components/dateCell/index.vue";
  197. import Uploader from "@/components/upload/gxuploader.vue";
  198. import OrgPicker from "@/components/OrgPicker/index.vue";
  199. import CalendarPicker from "@/components/CalendarPicker/index.vue";
  200. import {formatDate} from "@/filters/filter";
  201. import {mapGetters} from "vuex";
  202. import {imgUrl} from "@/utils";
  203. import { ImagePreview } from 'vant'
  204. import {visitAdd} from './api'
  205. import dayjs from "dayjs";
  206. export default {
  207. components: {SelectCell,Uploader,DateCell,CalendarPicker,OrgPicker},
  208. data(){
  209. return {
  210. visitType:2,
  211. checked:false,
  212. visitInfo: {},
  213. formData:{
  214. receptionOrgIds:null,
  215. reasons:null,
  216. letterNo:null,
  217. letterFile:null,
  218. description:null,
  219. startTime:null,
  220. effectiveDays:null,
  221. },
  222. personnel:{
  223. companyName:null,
  224. userName:null,
  225. idCard:null,
  226. idType:null,
  227. imgFile:[],
  228. },
  229. pList:[],
  230. isAdd:true,
  231. showPicker:false,
  232. openCalendar:false,
  233. prop:{
  234. label:'name',
  235. value:'value'
  236. },
  237. typeList:[
  238. {
  239. name:'纸质',
  240. value:2
  241. },
  242. {
  243. name:'紧急',
  244. value:3
  245. }
  246. ],
  247. dicts:['letter_id_type'],
  248. showAddPicker:false,
  249. }
  250. },
  251. computed:{
  252. ...mapGetters(['orgId','id','dictionary'])
  253. },
  254. methods:{
  255. imgUrl,formatDate,
  256. onCancel() {
  257. this.showAddPicker = false;
  258. },
  259. onConfirm() {
  260. if(!this.selected.length){
  261. this.$toast('请选择')
  262. return;
  263. }
  264. this.showAddPicker = false;
  265. },
  266. openPicker(){
  267. this.showAddPicker = true;
  268. },
  269. changeType(){
  270. this.formData.startTime = dayjs(new Date()).format('YYYY-MM-DD');
  271. this.formData.effectiveDays = 1;
  272. },
  273. onSubmit(){
  274. // if(this.visitType == '1'){
  275. // if(!this.formData.receptionOrgIds){
  276. // this.$toast('请选择出入机构');
  277. // return;
  278. // }
  279. // if(!this.formData.letterNo){
  280. // this.$toast('请输入介绍信编号');
  281. // return;
  282. // }
  283. // if(!this.formData.letterFile){
  284. // this.$toast('请上传介绍信');
  285. // return;
  286. // }
  287. // }
  288. try{
  289. if (!this.visitType) {
  290. this.$toast('请选择介绍信类型');
  291. return;
  292. }
  293. if(this.visitType == '2') {
  294. if (!this.formData.letterNo) {
  295. this.$toast('请输入介绍信编号');
  296. return;
  297. }
  298. if (!this.formData.reasons) {
  299. this.$toast('请输入出入事由');
  300. return;
  301. }
  302. if (!this.formData.startTime) {
  303. this.$toast('请选择开具日期');
  304. return;
  305. }
  306. if (!this.formData.startTime) {
  307. this.$toast('请选择有效天数');
  308. return;
  309. }
  310. if (!this.formData.letterFile) {
  311. this.$toast('请上传介绍信');
  312. return;
  313. }
  314. if (this.pList.length == 0) {
  315. this.$toast('请添加人员信息');
  316. return;
  317. }
  318. }
  319. if(this.visitType == '3') {
  320. if (!this.formData.reasons) {
  321. this.$toast('请输入出入事由');
  322. return;
  323. }
  324. if (this.pList.length == 0) {
  325. this.$toast('请添加人员信息');
  326. return;
  327. }
  328. }
  329. //判断介绍信是否过期
  330. const inputDate = dayjs(this.formData.startTime);
  331. const newDate = inputDate.add(this.formData.effectiveDays,'day').startOf('day');
  332. const currentDate = dayjs();
  333. if (!dayjs(newDate).isAfter(dayjs(currentDate))){
  334. this.$toast("介绍信已过有效期,请重新选择开具日期或有效天数!");
  335. return;
  336. }
  337. this.formData.status = 1;
  338. this.formData.type = this.visitType;
  339. this.formData.receptionOrgIds = [this.orgId];
  340. this.formData.userInfos = JSON.parse(JSON.stringify(this.pList));
  341. let data = this.formData;
  342. if(this.formData.letterFile && this.formData.letterFile.length > 0){
  343. data.letterFile = this.formData.letterFile.map(v=>{
  344. return JSON.stringify(v);
  345. })
  346. }
  347. data.userInfos = this.pList.map(user=>{
  348. let urlArr = user.imgFile.map(v=>{
  349. return v.imgPath
  350. })
  351. user.imgFile = urlArr.join(',');
  352. return user
  353. })
  354. //alert(JSON.stringify(data));
  355. // return;
  356. visitAdd(data).then(res=>{
  357. this.$toast.success('提交成功');
  358. this.$router.replace({
  359. name:'visitRegister',
  360. path:'/visitRegister',
  361. params:{event:'refresh'},
  362. });
  363. })
  364. }catch (e) {
  365. alert(e)
  366. }
  367. },
  368. onFailed(errorInfo) {
  369. console.log('failed', errorInfo);
  370. },
  371. getDate(date){
  372. const [start, end] = date;
  373. this.formData.range = date;
  374. this.formData.date = `${start} ~ ${end}`;
  375. },
  376. showCalendar(){
  377. this.$refs.CalendarPicker.show = true;
  378. },
  379. editPerson(v,i){
  380. this.showAddPicker = true;
  381. this.isAdd = false;
  382. this.personnel = JSON.parse(JSON.stringify(v));
  383. },
  384. deletePerson(v,i){
  385. this.pList.splice(i,1);
  386. },
  387. onEdit(){
  388. if(!this.personnel.companyName || !this.personnel.userName || !this.personnel.idType || !this.personnel.idCard || !this.personnel.imgFile){
  389. this.$toast('请完善人员信息');
  390. return;
  391. }
  392. let strObj = JSON.parse(JSON.stringify(this.personnel));
  393. let index = this.pList.findIndex(v=>{return v.uuid === strObj.uuid});
  394. this.pList.splice(index,1,strObj);
  395. this.personnel = {
  396. companyName:null,
  397. userName:null,
  398. idType:null,
  399. idCard:null,
  400. imgFile:[],
  401. };
  402. this.isAdd = true;
  403. this.showAddPicker = false;
  404. },
  405. onAdd(){
  406. //测试模拟
  407. // if(!this.personnel.idCard){
  408. // this.personnel.imgFile = [{
  409. // url:'askjdkajsdjajkdsa',
  410. // imgPath:'asjkdklaslkdasdlasld',
  411. // name:'asdasdasd'
  412. // },
  413. // {
  414. // url:'asdaaskjdkajsdjajkdsa',
  415. // imgPath:'dsaasjkdklaslkdasdlasld',
  416. // name:'asdasdasd'
  417. // }
  418. // ];
  419. // this.personnel.userName = '张三';
  420. // this.personnel.idCard = '123456789012345678'
  421. // this.personnel.companyName = '测试单位';
  422. // }
  423. if(!this.personnel.companyName || !this.personnel.userName || !this.personnel.idType || !this.personnel.idCard || !this.personnel.imgFile){
  424. this.$toast('请完善人员信息');
  425. return;
  426. }
  427. let strObj = JSON.parse(JSON.stringify(this.personnel));
  428. //判断是否已添加
  429. let flag = this.pList.some(v=> {return v.idCard === strObj.idCard});
  430. if(flag) {
  431. this.$toast('该人员信息已添加');
  432. return;
  433. };
  434. strObj.uuid = `${new Date().getTime()}`;
  435. this.pList.push(strObj);
  436. this.personnel = {
  437. companyName:null,
  438. userName:null,
  439. idType:null,
  440. idCard:null,
  441. imgFile:[],
  442. };
  443. this.showAddPicker = false;
  444. },
  445. showOrg(){
  446. this.showPicker = true;
  447. },
  448. changeOrg(selected){
  449. this.showPicker = false;
  450. this.formData.orgName = selected[0].text;
  451. this.formData.receptionOrgIds = [selected[0].id];
  452. },
  453. cancelPicker(){
  454. this.showPicker = false;
  455. },
  456. preView(val) {
  457. if(Array.isArray(val)){
  458. let arr = val.map(v=>{
  459. return imgUrl(v.imgPath);
  460. })
  461. ImagePreview(arr);
  462. }else {
  463. ImagePreview([imgUrl(val)]);
  464. }
  465. },
  466. }
  467. }
  468. </script>
  469. <style lang="scss">
  470. .visit-add{
  471. .van-card{
  472. padding: 20px;
  473. }
  474. .card-cell-box{
  475. width: 70%;
  476. .van-cell{
  477. padding: 4px;
  478. &::after{
  479. left:10px;
  480. right:10px;
  481. }
  482. }
  483. .van-cell__title{
  484. flex:.25;
  485. }
  486. .van-cell__value{
  487. flex:.75;
  488. }
  489. }
  490. }
  491. </style>
  492. <style scoped lang="scss">
  493. .visit-add{
  494. height: 100%;
  495. overflow: hidden;
  496. }
  497. .page-container{
  498. height: calc(100vh - 94px);
  499. overflow: auto;
  500. padding: 20px;
  501. }
  502. .flex-box{
  503. display: flex;
  504. justify-content: space-between;
  505. align-items: center;
  506. >span{
  507. margin: 0 20px;
  508. }
  509. }
  510. .card{
  511. margin-bottom: 20px;
  512. box-shadow: 0 10px 10px #eaeaea;
  513. }
  514. .card:last-child{
  515. margin-bottom: 0;
  516. }
  517. .panel-box{
  518. padding:0 20px;
  519. background-color: #fff;
  520. }
  521. .panel-box-item{
  522. height: 36px;
  523. line-height: 36px;
  524. }
  525. .item-label{
  526. width: 100%;
  527. display: flex;
  528. justify-content: right;
  529. align-items: center;
  530. }
  531. .item-value{
  532. width: 100%;
  533. display: flex;
  534. justify-content: left;
  535. align-items: center;
  536. }
  537. .upload-box{
  538. padding: 0 30px;
  539. display: flex;
  540. >span{
  541. display: inline-block;
  542. height: 160px;
  543. width: 200px;
  544. line-height: 160px;
  545. font-size: 28px;
  546. color:#999;
  547. position: relative;
  548. }
  549. }
  550. .goods-card{
  551. width: 100%;
  552. display: flex;
  553. align-items: center;
  554. padding: 10px;
  555. background-color: #fff;
  556. .card-img-box{
  557. width: 200px;
  558. height: 200px;
  559. margin-right: 10px;
  560. >img{
  561. width: 100%;
  562. height: 100%;
  563. object-fit: cover;
  564. border-radius: 10px;
  565. }
  566. }
  567. }
  568. .tip-text{
  569. line-height: 60px;
  570. color:red;
  571. background-color: #fff;
  572. }
  573. .big-btn-box{
  574. padding-bottom: 20px;
  575. }
  576. .add-picker{
  577. .header-line {
  578. display: flex;
  579. justify-content: space-between;
  580. align-items: center;
  581. height: 90px;
  582. }
  583. .header-line .cancel {
  584. padding: 0 30px;
  585. font-size: 28px;
  586. color: #969799;
  587. }
  588. .header-line .title {
  589. font-weight: 500;
  590. font-size: 30px;
  591. color: #343434;
  592. }
  593. .header-line .sure {
  594. padding: 0 30px;
  595. font-size: 28px;
  596. color: #1989fa;
  597. }
  598. .lists {
  599. padding: 10px 20px 20px 20px;
  600. min-height: 300px;
  601. max-height: 700px;
  602. overflow: auto;
  603. touch-action: pan-y;
  604. }
  605. .tip {
  606. color: #666;
  607. padding-bottom: 5px;
  608. }
  609. .van-empty{
  610. padding: 0;
  611. }
  612. }
  613. </style>