detail.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <template>
  2. <view class="detail white-wrap">
  3. <image :src="statusImg" mode="aspectFill" class="status-img" v-if="statusImg"></image>
  4. <view class="section white-wrap">
  5. <view class="section-title require">用印用途</view>
  6. <view :class="opButton.CheckEdit?'section-select-box':null" :style="{color:oldUse?'#333':'#999'}" @click="handleOperation('showPurpose')">{{oldUse?oldUse:'请选择'}}</view>
  7. </view>
  8. <view class="section white-wrap">
  9. <view class="section-title require">客户名称(全称)</view>
  10. <view>{{detail.CompanyName}}</view>
  11. </view>
  12. <view class="section white-wrap">
  13. <view class="section-title require">统一社会信用码</view>
  14. <input type="text" v-model="detail.CreditCode" placeholder="请填写统一社会信用码" disabled/>
  15. </view>
  16. <view class="section white-wrap">
  17. <view class="section-title">实际使用方名称</view>
  18. <input type="text" v-model="detail.UseCompanyName" placeholder="请填写实际使用方名称" disabled/>
  19. </view>
  20. <view class="section white-wrap">
  21. <view class="section-title require">业务类型</view>
  22. <input type="text" v-model="detail.ServiceType" placeholder="请填写业务类型" disabled/>
  23. </view>
  24. <view class="section white-wrap">
  25. <view class="section-title require">文件份数</view>
  26. <input type="number" v-model="oldFileNum" placeholder="请填写总共盖章文件份数" :disabled="!opButton.CheckEdit"/>
  27. </view>
  28. <view class="section white-wrap">
  29. <view class="section-title require">加盖何种印章</view>
  30. <view :class="opButton.CheckEdit?'section-select-box':null" :style="{color:oldSealType?'#333':'#999'}" @click="handleOperation('showType')">{{oldSealType?oldSealType:'请选择'}}</view>
  31. </view>
  32. <view class="section white-wrap" v-if="detail.ContractId>0">
  33. <view class="section-title require">合同附件</view>
  34. <image
  35. :src="files.img"
  36. mode="aspectFill"
  37. style="width: 102rpx;height: 120rpx"
  38. @click="handlepreViewFile(files)">
  39. </image>
  40. </view>
  41. <view class="section white-wrap" v-else>
  42. <view class="section-title require">合同附件</view>
  43. <!-- 合规可修改上传 -->
  44. <div class="check-file-box" :style="'background-image:url('+files.img+')'" v-if="files.url" @click="handlepreViewFile(files)">
  45. <image class="del-icon" src="../static/del-icon.png" @click.stop="handleDeleteCheckFile" v-if="opButton.CheckEdit"></image>
  46. </div>
  47. <image v-else @click="handleUpload" src="../static/upload-icon.png" mode="aspectFill" style="width: 102rpx;height: 120rpx;"></image>
  48. </view>
  49. <view class="section white-wrap" v-if="detail.Status==='已驳回'">
  50. <view class="section-title">驳回理由</view>
  51. <view style="color: #F55768;">{{detail.ApprovalRemark}}</view>
  52. </view>
  53. <view class="section white-wrap">
  54. <view class="section-title">备注</view>
  55. <textarea type="text" v-model="oldRemark" placeholder="请填写备注" :disabled="!opButton.CheckEdit"></textarea>
  56. </view>
  57. <!-- 流程模块 -->
  58. <view class="section white-wrap process-wrap">
  59. <view class="title" style="font-size: 16px;font-weight: bold;">审批流程</view>
  60. <steps :data="processData"></steps>
  61. </view>
  62. <!-- 审批/撤回申请 -->
  63. <view class="fix-bottom-wrap" style="text-align: center;" v-if="opButton.Approval||opButton.Cancel">
  64. <div class="flex" style="justify-content: space-between;width:100%">
  65. <van-button type="info" color="#3385FF" style="flex:1;" custom-class="btn-small" round @click="handleClickPass" v-if="opButton.Approval">通过</van-button>
  66. <van-button type="info" color="#F55768" style="flex:1;" custom-class="btn-small" round @click="handleApprovalReject" v-if="opButton.Approval">驳回</van-button>
  67. <van-button type="info" color="#F55768" style="flex:1;" :custom-class="opButton.Approval?'btn-small':'btn-big'" round @click="handleCancelApply" v-if="opButton.Cancel">撤回申请</van-button>
  68. </div>
  69. </view>
  70. <!-- 作废 -->
  71. <view class="fix-bottom-wrap" style="text-align: center;" v-if="opButton.Invalid">
  72. <view v-if="detail.ContractId>0" style="margin-bottom: 10rpx;" @click="checked=!checked"><radio value="同时作废合同" :checked="checked" color="#3385FF" style="transform:scale(0.8)"/>是否同时作废合同?</view>
  73. <van-button type="info" color="#F55768" custom-class="btn-big" round @click="handleSealInvalid">用印作废</van-button>
  74. </view>
  75. <!-- 重新提交 -->
  76. <view class="fix-bottom-wrap" style="text-align: center;" v-if="opButton.Edit">
  77. <van-button type="info" color="#3385FF" custom-class="btn-big" round @click="handleEdit">重新申请</van-button>
  78. </view>
  79. <!-- 撤回申请 -->
  80. <!-- <view class="fix-bottom-wrap" style="text-align: center;" v-if="opButton.Cancel">
  81. <van-button type="info" color="#3385FF" custom-class="btn-big" round @click="handleCancelApply">撤回申请</van-button>
  82. </view> -->
  83. <!-- 用印用途 -->
  84. <van-popup :show="showPurpose" @close="showPurpose=false" position="bottom">
  85. <van-picker
  86. show-toolbar
  87. title="选择用印用途"
  88. :columns="purposeArr"
  89. @confirm="handlePurposeConfirm"
  90. @cancel="showPurpose=false"
  91. />
  92. </van-popup>
  93. <!-- 何种印章 -->
  94. <van-popup :show="showType" @close="showType=false" position="bottom">
  95. <van-picker
  96. show-toolbar
  97. title="选择何种印章"
  98. :columns="typeArr"
  99. @confirm="handleTypeConfirm"
  100. @cancel="showType=false"
  101. />
  102. </van-popup>
  103. <!-- 客户搜索 -->
  104. <van-popup :show="showCustome" @close="showCustome=false" position="bottom" custom-style="height: 100vh">
  105. <view class="custome-search-wrap">
  106. <van-search use-left-icon-slot use-action-slot shape="round" :value="searchCustomeVal" placeholder="请输入客户名称/社会信用码" @change="onSearchValChange" @search="onSearch"
  107. custom-class="search-box" field-class="search-con">
  108. <view slot="left-icon">
  109. <image src="../static/search-icon.png" mode="aspectFill" class="search-icon"></image>
  110. </view>
  111. <view slot="action" @click="showCustome=false" class="search-btn">取消</view>
  112. </van-search>
  113. <view class="search-result">
  114. <view class="result-custome-box" v-if="searchContractList.length===0">
  115. <view class="result-item flex" v-for="item in searchCustomeList" :key="item" @click="getContract(item)">
  116. <image src="../static/search-icon.png" mode="aspectFill" class="search-icon"></image>
  117. <view class="con van-ellipsis">{{item}}</view>
  118. <image src="../static/click-icon.png" mode="aspectFill" class="click-icon"></image>
  119. </view>
  120. </view>
  121. <view class="result-contract-box" v-else>
  122. <view class="result-contract-item" v-for="item in searchContractList" :key="item.ContractId" @click="handleChooseContract(item)">
  123. <view class="name">{{item.CompanyName}}</view>
  124. <view style="margin-top: 20rpx;">合同编号:{{item.ContractCode}}</view>
  125. <view style="margin-top: 20rpx;">合同类型:{{item.ContractType}}</view>
  126. <view style="margin-top: 20rpx;">合同金额:{{item.Price}}</view>
  127. </view>
  128. </view>
  129. </view>
  130. </view>
  131. </van-popup>
  132. <van-dialog id="van-dialog" />
  133. </view>
  134. </template>
  135. <script>
  136. import {
  137. apiSealDetail,
  138. apiSearchCustome,
  139. apiSearchContract,
  140. apiApprovalPass,
  141. apiInvalidSeal,
  142. apiApprovalPassModify,
  143. apiSealCancelApply
  144. } from '@/api/approve/seal.js'
  145. import steps from '../components/steps.vue'
  146. import {preViewFile} from '../utils/util.js'
  147. import {uploadFiles} from '@/utils/uploadFile.js'
  148. export default{
  149. components:{
  150. steps
  151. },
  152. computed:{
  153. statusImg(){
  154. if(this.detail.Status==='已审批'){
  155. return require('../static/pass-icon.png')
  156. }else if(this.detail.Status==='已驳回'){
  157. return require('../static/fail-icon.png')
  158. }else if(this.detail.Status==='处理中'){
  159. return require('../static/processing-icon.png')
  160. }else if(this.detail.Status==='已撤回'){
  161. return require('../static/recall-icon.png')
  162. }else if(this.detail.Status==='已作废'){
  163. return require('../static/cancel-icon.png')
  164. }
  165. }
  166. },
  167. data() {
  168. return {
  169. val:'',
  170. ContractApprovalId:0,
  171. ContractApprovalRecordId:0,
  172. processData:null,
  173. detail:{},
  174. opButton:{},
  175. files:{
  176. type:'',
  177. img:'',
  178. url:''
  179. },//合同附件
  180. showPurpose:false,//显示用印用途选项
  181. purposeArr:['销售合同','渠道合同','付款通知函','招投标','战略合作协议'],
  182. showType:false,//显示用印用途选项
  183. typeArr:['公章','合同章','法人章'],
  184. showCustome:false,//显示搜索客户名称
  185. searchCustomeVal:'',//搜索客户输入数据
  186. searchCustomeList:[],//搜索到的客户名称列表
  187. searchContractList:[],//选择搜索中的客户后合同列表数据
  188. checked:false,//是否同时作废合同
  189. oldUse:"",
  190. oldFileNum:'',
  191. oldSealType:'',
  192. oldRemark:'',
  193. oldFile:''
  194. }
  195. },
  196. onLoad(options) {
  197. this.ContractApprovalId=options.ContractApprovalId
  198. this.ContractApprovalRecordId=options.ContractApprovalRecordId
  199. this.getDetail()
  200. },
  201. // onShow() {
  202. // this.getDetail()
  203. // },
  204. onPullDownRefresh() {
  205. this.getDetail()
  206. setTimeout(()=>{
  207. uni.stopPullDownRefresh()
  208. },1000)
  209. },
  210. methods: {
  211. // 合规删除合同附件
  212. handleDeleteCheckFile(){
  213. this.files={
  214. type:'',
  215. img:'',
  216. url:''
  217. }
  218. },
  219. //合规上传附件
  220. async handleUpload(){
  221. const res=await uploadFiles({type:'all'})
  222. const reg = /\.(pdf)$/;
  223. if(reg.test(res[0])){
  224. this.files={
  225. type:'pdf',
  226. url:res[0],
  227. img:require('../static/pdf.png')
  228. }
  229. }else{
  230. this.files={
  231. type:'img',
  232. url:res[0],
  233. img:res[0]
  234. }
  235. }
  236. },
  237. // 撤回申请
  238. handleCancelApply(){
  239. this.$dialog.confirm({
  240. title: '提示',
  241. message: '是否确认撤回',
  242. }).then(async ()=>{
  243. const res=await apiSealCancelApply({SealId:Number(this.detail.SealId)})
  244. if(res.code===200){
  245. uni.showToast({
  246. title:'撤回成功',
  247. icon:'none'
  248. })
  249. this.getDetail()
  250. }
  251. }).catch(() => {
  252. console.log('取消撤回');
  253. });
  254. },
  255. handlePurposeConfirm(e){
  256. this.oldUse=e.detail.value
  257. this.showPurpose=false
  258. },
  259. handleTypeConfirm(e){
  260. this.oldSealType=e.detail.value
  261. this.showType=false
  262. },
  263. //前去重审
  264. handleEdit(){
  265. uni.navigateTo({
  266. url:`./edit?ContractApprovalId=${this.ContractApprovalId}&ContractApprovalRecordId=${this.ContractApprovalRecordId}`
  267. })
  268. },
  269. //用印作废
  270. handleSealInvalid(){
  271. this.$dialog.confirm({
  272. title: '提示',
  273. message: '是否确认作废',
  274. }).then(async ()=>{
  275. const res=await apiInvalidSeal({
  276. IsInvalidContract:this.checked,
  277. SealId:this.detail.SealId
  278. })
  279. if(res.code===200){
  280. uni.showToast({
  281. title:'操作成功',
  282. icon:'none'
  283. })
  284. this.getDetail()
  285. }
  286. }).catch(() => {
  287. console.log('取消作废');
  288. });
  289. },
  290. //点击通过
  291. handleClickPass(){
  292. //判断是否有内容修改
  293. const flag1=this.oldUse===this.detail.Use
  294. const flag2=Number(this.oldFileNum)===Number(this.detail.FileNum)
  295. const flag3=this.oldSealType===this.detail.SealType
  296. const flag4=this.oldRemark===this.detail.Remark
  297. const flag5=this.files.url===this.detail.FileUrl
  298. if(flag1&&flag2&&flag3&&flag4&&flag5){
  299. this.handleApprovalPass()
  300. }else{
  301. this.handleApprovePassModify()
  302. }
  303. },
  304. //审批通过 (修改内容)
  305. async handleApprovePassModify(){
  306. const res=await apiApprovalPassModify({
  307. FileNum:Number(this.oldFileNum),
  308. Remark:this.oldRemark,
  309. SealId:Number(this.detail.SealId),
  310. SealType:this.oldSealType,
  311. Use:this.oldUse,
  312. FileUrl:this.files.url
  313. })
  314. if(res.code===200){
  315. this.$dialog.alert({
  316. title: "处理成功",
  317. confirmButtonColor: "#5890FB",
  318. }).then(() => {
  319. this.getDetail()
  320. });
  321. }
  322. },
  323. // 审批通过 (未修改内容)
  324. async handleApprovalPass(){
  325. const res=await apiApprovalPass({
  326. SealId:Number(this.detail.SealId),
  327. Remark:""
  328. })
  329. if(res.code===200){
  330. this.$dialog.alert({
  331. title: "处理成功",
  332. confirmButtonColor: "#5890FB",
  333. }).then(() => {
  334. this.getDetail()
  335. });
  336. }
  337. },
  338. //驳回
  339. handleApprovalReject(){
  340. uni.navigateTo({
  341. url:`./reason?SealId=${this.detail.SealId}`
  342. })
  343. },
  344. //预览文件
  345. handlepreViewFile(e){
  346. if (e.type === "pdf") {
  347. preViewFile(e.url)
  348. } else {
  349. uni.previewImage({
  350. urls: [e.url]
  351. })
  352. }
  353. },
  354. // 只有当 checkEdit 为true 即合规才能修改
  355. handleOperation(key){
  356. if(this.opButton.CheckEdit){
  357. this[key]=true
  358. }
  359. },
  360. // 客户搜索
  361. // 先搜索出客户 再通过客户去请求出客户下面存在的合同
  362. onSearchValChange(e){
  363. this.searchCustomeVal=e.detail
  364. },
  365. //搜索客户
  366. async onSearch(){
  367. this.searchContractList=[]
  368. this.searchCustomeList=[]
  369. const res=await apiSearchCustome({Keyword:this.searchCustomeVal})
  370. if(res.code===200){
  371. this.searchCustomeList=res.data
  372. }
  373. },
  374. // 搜索客户对应的合同
  375. async getContract(e){
  376. const res=await apiSearchContract({Keyword:e})
  377. if(res.code===200){
  378. if(res.data.List){
  379. this.searchContractList=res.data.List
  380. }else{
  381. uni.showToast({
  382. title:"此客户无合同,请重新选择",
  383. icon:"none"
  384. })
  385. }
  386. }
  387. },
  388. // 选择合同 更新表单数据
  389. handleChooseContract(e){
  390. this.detail.CompanyName=e.CompanyName
  391. this.detail.ServiceType=e.ContractType
  392. this.detail.CreditCode=e.CreditCode
  393. this.detail.UseCompanyName=e.CompanyName
  394. this.detail.ContractId=e.ContractId
  395. this.detail.ContractfileUrl=e.FileUrl
  396. // 关闭搜索弹窗
  397. this.showCustome=false
  398. this.searchCustomeVal=''
  399. this.searchContractList=[]
  400. this.searchCustomeList=[]
  401. },
  402. //获取详情
  403. async getDetail() {
  404. const res=await apiSealDetail({
  405. ContractApprovalId:Number(this.ContractApprovalId),
  406. ContractApprovalRecordId:Number(this.ContractApprovalRecordId)
  407. })
  408. if(res.code===200){
  409. this.detail=res.data.SealDetail
  410. this.oldUse=res.data.SealDetail.Use
  411. this.oldFileNum=res.data.SealDetail.FileNum
  412. this.oldSealType=res.data.SealDetail.SealType
  413. this.oldRemark=res.data.SealDetail.Remark
  414. this.processData=res.data.FlowNodeList
  415. this.opButton=res.data.OpButton
  416. this.handleFile(res.data.SealDetail.FileUrl)
  417. }
  418. },
  419. //处理文件
  420. handleFile(filesUrl){
  421. const reg = /\.(pdf)$/;
  422. if(reg.test(filesUrl)){
  423. this.files={
  424. type: "pdf",
  425. url: filesUrl,
  426. img: require("../static/pdf.png"),
  427. }
  428. }else{
  429. this.files={
  430. type: "img",
  431. url: filesUrl,
  432. img: filesUrl,
  433. }
  434. }
  435. },
  436. },
  437. }
  438. </script>
  439. <style lang="scss">
  440. .check-file-box{
  441. width: 102rpx;
  442. height: 120rpx;
  443. background-size: cover;
  444. background-position: center;
  445. position: relative;
  446. .del-icon{
  447. position: absolute;
  448. width: 30rpx;
  449. height: 30rpx;
  450. top: -15rpx;
  451. right: -15rpx;
  452. }
  453. }
  454. .detail{
  455. width: 100%;
  456. min-height: 100vh;
  457. padding-bottom: calc(150rpx + constant(safe-area-inset-bottom));
  458. padding-bottom: calc(150rpx + env(safe-area-inset-bottom));
  459. position: relative;
  460. }
  461. .status-img{
  462. position: absolute;
  463. right: 0;
  464. top: 50rpx;
  465. width: 220rpx;
  466. height: 220rpx;
  467. z-index: 10;
  468. }
  469. .section{
  470. padding: 30rpx 34rpx;
  471. border-top: 10rpx solid #F5F5F5;
  472. position: relative;
  473. .section-title{
  474. font-size: 16px;
  475. margin-bottom: 20rpx;
  476. }
  477. .require::before{
  478. content: '*';
  479. font-size: 16px;
  480. color: #FF0000;
  481. position: absolute;
  482. left: 20rpx;
  483. }
  484. .section-select-box{
  485. color: #999;
  486. position: relative;
  487. &::after{
  488. position: absolute;
  489. right: 0;
  490. top: 50%;
  491. content: '';
  492. display: block;
  493. width: 18rpx;
  494. height: 18rpx;
  495. border-top: 1px solid #999;
  496. border-right: 1px solid #999;
  497. transform: translateY(-50%) rotate(45deg);
  498. }
  499. }
  500. }
  501. .btn-big{
  502. width: 450rpx;
  503. height: 60rpx;
  504. }
  505. .btn-small{
  506. min-width: 220rpx;
  507. height: 60rpx;
  508. }
  509. .custome-search-wrap{
  510. padding: 34rpx;
  511. height: 100%;
  512. .search-box {
  513. border: 1px solid #3385FF;
  514. padding: 0 !important;
  515. border-radius: 60rpx;
  516. background-color: #fff !important;
  517. }
  518. .search-con {
  519. background-color: #fff !important;
  520. }
  521. .van-search__content {
  522. background-color: #fff !important;
  523. padding-left: 30rpx !important;
  524. }
  525. .search-btn {
  526. position: relative;
  527. color: #3385FF;
  528. &::before {
  529. content: '';
  530. display: block;
  531. width: 1px;
  532. height: 60%;
  533. background-color: #D1D1D1;
  534. position: absolute;
  535. left: -16rpx;
  536. top: 20%;
  537. }
  538. }
  539. .search-icon{
  540. width: 40rpx;
  541. height: 40rpx;
  542. display: block;
  543. position: relative;
  544. top: 4rpx;
  545. margin-right: 20rpx;
  546. }
  547. .click-icon{
  548. width: 24rpx;
  549. height: 24rpx;
  550. }
  551. .result-item{
  552. align-items: center;
  553. padding: 20rpx 0;
  554. border-bottom: 1px solid #EBEBEB;
  555. .con{
  556. flex: 1;
  557. margin-right: 20rpx;
  558. }
  559. }
  560. .search-result{
  561. overflow-y: auto;
  562. height: 100%;
  563. }
  564. .result-contract-box{
  565. padding: 0 10rpx;
  566. .result-contract-item{
  567. margin-top: 30rpx;
  568. box-shadow: 0px 0px 12rpx rgba(175, 175, 175, 0.38);
  569. padding: 30rpx;
  570. border-radius: 8px;
  571. .name{
  572. font-size: 16px;
  573. font-weight: bold;
  574. &::before{
  575. content:'';
  576. display:inline-block;
  577. width: 31rpx;
  578. height: 34rpx;
  579. background-image: url(../../static/man.png);
  580. background-size: cover;
  581. position: relative;
  582. top: 4rpx;
  583. margin-right: 10rpx;
  584. }
  585. }
  586. }
  587. }
  588. }
  589. </style>