ReviewManageRejected.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. <template>
  2. <div style=" background-color: #fff; padding:15px;">
  3. <div style="margin-top:2px; margin-bottom:15px;" class="inline-block-btn-list">
  4. <el-select
  5. class="gap-right-8 first-element-btn"
  6. clearable
  7. filterable
  8. placeholder="选择奖扣对象进行筛选"
  9. v-model="filter.target_id"
  10. @change="onFilterChanged">
  11. <el-option
  12. v-for="item in employeeList"
  13. :key="item.id"
  14. :label="item.name"
  15. :value="item.id">
  16. </el-option>
  17. </el-select>
  18. <el-date-picker
  19. class="gap-right-8"
  20. v-model="filter.time_range"
  21. type="daterange"
  22. value-format="timestamp"
  23. range-separator="至"
  24. start-placeholder="开始日期"
  25. end-placeholder="结束日期"
  26. :picker-options="instantPickerOptions"
  27. @change="onFilterChanged">
  28. </el-date-picker>
  29. <div class="gap-right-8" style="display:inline-block; width:220px;">
  30. <el-input
  31. placeholder="输入关键词查找"
  32. ref="search-bar"
  33. v-model="filter.keywords"
  34. class="input-with-select"
  35. @keyup.enter.native="onFilterChanged">
  36. <el-button slot="append" icon="el-icon-search" @click="onFilterChanged"></el-button>
  37. </el-input>
  38. </div>
  39. </div>
  40. <el-table
  41. v-loading="loading"
  42. ref="multipleTable"
  43. :data="tableData"
  44. :border="false"
  45. tooltip-effect="dark"
  46. style="width: 100%">
  47. <!-- <el-table-column prop="mode_type" label="类型" :formatter="modeTypeFormatter"></el-table-column> -->
  48. <el-table-column label="类型">
  49. <template slot-scope="scope">
  50. <div>{{modeTypeFormatter('','',scope.row.mode_type,scope.row.task_id)}}</div>
  51. </template>
  52. </el-table-column>
  53. <el-table-column prop="target_name" label="姓名"></el-table-column>
  54. <el-table-column prop="recorder_name" label="录入者"></el-table-column>
  55. <el-table-column prop="category_path" label="积分分类"></el-table-column>
  56. <el-table-column label="附件">
  57. <template slot-scope="scope">
  58. <div>
  59. <a
  60. style="display: block; color:#409EFF; text-decoration: underline;"
  61. v-for="item in scope.row.file_list"
  62. @click="fileProview(item.url, scope.row.file_list, scope.row.id)"
  63. >{{item.name}}</a>
  64. </div>
  65. <div style="display:none;">
  66. <img
  67. v-for="(item,index) in scope.row.file_list"
  68. v-if="(['jpg', 'png', 'bmp', 'jpeg','JPG','PNG']).indexOf(item.url.split('.')[1]) >= 0"
  69. :src="item.url"
  70. :preview="scope.row.id"
  71. :preview-text="item.name"
  72. >
  73. </div>
  74. </template>
  75. </el-table-column>
  76. <el-table-column label="积分规则">
  77. <template slot-scope="scope">
  78. <div v-if="scope.row.rule_name && scope.row.item_content">
  79. {{ scope.row.rule_name }}:<br/>
  80. {{ scope.row.item_content }}
  81. </div>
  82. <div v-else>未指定</div>
  83. </template>
  84. </el-table-column>
  85. <el-table-column prop="remark" label="备注" :show-overflow-tooltip="true"></el-table-column>
  86. <el-table-column label="多人审批">
  87. <template slot-scope="scope">
  88. <span v-for="review_item of scope.row.review_list" :key="review_item.reviewer_id" v-if="review_item.status === 0" style="color: #aaa">
  89. <el-tooltip :content="review_item.name+'待审核'" placement="top">
  90. <span>
  91. {{review_item.name+' '}}
  92. </span>
  93. </el-tooltip>
  94. </span>
  95. <span v-for="review_item of scope.row.review_list" :key="review_item.reviewer_id" v-if="review_item.status === 1" style="color: green">
  96. <el-tooltip :content="review_item.name+'审核通过,得分'+review_item.point+'分'" placement="top">
  97. <span>
  98. {{review_item.name+' '}}
  99. </span>
  100. </el-tooltip>
  101. </span>
  102. <span v-for="review_item of scope.row.review_list" :key="review_item.reviewer_id" v-if="review_item.status === -1" style="color: red">
  103. <el-tooltip :content="review_item.name+'驳回,原因:'+review_item.comment" placement="top">
  104. <span>
  105. {{review_item.name+' '}}
  106. </span>
  107. </el-tooltip>
  108. </span>
  109. <!-- <span v-bind:class="scope.row.point < 0 ? 'point-negative' : 'point-positive'">{{ scope.row.point }}</span> -->
  110. </template>
  111. </el-table-column>
  112. <el-table-column prop="point_type" label="积分">
  113. <template slot-scope="scope">
  114. <div v-html="pointTypeFormatter(scope.row)"></div>
  115. </template>
  116. </el-table-column>
  117. <el-table-column label="事件日期">
  118. <template slot-scope="scope">
  119. <i v-if="scope.row.event_time" class="el-icon-time"></i>
  120. <span v-html="dateFormatter(scope.row,'',scope.row.event_time)"></span>
  121. </template>
  122. </el-table-column>
  123. <el-table-column prop="comment" label="驳回意见" :show-overflow-tooltip="true"></el-table-column>
  124. <el-table-column label="操作">
  125. <template slot-scope="scope">
  126. <el-button type="text" @click="sendReviewRecallRequest(scope.row.id)"
  127. :disabled="checkExpire(scope.row.finish_time)">撤消
  128. </el-button>
  129. </template>
  130. </el-table-column>
  131. </el-table>
  132. <el-pagination
  133. background
  134. layout="prev, pager, next"
  135. @size-change="handleSizeChange"
  136. :page-size="10"
  137. :page-sizes="[10, 20, 50, 100]"
  138. :total="totalCount"
  139. :current-page.sync="currentPage"
  140. @current-change="changePage">
  141. </el-pagination>
  142. </div>
  143. </template>
  144. <script>
  145. import Vue from 'vue'
  146. import preview from 'vue-photo-preview'
  147. import 'vue-photo-preview/dist/skin.css'
  148. Vue.use(preview, {
  149. tapToClose: false
  150. })
  151. export default {
  152. data() {
  153. return {
  154. profile: this.$store.getters.user_info,
  155. totalCount: 0,
  156. currentPage: 1,
  157. tableData: null,
  158. employeeList: [],
  159. filter: {
  160. keywords: '',
  161. target_id: '',
  162. time_range: []
  163. },
  164. loading: false,
  165. pointTypes: [],
  166. instantPickerOptions: {
  167. shortcuts: [{
  168. text: '本周',
  169. onClick(picker) {
  170. const now = new Date(new Date().toLocaleDateString())
  171. const start = now.getTime() - (now.getDay() - 1) * 24 * 60 * 60 * 1000
  172. const end = start + 7 * 24 * 60 * 60 * 1000 - 1000
  173. picker.$emit('pick', [start, end])
  174. }
  175. }, {
  176. text: '上周',
  177. onClick(picker) {
  178. const now = new Date(new Date().toLocaleDateString())
  179. const start = now.getTime() - (now.getDay() + 6) * 24 * 60 * 60 * 1000
  180. const end = start + 7 * 24 * 60 * 60 * 1000 - 1000
  181. picker.$emit('pick', [start, end])
  182. }
  183. }, {
  184. text: '本月',
  185. onClick(picker) {
  186. const now = new Date()
  187. const startDate = new Date(now.getFullYear(), now.getMonth(), 1)
  188. const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0)
  189. picker.$emit('pick', [startDate.getTime(), endDate.getTime()])
  190. }
  191. }, {
  192. text: '上月',
  193. onClick(picker) {
  194. const now = new Date()
  195. const startDate = new Date(now.getFullYear() - (now.getMonth() > 0 ? 0 : 1), (now.getMonth() + 11) % 12, 1)
  196. const endDate = new Date(now.getFullYear(), now.getMonth(), 0)
  197. picker.$emit('pick', [startDate.getTime(), endDate.getTime()])
  198. }
  199. }]
  200. }
  201. }
  202. },
  203. methods: {
  204. handleSizeChange(val) {
  205. this.pageLimit = val
  206. this.onFilterChanged()
  207. },
  208. onFilterChanged: function() {
  209. this.currentPage = 1
  210. this.loadReviewList()
  211. },
  212. modeTypeFormatter: function(row, column, cellValue, task_id) {
  213. switch (cellValue) {
  214. case 1:
  215. return '积分录入';
  216. case 2:
  217. if (task_id) { return '任务审核' }
  218. return '积分申请';
  219. default:
  220. return '';
  221. }
  222. },
  223. pointTypeFormatter: function(row) {
  224. for (let index = 0; index < this.pointTypes.length; index++) {
  225. const pointType = this.pointTypes[index]
  226. console.log(row, pointType.value)
  227. if (row.point_type == pointType.value) {
  228. if(row.point > 0){
  229. return '<span style="color:#f00;">+' +row.point +pointType.label+ '</span>'
  230. }else if(row.point < 0){
  231. return '<span style="color:#1a8dff;">' +row.point +pointType.label+ '</span>'
  232. }else{
  233. return row.point +pointType.label
  234. }
  235. }
  236. }
  237. return ''
  238. },
  239. fileProview(url, list, key) {
  240. const $ext_list = ['doc', 'docx', 'pptx', 'xls', 'xlsx', 'ppt', 'txt']
  241. const $ext_name = url.split('.')[1]
  242. if ($ext_list.indexOf($ext_name) >= 0) {
  243. console.log(
  244. 'https://view.officeapps.live.com/op/view.aspx?src=' +
  245. this.serverdomain +
  246. url
  247. )
  248. window.open(
  249. 'https://view.officeapps.live.com/op/view.aspx?src=' +
  250. this.serverdomain +
  251. url,
  252. '_blank'
  253. )
  254. }
  255. const $ext_list1 = ['jpg', 'png', 'bmp', 'jpeg','JPG','PNG']
  256. const $ext_name1 = url.split('.')[1]
  257. if ($ext_list1.indexOf($ext_name1) >= 0) {
  258. console.log(this.serverdomain + url)
  259. let ii = 0
  260. for (const i in list) {
  261. if (
  262. ['jpg', 'png', 'bmp', 'jpeg','JPG','PNG'].indexOf(list[i].url.split('.')[1]) >=
  263. 0
  264. ) {
  265. if (list[i].url == url) {
  266. console.log(ii)
  267. this.openPhotoSwipe(
  268. ii,
  269. document.querySelectorAll('img[preview="' + key + '"]')
  270. )
  271. return
  272. }
  273. ii++
  274. }
  275. }
  276. }
  277. },
  278. task_status: function(time){
  279. if(time >= 0 && time <= 60){
  280. return '按时完成';
  281. }else if(time > 60){
  282. return '提前'+(time/3600).toFixed(2)+'小时';
  283. }else if(time < 0 && time > -60){
  284. return '按时完成'
  285. }else if(time < -60){
  286. return '延期'+(Math.abs(time)/3600).toFixed(2)+'小时'
  287. }
  288. },
  289. dateFormatter: function(row, column, cellValue) {
  290. let ret = this.$moment(cellValue * 1000).format('MM月DD日')
  291. if(row.task_id > 0){
  292. ret = ret + '<br/>('+this.task_status(row.task_expiretime)+')'
  293. }
  294. return ret
  295. },
  296. checkExpire: function(timestamp) {
  297. if (timestamp && !isNaN(timestamp)) {
  298. if (new Date().getTime() - timestamp * 1000 < 15 * 60 * 60 * 1000) {
  299. return false
  300. }
  301. }
  302. return true
  303. },
  304. changePage(current) {
  305. if (isNaN(current) || current < 1) {
  306. return false
  307. }
  308. this.loadReviewList()
  309. },
  310. loadReviewList: function() {
  311. const params = {
  312. reviewer_id: this.profile.id,
  313. status: -1,
  314. page: this.currentPage
  315. }
  316. for (const item in this.filter) {
  317. const value = this.filter[item]
  318. if (item == 'time_range') {
  319. if (!value || value.length < 2) {
  320. continue
  321. }
  322. const timeRangeArr = value.map(x => parseInt(x / 1000))
  323. timeRangeArr[1] += 60 * 60 * 24 - 1
  324. params[item] = timeRangeArr.join(',')
  325. } else {
  326. params[item] = value
  327. }
  328. }
  329. var self = this
  330. self.loading = true
  331. this.$http('get','/integral.php/ajax_request_common/get_review_list',params).then(function(response) {
  332. if (response.status == 200) {
  333. self.loading = false
  334. var jsonData = response.data
  335. try {
  336. self.totalCount = jsonData.total_count
  337. self.tableData = jsonData.list_data
  338. } catch (err) {
  339. console.log(err)
  340. }
  341. }
  342. }).catch(function(error) {
  343. console.log(error)
  344. })
  345. },
  346. loadPointType: function() {
  347. var self = this
  348. this.$http('get','/integral.php/ajax_request_common/get_point_types').then(function(response) {
  349. if (response.status == 200) {
  350. const jsonData = response.data
  351. try {
  352. self.pointTypes = jsonData
  353. } catch (err) {
  354. console.log(err)
  355. }
  356. }
  357. }).catch(function(error) {
  358. console.log(error)
  359. })
  360. },
  361. // 获取员工列表
  362. loadEmployeeList: function() {
  363. var self = this
  364. this.$http('get','/integral.php/ajax_request_common/prepare_integral_options',{
  365. id: this.profile.id,
  366. employee_list: 1
  367. }).then(function(response) {
  368. if (response.status == 200) {
  369. var jsonData = response.data
  370. try {
  371. self.employeeList = jsonData.employee_list
  372. } catch (err) {
  373. console.log(err)
  374. }
  375. }
  376. }).catch(function(error) {
  377. console.log(error)
  378. })
  379. },
  380. sendReviewRecallRequest: function(reviewId) {
  381. const params = {
  382. id: reviewId
  383. }
  384. var self = this
  385. this.$http('post','/integral.php/ajax_request_common/review_recall',params,'','',
  386. {transformRequest: [(data) => {
  387. const paramArray = new Array()
  388. for (const it in data) {
  389. paramArray.push(encodeURIComponent(it) + '=' + encodeURIComponent(data[it]))
  390. }
  391. return paramArray.join('&')
  392. }]},
  393. // headers: {
  394. // 'Content-Type': 'application/x-www-form-urlencoded'
  395. // }
  396. ).then(function(response) {
  397. let message = ''
  398. let status = 0
  399. if (response.status == 200) {
  400. const data = response.data
  401. status = isNaN(data.status) ? 0 : parseInt(data.status)
  402. switch (status) {
  403. case 1:
  404. message = '审核撤消成功'
  405. break
  406. case -1:
  407. message = '表单参数错误'
  408. break
  409. default:
  410. message = data.info ? data.info : '审核撤消失败'
  411. }
  412. } else {
  413. message = '服务器出现问题';
  414. }
  415. self.$message({
  416. message: message,
  417. type: status == 1 ? 'success' : 'error'
  418. })
  419. if (status == 1) {
  420. self.currentPage = 1
  421. self.loadReviewList()
  422. self.$emit('update-count-indicator')
  423. }
  424. }).catch(function(error) {
  425. console.log(error)
  426. })
  427. }
  428. },
  429. created() {
  430. this.loadPointType()
  431. this.loadEmployeeList()
  432. this.loadReviewList()
  433. }
  434. }
  435. </script>
  436. <style>
  437. .el-pagination {
  438. text-align: center;
  439. margin-top: 15px;
  440. }
  441. </style>