vitae.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <template>
  2. <div class="card-search">
  3. <div class="jl-content">
  4. <!-- 头像等信息 -->
  5. <div class="avt-content">
  6. <!--头像 -->
  7. <div class="avt-image">
  8. <img src="../../../assets/images/njl-avt.png" v-if="jobUserInfo.genderName=='女'">
  9. <img src="../../../assets/images/jl-avt.png" v-if="jobUserInfo.genderName=='男'">
  10. <!-- <a-avatar :size="72" :src="jobUserInfo.genderName === '男'?avtImg:avtNImg"></a-avatar>-->
  11. </div>
  12. <!-- 姓名 -->
  13. <p class="nameTitle">{{ jobUserInfo.name }}</p>
  14. <!-- 性别,年龄,民族 -->
  15. <div class="age-info">
  16. <span>
  17. <man-outlined v-if="jobUserInfo.genderName === '男'"/>
  18. <woman-outlined v-if="jobUserInfo.genderName === '女'"/>
  19. {{ jobUserInfo.genderName }}
  20. </span>
  21. <span>
  22. {{ jobUserInfo.age }}岁
  23. </span>
  24. <span>
  25. {{ jobUserInfo.nationName }}
  26. </span>
  27. </div>
  28. <!-- 政治面貌,学历,手机 -->
  29. <div class="politics-info">
  30. <span class="label-span">
  31. 政治面貌:
  32. </span>
  33. <span>
  34. {{ jobUserInfo.politicsStatusName }}
  35. </span>
  36. <span class="label-span">
  37. 学历:
  38. </span>
  39. <span>
  40. {{ jobUserInfo.cultureName }}
  41. </span>
  42. <span class="label-span">
  43. 手机:
  44. </span>
  45. <span>
  46. {{ jobUserInfo.userMobile }}
  47. </span>
  48. </div>
  49. <!-- 标签 -->
  50. <div class="label-info" v-if="jobUserInfo.listLabel.length >= 1">
  51. <p class="title">标签</p>
  52. <div class="flex-box">
  53. <a-tag v-for="(item, index) in jobUserInfo.listLabel" :key="index">
  54. {{ item.labelName }}
  55. </a-tag>
  56. </div>
  57. </div>
  58. </div>
  59. <!-- 基本信息与学历,工作经历 -->
  60. <div class="info-content">
  61. <a-divider orientation="left">基本信息</a-divider>
  62. <a-descriptions :column="2" bordered style="margin-left: 25px;">
  63. <a-descriptions-item label="重点人员类别">{{ jobUserInfo.keyTypeName }}</a-descriptions-item>
  64. <a-descriptions-item label="健康状况">{{ jobUserInfo.healthName }}</a-descriptions-item>
  65. <a-descriptions-item label="就业状态">{{ jobUserInfo.jobStatusName }}</a-descriptions-item>
  66. <a-descriptions-item label="住址">{{ jobUserInfo.address }}</a-descriptions-item>
  67. <a-descriptions-item :span="2" label="兴趣爱好">{{ jobUserInfo.hobby }}</a-descriptions-item>
  68. <a-descriptions-item :span="2" label="专业技术特长">{{ jobUserInfo.personalSkills }}</a-descriptions-item>
  69. </a-descriptions>
  70. <a-divider orientation="left">教育经历</a-divider>
  71. <a-table :columns="educationColumns" :data-source="educationData" :pagination="false" bordered
  72. style="margin-left: 11px;">
  73. <template #bodyCell="{ column, index, record}">
  74. <template v-if="column.key === 'cultureRank'">
  75. <div>
  76. {{
  77. getCultureName(record.cultureRank)
  78. }}
  79. </div>
  80. </template>
  81. <template v-if="column.key === 'schoolTime'">
  82. <div>
  83. {{
  84. dayjs(record.schoolTime).format('YYYY-MM-DD')
  85. }}
  86. </div>
  87. </template>
  88. <template v-if="column.key === 'overTime'">
  89. <div>
  90. {{
  91. dayjs(record.overTime).format('YYYY-MM-DD')
  92. }}
  93. </div>
  94. </template>
  95. </template>
  96. </a-table>
  97. <a-divider orientation="left">求职意向</a-divider>
  98. <a-table :columns="jobHuntColumns" :data-source="jobHuntList" bordered :pagination="false"
  99. style="margin-left: 11px">
  100. </a-table>
  101. <a-divider orientation="left">工作经历</a-divider>
  102. <a-timeline style="margin-left: 25px;">
  103. <a-timeline-item v-for="(item, key) in experienceData" :key="key" position="left">
  104. <p>{{ dayjs(item.startTime).format('YYYY-MM-DD') }}至{{ dayjs(item.endTime).format('YYYY-MM-DD') }}</p>
  105. <p>{{ item.workAddress }}</p>
  106. <p>{{ item.duties }}</p>
  107. </a-timeline-item>
  108. </a-timeline>
  109. </div>
  110. </div>
  111. </div>
  112. </template>
  113. <script setup lang="ts">
  114. import {onMounted, reactive, ref} from "vue";
  115. import {getDataById, getEducationList, getExperienceList} from "@/api/jobUserManager/jobuser";
  116. import {ManOutlined, WomanOutlined} from '@ant-design/icons-vue';
  117. import type {SelectProps, TableColumnsType} from "ant-design-vue";
  118. import dayjs from "dayjs";
  119. import {getSysDictionaryList} from "@/api/system/dictionary";
  120. import {getJobHuntList} from "@/api/jobUserManager/jobhunt";
  121. import {useUserStore} from "@/store/modules/user";
  122. import crtyptoHelp from "@/utils/crypto";
  123. const userStore = useUserStore();
  124. const userInfo = ref(userStore.getUserInfo)
  125. // 求职人员信息
  126. const jobUserInfo = reactive({
  127. name: "",
  128. genderName: "",
  129. age: null,
  130. nationName: "",
  131. politicsStatusName: "",
  132. cultureName: "",
  133. userMobile: "",
  134. birthPlace: "",
  135. identityNumber: "",
  136. keyTypeName: "",
  137. healthName: "",
  138. jobStatusName: "",
  139. familyNatureName: "",
  140. address: "",
  141. familyAddress: "",
  142. hobby: "",
  143. personalSkills: "",
  144. listLabel: new Array<any>()
  145. })
  146. // 受教育经历
  147. const educationData = ref<Array<any>>([]);
  148. // 受教育经历表格定义
  149. const educationColumns: TableColumnsType = [
  150. {
  151. title: '序号',
  152. align: "center",
  153. key: 'educationID',
  154. width: 120,
  155. customRender: item => `${searchParams.pageSize * (searchParams.pageIndex - 1) + item.index + 1}`
  156. },
  157. {
  158. title: '学校名',
  159. dataIndex: 'schoolName',
  160. key: 'schoolName',
  161. align: "center",
  162. width: 120
  163. },
  164. {
  165. title: '文化程度',
  166. dataIndex: 'cultureRank',
  167. key: 'cultureRank',
  168. align: "center",
  169. width: 120
  170. },
  171. {
  172. title: '就读时间',
  173. dataIndex: 'schoolTime',
  174. key: 'schoolTime',
  175. align: "center",
  176. width: 120
  177. },
  178. {
  179. title: '毕业时间',
  180. dataIndex: 'overTime',
  181. key: 'overTime',
  182. align: "center",
  183. width: 120
  184. },
  185. {
  186. title: '专业',
  187. dataIndex: 'major',
  188. key: 'major',
  189. align: "center",
  190. width: 120
  191. },
  192. ];
  193. const searchParams = reactive({
  194. pageIndex: 1,
  195. pageSize: 99
  196. });
  197. // 工作经验数据
  198. const experienceData = ref<Array<any>>([]);
  199. // 求职意向数据
  200. const jobHuntList = ref<Array<any>>([]);
  201. // 求职意向表格定义
  202. const jobHuntColumns: TableColumnsType = [
  203. {
  204. title: '序号',
  205. align: 'center',
  206. width: 80,
  207. key: 'jobHuntID',
  208. customRender: (item) =>
  209. `${searchParams.pageSize * (searchParams.pageIndex - 1) + item.index + 1}`,
  210. },
  211. {title: '希望工作地区', dataIndex: 'areaWork', key: 'areaWork', width: 150, align: "center",},
  212. {
  213. title: '可到职日期', dataIndex: 'inDate', key: 'inDate', width: 100, align: "center",
  214. customRender: ({record}) => record.inDate == null ? "" : dayjs(record.inDate).format('YYYY-MM-DD'),
  215. },
  216. {title: '工作年限', dataIndex: 'workYear', key: 'workYear', align: "center",},
  217. {title: '求职类型', dataIndex: 'jobHuntTypeStr', key: 'jobHuntTypeStr', align: "center",},
  218. {title: '求职岗位', dataIndex: 'professionName', key: 'professionName', align: "center",},
  219. {title: '人才类型', dataIndex: 'jobUserTypeStr', key: 'jobUserTypeStr', align: "center",},
  220. {
  221. title: '月薪要求', dataIndex: 'salary', key: 'salary', align: "center",
  222. customRender: (item) => {
  223. const salary = showSalary(item.record.minSalary, item.record.maxSalary);
  224. return salary;
  225. }
  226. },
  227. ];
  228. // 期望月薪显示优化方法
  229. const showSalary = (minSalary: any, maxSalary: any) => {
  230. if (minSalary != null) {
  231. if (maxSalary != null) {
  232. return minSalary.toString() + "-" + maxSalary.toString();
  233. } else {
  234. return "≥" + minSalary.toString();
  235. }
  236. } else {
  237. if (maxSalary != null) {
  238. return "≤" + maxSalary.toString();
  239. } else {
  240. return "";
  241. }
  242. }
  243. }
  244. // 教育经历数据
  245. const cultureList = ref<SelectProps['options']>();
  246. // 加载求职人员数据
  247. const loadData = (id: any) => {
  248. getDataById(id, userInfo.value.userID, 1).then(data => {
  249. Object.keys(jobUserInfo).forEach(key => {
  250. jobUserInfo[key] = data[key];
  251. })
  252. jobUserInfo.userMobile = crtyptoHelp.decryptDesText(jobUserInfo.userMobile);
  253. jobUserInfo.identityNumber = crtyptoHelp.decryptDesText(jobUserInfo.identityNumber);
  254. });
  255. };
  256. // 加载教育经历
  257. const loadEducation = (id: any) => {
  258. getEducationList(id).then(data => {
  259. if (data) {
  260. educationData.value = data;
  261. }
  262. });
  263. }
  264. // 加载工作经历
  265. const loadExperienceData = (id: any) => {
  266. getExperienceList(id).then(data => {
  267. if (data) {
  268. data.sort((a, b) => {
  269. // 将 startTime 字段转换为日期对象进行比较
  270. const startTimeA = new Date(a.startTime);
  271. const startTimeB = new Date(b.startTime);
  272. return startTimeB - startTimeA;
  273. })
  274. experienceData.value = data;
  275. }
  276. })
  277. }
  278. // 加载求职意向数据
  279. function loadJobHuntData(jobUserID: any) {
  280. let params = {
  281. pageIndex: 1,
  282. pageSize: 999,
  283. jobUserID
  284. }
  285. getJobHuntList(params).then(result => {
  286. jobHuntList.value = result.list
  287. })
  288. }
  289. // 获取教育经历数据
  290. const getCultureList = () => {
  291. getSysDictionaryList('HighestDegree').then((data) => {
  292. cultureList.value = data;
  293. });
  294. };
  295. function getCultureName(value: any) {
  296. let filter = cultureList.value?.filter(item => item.value == value);
  297. if (filter && filter.length > 0) {
  298. return filter[0].name
  299. }
  300. return "";
  301. }
  302. // 页面初始化
  303. onMounted(() => {
  304. const id = history.state.params?.id;
  305. if (id) {
  306. loadData(id);
  307. loadEducation(id);
  308. loadExperienceData(id);
  309. loadJobHuntData(id);
  310. }
  311. getCultureList()
  312. })
  313. </script>
  314. <script lang="ts">
  315. // 设置页面名称进行组件缓存
  316. export default {
  317. name: "JobUserVitae"
  318. }
  319. </script>
  320. <style lang="less" scoped>
  321. .card-search {
  322. .jl-content {
  323. min-height: calc(100vh - 240px);
  324. width: 100%;
  325. display: flex;
  326. .avt-content {
  327. width: 20%;
  328. background-color: #e7e7e7;
  329. padding: 10px;
  330. .avt-image {
  331. display: flex;
  332. flex-wrap: wrap;
  333. justify-content: center;
  334. img{
  335. width:120px;
  336. height:120px;
  337. }
  338. }
  339. .age-info {
  340. width: 100%;
  341. display: flex;
  342. justify-content: space-between;
  343. margin-top: 15px;
  344. padding: 0 20%;
  345. }
  346. .politics-info {
  347. margin-top: 25px;
  348. display: grid;
  349. row-gap: 22px;
  350. grid-template-columns: repeat(2, minmax(0, 1fr));
  351. .label-span {
  352. text-align: right;
  353. }
  354. }
  355. .nameTitle {
  356. margin-top: 1rem;
  357. text-align: center;
  358. font-size: 20px;
  359. font-weight: 700;
  360. }
  361. .label-info {
  362. margin-top: 15px;
  363. padding: 0 5%;
  364. .title {
  365. margin-bottom: 10px;
  366. }
  367. .flex-box {
  368. display: flex;
  369. flex-wrap: wrap;
  370. .ant-tag {
  371. text-align: center;
  372. margin-bottom: 8px;
  373. overflow: hidden;
  374. text-overflow: ellipsis;
  375. white-space: nowrap;
  376. }
  377. }
  378. }
  379. }
  380. .info-content {
  381. width: 80%;
  382. height: 100%;
  383. margin-left: 10px;
  384. }
  385. }
  386. }
  387. </style>