Files
ks-app-employment-service/packageA/pages/UnitDetails/UnitDetails.vue
2025-11-04 21:12:12 +08:00

573 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<AppLayout title="" :use-scroll-view="false">
<template #headerleft>
<view class="btnback">
<image src="@/static/icon/back.png" @click="navBack"></image>
</view>
</template>
<template #headerright>
<view class="btn mar_ri10">
<image
src="@/static/icon/collect3.png"
v-if="!companyInfo.isCollection"
></image>
<image src="@/static/icon/collect2.png" v-else></image>
</view>
</template>
<view class="content">
<view class="content-top">
<view class="companyinfo-left">
<image src="@/static/icon/companyIcon.png" mode=""></image>
</view>
<view class="companyinfo-right">
<view class="row1">{{ companyInfo?.companyName }}</view>
<view class="row2" v-if="companyInfo?.industry || companyInfo?.scale">
<dict-tree-Label
v-if="companyInfo?.industry"
dictType="industry"
:value="companyInfo?.industry"
></dict-tree-Label>
<span v-if="companyInfo?.industry && companyInfo?.scale">&nbsp;·&nbsp;</span>
<dict-Label
v-if="companyInfo?.scale"
dictType="scale"
:value="companyInfo?.scale"
></dict-Label>
</view>
</view>
</view>
<view class="conetent-info" :class="{ expanded: isExpanded }">
<view class="info-title">公司介绍</view>
<view class="info-desirption">{{
companyInfo.description
}}</view>
<!-- <view class="info-title title2">公司地址</view>
<view class="locationCompany"></view> -->
</view>
<view class="expand" @click="expand">
<text>{{ isExpanded ? "收起" : "展开" }}</text>
<image
class="expand-img"
:class="{ 'expand-img-active': !isExpanded }"
src="@/static/icon/downs.png"
></image>
</view>
<scroll-view scroll-y class="Detailscroll-view">
<view class="views">
<view class="Detail-title"><text class="title">在招职位</text></view>
<template v-if="companyInfo.jobInfoList.length != 0">
<view v-for="job in companyInfo.jobInfoList" :key="job.jobId" class="job-card-wrapper">
<view class="cards" @click="navTo(`/packageA/pages/post/post?jobId=${job.jobId}`)">
<view class="card-header">
<view class="card-title-row">
<text class="job-title">{{ job.jobTitle }}</text>
<view class="card-pay">
<view class="pay-text">
<text class="salary-amount">{{ formatSalary(job.minSalary, job.maxSalary) }}</text>
<text class="salary-unit">/</text>
</view>
</view>
</view>
</view>
<view class="card-tags" v-if="job.experience || job.education">
<view class="tag tag-experience" v-if="job.experience">
<image class="tag-icon" :src="`${baseUrl}/jobfair/jy.png`" mode="aspectFit"></image>
<view class="tag-text">
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
</view>
</view>
<view class="tag tag-education" v-if="job.education">
<image class="tag-icon" :src="`${baseUrl}/jobfair/xx.png`" mode="aspectFit"></image>
<view class="tag-text">
<dict-Label dictType="education" :value="job.education"></dict-Label>
</view>
</view>
</view>
<view class="card-location" v-if="job.jobLocation">
<image class="location-icon" src="/static/icon/point3.png" mode="aspectFit"></image>
<text class="location-text">{{ job.jobLocation }}</text>
</view>
</view>
</view>
</template>
<empty v-else pdTop="200"></empty>
</view>
</scroll-view>
</view>
</AppLayout>
</template>
<script setup>
import { reactive, inject, watch, ref, onMounted, computed } from "vue";
import { onLoad, onShow } from "@dcloudio/uni-app";
import dictLabel from "@/components/dict-Label/dict-Label.vue";
import config from "@/config.js";
import { storeToRefs } from "pinia";
import useLocationStore from "@/stores/useLocationStore";
const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
const { $api, navTo, vacanciesTo, navBack, parseQueryParams } = inject("globalFunction");
const isExpanded = ref(false);
const pageState = reactive({
page: 0,
list: [],
total: 0,
maxPage: 1,
pageSize: 10,
});
const companyInfo = ref({
jobInfoList: [],
companyName: '',
scale: '',
industry: '',
description: '',
isCollection: false
});
const baseUrl = config.imgBaseUrl;
const companyIdRef = ref(null);
const getItemBackgroundStyle = (imageName) => ({
backgroundImage: `url(${baseUrl}/jobfair/${imageName})`,
backgroundSize: "100% 100%", // 覆盖整个容器
backgroundPosition: "center", // 居中
backgroundRepeat: "no-repeat",
});
// 获取公司详情
function getCompanyDetail(companyId) {
if (!companyId) {
console.error('companyId 不能为空');
return;
}
// 尝试获取公司详情,如果接口不存在,可能公司详情会包含在职位数据中
$api.createRequest(`/app/company/${companyId}`).then((resData) => {
if (resData && resData.data) {
const data = resData.data;
companyInfo.value = {
...companyInfo.value,
...data,
companyName: data.name || data.companyName || data.company?.name || '',
scale: data.scale || data.company?.scale || '',
industry: data.industry || data.company?.industry || '',
description: data.description || data.companyIntroduction || data.introduction || data.company?.introduction || '',
isCollection: data.isCollection || false,
// 如果接口直接返回了职位列表,也设置进去
jobInfoList: data.jobInfoList || data.jobs || data.list || companyInfo.value.jobInfoList || []
};
console.log('companyInfo',companyInfo.value);
}
// 获取在招职位列表
getCompanyJobs(companyId);
}).catch((error) => {
console.error('获取公司详情失败:', error);
// 如果获取公司详情失败,尝试通过职位列表接口获取公司信息
// 或者直接获取职位列表
getCompanyJobs(companyId);
});
}
// 获取公司在招职位列表
function getCompanyJobs(companyId) {
if (!companyId) {
return;
}
// 使用正确的 API 路径:/app/company/job/{companyId}
$api.createRequest(`/app/company/job/${companyId}`, {}, 'GET').then((resData) => {
console.log('获取职位列表返回数据:', resData);
if (resData) {
// 优先检查 rows 字段(根据实际返回的数据结构)
if (resData.rows && Array.isArray(resData.rows)) {
companyInfo.value.jobInfoList = resData.rows;
}
// 如果返回的是数组
else if (Array.isArray(resData)) {
companyInfo.value.jobInfoList = resData;
}
// 如果返回的是对象,包含列表字段
else if (resData.data) {
if (Array.isArray(resData.data)) {
companyInfo.value.jobInfoList = resData.data;
} else if (resData.data.rows && Array.isArray(resData.data.rows)) {
companyInfo.value.jobInfoList = resData.data.rows;
} else if (resData.data.list && Array.isArray(resData.data.list)) {
companyInfo.value.jobInfoList = resData.data.list;
} else if (resData.data.jobInfoList && Array.isArray(resData.data.jobInfoList)) {
companyInfo.value.jobInfoList = resData.data.jobInfoList;
} else {
companyInfo.value.jobInfoList = [];
}
} else {
companyInfo.value.jobInfoList = [];
}
} else {
companyInfo.value.jobInfoList = [];
}
}).catch((error) => {
console.error('获取在招职位列表失败:', error);
companyInfo.value.jobInfoList = [];
});
}
onLoad((options) => {
console.log('options',options);
let companyId = null;
// 优先从 options 中获取 companyId小程序和 H5 都支持)
if (options && options.companyId) {
companyId = decodeURIComponent(options.companyId);
}
// 如果 options 中没有,尝试从 URL 解析(仅 H5 环境)
else {
// 使用 try-catch 包裹,避免在小程序环境中访问 window.location 报错
try {
// #ifdef H5
const params = parseQueryParams();
companyId = params.companyId;
// #endif
} catch (e) {
console.warn('解析 URL 参数失败:', e);
}
}
console.log('companyId', companyId);
if (companyId) {
companyIdRef.value = companyId;
getCompanyDetail(companyId);
} else {
console.error('未获取到 companyId 参数');
// 如果参数名是 job尝试兼容旧的方式
if (options && options.job) {
try {
const parsedData = JSON.parse(options.job);
if (parsedData.companyId) {
companyIdRef.value = parsedData.companyId;
getCompanyDetail(parsedData.companyId);
} else {
companyInfo.value = { ...companyInfo.value, ...parsedData };
}
} catch (e) {
console.error('解析 job 参数失败:', e);
}
}
}
});
onShow(() => {
// 仅在 H5 环境中从 URL 获取参数(小程序环境中 onShow 不会传递 URL 参数)
// #ifdef H5
try {
const params = parseQueryParams();
const companyId = params.companyId;
if (companyId && companyId !== companyIdRef.value) {
companyIdRef.value = companyId;
getCompanyDetail(companyId);
}
} catch (e) {
console.warn('onShow 中解析 URL 参数失败:', e);
}
// #endif
});
function expand() {
isExpanded.value = !isExpanded.value;
}
// 格式化薪资范围
function formatSalary(minSalary, maxSalary) {
if (minSalary && maxSalary) {
return `${minSalary}-${maxSalary}`;
} else if (minSalary) {
return `${minSalary}`;
} else if (maxSalary) {
return `最高${maxSalary}`;
}
return '面议';
}
// 截断文本,超过指定长度显示省略号
function truncateText(text, maxLength) {
if (!text) return '';
if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + '...';
}
</script>
<style lang="stylus" scoped>
.btnback {
width: 64rpx;
height: 64rpx;
}
.btn {
display: flex;
justify-content: space-between;
align-items: center;
width: 52rpx;
height: 52rpx;
}
image {
height: 100%;
width: 100%;
}
.content {
height: 100%;
display: flex;
flex-direction: column;
.content-top {
padding: 28rpx;
padding-top: 50rpx;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
.companyinfo-left {
width: 96rpx;
height: 96rpx;
margin-right: 24rpx;
}
.companyinfo-right {
.row1 {
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.row2 {
font-weight: 400;
font-size: 28rpx;
color: #6C7282;
line-height: 45rpx;
}
}
}
.conetent-info {
padding: 0 28rpx;
overflow: hidden;
max-height: 0rpx;
transition: max-height 0.3s ease;
.info-title {
font-weight: 600;
font-size: 28rpx;
color: #000000;
}
.info-desirption {
margin-top: 12rpx;
font-weight: 400;
font-size: 28rpx;
color: #495265;
text-align: justified;
}
.title2 {
margin-top: 48rpx;
}
}
.expanded {
max-height: 1000rpx; // 足够显示完整内容
}
.expand {
display: flex;
flex-wrap: nowrap;
white-space: nowrap;
justify-content: center;
margin-top: 20rpx;
margin-bottom: 28rpx;
font-weight: 400;
font-size: 28rpx;
color: #256BFA;
.expand-img {
width: 40rpx;
height: 40rpx;
}
.expand-img-active {
transform: rotate(180deg);
}
}
}
.Detailscroll-view {
flex: 1;
overflow: hidden;
background: #F4F4F4;
.views {
padding: 28rpx;
.Detail-title {
font-weight: 600;
font-size: 32rpx;
color: #000000;
position: relative;
display: flex;
justify-content: space-between;
.title {
position: relative;
z-index: 2;
}
}
.Detail-title::before {
position: absolute;
content: '';
left: -14rpx;
bottom: 0;
height: 16rpx;
width: 108rpx;
background: linear-gradient(to right, #CBDEFF, #FFFFFF);
border-radius: 8rpx;
z-index: 1;
}
.job-card-wrapper {
margin-top: 22rpx;
&:first-child {
margin-top: 0;
}
}
.cards {
padding: 30rpx;
background: #FFFFFF;
box-shadow: 0rpx 2rpx 12rpx 0rpx rgba(0, 0, 0, 0.08);
border-radius: 24rpx;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
&:active {
transform: scale(0.98);
box-shadow: 0rpx 1rpx 8rpx 0rpx rgba(0, 0, 0, 0.12);
}
.card-header {
margin-bottom: 0;
.card-title-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20rpx;
.job-title {
flex: 1;
font-family: 'PingFangSC-Medium', 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, 'Microsoft YaHei', sans-serif;
text-align: left;
word-break: break-all;
font-weight: 500;
font-size: 32rpx;
color: #333333;
}
.card-pay {
flex-shrink: 0;
display: flex;
align-items: center;
.pay-text {
font-family: DIN-Medium;
font-weight: 500;
font-size: 28rpx;
color: #4C6EFB;
line-height: 45rpx;
white-space: nowrap;
.salary-amount {
font-family: DIN-Medium;
font-weight: 500;
font-size: 28rpx;
color: #4C6EFB;
line-height: 45rpx;
}
.salary-unit {
font-weight: 400;
font-size: 20rpx;
color: #4C6EFB;
margin-left: 4rpx;
}
}
}
}
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 10rpx;
margin-top: 20rpx;
margin-bottom: 20rpx;
.tag {
display: flex;
align-items: center;
width: fit-content;
height: 30rpx;
padding: 6rpx 20rpx;
border-radius: 4rpx;
background: #F4F4F4;
font-weight: 400;
font-size: 24rpx;
color: #6C7282;
white-space: nowrap;
line-height: 30rpx;
text-align: center;
.tag-icon {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
flex-shrink: 0;
}
.tag-text {
line-height: 1;
}
}
}
.card-location {
display: flex;
align-items: flex-start;
margin-top: 20rpx;
.location-icon {
width: 28rpx;
height: 28rpx;
margin-right: 4rpx;
margin-top: 0;
flex-shrink: 0;
}
.location-text {
flex: 1;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 25rpx;
word-break: break-all;
}
}
}
}
}
</style>