add.vue 19 KB

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