organizationExamine.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. <template>
  2. <div class="all" :class="{ bg_fff: skeletonLoad }">
  3. <van-nav-bar title="组织考核" left-text="返回" @click-left="goHomePage" :right-text="right_text" @click-right="multi_option" left-arrow></van-nav-bar>
  4. <van-notice-bar
  5. left-icon="volume-o"
  6. text="默认显示每个人的最新考核数据,可选择人员添加考核数据,也可以移除某个人员的考核数据,或点击人员姓名替换某条考核数据"
  7. />
  8. <div class="search-box flex-box-ce">
  9. <div class="flex-1 flex-box-ce flex-center-center fontColorC" @click="openPanel">
  10. 周期选择 <van-icon name="arrow-down" size="12" style="margin-left: 0.2rem;" />
  11. </div>
  12. <div class="flex-1 flex-box-ce flex-center-center fontColorC" @click="openPanel2">
  13. 部门选择
  14. <van-icon name="arrow-down" size="12" style="margin-left: 0.2rem;" />
  15. </div>
  16. </div>
  17. <div class="overall">
  18. <VanSkeleton :skeLoad="skeletonLoad">
  19. <scroller>
  20. <div style="padding-bottom: 1rem;">
  21. <div class="list-box" v-for="(item, index) in employeeList" :key="item.employeeId">
  22. <van-checkbox v-if="multi" v-model="item.selected" shape="square" style="margin-bottom: 0.1rem;" />
  23. <div class="flex-box-ce" style="margin-bottom: 0.2rem;" @click="chooseExamineInfo(index, item.employeeId)">
  24. <div class="flex-box-ce">
  25. <div>
  26. <userImage class="about-me__avatar" :id="item.userInfo.id" :img_url="item.userInfo.img_url" :user_name="item.userInfo.name" fontSize="0.24" width="0.8rem" height="0.8rem"></userImage>
  27. </div>
  28. <div class="user-info">
  29. <div style="margin-bottom: 0.05rem; color: #000;">{{ item.employeeName }}</div>
  30. <template v-if="item.deptList && item.deptList.length > 0">
  31. <span v-for="(dept, index) in item.deptList" :key="index">{{ dept }}&nbsp;</span>
  32. </template>
  33. </div>
  34. </div>
  35. <div v-if="item.status == 1" class="examine-item-status" style="background-color: #FF9600;">
  36. 已结束
  37. </div>
  38. <div v-if="item.status == 0" class="examine-item-status" >
  39. 进行中
  40. </div>
  41. </div>
  42. <div class="examine-info">
  43. <div class="info-item flex-box-ce">
  44. 考核周期:&nbsp;&nbsp;&nbsp; <div class="cycle-type">{{ item.cycleType | formatCycleType }}</div>
  45. </div>
  46. <div class="info-item">
  47. <van-icon name="calendar" />考核时间:&nbsp;&nbsp;&nbsp;{{ item.startTime | formatDate }} 至 {{ item.endTime | formatDate }}
  48. </div>
  49. <div class="info-item">
  50. 考核等级:&nbsp;&nbsp;&nbsp; <span style="color: #ff9600;">{{ item.levelName || '-' }}</span>
  51. </div>
  52. <div class="info-item">
  53. 考核评分:&nbsp;&nbsp;&nbsp; <span style="color: #ff9600;">{{ item.score == undefined || item.score == null || item.score == '' ? '-' : item.score }}</span>
  54. </div>
  55. <div class="info-item">
  56. 较上次:&nbsp;&nbsp;&nbsp;
  57. <span v-if="item.levelChange && item.levelChange > 0" style="color: #67c23a !important;">
  58. {{ item.levelChange }}
  59. </span>
  60. <span v-else-if="item.levelChange && item.levelChange < 0" style="color: #f56c6c !important;">
  61. {{ item.levelChange }}
  62. </span>
  63. <span v-else class="gray" style="color: #999;">
  64. --
  65. </span>
  66. </div>
  67. </div>
  68. </div>
  69. </div>
  70. </scroller>
  71. </VanSkeleton>
  72. </div>
  73. <footer class="footer">
  74. <div v-if="multi" class="flex-box-ce" style="justify-content: space-around;">
  75. <div class="flex-box-ce" style="margin: 0 0.2rem; font-size: 0.28rem;" >
  76. <van-checkbox v-model="selectAll" shape="square" style="margin-right: 0.2rem;" />
  77. 全选
  78. </div>
  79. <div class="btn flex-1 danger" @click="handleDelete()">删除人员</div>
  80. </div>
  81. <div v-else class="flex-box-ce" style="justify-content: space-around;">
  82. <div class="btn" @click="openUserSelector()">添加人员</div>
  83. <!-- <div class="btn">删除人员</div> -->
  84. <div class="btn plain" @click="resetData()">重置数据</div>
  85. </div>
  86. </footer>
  87. <!-- 周期选择弹框 -->
  88. <van-action-sheet v-model="pullonThePanel" :closeable="false">
  89. <div class="content">
  90. <van-picker ref="van_picker" show-toolbar :columns="columns" @cancel="pullonThePanel = false" value-key="name" @confirm="onConfirm" confirm-button-text="完成" />
  91. </div>
  92. </van-action-sheet>
  93. <!-- 部门选择 -->
  94. <!-- <EmployeeSelector
  95. :max="1"
  96. :close_clear_data="false"
  97. :can_select_employee="false"
  98. :dept_multi="false"
  99. @confirm="confirmDept"
  100. :visible.sync="show_dept_selector"
  101. :selected.sync="selected_data"
  102. :isShowDepts="true"
  103. ></EmployeeSelector> -->
  104. <!-- 人员选择 -->
  105. <EmployeeSelector title="人员"
  106. :visible.sync="show_user_selector"
  107. @confirm="confirmCreator"
  108. :selected.sync="selected_user_all"
  109. :can_select_dept="false"
  110. :dept_multi="false"
  111. :append_body="true"
  112. :isShowDepts="false"
  113. :max='120'
  114. />
  115. </div>
  116. </template>
  117. <script>
  118. import Vue from 'vue';
  119. import { NoticeBar } from 'vant';
  120. import VanSkeleton from '@/performance/components/public/VanSkeleton';
  121. import EmployeeSelector from '@/components/EmployeeSelector';
  122. import moment from 'moment';
  123. Vue.use(NoticeBar)
  124. export default {
  125. components: {
  126. VanSkeleton,
  127. EmployeeSelector
  128. },
  129. data() {
  130. return {
  131. skeletonLoad: true,
  132. employeeList: [],
  133. // 周期类型 0-自定义 1-年度 2-半年度 3-季度 4-月度
  134. cycleType: '-1',
  135. right_text: "批量",
  136. columns: [
  137. {
  138. value: "-1",
  139. name: "全部",
  140. text: "全部"
  141. },
  142. {
  143. value: "0",
  144. name: "自定义",
  145. text: "自定义"
  146. },
  147. {
  148. value: "1",
  149. name: "年度",
  150. text: "年度"
  151. },
  152. {
  153. value: "2",
  154. name: "半年度",
  155. text: "半年度"
  156. },
  157. {
  158. value: "3",
  159. name: "季度",
  160. text: "季度"
  161. },
  162. {
  163. value: "4",
  164. name: "月度",
  165. text: "月度"
  166. }
  167. ],
  168. currentValue: '-1', // 选项回显
  169. pullonThePanel: false,
  170. dept_id: 0,
  171. show_dept_selector: false,
  172. show_user_selector: false,
  173. selected_data: { dept: [], employee: [] },
  174. selected_user_all: { dept: [], employee: [] }, //选择人员
  175. multi: false,
  176. reviewId: '', // 选择的考核信息ID
  177. params: {
  178. deptIds: '',
  179. employeeIds: '',
  180. cateId: '',
  181. pages: 1,
  182. pageSize: 10
  183. },
  184. }
  185. },
  186. computed: {
  187. selectEmployeeIds() {
  188. let selectEmployeeIds = this.employeeList.map(item => item.employeeId)
  189. selectEmployeeIds = Array.from(
  190. new Set(selectEmployeeIds.map(item => JSON.stringify(item)))
  191. ).map(item => JSON.parse(item));
  192. return selectEmployeeIds
  193. },
  194. selectEmployees() {
  195. let selectEmployees = this.employeeList.map(item => item.userInfo)
  196. selectEmployees = Array.from(
  197. new Set(selectEmployees.map(item => JSON.stringify(item)))
  198. ).map(item => JSON.parse(item));
  199. return selectEmployees
  200. },
  201. // 全选 / 全不选
  202. selectAll: {
  203. get() {
  204. // 所有都选中 → 全选按钮 true
  205. return this.employeeList.every(item => item.selected);
  206. },
  207. set(val) {
  208. // 点击全选按钮时,一键同步到所有
  209. this.employeeList.forEach(item => (item.selected = val));
  210. }
  211. }
  212. },
  213. filters: {
  214. filterNodeStatus(v) {
  215. if (v === 'start') return '开始'
  216. if (v === 'target_confirm') return '确认目标'
  217. if (v === 'result_input') return '录入结果值'
  218. if (v === 'score_self') return '自评'
  219. if (v === 'score_each_other') return '互评'
  220. if (v === 'score') return '评分'
  221. if (v === 'review') return '审批'
  222. if (v === 'cc') return '抄送'
  223. if (v === 'end') return '结束'
  224. },
  225. formatDate(val) {
  226. if (val) return moment(val).format('YYYY-MM-DD')
  227. else return "--"
  228. },
  229. formatCycleType(val) {
  230. if (val == 0) return '自定义'
  231. if (val == 1) return '年度'
  232. if (val == 2) return '半年'
  233. if (val == 3) return '季度'
  234. if (val == 4) return '月度'
  235. else return '--'
  236. },
  237. },
  238. watch: {
  239. // 路由参数变化(浏览器返回/前进、query 变化)也会再次执行
  240. '$route'(to, from) {
  241. this.getExamineInfo()
  242. }
  243. },
  244. created() {
  245. // this.show_dept_selector = true
  246. this.getList()
  247. },
  248. methods: {
  249. goHomePage() {
  250. this.$router.push("/home")
  251. },
  252. // 批量操作
  253. multi_option () {
  254. if (this.multi) {
  255. this.multi = false
  256. this.right_text = '批量'
  257. } else {
  258. this.multi = true
  259. this.right_text = '取消'
  260. }
  261. },
  262. // 获取数据
  263. getList() {
  264. this.skeletonLoad = true;
  265. let url = `/performance/statistics/review/last/${this.$userInfo().site_id}`
  266. let requestdata
  267. if (this.cycleType == '-1') requestdata = { ...this.params }
  268. else {
  269. requestdata = { ...this.params, cycleType: this.cycleType }
  270. }
  271. delete requestdata['employeeIds'] // 删除部门字段
  272. this.$axiosUser('get', url, requestdata).then(res => {
  273. this.skeletonLoad = false;
  274. let { data: { data: { list, total }, code } } = res
  275. if (code == 1) {
  276. if(list && list.length > 0) {
  277. list.forEach(item => {
  278. item.selected = false
  279. item.userInfo = this.$getEmployeeMapItem(item.employeeId);
  280. })
  281. }
  282. this.employeeList = list;
  283. // this.total = total
  284. }
  285. });
  286. },
  287. /* 添加的人员请求考核数据 */
  288. getListByPerson() {
  289. let url = `/performance/statistics/review/last/${this.$userInfo().site_id}`
  290. // this.selected_dept_ids = []
  291. // this.params.deptIds = ''
  292. // this.params.employeeIds = this.params.employeeIds && this.params.employeeIds.length > 0 ? this.params.employeeIds.toString() : ''
  293. this.$axiosUser('get', url, this.params).then(res => {
  294. // this.loading = false;
  295. let { data: { data: { list, total }, code } } = res
  296. if (code == 1) {
  297. let contactList = [...this.employeeList, ...list];
  298. // 去重
  299. this.employeeList = Array.from(
  300. new Set(contactList.map(item => JSON.stringify(item)))
  301. ).map(item => JSON.parse(item));
  302. // this.total = this.tableData.length
  303. this.employeeList.forEach(item => {
  304. item.selected = false
  305. item.userInfo = this.$getEmployeeMapItem(item.employeeId);
  306. })
  307. this.cycleType = '-1';
  308. }
  309. });
  310. },
  311. // 获取考核信息
  312. getExamineInfo() {
  313. let reviewId = this.$route.query.reviewId
  314. if(!reviewId) return
  315. console.log("reviewId")
  316. console.log(reviewId)
  317. let url = `/performance/statistics/review/info/${this.$userInfo().site_id}/${reviewId}`
  318. this.$axiosUser('get', url).then(res => {
  319. let { data, code } = res.data
  320. if (code == 1) {
  321. if (data) {
  322. delete data['deptList'] // 删除部门字段
  323. let replaceData = {
  324. ...this.employeeList[this.currentIndex],
  325. ...data
  326. }
  327. this.employeeList.splice(this.currentIndex, 1, replaceData);
  328. }
  329. }
  330. });
  331. },
  332. // 打开周期选择弹框
  333. openPanel(){
  334. this.pullonThePanel = true;
  335. // 等 DOM 渲染完成后设置索引
  336. this.$nextTick(() => {
  337. const index = this.columns.findIndex(item => item.value == this.currentValue);
  338. // 单列只传一个索引
  339. this.$refs.van_picker.setIndexes([index]);
  340. });
  341. },
  342. openPanel2() {
  343. this.show_dept_selector = true
  344. console.log(this.show_dept_selector)
  345. },
  346. // 确认周期选择
  347. onConfirm (data, value) {
  348. console.log(data)
  349. console.log(value)
  350. this.cycleType = data.value
  351. this.currentValue = data.value
  352. this.getList()
  353. this.pullonThePanel = false
  354. },
  355. confirmDept(val){
  356. this.selected_data = val;
  357. if(val.dept.length > 0){
  358. this.dept_id = val.dept[0].dept_id;
  359. }else{
  360. this.dept_id = 0;
  361. }
  362. // this.pullDown();
  363. },
  364. openUserSelector() {
  365. this.selected_user_all.employee = this.selectEmployees
  366. this.show_user_selector = true
  367. },
  368. resetData() {
  369. let url = `/performance/statistics/review/last/${this.$userInfo().site_id}`
  370. let requestdata
  371. this.cycleType = '-1';
  372. this.params = {
  373. deptIds: '',
  374. employeeIds: '',
  375. cateId: '',
  376. pages: 1,
  377. pageSize: 10
  378. }
  379. // this.selected_dept_ids = []
  380. requestdata = { ...this.params }
  381. if ('deptIds' in requestdata) delete requestdata['deptIds'] // 删除部门字段
  382. this.$axiosUser('get', url, requestdata).then(res => {
  383. // this.loading = false;
  384. let { data: { data: { list, total }, code } } = res
  385. if (code == 1) {
  386. if(list && list.length > 0) {
  387. list.forEach(item => {
  388. item.selected = false
  389. item.userInfo = this.$getEmployeeMapItem(item.employeeId);
  390. })
  391. }
  392. this.employeeList = list;
  393. }
  394. });
  395. },
  396. confirmCreator(arr){
  397. let target_ids = arr.employee.map(item=>{
  398. return item.id
  399. }).filter(item => !this.selectEmployeeIds.includes(item)).toString();
  400. // target_ids = target_ids.filter(target => )
  401. console.log(target_ids)
  402. this.params.employeeIds = target_ids;
  403. this.getListByPerson();
  404. // let data = {
  405. // employeeId: this.$userInfo().id,
  406. // targetIds: target_ids
  407. // }
  408. },
  409. handleDelete() {
  410. this.employeeList = this.employeeList.filter(item => !item.selected)
  411. },
  412. chooseExamineInfo(index, employeeId) {
  413. this.currentIndex = index
  414. this.$router.push({ path: "/more", query: { employeeId, from: "orgExamine" } })
  415. }
  416. }
  417. }
  418. </script>
  419. <style scoped lang="less">
  420. .all {
  421. width: 100%;
  422. height: 100%;
  423. position: relative !important;
  424. background-color: #f5f7fa;
  425. box-sizing: border-box;
  426. .search-box {
  427. width: 100%;
  428. height: 0.8rem;
  429. background: #fff;
  430. font-size: 0.28rem;
  431. }
  432. .overall {
  433. height: calc(100% - 2.52rem) !important;
  434. position: relative;
  435. overflow-y: scroll;
  436. .list-box {
  437. width: 96%;
  438. padding: 0.24rem;
  439. font-size: 0.32rem;
  440. background-color: #fff;
  441. border-radius: 5px;
  442. box-sizing: border-box;
  443. margin: 0.24rem auto;
  444. position: relative;
  445. .examine-item-status {
  446. position: absolute;
  447. top: 0.2rem;
  448. right: 0.1rem;
  449. padding: 0.01rem 0.1rem;
  450. color: #fff;
  451. border-radius: 2px;
  452. font-size: 0.26rem;
  453. background-color: #67c23a;
  454. margin-right: 0.14rem;
  455. }
  456. .add-task-title {
  457. font-weight: 600;
  458. font-size: 0.32rem;
  459. }
  460. .user-info {
  461. font-size: 0.28rem;
  462. color: #89919F !important;
  463. margin: 0 0 0 0.2rem;
  464. }
  465. .cycle-type {
  466. padding: 0.08rem;
  467. border-radius: 0.1rem;
  468. color: #26a2ff;
  469. box-sizing: border-box;
  470. background-color: #ecf5ff;
  471. }
  472. .examine-info {
  473. font-size: 0.28rem;
  474. position: relative;
  475. .tips {
  476. position: absolute;
  477. top: 0.1rem;
  478. right: -0.2rem;
  479. .tip-item {
  480. padding: 0.1rem;
  481. border-top-left-radius: 0.1rem;
  482. border-bottom-left-radius: 0.1rem;
  483. color: #26a2ff;
  484. z-index: 999;
  485. box-sizing: border-box;
  486. background-color: #ecf5ff;
  487. margin-bottom: 0.1rem;
  488. }
  489. }
  490. .info-item {
  491. margin-bottom: 0.2rem;
  492. color: #89919F !important;
  493. .info-item-title {
  494. width: 1.4rem;
  495. color: #000;
  496. }
  497. .review-node {
  498. padding: 0.01rem 0.1rem;
  499. color: #fff;
  500. border-radius: 2px;
  501. font-size: 0.26rem;
  502. background-color: #67c23a;
  503. margin-left: 0.14rem;
  504. }
  505. }
  506. .line {
  507. width: 100%;
  508. margin: 0.5rem auto;
  509. height: 1px;
  510. background-color: #f1f1f1;
  511. }
  512. }
  513. }
  514. }
  515. }
  516. .footer {
  517. width: 100%;
  518. padding: 0.2rem;
  519. border-top: 0.02rem solid #f1f1f1;
  520. background: #fff;
  521. position: fixed;
  522. left: 0;
  523. right: 0;
  524. bottom: 0;
  525. z-index: 999;
  526. box-shadow: 0px -3px 0.15rem #f7f8fa;
  527. box-sizing: border-box;
  528. .btn {
  529. width: 48%;
  530. padding: 0.2rem;
  531. // border: 0.02rem solid #26A2FF;
  532. color: #fff;
  533. text-align: center;
  534. background: #26A2FF;
  535. font-size: 0.28rem;
  536. box-sizing: border-box;
  537. }
  538. .danger {
  539. background-color: transparent;
  540. color: rgb(245, 108, 108);
  541. border: 1px solid rgb(245, 108, 108);
  542. }
  543. .plain {
  544. background-color: transparent;
  545. color: #26A2FF;
  546. border: 1px solid #26A2FF;
  547. }
  548. }
  549. </style>