ReviewManageAccepted.vue 15 KB

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