ResumeEvaluation.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const common_config = require("../../common/config.js");
  4. const _sfc_main = {
  5. data() {
  6. return {
  7. applicationData: null,
  8. // 存储API返回的原始数据
  9. candidateInfo: {
  10. name: "",
  11. idNumber: "",
  12. phoneNumber: "",
  13. score: 0,
  14. availabilityPeriod: "",
  15. onboardingTime: "",
  16. dimensions: {
  17. teamwork: "",
  18. learningAbility: "",
  19. attention: "",
  20. workAdaptability: "",
  21. serviceAwareness: ""
  22. },
  23. dimensionDetails: {
  24. teamwork: "",
  25. learningAbility: "",
  26. attention: "",
  27. workAdaptability: "",
  28. serviceAwareness: ""
  29. },
  30. duvAnalysis: [],
  31. interviewRecord: [],
  32. videoRecords: [],
  33. additionalInfo: {
  34. idVerification: "",
  35. phoneVerification: "",
  36. leftHandGestures: {
  37. passed: true,
  38. images: []
  39. },
  40. rightHandGestures: {
  41. passed: true,
  42. images: []
  43. },
  44. faceVerification: {
  45. passed: true,
  46. images: []
  47. }
  48. }
  49. },
  50. evaluationScore: 0,
  51. evaluationComments: "",
  52. dimensionLabels: {
  53. teamwork: "团队合作能力",
  54. learningAbility: "学习能力",
  55. attention: "细致严谨",
  56. workAdaptability: "工作适应性",
  57. serviceAwareness: "服务意识"
  58. }
  59. };
  60. },
  61. onLoad(options) {
  62. const id = options.id || 1;
  63. const tenant_id = options.tenant_id || 1;
  64. const application_id = options.application_id || 1;
  65. this.fetchApplicationDetail(id, tenant_id, application_id);
  66. },
  67. methods: {
  68. // 获取申请详情数据
  69. fetchApplicationDetail(id, tenant_id, application_id) {
  70. common_vendor.index.showLoading({
  71. title: "加载中..."
  72. });
  73. common_vendor.index.request({
  74. url: `${common_config.apiBaseUrl}/api/job/application_detail?id=${id}&tenant_id=${tenant_id}&application_id=${application_id}`,
  75. method: "GET",
  76. success: (res) => {
  77. if (res.data && res.data.code === 2e3) {
  78. this.applicationData = res.data.data;
  79. this.processApiData();
  80. } else {
  81. common_vendor.index.showToast({
  82. title: "获取数据失败",
  83. icon: "none"
  84. });
  85. }
  86. },
  87. fail: () => {
  88. common_vendor.index.showToast({
  89. title: "网络请求失败",
  90. icon: "none"
  91. });
  92. },
  93. complete: () => {
  94. common_vendor.index.hideLoading();
  95. }
  96. });
  97. },
  98. // 处理API返回的数据,映射到现有数据结构
  99. processApiData() {
  100. if (!this.applicationData)
  101. return;
  102. const { application, applicant, position, interview_progress, posture_photos } = this.applicationData;
  103. this.candidateInfo.name = applicant.name || "";
  104. this.candidateInfo.idNumber = applicant.id || "";
  105. this.candidateInfo.phoneNumber = applicant.phone || "";
  106. if (application.comprehensive_score) {
  107. this.candidateInfo.score = application.comprehensive_score;
  108. } else if (application.ai_capability_scores) {
  109. const scores = Object.values(application.ai_capability_scores);
  110. this.candidateInfo.score = scores.length ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) : 0;
  111. }
  112. if (application.ai_capability_scores) {
  113. const scoreMapping = {
  114. "专业性": "workAdaptability",
  115. "沟通能力": "teamwork",
  116. "技术匹配度": "learningAbility",
  117. "解决问题能力": "attention"
  118. };
  119. Object.entries(application.ai_capability_scores).forEach(([key, value]) => {
  120. const mappedKey = scoreMapping[key] || "serviceAwareness";
  121. let rating = "中等";
  122. if (value >= 80)
  123. rating = "优秀";
  124. else if (value < 65)
  125. rating = "欠佳";
  126. this.candidateInfo.dimensions[mappedKey] = rating;
  127. });
  128. }
  129. if (application.ai_analysis_details && application.ai_analysis_details.requirements_feedback) {
  130. const feedback = application.ai_analysis_details.requirements_feedback;
  131. Object.keys(this.candidateInfo.dimensionDetails).forEach((key) => {
  132. this.candidateInfo.dimensionDetails[key] = feedback;
  133. });
  134. }
  135. if (application.ai_overall_feedback) {
  136. this.candidateInfo.duvAnalysis = [
  137. {
  138. title: "综合评估",
  139. content: application.ai_overall_feedback,
  140. score: this.candidateInfo.score >= 70 ? "良好" : "需改进",
  141. type: this.candidateInfo.score >= 70 ? "positive" : "negative"
  142. }
  143. ];
  144. if (position) {
  145. this.candidateInfo.duvAnalysis.push({
  146. title: "职位匹配度",
  147. content: `应聘职位: ${position.title}, ${position.department}, ${position.location}`,
  148. score: "匹配",
  149. type: "positive"
  150. });
  151. }
  152. }
  153. if (interview_progress && interview_progress.length) {
  154. this.candidateInfo.interviewRecord = interview_progress.filter((item) => item.question_text).map((item) => {
  155. const answer = this.extractAnswerFromNotes(application.note, item.question_text);
  156. return {
  157. question: item.question_text,
  158. answer: answer || "未回答",
  159. analysis: "候选人回答简短,需进一步评估",
  160. score: "待评估",
  161. videoUrl: item.video_answer ? item.video_answer.video_url : null,
  162. thumbnail: "/images/video-placeholder.jpg"
  163. };
  164. });
  165. }
  166. const videoAnswers = interview_progress.filter((item) => item.video_answer && item.video_answer.video_url);
  167. if (videoAnswers.length) {
  168. this.candidateInfo.videoRecords = [
  169. {
  170. category: "面试视频",
  171. videos: videoAnswers.map((item) => ({
  172. url: item.video_answer.video_url,
  173. thumbnail: "/images/thumbnail1.jpg",
  174. description: item.question_text
  175. }))
  176. }
  177. ];
  178. }
  179. if (posture_photos && posture_photos.length) {
  180. const leftHandPhotos = posture_photos.filter((p) => p.description.includes("left") && !p.description.includes("face"));
  181. const rightHandPhotos = posture_photos.filter((p) => p.description.includes("right") && !p.description.includes("face"));
  182. const facePhotos = posture_photos.filter((p) => !p.description.includes("left") && !p.description.includes("right"));
  183. this.candidateInfo.additionalInfo.leftHandGestures.images = leftHandPhotos.map((p) => p.photo_url);
  184. this.candidateInfo.additionalInfo.rightHandGestures.images = rightHandPhotos.map((p) => p.photo_url);
  185. this.candidateInfo.additionalInfo.faceVerification.images = facePhotos.map((p) => p.photo_url);
  186. }
  187. this.candidateInfo.additionalInfo.idVerification = "通过";
  188. this.candidateInfo.additionalInfo.phoneVerification = "通过";
  189. },
  190. // 从面试记录中提取答案
  191. extractAnswerFromNotes(notes, question) {
  192. if (!notes)
  193. return "";
  194. const pattern = new RegExp(`问题 ${question}:\\s*([^\\n]+)`, "i");
  195. const match = notes.match(pattern);
  196. return match ? match[1].trim() : "";
  197. },
  198. // 格式化日期
  199. formatDate(dateString) {
  200. if (!dateString)
  201. return "";
  202. try {
  203. const date = new Date(dateString);
  204. return date.toLocaleString("zh-CN", {
  205. year: "numeric",
  206. month: "2-digit",
  207. day: "2-digit",
  208. hour: "2-digit",
  209. minute: "2-digit",
  210. second: "2-digit"
  211. });
  212. } catch (e) {
  213. return dateString;
  214. }
  215. },
  216. handleSubmit() {
  217. if (this.evaluationScore === 0 || !this.evaluationComments.trim()) {
  218. common_vendor.index.showToast({
  219. title: "请完成所有必填项",
  220. icon: "none"
  221. });
  222. return;
  223. }
  224. common_vendor.index.showToast({
  225. title: "评估已提交",
  226. icon: "success"
  227. });
  228. },
  229. scrollToTop() {
  230. common_vendor.index.pageScrollTo({
  231. scrollTop: 0,
  232. duration: 300
  233. });
  234. },
  235. handleShare() {
  236. common_vendor.index.showToast({
  237. title: "分享链接已复制",
  238. icon: "success"
  239. });
  240. },
  241. handleDownload() {
  242. common_vendor.index.showToast({
  243. title: "报告下载中...",
  244. icon: "loading"
  245. });
  246. }
  247. }
  248. };
  249. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  250. var _a, _b;
  251. return {
  252. a: common_vendor.t($data.candidateInfo.idNumber || "未知"),
  253. b: common_vendor.t($options.formatDate((_b = (_a = $data.applicationData) == null ? void 0 : _a.application) == null ? void 0 : _b.create_datetime)),
  254. c: $data.candidateInfo.additionalInfo.faceVerification.images[0],
  255. d: common_vendor.t($data.candidateInfo.name),
  256. e: common_vendor.t($data.candidateInfo.phoneNumber),
  257. f: common_vendor.t($data.candidateInfo.score),
  258. g: common_vendor.t($data.candidateInfo.idNumber),
  259. h: common_vendor.t($data.candidateInfo.availabilityPeriod),
  260. i: common_vendor.t($data.candidateInfo.onboardingTime),
  261. j: common_vendor.f($data.candidateInfo.dimensions, (value, key, i0) => {
  262. return {
  263. a: common_vendor.t($data.dimensionLabels[key]),
  264. b: common_vendor.t(value),
  265. c: value === "欠佳" ? 1 : "",
  266. d: value === "优秀" ? 1 : "",
  267. e: value === "中等" ? 1 : "",
  268. f: common_vendor.t($data.candidateInfo.dimensionDetails[key]),
  269. g: key
  270. };
  271. }),
  272. k: common_vendor.f($data.candidateInfo.duvAnalysis, (item, index, i0) => {
  273. return {
  274. a: common_vendor.t(item.title),
  275. b: common_vendor.t(item.score),
  276. c: item.type === "positive" ? 1 : "",
  277. d: item.type === "negative" ? 1 : "",
  278. e: item.type === "neutral" ? 1 : "",
  279. f: common_vendor.t(item.content),
  280. g: index
  281. };
  282. }),
  283. l: common_vendor.f($data.candidateInfo.interviewRecord, (record, index, i0) => {
  284. return common_vendor.e({
  285. a: common_vendor.t(record.question),
  286. b: common_vendor.t(record.answer),
  287. c: common_vendor.t(record.analysis),
  288. d: record.videoUrl
  289. }, record.videoUrl ? {
  290. e: record.videoUrl,
  291. f: record.thumbnail
  292. } : {}, {
  293. g: common_vendor.t(record.score),
  294. h: index
  295. });
  296. }),
  297. m: common_vendor.f($data.candidateInfo.videoRecords, (category, index, i0) => {
  298. return {
  299. a: common_vendor.t(category.category),
  300. b: common_vendor.f(category.videos, (video, vIndex, i1) => {
  301. return {
  302. a: video.url,
  303. b: video.thumbnail,
  304. c: common_vendor.t(video.description),
  305. d: vIndex
  306. };
  307. }),
  308. c: index
  309. };
  310. }),
  311. n: common_vendor.t($data.candidateInfo.additionalInfo.idVerification),
  312. o: common_vendor.t($data.candidateInfo.additionalInfo.phoneVerification),
  313. p: common_vendor.f($data.candidateInfo.additionalInfo.leftHandGestures.images, (image, index, i0) => {
  314. return {
  315. a: image,
  316. b: index
  317. };
  318. }),
  319. q: common_vendor.f($data.candidateInfo.additionalInfo.rightHandGestures.images, (image, index, i0) => {
  320. return {
  321. a: image,
  322. b: index
  323. };
  324. }),
  325. r: common_vendor.f($data.candidateInfo.additionalInfo.faceVerification.images, (image, index, i0) => {
  326. return {
  327. a: image,
  328. b: index
  329. };
  330. })
  331. };
  332. }
  333. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  334. wx.createPage(MiniProgramPage);