index.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <div class="white pa-3">
  3. <m-search :items="searchItems" v-model="searchValues" class="mb-3" @search="onSearch"></m-search>
  4. <BonusTable ref="bonusTableRefs" :filter-header="auditStatus !== 0 && auditStatus !== 1 ? [] : ['actions']">
  5. <template #card-tools="{ items }">
  6. <div class="content">
  7. <div>
  8. <template v-if="auditStatusList[auditStatus]">
  9. 审批状态:
  10. <el-tag :type="auditStatusList[auditStatus]?.type ?? 'info'" class="mr-3">
  11. {{ auditStatusList[auditStatus]?.label ?? '未知状态' }}
  12. </el-tag>
  13. </template>
  14. 可发放绩效:<el-tag>{{ totalAllocationPerformanceSalary }}</el-tag>
  15. 总绩效: <el-tag>{{ totalGrantPerformanceSalary }}</el-tag>
  16. <m-button
  17. class="ml-3"
  18. type="orange"
  19. :loading="auditStatusLoading"
  20. v-show="auditStatus !== 0 && auditStatus !== 1 && items.length"
  21. @click="onSave">
  22. 确认分配
  23. </m-button>
  24. </div>
  25. </div>
  26. </template>
  27. <template #actions="{ row, items }">
  28. <el-input v-show="auditStatus !== 0 && auditStatus !== 1 && items.length" v-model="values[row.employeePerformanceId]" placeholder="请输入绩效" size="small"></el-input>
  29. </template>
  30. </BonusTable>
  31. </div>
  32. </template>
  33. <script>
  34. import BonusTable from '../components/bonusTable.vue'
  35. import { dateFormat } from '@/utils/date'
  36. import Decimal from 'decimal.js'
  37. import {
  38. // getAllocationPage,
  39. saveAllocationGrant,
  40. getAllocationEmployeeCategory,
  41. checkAllocationSubmitStatus,
  42. getAllocationStatistics,
  43. saveAllocation
  44. } from '@/api/bonus'
  45. import { STATUS_LIST } from '../utils'
  46. import { mapGetters } from 'vuex'
  47. export default {
  48. name: 'bonusAllocation',
  49. components: {
  50. BonusTable
  51. },
  52. data () {
  53. return {
  54. auditStatusList: STATUS_LIST,
  55. auditStatus: null,
  56. auditStatusLoading: true,
  57. values: {},
  58. searchValues: {
  59. month: dateFormat('YYYY-mm', new Date()),
  60. organizationNo: null,
  61. employeeCategory: null
  62. },
  63. query: {},
  64. employeeCategoryItems: [],
  65. totalGrantPerformanceSalary: 0,
  66. loading: false
  67. }
  68. },
  69. computed: {
  70. ...mapGetters(['employeeInfo', 'organizationTree']),
  71. totalAllocationPerformanceSalary () {
  72. return Object.values(this.values).reduce((r, v) => {
  73. return new Decimal(r).plus(v || 0)
  74. }, 0).toFixed(2)
  75. },
  76. searchItems () {
  77. return [
  78. {
  79. label: '月份',
  80. prop: 'month',
  81. type: 'datePicker',
  82. options: {
  83. placeholder: '请选择月份',
  84. clearable: false,
  85. type: 'month',
  86. valueFormat: 'yyyy-MM',
  87. format: 'yyyy 年 MM 月'
  88. },
  89. handles: {
  90. change: this.getEmployeeCategoryItems
  91. }
  92. },
  93. {
  94. label: '部门',
  95. prop: 'organizationNo',
  96. type: 'cascader',
  97. options: {
  98. clearable: true,
  99. placeholder: '请选择部门',
  100. options: this.organizationTree,
  101. showAllLevels: false,
  102. props: {
  103. emitPath: false,
  104. value: 'organizationNo',
  105. label: 'organizationName',
  106. children: 'child'
  107. }
  108. }
  109. },
  110. {
  111. label: '员工类型',
  112. prop: 'employeeCategory',
  113. type: 'select',
  114. options: {
  115. clearable: false,
  116. placeholder: '请选择员工类型',
  117. items: this.employeeCategoryItems
  118. }
  119. }
  120. ]
  121. }
  122. },
  123. async mounted () {
  124. this.loading = true
  125. await this.getEmployeeCategoryItems()
  126. this.searchValues.organizationNo = this.employeeInfo.organizationNo
  127. this.query = { ...this.searchValues }
  128. this.$nextTick(() => {
  129. this.$refs.bonusTableRefs && this.onInit()
  130. })
  131. },
  132. methods: {
  133. async onInit (pageInfo) {
  134. this.loading = true
  135. await this.onCheckStatus()
  136. await this.onStatistics()
  137. if (!this.$refs.bonusTableRefs) {
  138. return
  139. }
  140. const data = await this.$refs.bonusTableRefs.onInit(this.query, pageInfo)
  141. this.loading = false
  142. if (!data) {
  143. return
  144. }
  145. this.values = data.records.reduce((res, item) => {
  146. res[item.employeePerformanceId] = item.allocationPerformanceSalary || null
  147. return res
  148. }, {})
  149. },
  150. async getEmployeeCategoryItems () {
  151. try {
  152. const { data } = await getAllocationEmployeeCategory({
  153. month: this.searchValues.month
  154. })
  155. this.employeeCategoryItems = data.map(e => {
  156. return {
  157. label: e,
  158. value: e
  159. }
  160. })
  161. if (!data.length) {
  162. this.searchValues.employeeCategory = null
  163. return
  164. }
  165. this.searchValues.employeeCategory = this.employeeCategoryItems[0].value
  166. return data
  167. } catch (error) {
  168. this.employeeCategoryItems = []
  169. this.$message.error(error)
  170. }
  171. },
  172. async onSearch () {
  173. this.query = { ...this.searchValues }
  174. this.onInit({ current: 1 })
  175. },
  176. // 领导分配绩效薪资
  177. onSave () {
  178. const h = this.$createElement
  179. const _el = [
  180. h('p', undefined, `提交月份:${this.query.month}`),
  181. h('p', undefined, `提交员工类型:${this.query.employeeCategory ?? null}`)
  182. ]
  183. try {
  184. if (this.totalGrantPerformanceSalary !== this.totalAllocationPerformanceSalary) {
  185. const el = h('div', [
  186. h('p', undefined, '当前非完全配额,是否强制提交?'),
  187. ..._el
  188. ])
  189. this.$confirm(el, '提示').then(() => {
  190. this.onSaveAll(true)
  191. }).catch(_ => {})
  192. return
  193. }
  194. const el = h('div', [
  195. h('p', undefined, '确定提交所有数据?'),
  196. ..._el
  197. ])
  198. this.$confirm(el, '提示').then(() => {
  199. this.onSaveAll(false)
  200. }).catch(_ => {})
  201. } catch (error) {
  202. this.$message.error(error)
  203. }
  204. },
  205. async onSaveAll (force) {
  206. const employeePerformanceGrantItems = Object.keys(this.values).reduce((res, key) => {
  207. res.push({
  208. employeePerformanceId: key,
  209. allocationPerformanceSalary: this.values[key]
  210. })
  211. return res
  212. }, [])
  213. if (!employeePerformanceGrantItems.length) {
  214. this.$message.error('请先分配金额')
  215. return
  216. }
  217. try {
  218. await saveAllocationGrant({
  219. ...this.query,
  220. employeePerformanceGrantItems
  221. })
  222. await saveAllocation({
  223. ...this.query,
  224. force: force ? 1 : 0
  225. })
  226. this.$message.success('提交成功')
  227. this.onInit()
  228. } catch (error) {
  229. this.$message.error(error)
  230. }
  231. },
  232. // 查询提交状态
  233. async onCheckStatus () {
  234. this.auditStatusLoading = true
  235. try {
  236. const { data } = await checkAllocationSubmitStatus(this.query)
  237. this.auditStatus = data?.status ?? null
  238. } catch (error) {
  239. this.$message.error(error)
  240. } finally {
  241. this.auditStatusLoading = false
  242. }
  243. },
  244. // 统计分配
  245. async onStatistics () {
  246. try {
  247. const { data } = await getAllocationStatistics(this.query)
  248. const { totalGrantPerformanceSalary } = data
  249. this.totalGrantPerformanceSalary = totalGrantPerformanceSalary
  250. } catch (error) {
  251. this.$message.error(error)
  252. }
  253. }
  254. }
  255. }
  256. </script>
  257. <style lang="scss" scoped>
  258. .content {
  259. display: flex;
  260. justify-content: flex-end;
  261. }
  262. </style>