App.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <template>
  2. <div id="page-hr-app">
  3. <router-view v-if="isQiankun || isFullPage" :key="$route.fullPath" />
  4. <ele-pro-layout
  5. v-else
  6. :menus="menus"
  7. :tabs="pageTabs"
  8. :project-name="PROJECT_NAME"
  9. :collapse.sync="sidebarCollapsed"
  10. :show-tabs="true"
  11. :show-breadcrumb="false"
  12. :show-footer="false"
  13. tab-style="card"
  14. :tab-sortable="true"
  15. home-title="首页"
  16. home-path="/home"
  17. layout-path="/"
  18. @tab-add="onTabAdd"
  19. @tab-remove="onTabRemove"
  20. @tab-remove-left="onTabRemoveLeft"
  21. @tab-remove-right="onTabRemoveRight"
  22. @tab-remove-other="onTabRemoveOther"
  23. @tab-remove-all="onTabRemoveAll"
  24. @tabSortChange="onTabSortChange"
  25. @reload-page="onReloadPage"
  26. @set-home-components="onSetHomeComponents"
  27. @logo-click="onLogoClick"
  28. >
  29. <!-- 不缓存页面:切换选项卡时重新挂载并刷新全部数据 -->
  30. <router-view v-if="!pageRefreshing" :key="$route.fullPath" />
  31. </ele-pro-layout>
  32. </div>
  33. </template>
  34. <script>
  35. import { PROJECT_NAME } from '@/config/setting';
  36. export default {
  37. name: 'App',
  38. data() {
  39. return {
  40. PROJECT_NAME,
  41. sidebarCollapsed: false,
  42. pageTabs: [],
  43. homeComponents: [],
  44. pageRefreshing: false,
  45. menus: [
  46. { path: '/home', meta: { title: '首页', icon: 'el-icon-house' } },
  47. {
  48. path: '/position',
  49. meta: { title: '岗位管理', icon: 'el-icon-suitcase' },
  50. children: [
  51. { path: '/position-management', meta: { title: '岗位设定' } },
  52. { path: '/position-sequence', meta: { title: '岗位序列' } },
  53. { path: '/position-application', meta: { title: '岗位申请' } }
  54. ]
  55. },
  56. {
  57. path: '/hiring',
  58. meta: { title: '录用管理', icon: 'el-icon-s-check' },
  59. children: [
  60. { path: '/hiring-approval', meta: { title: '录用审批' } },
  61. { path: '/offer-notify', meta: { title: 'Offer 通知' } }
  62. ]
  63. },
  64. {
  65. path: '/hr-management',
  66. meta: { title: '人事管理', icon: 'el-icon-user' },
  67. children: [
  68. // { path: '/organization', meta: { title: '组织机构' } },
  69. { path: '/employee-archive', meta: { title: '员工档案' } },
  70. { path: '/onboarding-handling', meta: { title: '办理入职' } },
  71. { path: '/regularization-handling', meta: { title: '转正办理' } },
  72. { path: '/resignation-application', meta: { title: '离职申请' } },
  73. { path: '/resignation-handover-order', meta: { title: '离职交接单' } },
  74. { path: '/position-transfer', meta: { title: '岗位调动办理' } },
  75. { path: '/qualification-management', meta: { title: '资质管理' } },
  76. { path: '/term-management', meta: { title: '期限管理' } },
  77. {
  78. path: '/employee-template',
  79. meta: { title: '员工模板' },
  80. children: [
  81. { path: '/offer-letter-template', meta: { title: '录用通知书' } },
  82. { path: '/onboarding-contract-template', meta: { title: '合同模版' } },
  83. { path: '/regularization-template', meta: { title: '转正申请模板' } },
  84. { path: '/resignation-letter', meta: { title: '辞职申请书' } },
  85. { path: '/resignation-handover-table', meta: { title: '离职交接表' } },
  86. { path: '/resignation-certificate', meta: { title: '离职证明' } },
  87. { path: '/position-transfer-template', meta: { title: '岗位调动' } }
  88. ]
  89. }
  90. ]
  91. },
  92. { path: '/contract-management', meta: { title: '合同管理', icon: 'el-icon-document' } },
  93. // 合同模板类目暂时隐藏
  94. // {
  95. // path: '/contract',
  96. // meta: { title: '合同管理', icon: 'el-icon-document' },
  97. // children: [
  98. // { path: '/contract-template', meta: { title: '合同模版' } },
  99. // { path: '/contract-management', meta: { title: '合同管理' } }
  100. // ]
  101. // },
  102. // {
  103. // path: '/approval',
  104. // meta: { title: '行政审批', icon: 'el-icon-finished' },
  105. // children: [
  106. // { path: '/approval-sync-attendance', meta: { title: '行政审批同步考勤' } }
  107. // ]
  108. // },
  109. // { path: '/recruitment-plan', meta: { title: '招聘需求计划', icon: 'el-icon-suitcase' } },
  110. // { path: '/talent-pool', meta: { title: '人才库', icon: 'el-icon-user' } },
  111. // { path: '/performance-scoring', meta: { title: '绩效评分', icon: 'el-icon-edit-outline' } },
  112. // { path: '/performance-scheme', meta: { title: '绩效方案', icon: 'el-icon-document-checked' } },
  113. {
  114. path: '/attendance',
  115. meta: { title: '考勤管理', icon: 'el-icon-time' },
  116. children: [
  117. { path: '/attendance/rule', meta: { title: '打卡规则设定' } },
  118. { path: '/attendance/report', meta: { title: '考勤统计' } }
  119. ]
  120. },
  121. {
  122. path: '/hr-analysis',
  123. meta: { title: '人力资源分析报表', icon: 'el-icon-data-analysis' },
  124. children: [
  125. { path: '/personnel-structure-dashboard', meta: { title: '人员结构看板' } },
  126. { path: '/personnel-structure-analysis-board', meta: { title: '人员结构分析看板' } }
  127. ]
  128. }
  129. ] };
  130. },
  131. computed: {
  132. isQiankun() { return Boolean(window.__POWERED_BY_QIANKUN__); },
  133. isFullPage() { return Boolean(this.$route.meta?.fullPage); }
  134. },
  135. methods: {
  136. findTabIndex(key) {
  137. return this.pageTabs.findIndex((tab) => tab.key === key);
  138. },
  139. tabPath(tab) {
  140. return (tab && (tab.fullPath || tab.key)) || '/home';
  141. },
  142. goTabOrHome(tab) {
  143. const path = this.tabPath(tab);
  144. if (this.$route.fullPath !== path && this.$route.path !== path) {
  145. this.$router.push(path);
  146. }
  147. },
  148. onTabAdd(data) {
  149. if (!data?.key) return;
  150. const index = this.findTabIndex(data.key);
  151. if (index === -1) {
  152. this.pageTabs.push(data);
  153. return;
  154. }
  155. const current = this.pageTabs[index];
  156. if (current.fullPath !== data.fullPath || current.title !== data.title) {
  157. this.$set(this.pageTabs, index, { ...current, ...data });
  158. }
  159. },
  160. onTabRemove({ key, active }) {
  161. const index = this.findTabIndex(key);
  162. if (index === -1) return;
  163. const next = this.pageTabs[index + 1] || this.pageTabs[index - 1];
  164. this.pageTabs.splice(index, 1);
  165. if (active === key) this.goTabOrHome(next);
  166. },
  167. onTabRemoveLeft({ key, active }) {
  168. const index = this.findTabIndex(key);
  169. if (index <= 0) return;
  170. this.pageTabs.splice(0, index);
  171. if (!this.pageTabs.some((tab) => tab.key === active)) this.goTabOrHome(this.pageTabs[0]);
  172. },
  173. onTabRemoveRight({ key, active }) {
  174. const index = this.findTabIndex(key);
  175. if (index === -1 || index >= this.pageTabs.length - 1) return;
  176. this.pageTabs.splice(index + 1);
  177. if (!this.pageTabs.some((tab) => tab.key === active)) this.goTabOrHome(this.pageTabs[index]);
  178. },
  179. onTabRemoveOther({ key }) {
  180. this.pageTabs = this.pageTabs.filter((tab) => tab.key === key);
  181. this.goTabOrHome(this.pageTabs[0]);
  182. },
  183. onTabRemoveAll() {
  184. this.pageTabs = [];
  185. if (this.$route.path !== '/home') this.$router.push('/home');
  186. },
  187. onTabSortChange(tabs) {
  188. this.pageTabs = tabs || [];
  189. },
  190. onReloadPage() {
  191. this.pageRefreshing = true;
  192. this.$nextTick(() => {
  193. this.pageRefreshing = false;
  194. });
  195. },
  196. onSetHomeComponents(components) {
  197. this.homeComponents = components || [];
  198. },
  199. onLogoClick(isHome) {
  200. if (!isHome) this.$router.push('/home');
  201. }
  202. }
  203. };
  204. </script>
  205. <style src="./styles/App.css"></style>