index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. <template>
  2. <view class="detail-container">
  3. <scroll-view scroll-y class="scroll-wrapper">
  4. <!-- 顶部基础信息 -->
  5. <view class="section header-section">
  6. <view class="title-line">
  7. <view class="left-box">
  8. <text class="job-name">{{ jobInfo.postName || '' }}</text>
  9. <text class="urgent-tag" v-if="jobInfo.isUrgent === 1">急招</text>
  10. </view>
  11. <text class="salary">{{ jobInfo.salaryRange || '面议' }}</text>
  12. </view>
  13. <view class="meta-list">
  14. <view class="meta-item">
  15. <image src="/static/icons/location.svg" class="icon" mode="aspectFit"></image>
  16. <text>{{ jobInfo.workProvince || '' }}{{ jobInfo.workCity ? '·' + jobInfo.workCity : '' }}{{ jobInfo.workDistrict ? '·' + jobInfo.workDistrict : '' }}</text>
  17. </view>
  18. <view class="meta-item">
  19. <image src="/static/icons/user.svg" class="icon" mode="aspectFit"></image>
  20. <text>招录 {{ jobInfo.recruitNum || 1 }} 人</text>
  21. </view>
  22. <view class="meta-item">
  23. <image src="/static/icons/time.svg" class="icon" mode="aspectFit"></image>
  24. <text>截止时间:{{ jobInfo.registrationEndDate ? jobInfo.registrationEndDate.split(' ')[0] : '长期有效' }}</text>
  25. </view>
  26. </view>
  27. </view>
  28. <!-- HR 信息 -->
  29. <view class="section hr-section">
  30. <image :src="jobInfo.companyAvatar || '/static/images/hr_avatar.svg'" class="hr-avatar" mode="aspectFill"></image>
  31. <view class="hr-content">
  32. <text class="hr-name">{{ jobInfo.companyName || '平台推荐' }}</text>
  33. <text class="hr-desc">人事负责人</text>
  34. </view>
  35. </view>
  36. <!-- 岗位详情内容 -->
  37. <view class="section detail-content">
  38. <view class="section-title">岗位详情</view>
  39. <!-- 标签云 -->
  40. <view class="tag-cloud">
  41. <text class="tag-label" v-for="tag in tags" :key="tag">{{ tag }}</text>
  42. </view>
  43. <!-- 岗位描述(富文本,来自数据库 post_description) -->
  44. <view class="rich-text-wrapper" v-if="jobInfo.postDescription">
  45. <rich-text :nodes="jobInfo.postDescription"></rich-text>
  46. </view>
  47. <view class="info-block" v-else>
  48. <text class="block-text">暂无岗位详情</text>
  49. </view>
  50. </view>
  51. <!-- 办公地址 - 接入动态地图并使用气泡显示地址 -->
  52. <view class="section address-section">
  53. <view class="section-title">办公地址</view>
  54. <view class="map-wrapper">
  55. <map
  56. class="map-view"
  57. :latitude="latitude"
  58. :longitude="longitude"
  59. :markers="markers"
  60. :scale="16"
  61. show-location
  62. ></map>
  63. </view>
  64. </view>
  65. <!-- 公司概况 -->
  66. <view class="section company-section">
  67. <view class="company-header">
  68. <image :src="jobInfo.companyAvatar || '/static/images/logo1.png'" class="company-logo" mode="aspectFit"></image>
  69. <text class="company-name">{{ jobInfo.companyName || '未知企业' }}</text>
  70. </view>
  71. <text class="company-desc">
  72. 这是一段公司的概览信息,暂无详细内容。
  73. </text>
  74. </view>
  75. <!-- 到底提示 -->
  76. <view class="end-tip">
  77. <text>— 已到底啦~ —</text>
  78. </view>
  79. <view class="safe-bottom-holder"></view>
  80. </scroll-view>
  81. <!-- 底部操作栏 -->
  82. <view class="bottom-action-bar">
  83. <view class="collect-box" @click="toggleCollect">
  84. <image :src="isCollected ? '/static/icons/star_filled.svg' : '/static/icons/star_hollow.svg'"
  85. class="star-icon"
  86. mode="aspectFit"></image>
  87. <view class="collect-text">{{ isCollected ? '已收藏' : '收藏' }}</view>
  88. </view>
  89. <view
  90. class="consult-btn"
  91. :class="[jobState]"
  92. @click="handleMainAction"
  93. >
  94. <text>{{ btnText }}</text>
  95. </view>
  96. </view>
  97. </view>
  98. </template>
  99. <script setup lang="js">
  100. import { ref, computed, onUnmounted } from 'vue';
  101. import { onShow, onLoad } from '@dcloudio/uni-app';
  102. import { getPositionDetail } from '../../api/position.js';
  103. import { createOrGetSession } from '../../api/message.js';
  104. import { addCollection, delCollection, checkCollection } from '../../api/collection.js';
  105. import { getAssessmentRecordList, getAssessmentList, applyPosition } from '../../api/assessment.js';
  106. const isCollected = ref(false);
  107. const collectionId = ref(null);
  108. const jobInfo = ref({});
  109. const tags = ref([]);
  110. // 岗位状态: 'initial', 'paid', 'assessed', 'added'
  111. const jobState = ref('initial');
  112. const btnText = computed(() => {
  113. switch (jobState.value) {
  114. case 'initial': return '咨询';
  115. case 'paid': return '开始测评';
  116. case 'assessed': return '投递简历';
  117. case 'added': return '已投递';
  118. default: return '咨询';
  119. }
  120. });
  121. const positionId = ref(null);
  122. const checkState = async () => {
  123. console.log('Checking job state for position:', positionId.value);
  124. const userInfo = uni.getStorageSync('userInfo');
  125. if (!userInfo || !userInfo.studentId || !positionId.value) {
  126. jobState.value = 'initial';
  127. return;
  128. }
  129. // ① 已投递过 → 直接显示已投递
  130. const appliedKey = `candidate_applied_${positionId.value}`;
  131. if (uni.getStorageSync(appliedKey)) {
  132. jobState.value = 'added';
  133. return;
  134. }
  135. try {
  136. // ② 查询该岗位关联的测评列表
  137. const evalRes = await getAssessmentList({ positionId: positionId.value, pageNum: 1, pageSize: 100 });
  138. // 检查该岗位下是否有测评已支付(按evaluationId区分)
  139. const isAnyEvalPaid = evalRes.code === 200 && evalRes.rows
  140. ? evalRes.rows.some(e => uni.getStorageSync(`audit_paid_${e.id}`))
  141. : uni.getStorageSync(`audit_paid_${positionId.value}`);
  142. if (evalRes.code !== 200 || !evalRes.rows || evalRes.rows.length === 0) {
  143. // 无关联测评,检查是否已支付
  144. jobState.value = isAnyEvalPaid ? 'paid' : 'initial';
  145. return;
  146. }
  147. // ③ 获取用户的测评记录
  148. const recordRes = await getAssessmentRecordList(userInfo.studentId);
  149. if (recordRes.code !== 200 || !recordRes.data) {
  150. jobState.value = isAnyEvalPaid ? 'paid' : 'initial';
  151. return;
  152. }
  153. // ④ 检查用户是否通过了该岗位关联的任一测评
  154. const evaluationIds = evalRes.rows.map(e => e.id);
  155. const passedRecord = recordRes.data.find(r =>
  156. r.finalResult === '1' && evaluationIds.includes(r.evaluationId)
  157. );
  158. if (passedRecord) {
  159. // 测评通过 → 显示"投递简历"
  160. jobState.value = 'assessed';
  161. } else if (isAnyEvalPaid) {
  162. // 已付款但未通过测评 → 显示"开始测评"
  163. jobState.value = 'paid';
  164. } else {
  165. // 未支付测评费用,只显示咨询按钮
  166. jobState.value = 'initial';
  167. }
  168. } catch (err) {
  169. console.error('检查状态失败:', err);
  170. jobState.value = 'initial';
  171. }
  172. };
  173. const latitude = ref(31.22863);
  174. const longitude = ref(121.45039);
  175. const markers = ref([]);
  176. const fetchDetail = async (id) => {
  177. console.log('fetchDetail called with id:', id); // 调试日志
  178. uni.showLoading({ title: '加载中...' });
  179. try {
  180. const res = await getPositionDetail(id);
  181. console.log('getPositionDetail响应:', res); // 调试日志
  182. if (res.code === 200 && res.data) {
  183. jobInfo.value = res.data;
  184. positionId.value = res.data.id;
  185. const data = res.data;
  186. // 地图坐标赋值
  187. if (data.latitude && data.longitude) {
  188. latitude.value = parseFloat(data.latitude);
  189. longitude.value = parseFloat(data.longitude);
  190. markers.value = [{
  191. id: 1,
  192. latitude: latitude.value,
  193. longitude: longitude.value,
  194. title: data.postName || '办公地点',
  195. iconPath: '/static/icons/location.svg',
  196. width: 32,
  197. height: 32,
  198. callout: {
  199. content: data.workAddress || (data.workProvince + data.workCity + data.workDistrict),
  200. color: '#333333',
  201. fontSize: 12,
  202. borderRadius: 8,
  203. padding: 8,
  204. bgColor: '#ffffff',
  205. display: 'ALWAYS',
  206. boxShadow: '0 4rpx 12rpx rgba(0,0,0,0.1)'
  207. }
  208. }];
  209. } else {
  210. // 如果没有经纬度,显示一个默认位置或清空标记
  211. markers.value = [];
  212. }
  213. let t = [];
  214. if(data.postTypeLabel) t.push(data.postTypeLabel);
  215. if(data.schoolRequirementLabel) t.push(data.schoolRequirementLabel);
  216. if(data.gradeRequirementLabel) t.push(data.gradeRequirementLabel);
  217. if(data.welfareTags) {
  218. t.push(...data.welfareTags.split(',').filter(Boolean));
  219. }
  220. tags.value = t;
  221. // 检查是否已收藏
  222. console.log('准备检查收藏状态, id:', id);
  223. checkCollectionStatus(id);
  224. }
  225. } catch(err) {
  226. console.error('获取岗位详情失败:', err);
  227. } finally {
  228. uni.hideLoading();
  229. }
  230. };
  231. // 检查收藏状态
  232. const checkCollectionStatus = async (id) => {
  233. console.log('checkCollectionStatus called with id:', id); // 调试日志
  234. const userInfo = uni.getStorageSync('userInfo');
  235. console.log('checkCollectionStatus userInfo:', userInfo); // 调试日志
  236. if (!userInfo || !userInfo.studentId) {
  237. console.log('checkCollectionStatus: 用户未登录');
  238. return;
  239. }
  240. try {
  241. console.log('调用checkCollection API, studentId:', userInfo.studentId, 'targetId:', id, 'type: job'); // 调试日志
  242. const res = await checkCollection(userInfo.studentId, id, 'job');
  243. console.log('checkCollection API响应:', res); // 调试日志
  244. if (res.code === 200 && res.data) {
  245. isCollected.value = true;
  246. collectionId.value = res.data.id; // 保存收藏记录ID
  247. console.log('设置为已收藏, collectionId:', res.data.id);
  248. } else {
  249. isCollected.value = false;
  250. collectionId.value = null;
  251. console.log('设置为未收藏');
  252. }
  253. } catch (err) {
  254. console.error('检查收藏状态失败', err);
  255. }
  256. };
  257. // 切换收藏状态
  258. const toggleCollect = async () => {
  259. console.log('toggleCollect clicked'); // 调试日志
  260. const userInfo = uni.getStorageSync('userInfo');
  261. console.log('userInfo:', userInfo); // 调试日志
  262. if (!userInfo || !userInfo.studentId) {
  263. console.log('用户未登录'); // 调试日志
  264. uni.showToast({ title: '请先登录', icon: 'none' });
  265. setTimeout(() => {
  266. uni.navigateTo({ url: '/pages/login/login' });
  267. }, 1000);
  268. return;
  269. }
  270. if (!jobInfo.value.id) {
  271. console.log('jobInfo.value.id 为空:', jobInfo.value); // 调试日志
  272. return;
  273. }
  274. console.log('准备发送收藏请求, jobInfo.value.id:', jobInfo.value.id); // 调试日志
  275. uni.showLoading({ title: isCollected.value ? '取消收藏中...' : '收藏中...' });
  276. try {
  277. if (isCollected.value) {
  278. // 取消收藏
  279. console.log('取消收藏, collectionId:', collectionId.value); // 调试日志
  280. if (collectionId.value) {
  281. const res = await delCollection(collectionId.value);
  282. console.log('取消收藏响应:', res); // 调试日志
  283. if (res.code === 200) {
  284. isCollected.value = false;
  285. collectionId.value = null;
  286. uni.showToast({ title: '已取消收藏', icon: 'none' });
  287. }
  288. }
  289. } else {
  290. // 添加收藏
  291. const requestData = {
  292. studentId: userInfo.studentId,
  293. targetId: jobInfo.value.id,
  294. type: 'job'
  295. };
  296. console.log('添加收藏请求数据:', requestData); // 调试日志
  297. const res = await addCollection(requestData);
  298. console.log('添加收藏响应:', res); // 调试日志
  299. if (res.code === 200) {
  300. isCollected.value = true;
  301. // 添加成功后重新检查获取完整的收藏记录ID
  302. checkCollectionStatus(jobInfo.value.id);
  303. uni.showToast({ title: '收藏成功', icon: 'success' });
  304. } else {
  305. uni.showToast({ title: res.msg || '收藏失败', icon: 'none' });
  306. }
  307. }
  308. } catch (err) {
  309. console.error('操作收藏失败', err);
  310. uni.showToast({ title: '操作失败', icon: 'none' });
  311. } finally {
  312. uni.hideLoading();
  313. }
  314. };
  315. onLoad((options) => {
  316. if (options.id) {
  317. positionId.value = options.id;
  318. fetchDetail(options.id);
  319. }
  320. // 监听支付完成事件(chat.vue 支付成功后会 emit)
  321. uni.$on('payment_done', (data) => {
  322. console.log('收到 payment_done 事件:', data);
  323. checkState();
  324. });
  325. });
  326. onShow(() => {
  327. if (positionId.value) {
  328. checkState();
  329. }
  330. });
  331. onUnmounted(() => {
  332. uni.$off('payment_done');
  333. });
  334. const handleMainAction = async () => {
  335. if (jobState.value === 'initial') {
  336. try {
  337. uni.showLoading({ title: '正在连接客服...' });
  338. const userInfo = uni.getStorageSync('userInfo') || {};
  339. const userId = userInfo.studentId || null;
  340. const userName = userInfo.name || '用户';
  341. const userAvatar = userInfo.avatarUrl || '/static/images/user_avatar.svg';
  342. const res = await createOrGetSession({
  343. sessionType: 1,
  344. fromUserId: userId,
  345. fromUserName: userName,
  346. fromUserAvatar: userAvatar,
  347. sourceId: 'job_' + positionId.value
  348. });
  349. uni.hideLoading();
  350. if (res.data) {
  351. const session = res.data;
  352. uni.navigateTo({
  353. url: `/pages/chat/chat?sessionId=${session.sessionId}&sessionNo=${session.sessionNo || ''}&fromUserId=${userId}&userName=${encodeURIComponent(userName)}&jobName=${encodeURIComponent(jobInfo.value.postName || '')}&type=job&positionId=${positionId.value}&salaryRange=${encodeURIComponent(jobInfo.value.salaryRange || '')}&companyName=${encodeURIComponent(jobInfo.value.companyName || '')}&workCity=${encodeURIComponent(jobInfo.value.workCity || '')}`
  354. });
  355. } else {
  356. uni.showToast({ title: '创建会话失败', icon: 'none' });
  357. }
  358. } catch (err) {
  359. uni.hideLoading();
  360. console.error('创建会话失败:', err);
  361. uni.showToast({ title: '连接失败,请重试', icon: 'none' });
  362. }
  363. } else if (jobState.value === 'paid') {
  364. uni.navigateTo({
  365. url: '/pages/assessment/remind?family=audit'
  366. });
  367. } else if (jobState.value === 'assessed') {
  368. // 投递简历:向 main_back_candidate 表加数据
  369. const userInfo = uni.getStorageSync('userInfo') || {};
  370. if (!userInfo.studentId) {
  371. uni.showToast({ title: '请先登录', icon: 'none' });
  372. setTimeout(() => {
  373. uni.navigateTo({ url: '/pages/login/login' });
  374. }, 1000);
  375. return;
  376. }
  377. try {
  378. uni.showLoading({ title: '投递中...' });
  379. const res = await applyPosition({ postId: positionId.value });
  380. uni.hideLoading();
  381. if (res.code === 200) {
  382. uni.showToast({ title: '投递成功', icon: 'success' });
  383. } else if (res.msg && res.msg.includes('已投递')) {
  384. // 已投递过,视为成功
  385. } else {
  386. uni.showToast({ title: res.msg || '投递失败', icon: 'none' });
  387. }
  388. // 无论成功还是已投递,都标记为已投递状态
  389. jobState.value = 'added';
  390. uni.setStorageSync(`candidate_applied_${positionId.value}`, true);
  391. } catch (err) {
  392. uni.hideLoading();
  393. console.error('投递失败:', err);
  394. // 即使网络层报错(如500),如果业务上已投递或重复投递,也标记为已投递
  395. const errMsg = String(err?.msg || err?.message || '');
  396. if (errMsg.includes('已投递')) {
  397. jobState.value = 'added';
  398. uni.setStorageSync(`candidate_applied_${positionId.value}`, true);
  399. uni.showToast({ title: '您已投递过该岗位', icon: 'none' });
  400. } else {
  401. uni.showToast({ title: '网络错误,投递失败', icon: 'none' });
  402. }
  403. }
  404. }
  405. };
  406. const updateState = (state) => {
  407. jobState.value = state;
  408. };
  409. // 状态逻辑已移至 checkState 内部
  410. </script>
  411. <style lang="scss" scoped>
  412. .detail-container {
  413. width: 100%;
  414. height: 100vh;
  415. background-color: #FFFFFF;
  416. display: flex;
  417. flex-direction: column;
  418. }
  419. .scroll-wrapper {
  420. flex: 1;
  421. }
  422. .section {
  423. padding: 30rpx 40rpx;
  424. background-color: #FFFFFF;
  425. }
  426. .section-title {
  427. font-size: 34rpx;
  428. font-weight: bold;
  429. color: #1A1A1A;
  430. margin-bottom: 30rpx;
  431. }
  432. /* 头部样式 */
  433. .header-section {
  434. padding-top: 20rpx;
  435. .title-line {
  436. display: flex;
  437. justify-content: space-between;
  438. align-items: center;
  439. margin-bottom: 24rpx;
  440. .left-box {
  441. display: flex;
  442. align-items: center;
  443. .job-name {
  444. font-size: 44rpx;
  445. font-weight: bold;
  446. color: #1A1A1A;
  447. margin-right: 16rpx;
  448. }
  449. .urgent-tag {
  450. font-size: 20rpx;
  451. color: #FF4D4F;
  452. border: 1rpx solid #FF4D4F;
  453. padding: 2rpx 10rpx;
  454. border-radius: 6rpx;
  455. }
  456. }
  457. .salary {
  458. font-size: 38rpx;
  459. font-weight: bold;
  460. color: #1F6CFF;
  461. }
  462. }
  463. .meta-list {
  464. .meta-item {
  465. display: flex;
  466. align-items: center;
  467. margin-bottom: 12rpx;
  468. font-size: 26rpx;
  469. color: #777777;
  470. .icon {
  471. width: 30rpx;
  472. height: 30rpx;
  473. margin-right: 12rpx;
  474. opacity: 0.7;
  475. }
  476. .warning-text {
  477. color: #FF4D4F;
  478. margin-left: 16rpx;
  479. }
  480. }
  481. }
  482. }
  483. /* HR 区域 */
  484. .hr-section {
  485. border-top: 1rpx solid #F8F9FB;
  486. display: flex;
  487. align-items: center;
  488. padding: 30rpx 40rpx;
  489. .hr-avatar {
  490. width: 100rpx;
  491. height: 100rpx;
  492. border-radius: 50%;
  493. margin-right: 24rpx;
  494. background-color: #F0F0F0;
  495. }
  496. .hr-content {
  497. .hr-name {
  498. display: block;
  499. font-size: 30rpx;
  500. font-weight: bold;
  501. color: #1A1A1A;
  502. margin-bottom: 4rpx;
  503. }
  504. .hr-desc {
  505. font-size: 24rpx;
  506. color: #888888;
  507. }
  508. }
  509. }
  510. /* 岗位详情描述 */
  511. .detail-content {
  512. border-top: 10rpx solid #F8F9FB;
  513. .tag-cloud {
  514. display: flex;
  515. flex-wrap: wrap;
  516. gap: 16rpx;
  517. margin-bottom: 40rpx;
  518. .tag-label {
  519. background-color: #F5F7FA;
  520. color: #888888;
  521. font-size: 24rpx;
  522. padding: 10rpx 24rpx;
  523. border-radius: 6rpx;
  524. }
  525. }
  526. .rich-text-wrapper {
  527. font-size: 28rpx;
  528. color: #555555;
  529. line-height: 1.8;
  530. }
  531. .info-block {
  532. margin-bottom: 24rpx;
  533. .block-label {
  534. display: block;
  535. font-size: 28rpx;
  536. font-weight: bold;
  537. color: #1A1A1A;
  538. margin-bottom: 8rpx;
  539. }
  540. .block-text {
  541. font-size: 28rpx;
  542. color: #555555;
  543. line-height: 1.6;
  544. }
  545. .list-item {
  546. display: flex;
  547. margin-bottom: 8rpx;
  548. .dot {
  549. font-weight: bold;
  550. margin-right: 12rpx;
  551. color: #1A1A1A;
  552. }
  553. .list-text {
  554. font-size: 28rpx;
  555. color: #555555;
  556. line-height: 1.6;
  557. }
  558. }
  559. }
  560. }
  561. /* 办公地址区 - 动态地图 */
  562. .address-section {
  563. border-top: 10rpx solid #F8F9FB;
  564. .map-wrapper {
  565. position: relative;
  566. width: 100%;
  567. height: 360rpx;
  568. border-radius: 12rpx;
  569. overflow: hidden;
  570. box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.06);
  571. .map-view {
  572. width: 100%;
  573. height: 100%;
  574. }
  575. }
  576. }
  577. /* 公司概况区 */
  578. .company-section {
  579. border-top: 10rpx solid #F8F9FB;
  580. .company-header {
  581. display: flex;
  582. align-items: center;
  583. margin-bottom: 24rpx;
  584. .company-logo {
  585. width: 80rpx;
  586. height: 80rpx;
  587. border-radius: 12rpx;
  588. background: #f0f0f0;
  589. margin-right: 20rpx;
  590. }
  591. .company-name {
  592. font-size: 32rpx;
  593. font-weight: bold;
  594. color: #1A1A1A;
  595. }
  596. }
  597. .company-desc {
  598. font-size: 28rpx;
  599. color: #666666;
  600. line-height: 1.6;
  601. }
  602. }
  603. .end-tip {
  604. padding: 60rpx 0;
  605. text-align: center;
  606. text {
  607. font-size: 24rpx;
  608. color: #CCCCCC;
  609. }
  610. }
  611. .safe-bottom-holder {
  612. height: 140rpx;
  613. }
  614. /* 底部栏 */
  615. .bottom-action-bar {
  616. position: fixed;
  617. bottom: 0;
  618. left: 0;
  619. right: 0;
  620. height: 120rpx;
  621. background-color: #FFFFFF;
  622. display: flex;
  623. align-items: center;
  624. padding: 0 40rpx;
  625. padding-bottom: env(safe-area-inset-bottom);
  626. box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.08);
  627. z-index: 999;
  628. .collect-box {
  629. display: flex;
  630. flex-direction: column;
  631. align-items: center;
  632. width: 80rpx;
  633. margin-right: 40rpx;
  634. background: transparent; /* 强制背景透明 */
  635. .star-icon {
  636. width: 44rpx;
  637. height: 44rpx;
  638. margin-bottom: 4rpx;
  639. background: transparent;
  640. display: block;
  641. }
  642. .collect-text {
  643. font-size: 20rpx;
  644. color: #999999;
  645. }
  646. }
  647. .consult-btn {
  648. flex: 1;
  649. background-color: #FFB700;
  650. height: 88rpx;
  651. border-radius: 44rpx;
  652. display: flex;
  653. align-items: center;
  654. justify-content: center;
  655. transition: all 0.3s;
  656. text {
  657. color: #FFFFFF;
  658. font-size: 32rpx;
  659. font-weight: bold;
  660. }
  661. &.initial, &.paid {
  662. background-color: #FFB700;
  663. box-shadow: 0 8rpx 16rpx rgba(255, 183, 0, 0.2);
  664. }
  665. &.assessed {
  666. background-color: #1F6CFF; // 测评通过后变为蓝色,投递简历
  667. box-shadow: 0 8rpx 16rpx rgba(31, 108, 255, 0.2);
  668. }
  669. &.added {
  670. background-color: #E0E0E0 !important; // 已投递后禁用灰色
  671. box-shadow: none !important;
  672. pointer-events: none;
  673. text {
  674. color: #999 !important;
  675. }
  676. }
  677. &:active {
  678. opacity: 0.9;
  679. }
  680. }
  681. }
  682. </style>