6 Commits

Author SHA1 Message Date
francis_fh
5f85f6cd2a Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 2026-02-03 18:51:52 +08:00
francis_fh
58a113b34d 公交周边地铁线路不能选择bug修复 2026-02-03 18:51:50 +08:00
xuchao
bfdc358c24 添加预览简历图片功能 2026-02-03 17:25:10 +08:00
francis_fh
78a61ef42a AI页面增加政策查询和岗位推荐的tab 2026-02-03 14:50:56 +08:00
francis_fh
ed7ef9acfe Merge branch 'main' of http://124.243.245.42:3000/sdz/ks-app-employment-service 2026-02-03 13:46:14 +08:00
francis_fh
030183ceb6 最小薪资提示 2026-02-03 13:46:13 +08:00
6 changed files with 214 additions and 13 deletions

View File

@@ -50,9 +50,11 @@
<view class="label">最小薪资 (/)</view> <view class="label">最小薪资 (/)</view>
<input <input
class="input" class="input"
placeholder="请输入最小薪资" placeholder="请输入最小薪资最低2000元"
type="number" type="number"
v-model="formData.minSalary" v-model="formData.minSalary"
@input="handleMinSalaryInput"
@blur="handleMinSalaryBlur"
/> />
</view> </view>
<view class="form-group"> <view class="form-group">
@@ -285,7 +287,7 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'; import { ref, reactive, onMounted, onUnmounted, watch } from 'vue';
import { onShow } from '@dcloudio/uni-app'; import { onShow } from '@dcloudio/uni-app';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { createRequest } from '@/utils/request'; import { createRequest } from '@/utils/request';
@@ -393,6 +395,15 @@ onShow(() => {
getCompanyInfo(); getCompanyInfo();
}); });
// 监听最小薪资变化
watch(() => formData.minSalary, (newValue) => {
console.log('minSalary changed to:', newValue);
if (newValue && parseFloat(newValue) < 2000) {
console.log('setting minSalary to 2000 via watch');
formData.minSalary = '2000';
}
});
// 获取企业信息(参考首页方法) // 获取企业信息(参考首页方法)
const getCompanyInfo = () => { const getCompanyInfo = () => {
try { try {
@@ -704,6 +715,32 @@ const handleCompanySelected = (company) => {
formData.companyId = company.id; formData.companyId = company.id;
}; };
// 处理最小薪资输入
const handleMinSalaryInput = (e) => {
let value = e.detail.value;
if (value && parseFloat(value) < 2000) {
formData.minSalary = '2000';
uni.showToast({
title: '最小薪资最低为2000元',
icon: 'none'
});
}
};
// 处理最小薪资失去焦点
const handleMinSalaryBlur = () => {
console.log('blur event triggered');
console.log('current minSalary:', formData.minSalary);
let value = formData.minSalary;
if (value && parseFloat(value) < 2000) {
console.log('setting minSalary to 2000');
formData.minSalary = '2000';
uni.showToast({
title: '最小薪资最低为2000元',
icon: 'none'
});
}
};
// 发布岗位 // 发布岗位
const publishJob = async () => { const publishJob = async () => {
@@ -824,6 +861,14 @@ const validateForm = () => {
const minSalary = parseFloat(formData.minSalary); const minSalary = parseFloat(formData.minSalary);
const maxSalary = parseFloat(formData.maxSalary); const maxSalary = parseFloat(formData.maxSalary);
if (minSalary < 2000) {
uni.showToast({
title: '最小薪资最低为2000元',
icon: 'none'
});
return false;
}
if (minSalary >= maxSalary) { if (minSalary >= maxSalary) {
uni.showToast({ uni.showToast({
title: '最大薪资必须大于最小薪资', title: '最大薪资必须大于最小薪资',

View File

@@ -110,6 +110,10 @@
</scroll-view> </scroll-view>
<!-- 筛选 --> <!-- 筛选 -->
<select-filter ref="selectFilterModel"></select-filter> <select-filter ref="selectFilterModel"></select-filter>
<!-- #ifdef MP-WEIXIN -->
<selectPopup ref="selectPopupRef"></selectPopup>
<!-- #endif -->
</view> </view>
</template> </template>
@@ -117,7 +121,28 @@
import { reactive, inject, watch, ref, onMounted, onBeforeUnmount } from 'vue'; import { reactive, inject, watch, ref, onMounted, onBeforeUnmount } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app'; import { onLoad, onShow } from '@dcloudio/uni-app';
const { $api, navTo, debounce, customSystem } = inject('globalFunction'); const { $api, navTo, debounce, customSystem } = inject('globalFunction');
const openSelectPopup = inject('openSelectPopup'); // #ifdef H5
const injectedOpenSelectPopup = inject('openSelectPopup', null);
// #endif
// #ifdef MP-WEIXIN
const selectPopupRef = ref();
// #endif
// 创建本地的 openSelectPopup 函数,兼容 H5 和微信小程序
const openSelectPopup = (config) => {
// #ifdef MP-WEIXIN
if (selectPopupRef.value) {
selectPopupRef.value.open(config);
}
// #endif
// #ifdef H5
if (injectedOpenSelectPopup) {
injectedOpenSelectPopup(config);
}
// #endif
};
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import useLocationStore from '@/stores/useLocationStore'; import useLocationStore from '@/stores/useLocationStore';
import useUserStore from '@/stores/useUserStore'; import useUserStore from '@/stores/useUserStore';
@@ -128,6 +153,9 @@ const { longitudeVal, latitudeVal } = storeToRefs(useLocationStore());
import point2 from '@/static/icon/point2.png'; import point2 from '@/static/icon/point2.png';
import LocationPng from '@/static/icon/Location.png'; import LocationPng from '@/static/icon/Location.png';
import selectFilter from '@/components/selectFilter/selectFilter.vue'; import selectFilter from '@/components/selectFilter/selectFilter.vue';
// #ifdef MP-WEIXIN
import selectPopup from '@/components/selectPopup/selectPopup.vue';
// #endif
const emit = defineEmits(['onFilter']); const emit = defineEmits(['onFilter']);
// status // status
const showFiltersubway = ref(false); const showFiltersubway = ref(false);
@@ -205,18 +233,21 @@ function openFilter() {
} }
function openFilterSubway() { function openFilterSubway() {
showFiltersubway.value = true;
const diti = state.subwayList.map((item) => ({ ...item, label: item.lineName, value: item.lineId })); const diti = state.subwayList.map((item) => ({ ...item, label: item.lineName, value: item.lineId }));
openSelectPopup({ openSelectPopup({
title: '地铁', title: '地铁',
maskClick: true, maskClick: true,
data: [diti], data: [diti],
success: (_, [value]) => { success: (_, [value]) => {
showFiltersubway.value = false;
if (!value) return;
subwayCurrent.value = value; subwayCurrent.value = value;
state.subwayId = value.value; state.subwayId = value.value;
state.value = value.value; state.value = value.value;
const points = value.subwayStationList; const points = value.subwayStationList;
state.downup = true; state.downup = true;
if (points.length) { if (points && points.length) {
state.dont = 0; state.dont = 0;
state.dontObj = points[0]; state.dontObj = points[0];
state.subwayStart = points[0]; state.subwayStart = points[0];
@@ -224,6 +255,9 @@ function openFilterSubway() {
getJobList('refresh'); getJobList('refresh');
} }
}, },
cancel: () => {
showFiltersubway.value = false;
},
}); });
} }
@@ -251,8 +285,8 @@ function selectSubwayStation(point, index) {
function inputText(id) { function inputText(id) {
if (id) { if (id) {
const text = range.value.filter((item) => item.value === id)[0].text; const foundItem = range.value.filter((item) => item.value === id)[0];
return text; return foundItem ? foundItem.text : '';
} else { } else {
return ''; return '';
} }
@@ -260,13 +294,15 @@ function inputText(id) {
function bindPickerChange(e) { function bindPickerChange(e) {
const lineId = range.value[e.detail.value]; const lineId = range.value[e.detail.value];
if (!lineId) return;
const value = state.subwayList.filter((iv) => iv.lineId === lineId.value)[0]; const value = state.subwayList.filter((iv) => iv.lineId === lineId.value)[0];
if (!value) return;
subwayCurrent.value = value; subwayCurrent.value = value;
state.value = e.detail.value; state.value = e.detail.value;
state.subwayId = value.lineId; state.subwayId = value.lineId;
const points = value.subwayStationList; const points = value.subwayStationList;
state.downup = true; state.downup = true;
if (points.length) { if (points && points.length) {
state.dont = 0; state.dont = 0;
state.dontObj = points[0]; state.dontObj = points[0];
state.subwayStart = points[0]; state.subwayStart = points[0];

View File

@@ -698,7 +698,7 @@ const changePoliticalAffiliation = () => {
}; };
function generateDatePickerArrays(startYear = 1975, endYear = new Date().getFullYear()) { function generateDatePickerArrays(startYear = 1950, endYear = new Date().getFullYear()) {
const years = []; const years = [];
const months = []; const months = [];
const days = []; const days = [];

View File

@@ -206,6 +206,14 @@
{{detailObj.politicalAffiliation}} {{detailObj.politicalAffiliation}}
</view> </view>
</view> </view>
<view class="flexBox detail-item1" v-if="detailObj.resumePicPath">
<view class="label">简历图片</view>
<view class="value">
<view class="previewResume" @click="previewResume(detailObj.resumePicPath)">
查看简历图片
</view>
</view>
</view>
</view> </view>
<view class="btn-box"> <view class="btn-box">
<button type="default" @click="closeResumeDetailPopup">关闭</button> <button type="default" @click="closeResumeDetailPopup">关闭</button>
@@ -302,6 +310,7 @@
$api $api
} = inject("globalFunction"); } = inject("globalFunction");
const imgBaseUrl = config.imgBaseUrl; const imgBaseUrl = config.imgBaseUrl;
const trainVideoImgUrl = config.trainVideoImgUrl;
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const interviewPopup = ref(null); const interviewPopup = ref(null);
@@ -311,7 +320,15 @@
const jobFairId = ref(""); const jobFairId = ref("");
const userInfo = ref({}); const userInfo = ref({});
const isExpanded = ref(false); const isExpanded = ref(false);
//预览简历照片
const previewResume = (url) => {
if(url){
uni.previewImage({
urls: [trainVideoImgUrl+url],
current: 0
});
}
};
const publicUrl = config.LCBaseUrl; const publicUrl = config.LCBaseUrl;
onLoad((option) => { onLoad((option) => {
jobFairId.value = option.jobFairId; jobFairId.value = option.jobFairId;
@@ -940,6 +957,9 @@
height: 80%; height: 80%;
.flexBox{ .flexBox{
display: flex; display: flex;
.previewResume{
color:#0088ff
}
} }
.detail-item1 { .detail-item1 {
// display: flex; // display: flex;

View File

@@ -1,5 +1,23 @@
<template> <template>
<view class="chat-container"> <view class="chat-container">
<!-- Tab切换 -->
<view class="tab-container">
<view
class="tab-item"
:class="{ active: activeTab === 'policy' }"
@click="switchTab('policy')"
>
政策查询
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'job' }"
@click="switchTab('job')"
>
岗位推荐
</view>
</view>
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<view class="chat-background" v-if="!messages.length"> <view class="chat-background" v-if="!messages.length">
<image class="backlogo" src="/static/icon/backAI.png"></image> <image class="backlogo" src="/static/icon/backAI.png"></image>
@@ -51,6 +69,7 @@
<!-- #endif --> <!-- #endif -->
<view <view
v-for="(msg, index) in messages" v-for="(msg, index) in messages"
v-show="shouldShowMessage(msg)"
:key="index" :key="index"
:id="'msg-' + index" :id="'msg-' + index"
class="chat-item" class="chat-item"
@@ -352,6 +371,7 @@ const { speak, pause, resume, isSpeaking, isPaused, cancelAudio } = useTTSPlayer
const instance = getCurrentInstance(); const instance = getCurrentInstance();
// state // state
const activeTab = ref('policy'); // 'policy' or 'job'
const queries = ref([]); const queries = ref([]);
const guessList = ref([]); const guessList = ref([]);
const scrollTop = ref(0); const scrollTop = ref(0);
@@ -571,11 +591,12 @@ const delfile = (file) => {
const scrollToBottom = throttle(function () { const scrollToBottom = throttle(function () {
nextTick(() => { nextTick(() => {
try { try {
let query;
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
const query = uni.createSelectorQuery().in(instance); query = uni.createSelectorQuery().in(instance);
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
const query = uni.createSelectorQuery(); query = uni.createSelectorQuery();
// #endif // #endif
query.select('.scrollView').boundingClientRect(); query.select('.scrollView').boundingClientRect();
@@ -886,7 +907,42 @@ function getRandomJobQueries(queries, count = 2) {
return shuffled.slice(0, count); // 取前 count 条 return shuffled.slice(0, count); // 取前 count 条
} }
defineExpose({ scrollToBottom, closeGuess, closeFile, changeQueries, handleTouchCancel }); // 切换tab
function switchTab(tab) {
activeTab.value = tab;
}
// 检查消息是否应该显示在当前tab
function shouldShowMessage(msg) {
if (msg.self) {
return true; // 用户自己的消息总是显示
}
if (activeTab.value === 'policy') {
// 政策查询tab显示除了岗位卡片以外的所有内容
// 岗位卡片通常包含特定的标记,如```job-json或岗位推荐等关键词
const isJobCard = msg.displayText && (
msg.displayText.includes('```job-json') ||
msg.displayText.includes('岗位推荐') ||
msg.displayText.includes('推荐岗位') ||
msg.displayText.includes('岗位信息') ||
(msg.displayText.includes('```') && msg.displayText.includes('公司') && msg.displayText.includes('薪资'))
);
return !isJobCard;
} else {
// 岗位推荐tab只显示岗位卡片内容
const isJobCard = msg.displayText && (
msg.displayText.includes('```job-json') ||
msg.displayText.includes('岗位推荐') ||
msg.displayText.includes('推荐岗位') ||
msg.displayText.includes('岗位信息') ||
(msg.displayText.includes('```') && msg.displayText.includes('公司') && msg.displayText.includes('薪资'))
);
return isJobCard;
}
}
defineExpose({ scrollToBottom, closeGuess, closeFile, changeQueries, handleTouchCancel, switchTab });
</script> </script>
<style lang="stylus" scoped> <style lang="stylus" scoped>
@@ -1373,4 +1429,48 @@ image-margin-top = 40rpx
.ai-loading view:nth-child(3) { .ai-loading view:nth-child(3) {
animation-delay: 0s; animation-delay: 0s;
} }
/* Tab切换样式 */
.tab-container {
display: flex;
background: #FFFFFF;
border-bottom: 2rpx solid #F4F4F4;
padding: 0 44rpx;
height: 88rpx;
align-items: center;
z-index: 10;
}
.tab-item {
flex: 1;
text-align: center;
font-size: 28rpx;
font-weight: 500;
color: #666666;
line-height: 88rpx;
height: 88rpx;
position: relative;
transition: all 0.3s ease;
}
.tab-item.active {
color: #256BFA;
font-weight: bold;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: #256BFA;
border-radius: 2rpx;
}
.tab-item:active {
background-color: #F5F5F5;
}
</style> </style>

View File

@@ -680,7 +680,7 @@ const rangeOptions = ref([
{ value: 0, text: '推荐' }, { value: 0, text: '推荐' },
{ value: 1, text: '最热' }, { value: 1, text: '最热' },
{ value: 2, text: '最新发布' }, { value: 2, text: '最新发布' },
{ value: 3, text: '疆外' }, // { value: 3, text: '疆外' },
{ value: 4, text: '零工市场' } { value: 4, text: '零工市场' }
]); ]);
const isLoaded = ref(false); const isLoaded = ref(false);