approval_detail.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. <template>
  2. <div>
  3. <van-nav-bar :title="title" left-text="返回" @click-left="$route_back" left-arrow></van-nav-bar>
  4. <div class="body_com has_header" :class="{ can_complete: detail_info.can_complete == 1, can_complete_isIos: can_complete_isIos }">
  5. <scroller style="height: 100vh;">
  6. <!-- 审批内容 -->
  7. <!-- detail_info.process.length > 0 && -->
  8. <van-cell-group>
  9. <van-cell :title="detail_info.employee_info.name" v-if="detail_info.process !== null && detail_info.status == 0">
  10. <template slot="icon">
  11. <userImage
  12. :user_name="detail_info.employee_info.name"
  13. :img_url="detail_info.employee_info.img_url"
  14. width="0.9rem"
  15. height="0.9rem"
  16. style="margin-right: .1rem"
  17. ></userImage>
  18. </template>
  19. <template slot="title">
  20. <Wxopendata type="userName" :openid="detail_info.employee_info.name"></Wxopendata>
  21. </template>
  22. <template slot="label">
  23. <span v-show="detail_info.review_status == 0" :class="{ color_orange: detail_info.review_status == 0 }">{{ detail_info.review_status_mark }}</span>
  24. <span v-show="detail_info.review_status == 1" :class="{ color_red: detail_info.review_status == 1 }">{{ detail_info.review_status_mark }}</span>
  25. <span v-show="detail_info.review_status == 2" :class="{ color_green: detail_info.review_status == 2 }">{{ detail_info.review_status_mark }}</span>
  26. </template>
  27. </van-cell>
  28. </van-cell-group>
  29. <!-- 当审批状态不为待审批时 -->
  30. <div class="flex-box-v flex-center-center event-info__header" v-if="detail_info.status != 0 && detail_info.process !== null" style="padding:0.32rem;background-color:#fff;">
  31. <userImage class="about-me__avatar" :user_name="detail_info.employee_info.name" :img_url="detail_info.employee_info.img_url" width="1.12rem" height="1.12rem"></userImage>
  32. <span class="event-employee__name"><Wxopendata type="userName" :openid="detail_info.employee_info.name"></Wxopendata></span>
  33. <template v-if="detail_info.status == 1">
  34. <span class="event-info__value color_green" v-if="detail_info.review_point >= 0">+{{ detail_info.review_point }} {{ types_list[detail_info.pt_id] }}</span>
  35. <span class="event-info__value color_red" v-else>{{ detail_info.review_point }}{{ types_list[detail_info.pt_id] }}</span>
  36. </template>
  37. <span class="event-info__status">{{ detail_info.review_status_mark }}</span>
  38. </div>
  39. <!-- END -->
  40. <div class="detail_box">
  41. <div v-for="(item, index) in detail_info.detail" :key="index" class="detail_line">
  42. <template v-if="item.value">
  43. <div class="flex-box" v-if="item.key == '奖扣目标' || item.key == '申请人' || item.key == '收益人'">
  44. <span v-if="item.type == 'text'" class="detail_label">{{ item.key }}</span>
  45. <span v-if="item.type == 'text'" class="detail_value"><Wxopendata type="userName" :openid="item.value"></Wxopendata></span>
  46. </div>
  47. <div class="flex-box" v-else>
  48. <span v-if="item.type == 'text'" class="detail_label">{{ item.key }}</span>
  49. <span v-if="item.type == 'text'" class="detail_value">{{ item.value }}</span>
  50. </div>
  51. <span v-if="item.type == 'image'" class="detail_label">{{ item.key }}</span>
  52. <span v-if="item.type == 'image'" class="detail_value">
  53. <img
  54. :key="index"
  55. v-for="(items, index) in item.value"
  56. :src="items"
  57. style="width: 50px;height: 50px; margin-right: 0.2rem; vertical-align: text-top"
  58. @click="opremImage(item.value)"
  59. />
  60. </span>
  61. </template>
  62. </div>
  63. </div>
  64. <!-- 规则依据模块 -->
  65. <div class="event-rule__wrap">
  66. <div class="event-rule__header" style="margin-bottom:0.24rem;" v-show="detail_info.rule_id || detail_info.item_id">
  67. <span class="event-rule__title">规则依据</span>
  68. <span class="event-process__sub-title">此事件打分参考以下积分规则</span>
  69. </div>
  70. <div class="event-rule__item" v-if="detail_info.rule_id">
  71. <div class="detail_label">规则分类</div>
  72. <div class="detail_value">{{ detail_info.rule_name }}</div>
  73. </div>
  74. <div class="event-rule__item" v-if="detail_info.item_name && detail_info.item_id > 0">
  75. <div class="detail_label">积分规则</div>
  76. <div class="detail_value">{{ detail_info.item_name }}</div>
  77. </div>
  78. <div class="event-rule__item" v-if="detail_info.item_id > 0">
  79. <div class="detail_label">规则积分</div>
  80. <div class="detail_value">
  81. <span v-if="detail_info.item_range_type == 1">
  82. <span v-if="detail_info.item_prize_type == 1">+</span>
  83. {{ detail_info.item_min_point }}
  84. </span>
  85. <span v-if="detail_info.item_range_type == 2">
  86. <span v-if="detail_info.item_prize_type == 1">+</span>
  87. {{ detail_info.item_min_point }} ~ {{ detail_info.item_max_point }}
  88. </span>
  89. {{ types_list[detail_info.pt_id] }}
  90. </div>
  91. </div>
  92. </div>
  93. <!-- END -->
  94. <approvalProcess :data.sync="detail_info.process"></approvalProcess>
  95. <div style="height: 1.5rem;"></div>
  96. </scroller>
  97. <!-- 审批者 || -->
  98. <footer class="flex-box flex-v-ce footer" v-if="detail_info.can_refuse == '1'">
  99. <div class="flex-2">撤回后需重新审批</div>
  100. <van-button type="info" @click="revoke(1)" class="flex-1">撤回</van-button>
  101. </footer>
  102. <!-- 申请者 || -->
  103. <footer class="flex-box flex-v-ce footer" v-if="detail_info.applyor_id==$userInfo().id&&detail_info.can_refuse == '1'&&(detail_info.source_type==2||detail_info.source_type==3)">
  104. <div class="flex-2">撤销后数据将不可恢复</div>
  105. <van-button type="info" @click="revoke(2)" class="flex-1">撤销</van-button>
  106. </footer>
  107. <!-- 驳回弹窗 -->
  108. <van-popup v-model="show_refuse" position="right" :style="{ height: '100%', width: '100%', 'background-color': 'rgb(245, 245, 245)' }">
  109. <div :style="'padding-top:' + bar_height + 'px;background-color: #238dfa;'"></div>
  110. <van-nav-bar title="确认驳回" left-text="返回" @click-left="show_refuse = false" left-arrow></van-nav-bar>
  111. <van-cell-group><van-field v-model="refuse_msg" rows="5" autosize type="textarea" maxlength="50" placeholder="请输入审批意见" show-word-limit /></van-cell-group>
  112. <div style="padding:0.32rem;"><van-button block type="info" @click="confirm_refuse">确认驳回</van-button></div>
  113. </van-popup>
  114. </div>
  115. <van-row justify="center" type="flex" v-if="detail_info.can_complete == 1" class="btn-box">
  116. <van-col :span="detail_info.source_type != 4 ? 8 : 0">
  117. <div style="padding:0.16rem;">
  118. <van-button block type="info" plain :disabled="detail_info.source_type == '4'" v-if="detail_info.source_type != 4" @click="refuse">驳回</van-button>
  119. </div>
  120. </van-col>
  121. <!-- v-if="detail_info.status" -->
  122. <van-col :span="detail_info.source_type != 4 ? 16 : 24">
  123. <div style="padding:0.16rem; padding-left:0;">
  124. <van-button block type="info" v-if="detail_info.source_type == '1'" @click="$router.push({ name: 'integral_approval_integral', query: { review_id: detail_info.id } })">
  125. 通过
  126. </van-button>
  127. <van-button block type="info" v-if="detail_info.source_type == '2'" @click="$router.push({ name: 'integral_approval_integral', query: { review_id: detail_info.id } })">
  128. 通过
  129. </van-button>
  130. <van-button block type="info" v-if="detail_info.source_type == '3'" @click="$router.push({ name: 'integral_approval_integral', query: { review_id: detail_info.id } })">
  131. 通过
  132. </van-button>
  133. <van-button
  134. block
  135. type="info"
  136. v-if="detail_info.source_type == '4'"
  137. @click="$router.push({ name: 'integral_approval_performance', query: { review_id: detail_info.id } })"
  138. >
  139. 通过
  140. </van-button>
  141. </div>
  142. </van-col>
  143. </van-row>
  144. <van-image-preview v-model="show" :images="imageSrc"></van-image-preview>
  145. </div>
  146. </template>
  147. <script>
  148. import request from '@/utils/request'
  149. import Vue from 'vue'
  150. import approvalProcess from '@/components/integral/approval_process'
  151. import userImage from '@/components/common/user_image'
  152. import { Dialog, Panel, Step, Steps, Overlay, ImagePreview } from 'vant'
  153. Vue.use(Dialog)
  154. .use(Panel)
  155. .use(Step)
  156. .use(Steps)
  157. .use(Overlay)
  158. .use(ImagePreview)
  159. export default {
  160. // 数据
  161. components: { approvalProcess, userImage },
  162. data () {
  163. return {
  164. imageSrc: [],
  165. show: false,
  166. title: '审批详情',
  167. detail_info: {
  168. employee_info: { name: '', img_url: '' },
  169. process: [{ name: '未知' }]
  170. },
  171. review_id: this.$route.query.review_id,
  172. action: '',
  173. show_refuse: false,
  174. refuse_msg: '',
  175. show_complete: false,
  176. complete_msg: '',
  177. show_approver: false,
  178. approver_selected: { employee: [], dept: [] },
  179. reviewer: {
  180. name: '',
  181. url: '',
  182. id: ''
  183. },
  184. bar_height: '',
  185. show_one: false,
  186. adopt_one: false,
  187. show_two: false,
  188. adopt_two: false,
  189. types_list: {},
  190. can_complete_isIos: false
  191. }
  192. },
  193. watch: {
  194. adopt_one (val) {
  195. if (val) {
  196. this.get_info()
  197. }
  198. }
  199. },
  200. // 方法
  201. methods: {
  202. get_point_types () {
  203. var types = this.$getTypes
  204. for (let i in types) {
  205. this.types_list[types[i].id] = types[i].name
  206. }
  207. },
  208. opremImage (item) {
  209. this.show = true
  210. this.imageSrc = item
  211. },
  212. // 加载
  213. showLoading () {
  214. this.$toast.loading({
  215. loadingType: 'spinner',
  216. message: '正在处理'
  217. })
  218. },
  219. // 请求数据
  220. get_info () {
  221. let self = this
  222. self.showLoading()
  223. let review_id = self.$route.query.review_id
  224. request('get', '/api/integral/review', { review_id: review_id }).then(res => {
  225. self.$toast.clear()
  226. if (res.data.code === 1) {
  227. self.detail_info = res.data.data
  228. } else {
  229. self.$toast(res.data.msg)
  230. self.$keep_alive_update('cancel_msg', { cancel_text: res.data.msg, id: localStorage.getItem('read_msg') })
  231. setTimeout(() => {
  232. self.$route_back()
  233. }, 2000)
  234. }
  235. })
  236. },
  237. sub (data) {
  238. let self = this
  239. self.showLoading()
  240. request('post', '/api/integral/review', data)
  241. .then(res => {
  242. if (res.data.code == 1) {
  243. if (self.action == 'complete') {
  244. self.show_complete = false
  245. } else if (self.action == 'refuse') {
  246. self.show_refuse = false
  247. }
  248. self.$toast.clear()
  249. self.$toast(res.data.msg)
  250. self.get_info()
  251. } else {
  252. self.show_refuse = false
  253. self.$toast.clear()
  254. self.$toast(res.data.msg)
  255. }
  256. })
  257. .catch(e => {
  258. self.$toast.clear()
  259. })
  260. },
  261. // 通过
  262. complete () {
  263. let self = this
  264. self.action = 'complete'
  265. self.show_complete = true
  266. },
  267. confirm_complete () {
  268. let self = this
  269. let data = {
  270. review_id: self.review_id,
  271. action: self.action,
  272. rule_id: self.detail_info.rule_id,
  273. item_id: self.detail_info.item_id,
  274. point: self.detail_info.point,
  275. reviewer_id: self.reviewer.id,
  276. remark: self.complete_msg,
  277. ticket_count: '0'
  278. }
  279. if (!data.reviewer_id) {
  280. // 判断
  281. self.$notify({ type: 'danger', message: '您没有权限审批此条申请,请指定下一个审批人' })
  282. } else {
  283. self.$keep_alive_update('update_approval_list', data)
  284. self.sub(data)
  285. }
  286. },
  287. // 驳回
  288. refuse () {
  289. let self = this
  290. self.show_refuse = true
  291. },
  292. confirm_refuse () {
  293. let self = this
  294. self.action = 'refuse'
  295. let data = {
  296. review_id: self.review_id,
  297. action: self.action,
  298. rule_id: self.detail_info.rule_id,
  299. remark: self.refuse_msg,
  300. ticket_count: '0'
  301. }
  302. if (!self.refuse_msg) {
  303. self.$notify({ type: 'danger', message: '审批意见不能为空' })
  304. } else {
  305. self.$keep_alive_update('update_approval_list', data)
  306. self.sub(data)
  307. }
  308. },
  309. // 选择审批人确认
  310. approver_confirm (data) {
  311. let self = this
  312. if (data.employee) {
  313. self.reviewer = data.employee[0]
  314. self.approver_selected = data
  315. }
  316. self.show_approver = false
  317. },
  318. // 关闭选择审批人
  319. approver_cancel () {
  320. this.show_approver = false
  321. },
  322. // 撤销申请
  323. revoke (type) {
  324. let str = type == 1 ? '撤回' : '撤销'
  325. let self = this
  326. Dialog.confirm({
  327. title: '提示',
  328. message: '您确定要' + str + '此项吗?'
  329. })
  330. .then(() => {
  331. self.showLoading()
  332. request('DELETE', '/api/integral/review', { review_id: self.review_id })
  333. .then(res => {
  334. if (res.data.code == 1) {
  335. self.$keep_alive_update('update_approval_list', { review_id: self.review_id })
  336. self.$toast.clear()
  337. setTimeout(() => {
  338. this.$route_back()
  339. }, 200)
  340. } else {
  341. self.$toast.clear()
  342. self.$toast(res.data.msg)
  343. }
  344. })
  345. .catch(e => {
  346. self.$toast.clear()
  347. })
  348. })
  349. .catch(() => {
  350. // on cancel
  351. })
  352. }
  353. },
  354. // 生命周期 --- 创建完成
  355. created () {
  356. let self = this
  357. this.get_point_types()
  358. if (window.plus) {
  359. this.can_complete_isIos = window.plus.storage.getItem('iPhone')
  360. self.bar_height = window.plus.navigator.getStatusbarHeight()
  361. }
  362. self.get_info()
  363. if (this.$route.query.title) {
  364. this.title = this.$route.query.title
  365. }
  366. },
  367. keep_alive_update: {
  368. // 运用缓存更新方法来完成返回后的更新
  369. update_approval_detail: function (vm, data) {
  370. vm.get_info()
  371. },
  372. update_integral_approval_performance: function (vm, data) {
  373. vm.get_info()
  374. },
  375. withdraw_apply: function (vm, data) {
  376. vm.get_info()
  377. }
  378. }
  379. }
  380. </script>
  381. <style scoped lang="less">
  382. .footer {
  383. position: fixed;
  384. bottom: 0;
  385. left: 0;
  386. right: 0;
  387. background: #fff;
  388. padding: 0.16rem 0.3rem;
  389. border-top: 1px solid #f1f1f1;
  390. }
  391. .footer .flex-2 {
  392. font-size: 0.28rem;
  393. color: #909399;
  394. }
  395. .event-info__status {
  396. font-size: 0.32rem;
  397. color: #303133;
  398. margin-top: 0.2rem;
  399. }
  400. & .event-info__header {
  401. padding: 0.32rem;
  402. background: #fff;
  403. position: relative;
  404. &:after {
  405. position: absolute;
  406. box-sizing: border-box;
  407. content: ' ';
  408. pointer-events: none;
  409. right: 0.32rem;
  410. bottom: 0;
  411. left: 0.32rem;
  412. border-bottom: 1px solid #ebedf0;
  413. -webkit-transform: scaleY(0.5);
  414. transform: scaleY(0.5);
  415. }
  416. }
  417. & .event-info__value {
  418. font-size: 0.36rem;
  419. color: #f56c6c;
  420. text-align: right;
  421. font-weight: 600;
  422. }
  423. .event-employee__name {
  424. font-weight: 600;
  425. margin: 0.2rem 0;
  426. }
  427. .body_com {
  428. height: calc(100% - 0.92rem);
  429. position: relative;
  430. }
  431. .can_complete {
  432. height: calc(100% - 2.12rem);
  433. position: relative;
  434. }
  435. .can_complete_isIos {
  436. height: calc(100% - 2.52rem);
  437. }
  438. .detail_box {
  439. padding: 0.32rem;
  440. font-size: 0.32rem;
  441. }
  442. .detail_line {
  443. line-height: 1.75;
  444. }
  445. .detail_label {
  446. color: #969799;
  447. display: inline-block;
  448. width: 1.5rem;
  449. font-size: 0.32rem;
  450. }
  451. /deep/ .van-step--vertical:not(:last-child):after {
  452. border: none;
  453. }
  454. /deep/ .van-step--vertical .van-cell {
  455. padding: 0;
  456. }
  457. .steps_time {
  458. color: #999;
  459. font-size: 0.28rem;
  460. }
  461. .detail_value {
  462. color: #323233;
  463. font-size: 0.32rem;
  464. width: calc(100% - 1.5rem);
  465. }
  466. /deep/ .btn-box {
  467. background-color: #fff;
  468. padding-bottom: 0.4rem;
  469. }
  470. .detail_box {
  471. background-color: #fff;
  472. margin-bottom: 0.2rem;
  473. }
  474. & .event-process__wrap,
  475. .event-rule__wrap {
  476. margin-top: 0.24rem;
  477. padding: 0 0.36rem;
  478. background: #fff;
  479. & .event-process__header,
  480. .event-rule__header {
  481. position: relative;
  482. // display: flex;
  483. padding: 0.24rem 0;
  484. color: #303133;
  485. flex-direction: column;
  486. &:after {
  487. position: absolute;
  488. box-sizing: border-box;
  489. content: ' ';
  490. pointer-events: none;
  491. right: 0;
  492. bottom: 0;
  493. left: 0;
  494. border-bottom: 1px solid #ebedf0;
  495. -webkit-transform: scaleY(0.5);
  496. transform: scaleY(0.5);
  497. }
  498. & .event-process__title,
  499. .event-rule__title {
  500. font-weight: 600;
  501. }
  502. & .event-process__sub-title {
  503. font-size: 0.28rem;
  504. color: #909399;
  505. }
  506. }
  507. & .event-process__icon {
  508. display: flex;
  509. width: 0.72rem;
  510. height: 0.72rem;
  511. font-size: 0.28rem;
  512. color: #fff;
  513. background: #26a2ff;
  514. align-items: center;
  515. justify-content: center;
  516. border-radius: 100%;
  517. }
  518. & .event-process__item {
  519. position: relative;
  520. display: flex;
  521. height: 1.28rem;
  522. flex-direction: row;
  523. align-items: center;
  524. }
  525. & .process-item__content {
  526. display: flex;
  527. flex: 1;
  528. padding-left: 0.2rem;
  529. flex-direction: column;
  530. & .process-item__time {
  531. padding-top: 0.06rem;
  532. font-size: 0.24rem;
  533. color: #909399;
  534. }
  535. }
  536. & .process-item__point {
  537. display: flex;
  538. font-size: 0.36rem;
  539. font-weight: 500;
  540. align-items: center;
  541. }
  542. & .event-process__line {
  543. position: absolute;
  544. top: 1.04rem;
  545. left: 0.35rem;
  546. width: 0.02rem;
  547. height: 0.48rem;
  548. background-color: #ff0000;
  549. background: repeating-linear-gradient(0, #979797 0, #979797 11%, transparent 0, transparent 21%);
  550. }
  551. }
  552. .event-rule__item {
  553. display: flex;
  554. padding-bottom: 0.16rem;
  555. flex-direction: row;
  556. & .rule-item__label {
  557. display: flex;
  558. width: 1.45rem;
  559. color: #909399;
  560. }
  561. & .rule-item__value {
  562. display: flex;
  563. flex: 1;
  564. color: #303133;
  565. flex-wrap: wrap;
  566. }
  567. }
  568. .color_red{
  569. color: #F56C6C;
  570. }
  571. .color_green{
  572. color: #4BD964;
  573. }
  574. </style>