positionSequence.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import { getApiBaseUrl, getServerConfig, request } from '@/utils/auth'
  2. // ============ 模式判断 ============
  3. function isServerMode() {
  4. return getServerConfig().mode === 'server'
  5. }
  6. function serverPath() {
  7. const base = getApiBaseUrl()
  8. if (!base) throw new Error('缺少服务器地址,请先在登录页右上角配置')
  9. return base
  10. }
  11. // ============ 枚举 ============
  12. // 岗位序列状态:1-启用 / 0-停用(与后端约定)
  13. export const SEQUENCE_STATUS_LABEL = {
  14. 1: '启用',
  15. 0: '停用',
  16. '1': '启用',
  17. '0': '停用',
  18. }
  19. // 排序方式(与后端 orderBy 枚举一致)
  20. export const ORDER_BY = {
  21. ASC: 'ascending',
  22. DESC: 'descending',
  23. }
  24. // 常见的 sortName:默认 createTime
  25. export const DEFAULT_SORT_NAME = 'createTime'
  26. // ============ Demo 数据 ============
  27. // demo 模式内存 mock,避免页面硬编码常量。
  28. // 序列覆盖 管理/专业/技术/操作 4 大类,每类 2-3 个层级。
  29. let demoIdCounter = 1000
  30. const DEMO_SEQUENCES = [
  31. {
  32. id: 1,
  33. sequence: '管理',
  34. status: '1',
  35. levelList: [
  36. { id: 11, level: 'M1', levelGrade: 1, sequenceId: 1, status: '1' },
  37. { id: 12, level: 'M2', levelGrade: 2, sequenceId: 1, status: '1' },
  38. { id: 13, level: 'M3', levelGrade: 3, sequenceId: 1, status: '1' },
  39. ],
  40. },
  41. {
  42. id: 2,
  43. sequence: '专业',
  44. status: '1',
  45. levelList: [
  46. { id: 21, level: 'P1', levelGrade: 1, sequenceId: 2, status: '1' },
  47. { id: 22, level: 'P2', levelGrade: 2, sequenceId: 2, status: '1' },
  48. { id: 23, level: 'P3', levelGrade: 3, sequenceId: 2, status: '0' },
  49. ],
  50. },
  51. {
  52. id: 3,
  53. sequence: '技术',
  54. status: '1',
  55. levelList: [
  56. { id: 31, level: 'T1', levelGrade: 1, sequenceId: 3, status: '1' },
  57. { id: 32, level: 'T2', levelGrade: 2, sequenceId: 3, status: '1' },
  58. { id: 33, level: 'T3', levelGrade: 3, sequenceId: 3, status: '1' },
  59. { id: 34, level: 'T4', levelGrade: 4, sequenceId: 3, status: '1' },
  60. ],
  61. },
  62. {
  63. id: 4,
  64. sequence: '操作',
  65. status: '0',
  66. levelList: [
  67. { id: 41, level: 'O1', levelGrade: 1, sequenceId: 4, status: '0' },
  68. { id: 42, level: 'O2', levelGrade: 2, sequenceId: 4, status: '0' },
  69. ],
  70. },
  71. ]
  72. function matchDemoSequence(query) {
  73. const sequence = (query.sequence || '').trim()
  74. const status = query.status === undefined || query.status === null ? '' : String(query.status)
  75. return DEMO_SEQUENCES.filter((s) => {
  76. if (sequence && !String(s.sequence).includes(sequence)) return false
  77. if (status && String(s.status) !== status) return false
  78. return true
  79. })
  80. }
  81. function paginate(list, pageNum, size) {
  82. const safePage = Math.max(1, Number(pageNum) || 1)
  83. const safeSize = Math.max(1, Number(size) || 20)
  84. const start = (safePage - 1) * safeSize
  85. return list.slice(start, start + safeSize)
  86. }
  87. function sortDemoSequences(list, sortName, orderBy) {
  88. if (!sortName) return list
  89. const desc = String(orderBy || 'ascending').toLowerCase() === 'descending'
  90. const key = String(sortName)
  91. const sorted = [...list].sort((a, b) => {
  92. const av = a[key]
  93. const bv = b[key]
  94. if (av === bv) return 0
  95. if (av === undefined || av === null) return 1
  96. if (bv === undefined || bv === null) return -1
  97. return av > bv ? 1 : -1
  98. })
  99. return desc ? sorted.reverse() : sorted
  100. }
  101. // ============ 对外 API ============
  102. /**
  103. * 分页查询岗位序列
  104. * POST /hr/positionSequence/page
  105. *
  106. * 请求参数(与后端约定):
  107. * - deptId 机构 id(非必填)
  108. * - offset 偏移量(非必填,由后端按 pageNum/size 计算)
  109. * - orderBy 排序方式 ascending | descending
  110. * - pageNum 当前页(从 1 开始)
  111. * - sequence 岗位序列名称(模糊匹配)
  112. * - size 每页显示数
  113. * - sortName 排序字段(默认 createTime)
  114. * - status 状态 1:启用、0:停用
  115. *
  116. * 响应:{ code, data: Pagination, message }
  117. * Pagination.list 每项为 岗位序列列表:{ id, sequence, status, levelList: [{id, level, levelGrade, sequenceId, status}] }
  118. *
  119. * @param {object} query 详见 JSDoc
  120. * @returns {Promise<{ count: number, list: Array, pageNum: number, size: number, current: number, currentUserId?: number, deptId?: number, extInfo?: object }>}
  121. */
  122. export async function pagePositionSequence(query = {}) {
  123. // 归一化入参:status / orderBy / sortName 给后端的默认值
  124. const body = {
  125. pageNum: Number(query.pageNum) || 1,
  126. size: Number(query.size) || 20,
  127. sortName: query.sortName || DEFAULT_SORT_NAME,
  128. orderBy: query.orderBy || ORDER_BY.ASC,
  129. }
  130. if (query.deptId !== undefined && query.deptId !== null && query.deptId !== '') {
  131. body.deptId = Number(query.deptId) || 0
  132. }
  133. if (query.sequence !== undefined && query.sequence !== null) {
  134. body.sequence = String(query.sequence)
  135. }
  136. if (query.status !== undefined && query.status !== null && query.status !== '') {
  137. body.status = String(query.status)
  138. }
  139. if (query.offset !== undefined && query.offset !== null) {
  140. body.offset = Number(query.offset) || 0
  141. }
  142. if (!isServerMode()) {
  143. await new Promise((r) => setTimeout(r, 200))
  144. const filtered = matchDemoSequence(body)
  145. const sorted = sortDemoSequences(filtered, body.sortName, body.orderBy)
  146. const list = paginate(sorted, body.pageNum, body.size)
  147. return {
  148. count: sorted.length,
  149. current: body.pageNum,
  150. currentUserId: 0,
  151. deptId: body.deptId || 0,
  152. extInfo: {},
  153. list,
  154. pageNum: body.pageNum,
  155. size: body.size,
  156. }
  157. }
  158. const path = `${serverPath()}/hr/positionSequence/page`
  159. const res = await request({ url: path, method: 'POST', data: body })
  160. return res.data || {
  161. count: 0,
  162. current: body.pageNum,
  163. list: [],
  164. pageNum: body.pageNum,
  165. size: body.size,
  166. }
  167. }
  168. /**
  169. * 查询岗位序列列表(仅启用)
  170. * GET /hr/positionSequence/getPositionSequenceList
  171. *
  172. * 接口描述:返回启用的岗位序列及其启用层级集合;层级包含文本、数值级别和主键,
  173. * 供岗位管理展示或级联选择。
  174. *
  175. * 响应:{ code, data: Array<岗位序列列表>, message }
  176. *
  177. * @returns {Promise<Array<{ id: number, sequence: string, status: string, levelList: Array<{id, level, levelGrade, sequenceId, status}> }>>}
  178. */
  179. export async function getPositionSequenceList() {
  180. if (!isServerMode()) {
  181. await new Promise((r) => setTimeout(r, 150))
  182. return DEMO_SEQUENCES
  183. .filter((s) => String(s.status) === '1')
  184. .map((s) => ({
  185. ...s,
  186. levelList: (s.levelList || []).filter((lv) => String(lv.status) === '1'),
  187. }))
  188. }
  189. const path = `${serverPath()}/hr/positionSequence/getPositionSequenceList`
  190. const res = await request({ url: path, method: 'GET' })
  191. return Array.isArray(res.data) ? res.data : []
  192. }
  193. /**
  194. * 把后端 status('0' | '1' | 0 | 1)翻译成中文标签
  195. */
  196. export function translateSequenceStatus(status) {
  197. if (status === undefined || status === null || status === '') return ''
  198. return SEQUENCE_STATUS_LABEL[status] || String(status)
  199. }
  200. /**
  201. * 把后端层级数组按 levelGrade 升序排序(数值越大层级越高 → 排序时大的在后,
  202. * 调用方若要"高层在前"自行 reverse)。
  203. */
  204. export function sortLevelsByGrade(levels) {
  205. if (!Array.isArray(levels)) return []
  206. return [...levels].sort((a, b) => (a.levelGrade || 0) - (b.levelGrade || 0))
  207. }