flat:AI+
This commit is contained in:
BIN
pages/.DS_Store
vendored
Normal file
BIN
pages/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -77,6 +77,7 @@ function getNextMonthDates() {
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed
|
||||
.careerfair-AI
|
||||
height: 42rpx;
|
||||
font-family: Inter, Inter;
|
||||
|
||||
221
pages/chat/chat.vue
Normal file
221
pages/chat/chat.vue
Normal file
@@ -0,0 +1,221 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 抽屉遮罩层 -->
|
||||
<view v-if="isDrawerOpen" class="overlay" @click="toggleDrawer"></view>
|
||||
|
||||
<!-- 抽屉窗口 -->
|
||||
<view class="drawer" :class="{ open: isDrawerOpen }">
|
||||
<view class="drawer-content">
|
||||
<view class="drawer-title">历史对话</view>
|
||||
<scroll-view scroll-y :show-scrollbar="false" class="chat-scroll">
|
||||
<view
|
||||
class="drawer-rows"
|
||||
@click="changeDialogue(item)"
|
||||
v-for="(item, index) in tabeList"
|
||||
:key="item.id"
|
||||
>
|
||||
<view
|
||||
v-if="!item.isTitle"
|
||||
class="drawer-row-list"
|
||||
:class="{ 'drawer-row-active': item.sessionId === chatSessionID }"
|
||||
>
|
||||
{{ item.title }}
|
||||
</view>
|
||||
<view class="drawer-row-title" v-else>
|
||||
{{ item.title }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 主要内容,挤压效果 -->
|
||||
<view class="main-content" :class="{ shift: isDrawerOpen }">
|
||||
<!-- header -->
|
||||
<header class="head">
|
||||
<view class="main-header">
|
||||
<image src="/static/icon/Hamburger-button.png" @click="toggleDrawer"></image>
|
||||
<view class="title">青岛市岗位推荐</view>
|
||||
<image src="/static/icon/Comment-one.png" @click="addNewDialogue"></image>
|
||||
</view>
|
||||
</header>
|
||||
<view class="chatmain-warpper">
|
||||
<ai-paging ref="paging"></ai-paging>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, nextTick } from 'vue';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useChatGroupDBStore from '@/stores/userChatGroupStore';
|
||||
import aiPaging from './components/ai-paging.vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { isTyping, tabeList, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
||||
const isDrawerOpen = ref(false);
|
||||
const scrollIntoView = ref(false);
|
||||
import config from '@/config';
|
||||
|
||||
const paging = ref(null);
|
||||
|
||||
onLoad(() => {
|
||||
// useChatGroupDBStore().getHistory();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
nextTick(() => {
|
||||
paging.value?.colseFile();
|
||||
});
|
||||
});
|
||||
|
||||
const toggleDrawer = () => {
|
||||
isDrawerOpen.value = !isDrawerOpen.value;
|
||||
};
|
||||
|
||||
const addNewDialogue = () => {
|
||||
$api.msg('新对话');
|
||||
useChatGroupDBStore().addNewDialogue();
|
||||
};
|
||||
|
||||
const changeDialogue = (item) => {
|
||||
if (item.sessionId) {
|
||||
paging.value?.closeGuess();
|
||||
useChatGroupDBStore().changeDialogue(item);
|
||||
toggleDrawer();
|
||||
nextTick(() => {
|
||||
paging.value?.scrollToBottom();
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
/* 页面容器 */
|
||||
.container {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 遮罩层 */
|
||||
.overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
/* 抽屉窗口 */
|
||||
.drawer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0; /* 如果要右侧弹出改为 right: 0; */
|
||||
width: 500rpx;
|
||||
height: 100vh;
|
||||
background: #e7e7e6;
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.3s ease-in-out;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
/* 抽屉展开 */
|
||||
.drawer.open {
|
||||
box-shadow: 4rpx 0 20rpx rgba(0, 0, 0, 0.2);
|
||||
transform: translateX(0);
|
||||
|
||||
}
|
||||
|
||||
/* 抽屉内容 */
|
||||
.drawer-content
|
||||
height: 100%
|
||||
.drawer-title
|
||||
height: calc(88rpx + env(safe-area-inset-top));
|
||||
line-height: calc(88rpx + env(safe-area-inset-top));
|
||||
padding: 0 20rpx;
|
||||
background: rgba(71, 120, 236, 1);
|
||||
color: #FFFFFF;
|
||||
font-size: 30rpx
|
||||
.chat-scroll
|
||||
height: calc(100% - 88rpx + env(safe-area-inset-top));
|
||||
.drawer-rows
|
||||
padding: 0 20rpx;
|
||||
// border-bottom: 2rpx dashed #e8e8e8
|
||||
overflow:hidden; //超出的文本隐藏
|
||||
text-overflow:ellipsis; //溢出用省略号显示
|
||||
white-space:nowrap; //溢出不换行
|
||||
.drawer-row-title
|
||||
color: #5d5d5d;
|
||||
font-weight: bold;
|
||||
font-size: 24rpx
|
||||
line-height: 88rpx
|
||||
height: 88rpx
|
||||
margin-top: 16rpx
|
||||
// border-bottom: 2rpx dashed #5d5d5d
|
||||
.drawer-row-list
|
||||
height: 66rpx;
|
||||
line-height: 66rpx
|
||||
color: #000000
|
||||
font-size: 28rpx
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
.drawer-row-active
|
||||
.drawer-row-list:active
|
||||
background: #DCDCDB
|
||||
border-radius: 8rpx
|
||||
padding: 0 10rpx
|
||||
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main-content
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
// background: #f8f8f8;
|
||||
transition: margin-left 0.3s ease-in-out;
|
||||
position: relative
|
||||
background: #FFFFFF
|
||||
.head
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
height: calc(88rpx + env(safe-area-inset-top));
|
||||
user-select: none;
|
||||
.main-header
|
||||
position: fixed;
|
||||
left: var(--window-left);
|
||||
right: var(--window-right);
|
||||
height: calc(88rpx + env(safe-area-inset-top));
|
||||
padding-top: calc(14rpx + env(safe-area-inset-top));
|
||||
border: 2rpx solid #F4F4F4;
|
||||
background: #FFFFFF
|
||||
z-index: 998;
|
||||
transition-property: all;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between
|
||||
font-size: 28rpx
|
||||
color: #000000
|
||||
padding: 0 30rpx;
|
||||
font-weight: bold
|
||||
text-align: center
|
||||
image
|
||||
width: 36rpx;
|
||||
height: 37rpx;
|
||||
|
||||
.chatmain-warpper
|
||||
height: calc(100% - 88rpx - env(safe-area-inset-top));
|
||||
position: relative;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
/* 页面被挤压时向右移动 */
|
||||
.main-content.shift {
|
||||
margin-left: 500rpx;
|
||||
}
|
||||
</style>
|
||||
66
pages/chat/components/AudioWave.vue
Normal file
66
pages/chat/components/AudioWave.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<view class="wave-container" :style="{ background }">
|
||||
<view v-for="(bar, index) in bars" :key="index" class="bar" :style="getBarStyle(index)" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
background: {
|
||||
type: String,
|
||||
default: 'linear-gradient(to right, #377dff, #9a60ff)',
|
||||
},
|
||||
});
|
||||
|
||||
// 默认参数(不暴露)
|
||||
const barCount = 20;
|
||||
const barWidth = 4;
|
||||
const barHeight = 40;
|
||||
const barRadius = 2;
|
||||
const duration = 1200;
|
||||
const gap = 4;
|
||||
|
||||
const bars = computed(() => new Array(barCount).fill(0));
|
||||
|
||||
const getBarStyle = (index) => {
|
||||
const delay = (index * (duration / barCount)) % duration;
|
||||
return {
|
||||
width: `${barWidth}rpx`,
|
||||
height: `${barHeight}rpx`,
|
||||
background: '#fff',
|
||||
borderRadius: `${barRadius}rpx`,
|
||||
animation: `waveAnim ${duration}ms ease-in-out ${delay}ms infinite`,
|
||||
transformOrigin: 'bottom center',
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.wave-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 16rpx;
|
||||
border-radius: 36rpx;
|
||||
height: calc(102rpx - 40rpx);
|
||||
gap: 4rpx;
|
||||
/* background: linear-gradient(90deg, #9e74fd 0%, #256bfa 100%); */
|
||||
box-shadow: 0rpx 8rpx 40rpx 0rpx rgba(0, 54, 170, 0.15);
|
||||
}
|
||||
|
||||
@keyframes waveAnim {
|
||||
0%,
|
||||
100% {
|
||||
transform: scaleY(0.4);
|
||||
}
|
||||
50% {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
.bar {
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
</style>
|
||||
783
pages/chat/components/ai-paging.vue
Normal file
783
pages/chat/components/ai-paging.vue
Normal file
@@ -0,0 +1,783 @@
|
||||
<template>
|
||||
<view class="chat-container">
|
||||
<FadeView :show="!messages.length" :duration="600">
|
||||
<view class="chat-background">
|
||||
<image class="backlogo" src="/static/icon/backAI.png"></image>
|
||||
<view class="back-rowTitle">嗨!欢迎使用青岛AI智能求职</view>
|
||||
<view class="back-rowText">
|
||||
我可以根据您的简历和求职需求,帮你精准匹配青岛市互联网招聘信息,对比招聘信息的优缺点,提供面试指导等,请把你的任务交给我吧~
|
||||
</view>
|
||||
<view class="back-rowh3">猜你所想</view>
|
||||
<view class="back-rowmsg">我希望找青岛的IT行业岗位,薪资能否在12000以上?</view>
|
||||
<view class="back-rowmsg">我有三年的工作经验,能否推荐一些适合我的青岛的国企 岗位?</view>
|
||||
</view>
|
||||
</FadeView>
|
||||
<scroll-view class="chat-list scrollView" :scroll-top="scrollTop" :scroll-y="true" scroll-with-animation>
|
||||
<FadeView :show="messages.length" :duration="600">
|
||||
<view class="chat-list list-content">
|
||||
<view
|
||||
v-for="(msg, index) in messages"
|
||||
:key="index"
|
||||
:id="'msg-' + index"
|
||||
class="chat-item"
|
||||
:class="{ self: msg.self }"
|
||||
>
|
||||
<text class="message" v-if="msg.self">
|
||||
<view class="msg-filecontent" v-if="msg.files.length">
|
||||
<view
|
||||
class="msg-files"
|
||||
v-for="(file, vInex) in msg.files"
|
||||
:key="vInex"
|
||||
@click="jumpUrl(file)"
|
||||
>
|
||||
<image class="msg-file-icon" src="/static/icon/Vector2.png"></image>
|
||||
<text class="msg-file-text">{{ file.name || '附件' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
{{ msg.displayText }}
|
||||
</text>
|
||||
<text class="message" :class="{ messageNull: !msg.displayText }" v-else>
|
||||
<!-- {{ msg.displayText }} -->
|
||||
<md-render :content="msg.displayText"></md-render>
|
||||
<!-- guess -->
|
||||
<view
|
||||
class="guess"
|
||||
v-if="showGuess && !msg.self && messages.length - 1 === index && msg.displayText"
|
||||
>
|
||||
<view class="guess-top">
|
||||
<image class="guess-icon" src="/static/icon/tips2.png" mode=""></image>
|
||||
猜你所想
|
||||
</view>
|
||||
<view class="gulist">
|
||||
<view
|
||||
class="guess-list"
|
||||
@click="sendMessageGuess(item)"
|
||||
v-for="(item, index) in guessList"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</text>
|
||||
</view>
|
||||
<view v-if="isTyping" :class="{ self: true }">
|
||||
<text class="message msg-loading">
|
||||
<span class="ai-loading"></span>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</FadeView>
|
||||
</scroll-view>
|
||||
<view class="vio_container" :class="status" v-if="status !== 'idle'">
|
||||
<view class="record-tip">{{ statusText }}</view>
|
||||
<AudioWave :background="audiowaveStyle" />
|
||||
</view>
|
||||
<view class="input-area" v-else>
|
||||
<view class="areatext">
|
||||
<input
|
||||
v-model="textInput"
|
||||
placeholder-class="inputplaceholder"
|
||||
class="input"
|
||||
@confirm="sendMessage"
|
||||
:disabled="isTyping"
|
||||
:adjust-position="false"
|
||||
placeholder="请输入您的职位名称、薪资要求、岗位地址"
|
||||
v-if="!isVoice"
|
||||
/>
|
||||
<view
|
||||
class="input_vio"
|
||||
@touchstart="handleTouchStart"
|
||||
@touchmove="handleTouchMove"
|
||||
@touchend="handleTouchEnd"
|
||||
@touchcancel="handleTouchCancel"
|
||||
type="default"
|
||||
v-else
|
||||
>
|
||||
按住说话
|
||||
</view>
|
||||
<!-- upload -->
|
||||
<view class="btn-box" @click="changeShowFile">
|
||||
<image
|
||||
class="send-btn"
|
||||
:class="{ 'add-file-btn': showfile }"
|
||||
src="/static/icon/addGroup.png"
|
||||
></image>
|
||||
</view>
|
||||
|
||||
<!-- sendmessgae Button-->
|
||||
<view class="btn-box purple" v-if="textInput && !isTyping" @click="sendMessage">
|
||||
<image class="send-btn" src="/static/icon/send3.png"></image>
|
||||
</view>
|
||||
<view class="btn-box" v-else-if="!isTyping && !isVoice" @click="changeVoice">
|
||||
<image class="send-btn" src="/static/icon/send2x.png"></image>
|
||||
</view>
|
||||
<view class="btn-box" v-else-if="!isTyping" @click="changeVoice">
|
||||
<image class="send-btn" src="/static/icon/send4.png"></image>
|
||||
</view>
|
||||
<view class="btn-box" v-else>
|
||||
<image class="send-btn" src="/static/icon/send2xx.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- btn -->
|
||||
<CollapseTransition :show="showfile">
|
||||
<view class="area-file">
|
||||
<image class="file-img" @click="uploadCamera" src="/static/icon/carmreupload.png"></image>
|
||||
<image class="file-img" @click="getUploadFile" src="/static/icon/fileupload.png"></image>
|
||||
<image class="file-img" @click="uploadCamera('album')" src="/static/icon/imgupload.png"></image>
|
||||
</view>
|
||||
</CollapseTransition>
|
||||
|
||||
<!-- filelist -->
|
||||
<view class="area-uploadfiles" v-if="filesList.length">
|
||||
<scroll-view class="uploadfiles-scroll" scroll-x="true">
|
||||
<view class="uploadfiles-list">
|
||||
<view class="file-uploadsend" v-for="(file, index) in filesList" :key="index">
|
||||
<image
|
||||
class="file-icon"
|
||||
@click="jumpUrl(file)"
|
||||
v-if="isImage(file.type)"
|
||||
src="/static/icon/image.png"
|
||||
></image>
|
||||
<image
|
||||
class="file-icon"
|
||||
@click="jumpUrl(file)"
|
||||
v-if="isFile(file.type)"
|
||||
src="/static/icon/doc.png"
|
||||
></image>
|
||||
<text class="filename-text">{{ file.name }}</text>
|
||||
<view class="file-del" catchtouchmove="true" @click="delfile(file)">
|
||||
<uni-icons type="closeempty" color="#4B4B4B" size="10"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, inject, nextTick, defineProps, defineEmits, onMounted, toRaw, reactive, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import config from '@/config.js';
|
||||
import useChatGroupDBStore from '@/stores/userChatGroupStore';
|
||||
const { $api, navTo, throttle } = inject('globalFunction');
|
||||
const emit = defineEmits(['onConfirm']);
|
||||
import MdRender from '@/components/md-render/md-render.vue';
|
||||
const { messages, isTyping, textInput, chatSessionID } = storeToRefs(useChatGroupDBStore());
|
||||
import CollapseTransition from '@/components/CollapseTransition/CollapseTransition.vue';
|
||||
import FadeView from '@/components/FadeView/FadeView.vue';
|
||||
import AudioWave from './AudioWave.vue';
|
||||
import { useAudioRecorder } from '@/hook/useRealtimeRecorder.js';
|
||||
|
||||
const { isRecording, recognizedText, startRecording, stopRecording, cancelRecording } = useAudioRecorder(
|
||||
config.vioceBaseURl
|
||||
);
|
||||
|
||||
const guessList = ref([]);
|
||||
const scrollTop = ref(0);
|
||||
const showGuess = ref(false);
|
||||
const showfile = ref(false);
|
||||
const filesList = ref([]);
|
||||
const bgText = ref(false);
|
||||
const isVoice = ref(false);
|
||||
const status = ref('idle'); // idle | recording | cancel
|
||||
const startY = ref(0);
|
||||
const cancelThreshold = 100;
|
||||
let recordingTimer = null;
|
||||
|
||||
const state = reactive({
|
||||
uploadFileTips: '请根据以上附件,帮我推荐岗位。',
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
scrollToBottom();
|
||||
});
|
||||
|
||||
const sendMessage = () => {
|
||||
const values = textInput.value;
|
||||
showfile.value = false;
|
||||
showGuess.value = false;
|
||||
if (values.trim()) {
|
||||
// 判断是否有对话ID // 没有则创建对话列表
|
||||
const callback = () => {
|
||||
const normalArr = toRaw(filesList.value); // 转换为普通数组
|
||||
filesList.value = [];
|
||||
const newMsg = { text: values, self: true, displayText: values, files: normalArr };
|
||||
useChatGroupDBStore().addMessage(newMsg);
|
||||
useChatGroupDBStore()
|
||||
.getStearm(values, normalArr, scrollToBottom)
|
||||
.then(() => {
|
||||
console.log(messages);
|
||||
getGuess();
|
||||
scrollToBottom();
|
||||
});
|
||||
emit('onConfirm', values);
|
||||
textInput.value = '';
|
||||
scrollToBottom();
|
||||
};
|
||||
// 没有对话列表则创建
|
||||
if (!chatSessionID.value) {
|
||||
useChatGroupDBStore()
|
||||
.addTabel(values)
|
||||
.then((res) => {
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
if (filesList.value.length) {
|
||||
$api.msg('上传文件请输入想问的问题描述');
|
||||
} else {
|
||||
$api.msg('请输入职位信息或描述');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessageGuess = (item) => {
|
||||
showGuess.value = false;
|
||||
textInput.value = item;
|
||||
sendMessage(item);
|
||||
};
|
||||
|
||||
const delfile = (file) => {
|
||||
uni.showModal({
|
||||
content: '确认删除文件?',
|
||||
success() {
|
||||
filesList.value = filesList.value.filter((item) => item.url !== file.url);
|
||||
if (!filesList.value.length) {
|
||||
if (textInput.value === state.uploadFileTips) {
|
||||
textInput.value = '';
|
||||
}
|
||||
}
|
||||
$api.msg('附件删除成功');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const scrollToBottom = throttle(function () {
|
||||
nextTick(() => {
|
||||
try {
|
||||
setTimeout(() => {
|
||||
const query = uni.createSelectorQuery();
|
||||
query.select('.scrollView').boundingClientRect();
|
||||
query.select('.list-content').boundingClientRect();
|
||||
query.exec((res) => {
|
||||
const scrollViewHeight = res[0].height;
|
||||
const scrollContentHeight = res[1].height;
|
||||
if (scrollContentHeight > scrollViewHeight) {
|
||||
const scrolldistance = scrollContentHeight - scrollViewHeight;
|
||||
scrollTop.value = scrolldistance;
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
}
|
||||
});
|
||||
}, 500);
|
||||
|
||||
function getGuess() {
|
||||
$api.chatRequest('/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
|
||||
guessList.value = res.data;
|
||||
showGuess.value = true;
|
||||
nextTick(() => {
|
||||
scrollToBottom();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function isImage(fileNmae) {
|
||||
return new RegExp('image').test(fileNmae);
|
||||
}
|
||||
|
||||
function isFile(fileNmae) {
|
||||
return new RegExp('custom-doc').test(fileNmae);
|
||||
}
|
||||
|
||||
function jumpUrl(file) {
|
||||
if (file.url) {
|
||||
window.open(file.url);
|
||||
} else {
|
||||
$api.msg('文件地址丢失');
|
||||
}
|
||||
}
|
||||
|
||||
function VerifyNumberFiles(num) {
|
||||
if (filesList.value.length >= config.allowedFileNumber) {
|
||||
$api.msg(`最大上传文件数量 ${config.allowedFileNumber} 个`);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function uploadCamera(type = 'camera') {
|
||||
if (VerifyNumberFiles()) return;
|
||||
uni.chooseImage({
|
||||
count: 1, //默认9
|
||||
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
|
||||
sourceType: [type], //从相册选择
|
||||
success: function (res) {
|
||||
const tempFilePaths = res.tempFilePaths;
|
||||
const file = res.tempFiles[0];
|
||||
// 继续上传
|
||||
$api.uploadFile(tempFilePaths[0], true).then((resData) => {
|
||||
resData = JSON.parse(resData);
|
||||
if (isImage(file.type)) {
|
||||
filesList.value.push({
|
||||
url: resData.msg,
|
||||
type: file.type,
|
||||
name: file.name,
|
||||
});
|
||||
textInput.value = state.uploadFileTips;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function getUploadFile(type = 'camera') {
|
||||
if (VerifyNumberFiles()) return;
|
||||
uni.chooseFile({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
const tempFilePaths = res.tempFilePaths;
|
||||
const file = res.tempFiles[0];
|
||||
const allowedTypes = config.allowedFileTypes || [];
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
return $api.msg('仅支持 txt md html word pdf ppt csv excel 格式类型');
|
||||
}
|
||||
// 继续上传
|
||||
$api.uploadFile(tempFilePaths[0], true).then((resData) => {
|
||||
resData = JSON.parse(resData);
|
||||
filesList.value.push({
|
||||
url: resData.msg,
|
||||
type: 'custom-doc',
|
||||
name: file.name,
|
||||
});
|
||||
textInput.value = state.uploadFileTips;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const handleTouchStart = (e) => {
|
||||
startY.value = e.touches[0].clientY;
|
||||
status.value = 'recording';
|
||||
showfile.value = false;
|
||||
startRecording();
|
||||
};
|
||||
|
||||
const handleTouchMove = (e) => {
|
||||
const moveY = e.touches[0].clientY;
|
||||
if (startY.value - moveY > cancelThreshold) {
|
||||
status.value = 'cancel';
|
||||
} else {
|
||||
status.value = 'recording';
|
||||
}
|
||||
};
|
||||
|
||||
const handleTouchEnd = () => {
|
||||
if (status.value === 'cancel') {
|
||||
console.log('取消发送');
|
||||
cancelRecording();
|
||||
} else {
|
||||
stopRecording();
|
||||
console.log('发送语音');
|
||||
}
|
||||
status.value = 'idle';
|
||||
};
|
||||
|
||||
const handleTouchCancel = () => {
|
||||
stopRecording();
|
||||
status.value = 'idle';
|
||||
};
|
||||
|
||||
const statusText = computed(() => {
|
||||
switch (status.value) {
|
||||
case 'recording':
|
||||
return '松手发送,上划取消';
|
||||
case 'cancel':
|
||||
return '松手取消';
|
||||
default:
|
||||
return '按住说话';
|
||||
}
|
||||
});
|
||||
|
||||
const audiowaveStyle = computed(() => {
|
||||
return status.value === 'cancel'
|
||||
? '#f54545'
|
||||
: status.value === 'recording'
|
||||
? 'linear-gradient(to right, #377dff, #9a60ff)'
|
||||
: '#f1f1f1';
|
||||
});
|
||||
|
||||
function closeGuess() {
|
||||
showGuess.value = false;
|
||||
}
|
||||
|
||||
function changeVoice() {
|
||||
isVoice.value = !isVoice.value;
|
||||
}
|
||||
|
||||
function changeShowFile() {
|
||||
showfile.value = !showfile.value;
|
||||
}
|
||||
|
||||
function colseFile() {
|
||||
showfile.value = false;
|
||||
}
|
||||
defineExpose({ scrollToBottom, closeGuess, colseFile });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
/* 过渡样式 */
|
||||
.collapse-enter-active,
|
||||
.collapse-leave-active {
|
||||
transition: max-height 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.collapse-enter-from,
|
||||
.collapse-leave-to {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.collapse-enter-to,
|
||||
.collapse-leave-from {
|
||||
max-height: 400rpx; /* 根据你内容最大高度设定 */
|
||||
opacity: 1;
|
||||
}
|
||||
.msg-filecontent
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
.msg-files
|
||||
overflow: hidden
|
||||
margin-right: 10rpx
|
||||
height: 30rpx
|
||||
max-width: 201rpx
|
||||
background: #FFFFFF
|
||||
border-radius: 10rpx
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: flex-start
|
||||
padding: 10rpx
|
||||
color: #000000
|
||||
margin-bottom: 10rpx
|
||||
.msg-file-icon
|
||||
width: 29rpx
|
||||
height: 26rpx
|
||||
padding-right: 10rpx
|
||||
.msg-file-text
|
||||
flex: 1
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
color: rgba(96, 96, 96, 1)
|
||||
font-size: 24rpx
|
||||
.msg-files:active
|
||||
background: #e9e9e9
|
||||
.guess
|
||||
border-top: 2rpx solid #8c8c8c
|
||||
padding: 20rpx 0 10rpx 0
|
||||
.guess-top
|
||||
padding: 0 0 10rpx 0
|
||||
display: flex
|
||||
align-items: center
|
||||
color: rgba(255, 173, 71, 1)
|
||||
font-size: 28rpx
|
||||
.guess-icon
|
||||
width: 43rpx
|
||||
height: 43rpx
|
||||
.guess-list
|
||||
border: 2rpx solid #8c8c8c
|
||||
padding: 6rpx 12rpx
|
||||
border-radius: 10rpx;
|
||||
width: fit-content
|
||||
margin: 0 10rpx 10rpx 0
|
||||
font-size: 24rpx
|
||||
color: #8c8c8c
|
||||
.gulist
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
position: relative
|
||||
image-margin-top = 40rpx
|
||||
.chat-container
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: calc(100% - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
position: relative
|
||||
z-index: 1
|
||||
background: #FFFFFF
|
||||
|
||||
.chat-background
|
||||
position: absolute
|
||||
padding: 44rpx;
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: flex-start
|
||||
align-items: center
|
||||
.backlogo
|
||||
width: 313rpx;
|
||||
height: 190rpx;
|
||||
.back-rowTitle
|
||||
width: 100%;
|
||||
height: 56rpx;
|
||||
font-weight: bold;
|
||||
font-size: 40rpx;
|
||||
color: #333333;
|
||||
line-height: 47rpx;
|
||||
margin-top: 40rpx
|
||||
.back-rowText
|
||||
margin-top: 28rpx
|
||||
width: 100%;
|
||||
height: 144rpx;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
border-bottom: 2rpx dashed rgba(0, 0, 0, 0.2);
|
||||
.back-rowh3
|
||||
width: 100%;
|
||||
height: 30rpx;
|
||||
font-weight: 500;
|
||||
font-size: 22rpx;
|
||||
color: #000000;
|
||||
margin-top: 24rpx
|
||||
.back-rowmsg
|
||||
width: 630rpx
|
||||
margin-top: 20rpx
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
line-height: 28rpx;
|
||||
font-size: 24rpx
|
||||
background: #F6F6F6;
|
||||
border-radius: 8rpx 8rpx 8rpx 8rpx;
|
||||
padding: 32rpx 18rpx;
|
||||
|
||||
.chat-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.list-content {
|
||||
padding: 0 44rpx 44rpx 44rpx;
|
||||
}
|
||||
.chat-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.chat-item.self {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.message {
|
||||
margin-top: 40rpx
|
||||
padding: 20rpx 20rpx 0 20rpx;
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: #F6F6F6;
|
||||
// max-width: 80%;
|
||||
word-break: break-word;
|
||||
color: #333333;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
}
|
||||
.messageNull
|
||||
background: transparent;
|
||||
.msg-loading{
|
||||
background: transparent;
|
||||
font-size: 24rpx;
|
||||
color: #8f8d8e;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.loaded{
|
||||
padding-left: 20rpx
|
||||
}
|
||||
.chat-item.self .message {
|
||||
background: linear-gradient( 225deg, #DAE2FE 0%, #E9E3FF 100%);
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
.input-area {
|
||||
padding: 32rpx;
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
|
||||
transition: height 2s ease-in-out;
|
||||
}
|
||||
.input-area::after
|
||||
position: absolute
|
||||
content: ''
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
z-index: 1
|
||||
box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
|
||||
.areatext{
|
||||
display: flex;
|
||||
}
|
||||
.input {
|
||||
flex: 1;
|
||||
border-radius: 5rpx;
|
||||
min-height: 63rpx;
|
||||
line-height: 63rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
position: relative
|
||||
background: #F5F5F5;
|
||||
border-radius: 60rpx 60rpx 60rpx 60rpx;
|
||||
}
|
||||
.input_vio
|
||||
flex: 1;
|
||||
border-radius: 5rpx;
|
||||
min-height: 63rpx;
|
||||
line-height: 63rpx;
|
||||
padding: 4rpx 24rpx;
|
||||
// position: relative
|
||||
border-radius: 60rpx 60rpx 60rpx 60rpx;
|
||||
font-size: 28rpx
|
||||
color: #333333
|
||||
background: #F5F5F5;
|
||||
text-align: center
|
||||
font-size: 28rpx
|
||||
font-weight: 500
|
||||
-webkit-touch-callout:none;
|
||||
-webkit-user-select:none;
|
||||
-khtml-user-select:none;
|
||||
-moz-user-select:none;
|
||||
-ms-user-select:none;
|
||||
user-select:none;
|
||||
.input_vio:active
|
||||
background: #e8e8e8
|
||||
.vio_container
|
||||
background: transparent
|
||||
padding: 28rpx
|
||||
text-align: center
|
||||
.record-tip
|
||||
font-weight: 400;
|
||||
color: #909090;
|
||||
text-align: center;
|
||||
padding-bottom: 16rpx
|
||||
|
||||
|
||||
.inputplaceholder {
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #000000;
|
||||
line-height: 28rpx;
|
||||
opacity: 0.4
|
||||
}
|
||||
.btn-box
|
||||
margin-left: 12rpx;
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
border-radius: 50%
|
||||
background: #F5F5F5;
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
.send-btn,
|
||||
.receive-btn
|
||||
transition: transform 0.5s ease;
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
.purple
|
||||
background: linear-gradient( 225deg, #9E74FD 0%, #256BFA 100%);
|
||||
.add-file-btn{
|
||||
transform: rotate(45deg)
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
.area-file
|
||||
display: grid
|
||||
width: 100%
|
||||
grid-template-columns: repeat(3, 1fr)
|
||||
grid-gap: 20rpx
|
||||
padding: 20rpx 0 0 0;
|
||||
.file-img
|
||||
height: 179rpx
|
||||
width: 100%
|
||||
.area-uploadfiles
|
||||
position: absolute
|
||||
top: -100rpx
|
||||
width: calc(100% - 40rpx)
|
||||
background: #FFFFFF
|
||||
left: 0
|
||||
padding: 10rpx 20rpx
|
||||
box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
|
||||
.uploadfiles-scroll
|
||||
height: 100%
|
||||
.uploadfiles-list
|
||||
height: 100%
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
.file-uploadsend
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
justify-content: center
|
||||
align-items: center
|
||||
margin: 10rpx 18rpx 0 10rpx;
|
||||
height: 100%
|
||||
border-radius: 30rpx
|
||||
font-size: 24rpx
|
||||
position: relative
|
||||
width: 218rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
border: 2rpx solid #E2E2E2;
|
||||
.file-del
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 0
|
||||
z-index: 9
|
||||
border-radius: 50%
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
transform: translate(50%, -10rpx)
|
||||
height: 40rpx
|
||||
width: 23rpx;
|
||||
height: 23rpx;
|
||||
background: #FFFFFF;
|
||||
border: 2rpx solid #E2E2E2;
|
||||
.file-del:active
|
||||
background: #e8e8e8
|
||||
.filename-text
|
||||
overflow: hidden
|
||||
text-overflow: ellipsis
|
||||
white-space: nowrap
|
||||
color: #333333
|
||||
flex: 1
|
||||
font-weight: 500
|
||||
max-width: 100%
|
||||
.file-icon
|
||||
height: 40rpx
|
||||
width: 40rpx
|
||||
margin: 0 18rpx 0 18rpx
|
||||
|
||||
@keyframes ai-circle {
|
||||
0% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.ai-loading
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
background: 0 0;
|
||||
border-radius: 50%;
|
||||
border: 4rpx solid;
|
||||
border-color: #e5e5e5 #e5e5e5 #e5e5e5 #8f8d8e;
|
||||
-webkit-animation: ai-circle 1s linear infinite;
|
||||
animation: ai-circle 1s linear infinite;
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="app-containers">
|
||||
<view class="app-container">
|
||||
<view class="index-AI">AI+就业服务程序</view>
|
||||
<view class="index-option">
|
||||
<view class="option-left">
|
||||
@@ -8,126 +8,401 @@
|
||||
<view class="left-item">职业图谱</view>
|
||||
</view>
|
||||
<view class="option-right">
|
||||
<input class="uni-input right-input" confirm-type="search" />
|
||||
<uni-icons class="iconsearch" color="#FFFFFF" type="search" size="20"></uni-icons>
|
||||
<input
|
||||
class="uni-input right-input"
|
||||
adjust-position="false"
|
||||
confirm-type="search"
|
||||
v-model="inputText"
|
||||
@confirm="searchJobTitle"
|
||||
/>
|
||||
<uni-icons
|
||||
class="iconsearch"
|
||||
color="#FFFFFF"
|
||||
type="search"
|
||||
size="20"
|
||||
@click="searchJobTitle"
|
||||
></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<!-- tab -->
|
||||
<view class="tab-options">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<view class="tab-op-left">
|
||||
<view class="tab-list" v-for="(item, index) in 4" :key="index">中国万岁</view>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === 'all' }"
|
||||
@click="choosePosition('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === index }"
|
||||
v-for="(item, index) in userInfo.jobTitle"
|
||||
:key="index"
|
||||
@click="choosePosition(index)"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-op-right">
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view class="tab-recommend">推荐</view>
|
||||
<view class="tab-filter">
|
||||
<view class="tab-number">1000+</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20" @click="editojobs"></uni-icons>
|
||||
<view class="tab-recommend">
|
||||
<latestHotestStatus @confirm="handelHostestSearch"></latestHotestStatus>
|
||||
</view>
|
||||
<view class="tab-filter" @click="showFilter = true">
|
||||
<view class="tab-number" v-show="pageState.total">{{ formatTotal(pageState.total) }}</view>
|
||||
<image class="image" src="/static/icon/filter.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- waterfalls -->
|
||||
<scroll-view :scroll-y="true" class="falls-scroll">
|
||||
<scroll-view :scroll-y="true" class="falls-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="falls">
|
||||
<custom-waterfalls-flow ref="waterfallsFlowRef" :value="state.list">
|
||||
<template v-slot:default="item">
|
||||
<view class="item">
|
||||
<view class="falls-card" @click="navTo('/packageA/pages/post/post')">
|
||||
<view class="falls-card-title">销售工程师</view>
|
||||
<view class="falls-card-pay">1万-2万/月</view>
|
||||
<view class="falls-card-education">本科</view>
|
||||
<view class="falls-card-experience">3-5年</view>
|
||||
<view class="falls-card-company">德阳人社</view>
|
||||
<view class="falls-card-company">青岛 青岛经济技术开发区</view>
|
||||
<custom-waterfalls-flow ref="waterfallsFlowRef" :value="list">
|
||||
<template v-slot:default="job">
|
||||
<view class="item" v-if="!job.recommend">
|
||||
<view class="falls-card" @click="nextDetail(job)">
|
||||
<view class="falls-card-title">{{ job.jobTitle }}</view>
|
||||
<view class="falls-card-pay">
|
||||
<view class="pay-text">
|
||||
<Salary-Expectation
|
||||
:max-salary="job.maxSalary"
|
||||
:min-salary="job.minSalary"
|
||||
:is-month="true"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
<image v-if="job.isHot" class="flame" src="/static/icon/flame.png"></image>
|
||||
</view>
|
||||
|
||||
<view class="falls-card-education" v-if="job.education">
|
||||
<dict-Label dictType="education" :value="job.education"></dict-Label>
|
||||
</view>
|
||||
<view class="falls-card-experience" v-if="job.experience">
|
||||
<dict-Label dictType="experience" :value="job.experience"></dict-Label>
|
||||
</view>
|
||||
<view class="falls-card-company">{{ job.companyName }}</view>
|
||||
<view class="falls-card-company">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="job.jobLocationAreaCode"></dict-Label>
|
||||
</view>
|
||||
<view class="falls-card-pepleNumber">
|
||||
<view>2024.1.8</view>
|
||||
<view>8人</view>
|
||||
<view>{{ job.postingDate || '发布日期' }}</view>
|
||||
<view>{{ vacanciesTo(job.vacancies) }}</view>
|
||||
</view>
|
||||
<view class="falls-card-matchingrate">
|
||||
<view class="">匹配度95%</view>
|
||||
<view class=""><matchingDegree :job="job"></matchingDegree></view>
|
||||
<uni-icons type="star" size="30"></uni-icons>
|
||||
<uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons>
|
||||
<!-- <uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item" v-else>
|
||||
<view class="recommend-card">
|
||||
<view class="card-content">
|
||||
<view class="recommend-card-title">在找「{{ job.jobCategory }}」工作吗?</view>
|
||||
<view class="recommend-card-tip">{{ job.tip }}</view>
|
||||
<view class="recommend-card-controll">
|
||||
<view class="controll-yes" @click="findJob(job)">是的</view>
|
||||
<view class="controll-no">不是</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</custom-waterfalls-flow>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<screeningJobRequirementsVue
|
||||
v-model:show="showFilter"
|
||||
@confirm="handleFilterConfirm"
|
||||
></screeningJobRequirementsVue>
|
||||
<!-- 岗位推荐组件 -->
|
||||
<modify-expected-position-vue v-model:show="showModel" :jobList="jobList" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import img from '/static/icon/filter.png';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { reactive, inject, watch, ref, onMounted, getCurrentInstance } from 'vue';
|
||||
import img from '@/static/icon/filter.png';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
const { $api, navTo, vacanciesTo, formatTotal } = inject('globalFunction');
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '../../stores/useUserStore';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
const userStore = useUserStore();
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { userInfo } = storeToRefs(useUserStore());
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { getTransformChildren } = useDictStore();
|
||||
import screeningJobRequirementsVue from '@/components/screening-job-requirements/screening-job-requirements.vue';
|
||||
import modifyExpectedPositionVue from '@/components/modifyExpectedPosition/modifyExpectedPosition.vue';
|
||||
import { useRecommedIndexedDBStore, jobRecommender } from '@/stores/useRecommedIndexedDBStore.js';
|
||||
const recommedIndexDb = useRecommedIndexedDBStore();
|
||||
const waterfallsFlowRef = ref(null);
|
||||
const loadmoreRef = ref(null);
|
||||
const state = reactive({
|
||||
title: '123123123房贷首付打的手机家里好玩的很浓厚第卡后sdhiwohdijasnbdhoui1很努力',
|
||||
list: [
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
{
|
||||
image: img,
|
||||
hide: true,
|
||||
},
|
||||
],
|
||||
tabIndex: 'all',
|
||||
search: '',
|
||||
});
|
||||
onShow(() => {
|
||||
console.log('onShow');
|
||||
const list = ref([]);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const inputText = ref('');
|
||||
const showFilter = ref(false);
|
||||
const showModel = ref(false);
|
||||
const jobList = ref([
|
||||
{ name: '销售顾问', highlight: true },
|
||||
{ name: '销售管理', highlight: true },
|
||||
{ name: '销售工程师', highlight: true },
|
||||
{ name: '算法工程师', highlight: false },
|
||||
{ name: '生产经理', highlight: false },
|
||||
{ name: '市场策划', highlight: false },
|
||||
{ name: '商务服务', highlight: false },
|
||||
{ name: '客服', highlight: false },
|
||||
{ name: '创意总监', highlight: false },
|
||||
]);
|
||||
|
||||
onLoad(() => {
|
||||
console.log('onLoad');
|
||||
// $api.sleep(2000).then(() => {
|
||||
// navTo('/pages/login/login');
|
||||
// });
|
||||
getJobRecommend('refresh');
|
||||
});
|
||||
|
||||
watch(
|
||||
() => state.title,
|
||||
(newValue, oldValue) => {},
|
||||
{ deep: true }
|
||||
);
|
||||
function nextDetail(job) {
|
||||
// 记录岗位类型,用作数据分析
|
||||
if (job.jobCategory) {
|
||||
const recordData = recommedIndexDb.JobParameter(job);
|
||||
recommedIndexDb.addRecord(recordData);
|
||||
}
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(job.jobId)}`);
|
||||
}
|
||||
|
||||
function handleModelConfirm(val) {
|
||||
console.log(val);
|
||||
}
|
||||
|
||||
function findJob(item) {
|
||||
console.log(item);
|
||||
}
|
||||
|
||||
function handleFilterConfirm(val) {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
for (const [key, value] of Object.entries(val)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
loadmoreRef.value.change('loading');
|
||||
if (state.tabIndex === 'all') {
|
||||
getJobRecommend();
|
||||
} else {
|
||||
getJobList();
|
||||
}
|
||||
}
|
||||
|
||||
function editojobs() {
|
||||
console.log('jobs');
|
||||
showModel.value = true;
|
||||
}
|
||||
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
list.value = [];
|
||||
if (index === 'all') {
|
||||
pageState.search = {};
|
||||
inputText.value = '';
|
||||
getJobRecommend('refresh');
|
||||
} else {
|
||||
// const id = useUserStore().userInfo.jobTitleId.split(',')[index];
|
||||
pageState.search.jobTitle = useUserStore().userInfo.jobTitle[index];
|
||||
inputText.value = '';
|
||||
getJobList('refresh');
|
||||
}
|
||||
}
|
||||
|
||||
function searchJobTitle() {
|
||||
state.tabIndex = '-1';
|
||||
pageState.search = {
|
||||
jobTitle: inputText.value,
|
||||
};
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function changeRecommend() {}
|
||||
|
||||
function changeLatestHotestStatus(e) {}
|
||||
|
||||
function getJobRecommend(type = 'add') {
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
if (waterfallsFlowRef.value) waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
let params = {
|
||||
pageSize: pageState.pageSize,
|
||||
sessionId: useUserStore().seesionId,
|
||||
...pageState.search,
|
||||
};
|
||||
let comd = { recommend: true, jobCategory: '', tip: '确认你的兴趣,为您推荐更多合适的岗位' };
|
||||
$api.createRequest('/app/job/recommend', params).then((resData) => {
|
||||
const { data, total } = resData;
|
||||
pageState.total = 0;
|
||||
if (type === 'add') {
|
||||
// 记录系统
|
||||
recommedIndexDb.getRecord().then((res) => {
|
||||
if (res.length) {
|
||||
// 数据分析系统
|
||||
const resultData = recommedIndexDb.analyzer(res);
|
||||
const { sort, result } = resultData;
|
||||
// 岗位询问系统
|
||||
const conditionCounts = Object.fromEntries(
|
||||
sort.filter((item) => item[1] > 1) // 过滤掉次数为 1 的项
|
||||
);
|
||||
jobRecommender.updateConditions(conditionCounts);
|
||||
|
||||
const question = jobRecommender.getNextQuestion();
|
||||
if (question) {
|
||||
comd.jobCategory = question;
|
||||
data.unshift(comd);
|
||||
}
|
||||
}
|
||||
const reslist = dataToImg(data);
|
||||
list.value.push(...reslist);
|
||||
});
|
||||
} else {
|
||||
list.value = dataToImg(data);
|
||||
}
|
||||
// 切换状态
|
||||
if (data.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
// 当没有岗位,刷新sessionId重新啦
|
||||
if (!data.length) {
|
||||
useUserStore().initSeesionId();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
list.value = [];
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
waterfallsFlowRef.value.refresh();
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
...pageState.search,
|
||||
};
|
||||
|
||||
$api.createRequest('/app/job/list', params).then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = dataToImg(rows);
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = dataToImg(rows);
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function dataToImg(data) {
|
||||
return data.map((item) => ({
|
||||
...item,
|
||||
image: img,
|
||||
hide: true,
|
||||
}));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.app-containers
|
||||
// 推荐卡片
|
||||
.recommend-card::before
|
||||
position: absolute
|
||||
left: 0
|
||||
top: 0
|
||||
content: ''
|
||||
height: 60rpx
|
||||
width: 100%
|
||||
background: linear-gradient(to bottom, #FFAD47, #FFFFFF)
|
||||
.recommend-card::after
|
||||
position: absolute
|
||||
right: -20rpx
|
||||
top: 40rpx
|
||||
content: ''
|
||||
height: 100rpx
|
||||
width: 200rpx
|
||||
background: url('@/static/icon/Group1.png') center center no-repeat
|
||||
background-size: 100rpx 140rpx
|
||||
.recommend-card
|
||||
padding: 20rpx
|
||||
.card-content
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
.recommend-card-title
|
||||
color: #333333
|
||||
font-size: 32rpx
|
||||
.recommend-card-tip
|
||||
font-size: 24rpx;
|
||||
color: #606060;
|
||||
margin-top: 10rpx
|
||||
.recommend-card-controll
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: space-around
|
||||
margin-top: 40rpx
|
||||
.controll-yes
|
||||
border-radius: 39rpx
|
||||
padding: 0rpx 30rpx
|
||||
background: rgba(255, 173, 71, 1)
|
||||
border: 2rpx solid rgba(255, 173, 71, 1)
|
||||
color: #FFFFFF
|
||||
.controll-no
|
||||
border-radius: 39rpx
|
||||
border: 2rpx solid rgba(255, 173, 71, 1)
|
||||
padding: 0rpx 30rpx
|
||||
color: rgba(255, 173, 71, 1)
|
||||
.controll-yes:active, .controll-no:active
|
||||
background: #e8e8e8
|
||||
border: 2rpx solid #e8e8e8
|
||||
|
||||
.app-container
|
||||
width: 100%;
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
// background: linear-gradient(180deg, rgba(255,255,255,0.2) 0%, #fff 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed
|
||||
.index-AI
|
||||
height: 42rpx;
|
||||
font-family: Inter, Inter;
|
||||
@@ -204,7 +479,8 @@ watch(
|
||||
align-items: center;
|
||||
.tab-recommend
|
||||
white-space: nowrap;
|
||||
width: 92rpx;
|
||||
width: fit-content;
|
||||
padding: 0 10rpx;
|
||||
height: 42rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 17rpx 17rpx 0rpx 17rpx;
|
||||
@@ -212,7 +488,7 @@ watch(
|
||||
color: #FFFFFF;
|
||||
font-size: 21rpx;
|
||||
line-height: 42rpx;
|
||||
margin-right: 12rpx;
|
||||
margin-right: 14rpx;
|
||||
.tab-number
|
||||
font-size: 21rpx;
|
||||
color: #606060;
|
||||
@@ -225,54 +501,75 @@ watch(
|
||||
height: 27rpx;
|
||||
.falls-scroll
|
||||
flex: 1;
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,0.2) 0%, #fff 100%)
|
||||
.falls
|
||||
padding: 20rpx 40rpx;
|
||||
.falls-card
|
||||
padding: 30rpx;
|
||||
.falls-card-title
|
||||
height: 49rpx;
|
||||
font-size: 42rpx;
|
||||
color: #606060;
|
||||
line-height: 49rpx;
|
||||
text-align: left;
|
||||
.falls-card-pay
|
||||
height: 50rpx;
|
||||
font-size: 35rpx;
|
||||
color: #002979;
|
||||
line-height: 50rpx;
|
||||
text-align: left;
|
||||
.falls-card-education,.falls-card-experience
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #13C57C;
|
||||
border-radius: 17rpx 17rpx 17rpx 17rpx;
|
||||
padding: 0 10rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 21rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
.falls-card-company,.falls-card-pepleNumber
|
||||
margin-top: 14rpx;
|
||||
font-size: 21rpx;
|
||||
color: #606060;
|
||||
line-height: 25rpx;
|
||||
text-align: left;
|
||||
.falls-card-pepleNumber
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.falls-card-matchingrate
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 21rpx;
|
||||
color: #4778EC;
|
||||
text-align: left;
|
||||
.item
|
||||
position: relative;
|
||||
// background: linear-gradient( 180deg, rgba(19, 197, 124, 0.4) 0%, rgba(255, 255, 255, 0) 30%), rgba(255, 255, 255, 0);
|
||||
.falls-card
|
||||
padding: 30rpx;
|
||||
.falls-card-title
|
||||
// height: 49rpx;
|
||||
font-size: 42rpx;
|
||||
color: #606060;
|
||||
line-height: 49rpx;
|
||||
text-align: left;
|
||||
word-break:break-all
|
||||
.falls-card-pay
|
||||
// height: 50rpx;
|
||||
word-break:break-all
|
||||
font-size: 34rpx;
|
||||
color: #002979;
|
||||
line-height: 50rpx;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
position: relative
|
||||
.pay-text
|
||||
color: #002979;
|
||||
padding-right: 10rpx
|
||||
.flame
|
||||
position: absolute
|
||||
bottom: 0
|
||||
right: -10rpx
|
||||
transform: translate(0, -30%)
|
||||
width: 24rpx
|
||||
height: 31rpx
|
||||
.falls-card-education,.falls-card-experience
|
||||
width: fit-content;
|
||||
height: 30rpx;
|
||||
background: #13C57C;
|
||||
border-radius: 17rpx 17rpx 17rpx 17rpx;
|
||||
padding: 0 10rpx;
|
||||
line-height: 30rpx;
|
||||
font-weight: 400;
|
||||
font-size: 21rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
margin-top: 14rpx;
|
||||
.falls-card-company,.falls-card-pepleNumber
|
||||
margin-top: 14rpx;
|
||||
font-size: 21rpx;
|
||||
color: #606060;
|
||||
line-height: 25rpx;
|
||||
text-align: left;
|
||||
.falls-card-pepleNumber
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.falls-card-matchingrate
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 21rpx;
|
||||
color: #4778EC;
|
||||
text-align: left;
|
||||
.logo
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
.tabchecked
|
||||
color: #4778EC !important
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
<view class="logo-title">就业</view>
|
||||
</view>
|
||||
<view class="btns">
|
||||
<button open-type="getUserInfo" @getuserinfo="getuserinfo" class="wxlogin">微信登录</button>
|
||||
<button class="wxlogin" @click="loginTest">登录</button>
|
||||
<!-- <button open-type="getUserInfo" @getuserinfo="getuserinfo" class="wxlogin">登录</button> -->
|
||||
<view class="wxaddress">青岛市公共就业和人才服务中心</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -21,15 +22,17 @@
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="fl_box fl_justmiddle fl_1 fl_alstart">
|
||||
<view class="tabtwo-sex">
|
||||
<view class="tabtwo-sex" @click="changeSex(1)">
|
||||
<image class="sex-img" src="../../static/icon/woman.png"></image>
|
||||
<view class="mar_top5">女</view>
|
||||
<view class="dot"></view>
|
||||
<view v-if="fromValue.sex === 1" class="dot doted"></view>
|
||||
<view v-else class="dot"></view>
|
||||
</view>
|
||||
<view class="tabtwo-sex">
|
||||
<view class="tabtwo-sex" @click="changeSex(0)">
|
||||
<image class="sex-img" src="../../static/icon/man.png"></image>
|
||||
<view class="mar_top5">男</view>
|
||||
<view class="dot doted"></view>
|
||||
<view v-if="fromValue.sex === 0" class="dot doted"></view>
|
||||
<view v-else class="dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="nextstep" @tap="nextStep">下一步</view>
|
||||
@@ -43,10 +46,16 @@
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="fl_box fl_deri fl_almiddle">
|
||||
<view class="agebtn agebtned">30岁以下</view>
|
||||
<view class="agebtn">31-40岁</view>
|
||||
<view class="agebtn">41-50岁</view>
|
||||
<view class="agebtn">51岁以上</view>
|
||||
<!-- <view class="agebtn agebtned">30岁以下</view> -->
|
||||
<view
|
||||
class="agebtn"
|
||||
:class="{ agebtned: item.value === fromValue.age }"
|
||||
v-for="item in state.ageList"
|
||||
:key="item.value"
|
||||
@click="changeAge(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="fl_box fl_justmiddle"></view>
|
||||
<view class="nextstep" @tap="nextStep">下一步</view>
|
||||
@@ -60,17 +69,15 @@
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="eduction-content">
|
||||
<view class="eductionbtn eductionbtned">初中及以下</view>
|
||||
<view class="eductionbtn">中专/中技</view>
|
||||
<view class="eductionbtn">高中</view>
|
||||
<view class="eductionbtn">大专</view>
|
||||
<view class="eductionbtn">本科</view>
|
||||
<view class="eductionbtn">硕士</view>
|
||||
<view class="eductionbtn">博士</view>
|
||||
<view class="eductionbtn">MBA/EMBA</view>
|
||||
<view class="eductionbtn">留学-学士</view>
|
||||
<view class="eductionbtn">留学-硕士</view>
|
||||
<view class="eductionbtn">留学-博士</view>
|
||||
<view
|
||||
class="eductionbtn"
|
||||
:class="{ eductionbtned: item.value === fromValue.education }"
|
||||
v-for="item in oneDictData('education')"
|
||||
@click="changeEducation(item.value)"
|
||||
:key="item.value"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="nextstep" @tap="nextStep">下一步</view>
|
||||
</view>
|
||||
@@ -83,22 +90,28 @@
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="salary">
|
||||
<scroll-view class="salary-content" :show-scrollbar="false" :scroll-y="true">
|
||||
<view class="salary-content-item">不限</view>
|
||||
<view class="salary-content-item salary-content-item-selected">2k</view>
|
||||
<view class="salary-content-item">5k</view>
|
||||
<view class="salary-content-item">10k</view>
|
||||
<view class="salary-content-item">15k</view>
|
||||
</scroll-view>
|
||||
<view class="center-text">至</view>
|
||||
<scroll-view class="salary-content" :show-scrollbar="false" :scroll-y="true">
|
||||
<view class="salary-content-item">不限</view>
|
||||
<view class="salary-content-item salary-content-item-selected">2k</view>
|
||||
<view class="salary-content-item">5k</view>
|
||||
<view class="salary-content-item">10k</view>
|
||||
<view class="salary-content-item">15k</view>
|
||||
<view class="salary-content-item">15k</view>
|
||||
</scroll-view>
|
||||
<picker-view
|
||||
indicator-style="height: 140rpx;"
|
||||
:value="state.salayData"
|
||||
@change="bindChange"
|
||||
class="picker-view"
|
||||
>
|
||||
<picker-view-column>
|
||||
<view class="item" v-for="(item, index) in state.lfsalay" :key="index">
|
||||
<view class="item-child" :class="{ 'item-childed': state.salayData[0] === index }">
|
||||
{{ item }}k
|
||||
</view>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
<view class="item-center">至</view>
|
||||
<picker-view-column>
|
||||
<view class="item" v-for="(item, index) in state.risalay" :key="index">
|
||||
<view class="item-child" :class="{ 'item-childed': state.salayData[2] === index }">
|
||||
{{ item }}k
|
||||
</view>
|
||||
</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
<view class="fl_box fl_justmiddle"></view>
|
||||
<view class="nextstep" @tap="nextStep">下一步</view>
|
||||
@@ -112,17 +125,17 @@
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="eduction-content">
|
||||
<view class="eductionbtn eductionbtned">市南区</view>
|
||||
<view class="eductionbtn">市北区</view>
|
||||
<view class="eductionbtn">李沧区</view>
|
||||
<view class="eductionbtn">崂山区</view>
|
||||
<view class="eductionbtn">荒岛区</view>
|
||||
<view class="eductionbtn">城阳区</view>
|
||||
<view class="eductionbtn">即墨区</view>
|
||||
<view class="eductionbtn">胶州市</view>
|
||||
<view class="eductionbtn">平度市</view>
|
||||
<view class="eductionbtn">莱西市</view>
|
||||
<view class="eductionbtn">不限区域</view>
|
||||
<!-- <view class="eductionbtn eductionbtned">市南区</view> -->
|
||||
<view
|
||||
class="eductionbtn"
|
||||
:class="{ eductionbtned: item.value === fromValue.area }"
|
||||
v-for="item in oneDictData('area')"
|
||||
:key="item.value"
|
||||
@click="changeArea(item.value)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
<!-- <view class="eductionbtn">不限区域</view> -->
|
||||
</view>
|
||||
<view class="nextstep" @tap="nextStep">下一步</view>
|
||||
</view>
|
||||
@@ -134,37 +147,13 @@
|
||||
<view class="color_FFFFFF fs_30">您的期望岗位6/6</view>
|
||||
<view class="color_D9D9D9">个人信息仅用于推送优质内容</view>
|
||||
</view>
|
||||
<view class="sex-search">
|
||||
<uni-icons class="iconsearch" type="search" size="20"></uni-icons>
|
||||
<input class="uni-input searchinput" confirm-type="search" />
|
||||
</view>
|
||||
<view class="sex-content fl_1">
|
||||
<scroll-view :show-scrollbar="false" :scroll-y="true" class="sex-content-left">
|
||||
<view
|
||||
v-for="item in state.station"
|
||||
:key="item.value"
|
||||
class="left-list-btn"
|
||||
:class="{ 'left-list-btned': item.value === state.stationCateLog }"
|
||||
@click="changeStationLog(item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
<scroll-view :show-scrollbar="false" :scroll-y="true" class="sex-content-right">
|
||||
<view class="grid-sex">
|
||||
<view class="sex-right-btn sex-right-btned">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
<view class="sex-right-btn">客户经理</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<expected-station @onChange="changeJobTitleId" :station="state.station"></expected-station>
|
||||
</view>
|
||||
<navigator url="/pages/index/index" open-type="reLaunch" hover-class="other-navigator-hover">
|
||||
<button class="nextstep confirmStep">完成</button>
|
||||
</navigator>
|
||||
<button class="nextstep confirmStep" @click="complete">完成</button>
|
||||
<!-- <navigator url="/pages/index/index" open-type="reLaunch" hover-class="other-navigator-hover">
|
||||
<button class="nextstep confirmStep" @click="complete">完成</button>
|
||||
</navigator> -->
|
||||
</view>
|
||||
</template>
|
||||
</tabcontrolVue>
|
||||
@@ -174,61 +163,125 @@
|
||||
<script setup>
|
||||
import tabcontrolVue from './components/tabcontrol.vue';
|
||||
import { reactive, inject, watch, ref } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { statusBarHeight } = inject('deviceInfo');
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
// 初始化
|
||||
const station = [
|
||||
{ label: '销售/商务拓展', value: 1 },
|
||||
{ label: '人事/行政/财务/法务', value: 2 },
|
||||
{ label: '互联网/通信及硬件', value: 3 },
|
||||
{ label: '运维/测试', value: 4 },
|
||||
{ label: '销售/商务拓展', value: 5 },
|
||||
{ label: '人事/行政/财务/法务', value: 6 },
|
||||
{ label: '互联网/通信及硬件', value: 7 },
|
||||
{ label: '运维/测试', value: 8 },
|
||||
{ label: '销售/商务拓展', value: 9 },
|
||||
{ label: '人事/行政/财务/法务', value: 10 },
|
||||
{ label: '互联网/通信及硬件', value: 11 },
|
||||
{ label: '销售/商务拓展', value: 12 },
|
||||
{ label: '人事/行政/财务/法务', value: 13 },
|
||||
{ label: '互联网/通信及硬件', value: 14 },
|
||||
];
|
||||
const { loginSetToken, getUserResume } = useUserStore();
|
||||
const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
// status
|
||||
const tabCurrent = ref(0);
|
||||
const salay = [2, 5, 10, 15, 20, 25, 30, 50, 80, 100];
|
||||
const state = reactive({
|
||||
station: station,
|
||||
station: [],
|
||||
stationCateLog: 1,
|
||||
ageList: [],
|
||||
lfsalay: [2, 5, 10, 15, 20, 25, 30, 50],
|
||||
risalay: JSON.parse(JSON.stringify(salay)),
|
||||
salayData: [0, 0, 0],
|
||||
});
|
||||
const fromValue = reactive({
|
||||
sex: 1,
|
||||
age: '0',
|
||||
education: '4',
|
||||
salaryMin: 2000,
|
||||
salaryMax: 2000,
|
||||
area: 0,
|
||||
jobTitleId: '',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('gg');
|
||||
}, 4000);
|
||||
const getuserinfo = (e) => {
|
||||
console.log(e);
|
||||
};
|
||||
// 行为
|
||||
function changeStationLog(item) {
|
||||
state.stationCateLog = item.value;
|
||||
onLoad((parmas) => {
|
||||
getDictSelectOption('age').then((data) => {
|
||||
state.ageList = data;
|
||||
});
|
||||
getTreeselect();
|
||||
});
|
||||
|
||||
// 选择薪资
|
||||
function bindChange(val) {
|
||||
state.salayData = val.detail.value;
|
||||
const copyri = JSON.parse(JSON.stringify(salay));
|
||||
const [lf, _, ri] = val.detail.value;
|
||||
state.risalay = copyri.slice(lf, copyri.length);
|
||||
fromValue.salaryMin = copyri[lf] * 1000;
|
||||
fromValue.salaryMax = state.risalay[ri] * 1000;
|
||||
}
|
||||
function changeSex(sex) {
|
||||
fromValue.sex = sex;
|
||||
}
|
||||
function changeAge(age) {
|
||||
fromValue.age = age;
|
||||
}
|
||||
function changeEducation(education) {
|
||||
fromValue.education = education;
|
||||
}
|
||||
function changeArea(area) {
|
||||
fromValue.area = area;
|
||||
}
|
||||
function changeJobTitleId(jobTitleId) {
|
||||
fromValue.jobTitleId = jobTitleId;
|
||||
}
|
||||
// 行为
|
||||
// function changeStationLog(item) {
|
||||
// state.stationCateLog = item.value;
|
||||
// }
|
||||
function nextStep() {
|
||||
tabCurrent.value += 1;
|
||||
}
|
||||
function handleScroll(event) {
|
||||
console.log('滚动条滚动', event.detail.scrollTop);
|
||||
console.log(Math.round(event.detail.scrollTop / 75));
|
||||
// this.activeIndex = Math.round(event.detail.scrollTop / 75);
|
||||
// function handleScroll(event) {
|
||||
// console.log('滚动条滚动', event.detail.scrollTop);
|
||||
// console.log(Math.round(event.detail.scrollTop / 75));
|
||||
// // this.activeIndex = Math.round(event.detail.scrollTop / 75);
|
||||
// }
|
||||
|
||||
// 获取职位
|
||||
function getTreeselect() {
|
||||
$api.createRequest('/app/common/jobTitle/treeselect', {}, 'GET').then((resData) => {
|
||||
state.station = resData.data;
|
||||
});
|
||||
}
|
||||
|
||||
// 登录
|
||||
function loginTest() {
|
||||
const params = {
|
||||
username: 'test',
|
||||
password: 'test',
|
||||
};
|
||||
$api.createRequest('/app/login', params, 'post').then((resData) => {
|
||||
$api.msg('模拟帐号密码测试登录成功');
|
||||
loginSetToken(resData.token).then((resume) => {
|
||||
if (resume.data.jobTitleId) {
|
||||
// 设置推荐列表,每次退出登录都需要更新
|
||||
useUserStore().initSeesionId();
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
} else {
|
||||
nextStep();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function complete() {
|
||||
$api.createRequest('/app/user/resume', fromValue, 'post').then((resData) => {
|
||||
$api.msg('完成');
|
||||
getUserResume();
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
.container
|
||||
background: linear-gradient(#4778EC, #002979);
|
||||
width: 100%;
|
||||
height: calc(100vh - var(--window-top) - var(--status-bar-height) - var(--window-bottom));
|
||||
position: relative;
|
||||
position: fixed;
|
||||
|
||||
.login-content
|
||||
position: absolute;
|
||||
@@ -360,9 +413,53 @@ function handleScroll(event) {
|
||||
.salary
|
||||
width: fit-content;
|
||||
display: grid;
|
||||
grid-template-columns: 300rpx 40rpx 300rpx;
|
||||
// grid-gap: 20rpx;
|
||||
grid-template-columns: 640rpx;
|
||||
grid-gap: 20rpx;
|
||||
margin-top: 50rpx;
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
height: 600rpx;
|
||||
margin-top: 20rpx;
|
||||
.uni-picker-view-mask{
|
||||
background: rgba(0,0,0,0);
|
||||
}
|
||||
}
|
||||
.item {
|
||||
.item-child{
|
||||
line-height: 90rpx;
|
||||
font-size: 38rpx;
|
||||
color: #606060;
|
||||
text-align: center;
|
||||
background: #D9D9D9;
|
||||
border-radius: 20rpx;
|
||||
margin: 20rpx 10rpx 20rpx 10rpx;
|
||||
}
|
||||
.item-childed{
|
||||
line-height: 105rpx;
|
||||
margin: 10rpx 5rpx 10rpx 5rpx;
|
||||
background: #13C57C;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
.item-center{
|
||||
width: 40rpx;
|
||||
line-height: 600rpx;
|
||||
width: 51rpx;
|
||||
height: 47rpx;
|
||||
font-family: Inter, Inter;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
text-transform: none;
|
||||
}
|
||||
.uni-picker-view-indicator:after{
|
||||
border: 0
|
||||
}
|
||||
.uni-picker-view-indicator:before{
|
||||
border: 0
|
||||
}
|
||||
.center-text
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
@@ -386,71 +483,12 @@ function handleScroll(event) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
background: #4678ec;
|
||||
.sex-search
|
||||
width: calc(100% - 28rpx - 28rpx);
|
||||
padding: 10rpx 28rpx;
|
||||
display: grid;
|
||||
// grid-template-columns: 50rpx auto;
|
||||
position: relative;
|
||||
.iconsearch
|
||||
position: absolute;
|
||||
left: 40rpx;
|
||||
top: 20rpx;
|
||||
.searchinput
|
||||
border-radius: 10rpx;
|
||||
background: #FFFFFF;
|
||||
padding: 10rpx 0 10rpx 58rpx;
|
||||
.sex-content
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
width: 100%;
|
||||
margin-top: 20rpx;
|
||||
margin-bottom: 40rpx;
|
||||
display: flex;
|
||||
border-bottom: 2px solid #D9D9D9;
|
||||
overflow: hidden
|
||||
.sex-content-left
|
||||
width: 250rpx;
|
||||
.left-list-btn
|
||||
padding: 0 24rpx;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
color: #606060;
|
||||
font-size: 28rpx;
|
||||
.left-list-btned
|
||||
color: #4778EC;
|
||||
position: relative;
|
||||
.left-list-btned::after
|
||||
position: absolute;
|
||||
left: 20rpx;
|
||||
content: '';
|
||||
width: 7rpx;
|
||||
height: 38rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
|
||||
.sex-content-right
|
||||
border-left: 2px solid #D9D9D9;
|
||||
flex: 1;
|
||||
.grid-sex
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
place-items: center;
|
||||
.sex-right-btn
|
||||
width: 211rpx;
|
||||
height: 84rpx;
|
||||
font-size: 35rpx;
|
||||
line-height: 41rpx;
|
||||
text-align: center;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: #D9D9D9;
|
||||
border-radius: 20rpx;
|
||||
margin-top:30rpx;
|
||||
color: #606060;
|
||||
.sex-right-btned
|
||||
color: #FFFFFF;
|
||||
background: #4778EC;
|
||||
overflow: hidden;
|
||||
height: 100%
|
||||
</style>
|
||||
|
||||
@@ -3,11 +3,15 @@
|
||||
<view class="mine-AI">AI+就业服务程序</view>
|
||||
<view class="mine-userinfo">
|
||||
<view class="userindo-head">
|
||||
<image class="userindo-head-img" src="/static/icon/flame2.png"></image>
|
||||
<image class="userindo-head-img" v-if="userInfo.age === '0'" src="/static/icon/boy.png"></image>
|
||||
<image class="userindo-head-img" v-else src="/static/icon/girl.png"></image>
|
||||
</view>
|
||||
<view class="userinfo-ls">
|
||||
<view class="userinfo-ls-name">用户名</view>
|
||||
<view class="userinfo-ls-resume">简历完成度80%,建议优化</view>
|
||||
<view class="userinfo-ls-name">{{ userInfo.name || '暂无用户名' }}</view>
|
||||
<view class="userinfo-ls-resume" v-if="isAbove90(Completion)">
|
||||
简历完成度 {{ Completion }},建议优化
|
||||
</view>
|
||||
<view class="userinfo-ls-resume" v-else>简历完成度 {{ Completion }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="mine-tab">
|
||||
@@ -15,15 +19,15 @@
|
||||
<image class="item-img" src="/static/icon/resume.png"></image>
|
||||
<view class="item-text">我的简历</view>
|
||||
</view>
|
||||
<view class="tab-item">
|
||||
<view class="tab-item" @click="navTo('/packageA/pages/collection/collection')">
|
||||
<image class="item-img" src="/static/icon/collect.png"></image>
|
||||
<view class="item-text">我的收藏</view>
|
||||
</view>
|
||||
<view class="tab-item">
|
||||
<view class="tab-item" @click="navTo('/packageA/pages/browseJob/browseJob')">
|
||||
<image class="item-img" src="/static/icon/browse.png"></image>
|
||||
<view class="item-text">我的浏览</view>
|
||||
</view>
|
||||
<view class="tab-item">
|
||||
<view class="tab-item" @click="navTo('/packageA/pages/Intendedposition/Intendedposition')">
|
||||
<image class="item-img" src="/static/icon/quaters.png"></image>
|
||||
<view class="item-text">意向岗位</view>
|
||||
</view>
|
||||
@@ -32,18 +36,50 @@
|
||||
<view class="mine-options-item">实名认证</view>
|
||||
<view class="mine-options-item">素质测评</view>
|
||||
<view class="mine-options-item">AI面试</view>
|
||||
<view class="mine-options-item">账号与安全</view>
|
||||
<!-- <view class="mine-options-item">账号与安全</view> -->
|
||||
<view class="mine-options-item">通知与提醒</view>
|
||||
<view class="mine-logout">退出登录</view>
|
||||
<view class="mine-logout" @click="logOut">退出登录</view>
|
||||
</view>
|
||||
<uni-popup ref="popup" type="dialog">
|
||||
<uni-popup-dialog
|
||||
mode="base"
|
||||
title="确定退出登录吗?"
|
||||
type="info"
|
||||
:duration="2000"
|
||||
:before-close="true"
|
||||
@confirm="confirm"
|
||||
@close="close"
|
||||
></uni-popup-dialog>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '../../stores/useUserStore';
|
||||
const { $api, navTo } = inject('globalFunction');
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const userInfo = ref({});
|
||||
const Completion = ref({});
|
||||
const popup = ref(null);
|
||||
onShow(() => {
|
||||
userInfo.value = useUserStore().userInfo;
|
||||
Completion.value = useUserStore().Completion;
|
||||
});
|
||||
|
||||
function logOut() {
|
||||
popup.value.open();
|
||||
}
|
||||
|
||||
function close() {
|
||||
popup.value.close();
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
useUserStore().logOut();
|
||||
}
|
||||
|
||||
const isAbove90 = (percent) => parseFloat(percent) < 90;
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@@ -122,12 +158,17 @@ const { $api, navTo } = inject('globalFunction');
|
||||
.tab-item:nth-child(2)>.item-img
|
||||
width: 51rpx;
|
||||
height: 45rpx;
|
||||
margin-top: 6rpx;
|
||||
margin-bottom: 4rpx;
|
||||
.tab-item:nth-child(3)>.item-img
|
||||
width: 62rpx;
|
||||
height: 41rpx;
|
||||
margin-top: 6rpx
|
||||
margin-bottom: 10rpx;
|
||||
.tab-item:nth-child(4)>.item-img
|
||||
width: 45rpx;
|
||||
height: 47rpx;
|
||||
margin-bottom: 8rpx;
|
||||
.mine-options
|
||||
margin: 43rpx 30rpx;
|
||||
min-height: 155rpx;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<swiper-item class="list">
|
||||
<view class="list-card">
|
||||
<view class="card-img">
|
||||
<image class="card-img-flame" src="/static/icon/flame2.png"></image>
|
||||
<image class="card-img-flame" src="/static/icon/recommendday.png"></image>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="info-title">今日推荐</view>
|
||||
@@ -22,7 +22,7 @@
|
||||
<swiper-item class="list">
|
||||
<view class="list-card">
|
||||
<view class="card-img">
|
||||
<image class="card-img-flame" src="/static/icon/flame2.png"></image>
|
||||
<image class="card-img-flame" src="/static/icon/recommendday.png"></image>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="info-title">今日推荐</view>
|
||||
@@ -63,7 +63,6 @@ function seemsg(index) {
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.msg-AI
|
||||
height: 42rpx;
|
||||
font-family: Inter, Inter;
|
||||
@@ -83,7 +82,7 @@ function seemsg(index) {
|
||||
.actived
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
text-shadow: 0px 7px 7px rgba(0,0,0,0.25);
|
||||
text-shadow: 0rpx 14rpx 14rpx rgba(0,0,0,0.25);
|
||||
.msg-list
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
@@ -111,8 +110,8 @@ function seemsg(index) {
|
||||
place-items: center;
|
||||
margin-right: 30rpx;
|
||||
.card-img-flame
|
||||
width: 36rpx;
|
||||
height: 44rpx;
|
||||
width: 100%;
|
||||
height: 100%
|
||||
.card-info
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
@@ -1,64 +1,243 @@
|
||||
<template>
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll">
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="two-head">
|
||||
<view class="head-item active">市北区</view>
|
||||
<view class="head-item" v-for="(item, index) in 10" :key="index">中山路商圈</view>
|
||||
<!-- <view class="head-item active">市北区</view> -->
|
||||
<view
|
||||
class="head-item"
|
||||
:class="{ active: state.comId === item.commercialAreaId }"
|
||||
v-for="(item, index) in state.comlist"
|
||||
:key="item.commercialAreaId"
|
||||
@click="clickCommercialArea(item)"
|
||||
>
|
||||
{{ item.commercialAreaName }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="nearby-list">
|
||||
<view class="list-head" @touchmove.stop.prevent>
|
||||
<view class="tab-options">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll" @touchmove.stop>
|
||||
<view class="tab-op-left">
|
||||
<view class="tab-list" v-for="(item, index) in 4" :key="index">中国万岁</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === 'all' }"
|
||||
@click="choosePosition('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === index }"
|
||||
@click="choosePosition(index)"
|
||||
v-for="(item, index) in userInfo.jobTitle"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-op-right">
|
||||
<view class="tab-recommend">推荐</view>
|
||||
<view class="tab-filter">
|
||||
<view class="tab-number">1000+</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view class="tab-recommend">
|
||||
<latestHotestStatus @confirm="handelHostestSearch"></latestHotestStatus>
|
||||
</view>
|
||||
<view class="tab-filter" @click="emit('onFilter', 3)">
|
||||
<view class="tab-number" v-show="pageState.total">{{ formatTotal(pageState.total) }}</view>
|
||||
<image class="image" src="/static/icon/filter.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="one-cards">
|
||||
<view class="card-box" v-for="(item, index) in 20" :key="index">
|
||||
<view class="card-box" v-for="(item, index) in list" :key="item.jobId" @click="navToPost(item.jobId)">
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-left">销售工程师-高级销售经理</view>
|
||||
<view class="row-right">1万-2万</view>
|
||||
<view class="row-left">{{ item.jobTitle }}</view>
|
||||
<view class="row-right">
|
||||
<Salary-Expectation
|
||||
:max-salary="item.maxSalary"
|
||||
:min-salary="item.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left">
|
||||
<view class="row-tag">本科</view>
|
||||
<view class="row-tag">1-5年</view>
|
||||
<view class="row-tag" v-if="item.education">
|
||||
<dict-Label dictType="education" :value="item.education"></dict-Label>
|
||||
</view>
|
||||
<view class="row-tag" v-if="item.experience">
|
||||
<dict-Label dictType="experience" :value="item.experience"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-item mineText">2024.1.8</view>
|
||||
<view class="row-item mineText">8人</view>
|
||||
<view class="row-item mineText textblue">匹配度93%</view>
|
||||
<view class="row-item mineText">{{ item.postingDate || '发布日期' }}</view>
|
||||
<view class="row-item mineText">{{ vacanciesTo(item.vacancies) }}</view>
|
||||
<view class="row-item mineText textblue"><matchingDegree :job="item"></matchingDegree></view>
|
||||
<view class="row-item">
|
||||
<uni-icons type="star" size="28"></uni-icons>
|
||||
<!-- <uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left mineText">湖南沃森电气科技有限公司</view>
|
||||
<view class="row-right mineText">青岛 青岛经济技术开发区 550m</view>
|
||||
<view class="row-left mineText">{{ item.companyName }}</view>
|
||||
<view class="row-right mineText">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="item.jobLocationAreaCode"></dict-Label>
|
||||
<convert-distance
|
||||
:alat="item.latitude"
|
||||
:along="item.longitude"
|
||||
:blat="latitude()"
|
||||
:blong="longitude()"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
const state = reactive({});
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
const { $api, navTo, vacanciesTo, formatTotal } = inject('globalFunction');
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const { getLocation, longitude, latitude } = useLocationStore();
|
||||
const emit = defineEmits(['onFilter']);
|
||||
const state = reactive({
|
||||
tabIndex: 'all',
|
||||
comlist: [],
|
||||
comId: 0,
|
||||
});
|
||||
const fromValue = reactive({
|
||||
area: 0,
|
||||
areaInfo: {},
|
||||
});
|
||||
const loadmoreRef = ref(null);
|
||||
const userInfo = ref({});
|
||||
const isLoaded = ref(false);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const list = ref([]);
|
||||
|
||||
onShow(() => {
|
||||
userInfo.value = useUserStore().userInfo;
|
||||
});
|
||||
onLoad(() => {
|
||||
getBusinessDistrict();
|
||||
});
|
||||
|
||||
function navToPost(jobId) {
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(jobId)}`);
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
getJobList('refresh');
|
||||
isLoaded.value = true;
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function scrollBottom() {
|
||||
getJobList();
|
||||
loadmoreRef.value.change('loading');
|
||||
}
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
if (index === 'all') {
|
||||
pageState.search.jobTitle = '';
|
||||
} else {
|
||||
pageState.search.jobTitle = useUserStore().userInfo.jobTitle[index];
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function clickCommercialArea(area) {
|
||||
state.areaInfo = area;
|
||||
state.comId = area.commercialAreaId;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function getBusinessDistrict() {
|
||||
$api.createRequest(`/app/common/commercialArea`).then((resData) => {
|
||||
if (resData.data.length) {
|
||||
state.comlist = resData.data;
|
||||
state.areaInfo = resData.data[0];
|
||||
state.comId = resData.data[0].commercialAreaId;
|
||||
}
|
||||
});
|
||||
}
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
}
|
||||
let params = {
|
||||
longitude: state.areaInfo.longitude,
|
||||
latitude: state.areaInfo.latitude,
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
radius: 2,
|
||||
...pageState.search,
|
||||
};
|
||||
$api.createRequest('/app/job/commercialArea', params, 'POST').then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = rows;
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function handleFilterConfirm(val) {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
for (const [key, value] of Object.entries(val)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
defineExpose({ loadData, handleFilterConfirm });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tabchecked
|
||||
color: #4778EC !important
|
||||
.nearby-scroll
|
||||
overflow: hidden;
|
||||
.two-head
|
||||
@@ -85,7 +264,7 @@ const state = reactive({});
|
||||
color: #FFFFFF;
|
||||
.nearby-list
|
||||
margin-top: 40rpx;
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
// background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
.list-head
|
||||
height: 77rpx;
|
||||
background-color: #FFFFFF;
|
||||
@@ -123,7 +302,8 @@ const state = reactive({});
|
||||
align-items: center;
|
||||
.tab-recommend
|
||||
white-space: nowrap;
|
||||
width: 92rpx;
|
||||
width: fit-content;
|
||||
padding: 0 10rpx;
|
||||
height: 42rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 17rpx 17rpx 0rpx 17rpx;
|
||||
@@ -165,6 +345,9 @@ const state = reactive({});
|
||||
color: #606060;
|
||||
.textblue
|
||||
color: #4778EC;
|
||||
.row-right
|
||||
min-width: 120rpx
|
||||
text-align: right
|
||||
.row-left
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll">
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="nearby-map" @touchmove.stop.prevent>
|
||||
<zhuo-tianditu-MultiPoint-Mapper
|
||||
ref="tMap"
|
||||
:showLabel="false"
|
||||
:showCirle="true"
|
||||
api-key="e122b0518f43b32dcc256edbae20a5d1"
|
||||
@onLoad="LoadComplite"
|
||||
></zhuo-tianditu-MultiPoint-Mapper>
|
||||
<map
|
||||
style="width: 100%; height: 300px"
|
||||
:latitude="latitude()"
|
||||
:longitude="longitude()"
|
||||
:markers="mapCovers"
|
||||
:circles="mapCircles"
|
||||
:controls="mapControls"
|
||||
@controltap="handleControl"
|
||||
></map>
|
||||
</view>
|
||||
<view class="nearby-list">
|
||||
<view class="list-head" @touchmove.stop.prevent>
|
||||
@@ -32,81 +34,236 @@
|
||||
></bingProgressComponent>
|
||||
</view>
|
||||
<view class="tab-op-right">
|
||||
<view class="tab-recommend">推荐</view>
|
||||
<view class="tab-filter">
|
||||
<view class="tab-number">1000+</view>
|
||||
<view class="tab-recommend">
|
||||
<latestHotestStatus @confirm="handelHostestSearch"></latestHotestStatus>
|
||||
</view>
|
||||
<view class="tab-filter" @click="emit('onFilter', 0)">
|
||||
<view class="tab-number" v-show="pageState.total">{{ formatTotal(pageState.total) }}</view>
|
||||
<image class="image" src="/static/icon/filter.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="one-cards">
|
||||
<view class="card-box" v-for="(item, index) in 20" :key="index">
|
||||
<view class="card-box" v-for="(item, index) in list" :key="item.jobId" @click="navToPost(item.jobId)">
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-left">销售工程师-高级销售经理</view>
|
||||
<view class="row-right">1万-2万</view>
|
||||
<view class="row-left">{{ item.jobTitle }}</view>
|
||||
<view class="row-right">
|
||||
<Salary-Expectation
|
||||
:max-salary="item.maxSalary"
|
||||
:min-salary="item.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left">
|
||||
<view class="row-tag">本科</view>
|
||||
<view class="row-tag">1-5年</view>
|
||||
<view class="row-tag" v-if="item.education">
|
||||
<dict-Label dictType="education" :value="item.education"></dict-Label>
|
||||
</view>
|
||||
<view class="row-tag" v-if="item.experience">
|
||||
<dict-Label dictType="experience" :value="item.experience"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-item mineText">2024.1.8</view>
|
||||
<view class="row-item mineText">8人</view>
|
||||
<view class="row-item mineText textblue">匹配度93%</view>
|
||||
<view class="row-item mineText">{{ item.postingDate || '发布日期' }}</view>
|
||||
<view class="row-item mineText">{{ vacanciesTo(item.vacancies) }}</view>
|
||||
<view class="row-item mineText textblue"><matchingDegree :job="item"></matchingDegree></view>
|
||||
<view class="row-item">
|
||||
<uni-icons type="star" size="28"></uni-icons>
|
||||
<!-- <uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left mineText">湖南沃森电气科技有限公司</view>
|
||||
<view class="row-right mineText">青岛 青岛经济技术开发区 550m</view>
|
||||
<view class="row-left mineText">{{ item.companyName }}</view>
|
||||
<view class="row-right mineText">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="item.jobLocationAreaCode"></dict-Label>
|
||||
<convert-distance
|
||||
:alat="item.latitude"
|
||||
:along="item.longitude"
|
||||
:blat="latitude()"
|
||||
:blong="longitude()"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import point2 from '@/static/icon/point2.png';
|
||||
import LocationPng from '@/static/icon/Location.png';
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
import bingProgressComponent from '/components/bing-progress/bing-progress.vue';
|
||||
import screeningJobRequirementsVue from '@/components/screening-job-requirements/screening-job-requirements.vue';
|
||||
import { reactive, inject, watch, ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
const { getLocation, longitude, latitude } = useLocationStore();
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { msg } from '../../../common/globalFunction';
|
||||
const { $api, navTo, debounce, vacanciesTo, customSystem, formatTotal } = inject('globalFunction');
|
||||
const emit = defineEmits(['onFilter']);
|
||||
|
||||
const tMap = ref();
|
||||
const progress = ref();
|
||||
const state = reactive({
|
||||
progressWidth: '150px',
|
||||
const mapCovers = ref([]);
|
||||
const mapCircles = ref([]);
|
||||
const mapControls = ref([
|
||||
{
|
||||
id: 1,
|
||||
position: {
|
||||
// 控件位置
|
||||
left: customSystem.systemInfo.screenWidth - 50,
|
||||
top: 180,
|
||||
width: 30,
|
||||
height: 30,
|
||||
},
|
||||
iconPath: LocationPng, // 控件图标
|
||||
},
|
||||
]);
|
||||
const loadmoreRef = ref(null);
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 100,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
radius: 1,
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const isLoaded = ref(false);
|
||||
const list = ref([]);
|
||||
const state = reactive({
|
||||
progressWidth: '200px',
|
||||
});
|
||||
|
||||
onLoad(() => {});
|
||||
|
||||
function navToPost(jobId) {
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(jobId)}`);
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
isLoaded.value = true;
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
function scrollBottom() {
|
||||
getJobList();
|
||||
loadmoreRef.value.change('loading');
|
||||
}
|
||||
|
||||
function handleControl(e) {
|
||||
switch (e.detail.controlId) {
|
||||
case 1:
|
||||
getInit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query
|
||||
.select('.tab-scroll')
|
||||
.boundingClientRect((data) => {
|
||||
state.progressWidth = data.width - 50 + 'px';
|
||||
})
|
||||
.exec();
|
||||
tMap.value.open(104.397894, 31.126855);
|
||||
$api.msg('使用模拟定位');
|
||||
getInit();
|
||||
});
|
||||
|
||||
// 初始化
|
||||
function LoadComplite() {
|
||||
console.log('天地图加载完成');
|
||||
const list = [
|
||||
function getInit() {
|
||||
getLocation().then((res) => {
|
||||
mapCovers.value = [
|
||||
{
|
||||
latitude: res.latitude,
|
||||
longitude: res.longitude,
|
||||
iconPath: point2,
|
||||
},
|
||||
];
|
||||
mapCircles.value = [
|
||||
{
|
||||
latitude: res.latitude,
|
||||
longitude: res.longitude,
|
||||
radius: 1000,
|
||||
fillColor: '#00b8002e',
|
||||
},
|
||||
];
|
||||
getJobList('refresh');
|
||||
});
|
||||
}
|
||||
|
||||
function progressChange(e) {
|
||||
const range = 1 + e.value;
|
||||
pageState.search.radius = range;
|
||||
mapCircles.value = [
|
||||
{
|
||||
id: 0,
|
||||
label: '',
|
||||
lat: 31.126855,
|
||||
lon: 104.397894,
|
||||
latitude: latitude(),
|
||||
longitude: longitude(),
|
||||
radius: range * 1000,
|
||||
fillColor: '#00b8002e',
|
||||
},
|
||||
];
|
||||
tMap.value.addFeature(list);
|
||||
debounceAjax('refresh');
|
||||
}
|
||||
function progressChange(e) {
|
||||
tMap.value.changeRange(e.value);
|
||||
|
||||
let debounceAjax = debounce(getJobList, 500);
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
longitude: longitude(),
|
||||
latitude: latitude(),
|
||||
...pageState.search,
|
||||
};
|
||||
|
||||
$api.createRequest('/app/job/nearJob', params, 'POST').then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = rows;
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function handleFilterConfirm(val) {
|
||||
pageState.search = {
|
||||
radius: pageState.search.radius,
|
||||
order: pageState.search.order,
|
||||
};
|
||||
for (const [key, value] of Object.entries(val)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
defineExpose({ loadData, handleFilterConfirm });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@@ -115,8 +272,9 @@ function progressChange(e) {
|
||||
.nearby-map
|
||||
height: 467rpx;
|
||||
background: #e8e8e8;
|
||||
overflow: hidden
|
||||
.nearby-list
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
// background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
.list-head
|
||||
height: 77rpx;
|
||||
background-color: #FFFFFF;
|
||||
@@ -163,7 +321,8 @@ function progressChange(e) {
|
||||
align-items: center;
|
||||
.tab-recommend
|
||||
white-space: nowrap;
|
||||
width: 92rpx;
|
||||
width: fit-content;
|
||||
padding: 0 10rpx;
|
||||
height: 42rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 17rpx 17rpx 0rpx 17rpx;
|
||||
@@ -186,7 +345,7 @@ function progressChange(e) {
|
||||
.one-cards
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 20rpx;
|
||||
padding: 0 20rpx 20rpx 20rpx;
|
||||
.card-box
|
||||
width: calc(100% - 36rpx - 36rpx);
|
||||
border-radius: 0rpx 0rpx 0rpx 0rpx;
|
||||
@@ -205,6 +364,9 @@ function progressChange(e) {
|
||||
color: #606060;
|
||||
.textblue
|
||||
color: #4778EC;
|
||||
.row-right
|
||||
min-width: 120rpx
|
||||
text-align: right
|
||||
.row-left
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,20 +1,44 @@
|
||||
<template>
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll">
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="three-head" @touchmove.stop.prevent>
|
||||
<scroll-view class="scroll-head" :scroll-x="true" :show-scrollbar="false">
|
||||
<view class="metro">
|
||||
<view class="metro-one">1号线</view>
|
||||
<view class="metro-two">王家港-东郭庄</view>
|
||||
<view class="metro-one">
|
||||
<picker
|
||||
class="one-picker"
|
||||
@change="bindPickerChange"
|
||||
@cancel="state.downup = true"
|
||||
@click="state.downup = false"
|
||||
:value="state.value"
|
||||
range-key="text"
|
||||
:range="range"
|
||||
>
|
||||
<view class="one-picker">
|
||||
<view class="uni-input">{{ inputText(state.subwayId) }}</view>
|
||||
<uni-icons v-if="state.downup" type="down" size="16"></uni-icons>
|
||||
<uni-icons v-else type="up" size="16"></uni-icons>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="metro-two">{{ state.subwayStart.stationName }}-{{ state.subwayEnd.stationName }}</view>
|
||||
<view class="metro-three">
|
||||
<view class="three-background">
|
||||
<view class="three-items">
|
||||
<view class="three-item">
|
||||
<view class="item-dont dontstart"></view>
|
||||
<view class="item-text">王家港</view>
|
||||
</view>
|
||||
<view class="three-item" v-for="(item, index) in 20" :key="index">
|
||||
<view class="item-dont"></view>
|
||||
<view class="item-text">王家港</view>
|
||||
<view
|
||||
class="three-item"
|
||||
v-for="(item, index) in subwayCurrent.subwayStationList"
|
||||
@click="selectSubwayStation(item, index)"
|
||||
:key="index"
|
||||
>
|
||||
<view
|
||||
class="item-dont"
|
||||
:class="{
|
||||
dontstart: index === 0,
|
||||
dontend: index === subwayCurrent.subwayStationList.length - 1,
|
||||
donted: index === state.dont,
|
||||
}"
|
||||
></view>
|
||||
<view class="item-text">{{ item.stationName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -25,58 +49,271 @@
|
||||
<view class="nearby-list">
|
||||
<view class="list-head" @touchmove.stop.prevent>
|
||||
<view class="tab-options">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll" @touchmove.stop>
|
||||
<view class="tab-op-left">
|
||||
<view class="tab-list" v-for="(item, index) in 4" :key="index">中国万岁</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === 'all' }"
|
||||
@click="choosePosition('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === index }"
|
||||
v-for="(item, index) in userInfo.jobTitle"
|
||||
:key="index"
|
||||
@click="choosePosition(index)"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-op-right">
|
||||
<view class="tab-recommend">推荐</view>
|
||||
<view class="tab-filter">
|
||||
<view class="tab-number">1000+</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view class="tab-recommend">
|
||||
<latestHotestStatus @confirm="handelHostestSearch"></latestHotestStatus>
|
||||
</view>
|
||||
<view class="tab-filter" @click="emit('onFilter', 2)">
|
||||
<view class="tab-number" v-show="pageState.total">{{ formatTotal(pageState.total) }}</view>
|
||||
<image class="image" src="/static/icon/filter.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="one-cards">
|
||||
<view class="card-box" v-for="(item, index) in 20" :key="index">
|
||||
<view class="card-box" v-for="(item, index) in list" :key="item.jobId" @click="navToPost(item.jobId)">
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-left">销售工程师-高级销售经理</view>
|
||||
<view class="row-right">1万-2万</view>
|
||||
<view class="row-left">{{ item.jobTitle }}</view>
|
||||
<view class="row-right">
|
||||
<Salary-Expectation
|
||||
:max-salary="item.maxSalary"
|
||||
:min-salary="item.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left">
|
||||
<view class="row-tag">本科</view>
|
||||
<view class="row-tag">1-5年</view>
|
||||
<view class="row-tag" v-if="item.education">
|
||||
<dict-Label dictType="education" :value="item.education"></dict-Label>
|
||||
</view>
|
||||
<view class="row-tag" v-if="item.experience">
|
||||
<dict-Label dictType="experience" :value="item.experience"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-item mineText">2024.1.8</view>
|
||||
<view class="row-item mineText">8人</view>
|
||||
<view class="row-item mineText textblue">匹配度93%</view>
|
||||
<view class="row-item mineText">{{ item.postingDate || '发布日期' }}</view>
|
||||
<view class="row-item mineText">{{ vacanciesTo(item.vacancies) }}</view>
|
||||
<view class="row-item mineText textblue"><matchingDegree :job="item"></matchingDegree></view>
|
||||
<view class="row-item">
|
||||
<uni-icons type="star" size="28"></uni-icons>
|
||||
<!-- <uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left mineText">湖南沃森电气科技有限公司</view>
|
||||
<view class="row-right mineText">青岛 青岛经济技术开发区 550m</view>
|
||||
<view class="row-left mineText">{{ item.companyName }}</view>
|
||||
<view class="row-right mineText">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="item.jobLocationAreaCode"></dict-Label>
|
||||
<convert-distance
|
||||
:alat="item.latitude"
|
||||
:along="item.longitude"
|
||||
:blat="latitude()"
|
||||
:blong="longitude()"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
const state = reactive({});
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
const { $api, navTo, vacanciesTo, formatTotal } = inject('globalFunction');
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const { getLocation, longitude, latitude } = useLocationStore();
|
||||
const emit = defineEmits(['onFilter']);
|
||||
// status
|
||||
const subwayCurrent = ref([]);
|
||||
const isLoaded = ref(false);
|
||||
const range = ref([]);
|
||||
const userInfo = ref({});
|
||||
const state = reactive({
|
||||
subwayList: [],
|
||||
subwayStart: {},
|
||||
subwayEnd: {},
|
||||
value: 0,
|
||||
subwayId: 0,
|
||||
downup: true,
|
||||
dont: 0,
|
||||
dontObj: {},
|
||||
tabIndex: 'all',
|
||||
});
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const list = ref([]);
|
||||
const loadmoreRef = ref(null);
|
||||
|
||||
onLoad(() => {
|
||||
getSubway();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
userInfo.value = useUserStore().userInfo;
|
||||
});
|
||||
|
||||
function navToPost(jobId) {
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(jobId)}`);
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
getJobList('refresh');
|
||||
isLoaded.value = true;
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
getJobList();
|
||||
loadmoreRef.value.change('loading');
|
||||
}
|
||||
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
if (index === 'all') {
|
||||
pageState.search.jobTitle = '';
|
||||
} else {
|
||||
pageState.search.jobTitle = useUserStore().userInfo.jobTitle[index];
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function selectSubwayStation(point, index) {
|
||||
console.log(point, index);
|
||||
state.dont = index;
|
||||
state.dontObj = point;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function inputText(id) {
|
||||
if (id) {
|
||||
const text = range.value.filter((item) => item.value === id)[0].text;
|
||||
return text;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function bindPickerChange(e) {
|
||||
const lineId = range.value[e.detail.value];
|
||||
const value = state.subwayList.filter((iv) => iv.lineId === lineId.value)[0];
|
||||
subwayCurrent.value = value;
|
||||
state.value = e.detail.value;
|
||||
state.subwayId = value.lineId;
|
||||
const points = value.subwayStationList;
|
||||
state.downup = true;
|
||||
if (points.length) {
|
||||
state.dont = 0;
|
||||
state.dontObj = points[0];
|
||||
state.subwayStart = points[0];
|
||||
state.subwayEnd = points[points.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
function getSubway() {
|
||||
$api.createRequest(`/app/common/subway`).then((resData) => {
|
||||
state.subwayList = resData.data;
|
||||
subwayCurrent.value = resData.data[0];
|
||||
state.subwayId = resData.data[0].lineId;
|
||||
state.value = 0;
|
||||
state.dont = 0;
|
||||
range.value = resData.data.map((iv) => ({ text: iv.lineName, value: iv.lineId }));
|
||||
const points = resData.data[0].subwayStationList;
|
||||
if (points.length) {
|
||||
state.dont = 0;
|
||||
state.dontObj = points[0];
|
||||
state.subwayStart = points[0];
|
||||
state.subwayEnd = points[points.length - 1];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
subwayIds: [state.dontObj.stationId],
|
||||
latitude: state.dontObj.latitude,
|
||||
longitude: state.dontObj.longitude,
|
||||
radius: 2,
|
||||
...pageState.search,
|
||||
};
|
||||
$api.createRequest('/app/job/subway', params, 'POST').then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = rows;
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function handleFilterConfirm(val) {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
for (const [key, value] of Object.entries(val)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
defineExpose({ loadData, handleFilterConfirm });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tabchecked
|
||||
color: #4778EC !important;
|
||||
.nearby-scroll
|
||||
overflow: hidden;
|
||||
.three-head
|
||||
@@ -93,6 +330,14 @@ const state = reactive({});
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
line-height: 33rpx;
|
||||
width: fit-content;
|
||||
min-width: 100rpx;
|
||||
.one-picker
|
||||
width: 100%
|
||||
height: 100%
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
.metro-two
|
||||
font-size: 21rpx;
|
||||
color: #606060;
|
||||
@@ -118,6 +363,19 @@ const state = reactive({});
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin-bottom: 10rpx;
|
||||
.donted::after
|
||||
position: absolute;
|
||||
content: '';
|
||||
color: #FFFFFF;
|
||||
font-size: 20rpx;
|
||||
text-align: center;
|
||||
left: 0;
|
||||
top: -5rpx;
|
||||
width: 27rpx;
|
||||
height: 27rpx;
|
||||
line-height: 28rpx;
|
||||
background: blue !important;
|
||||
border-radius: 50%;
|
||||
.dontstart::after
|
||||
position: absolute;
|
||||
content: '始';
|
||||
@@ -129,7 +387,20 @@ const state = reactive({});
|
||||
width: 27rpx;
|
||||
height: 27rpx;
|
||||
line-height: 28rpx;
|
||||
background: blue;
|
||||
background: #666666;
|
||||
border-radius: 50%;
|
||||
.dontend::after
|
||||
position: absolute;
|
||||
content: '终点';
|
||||
color: #FFFFFF;
|
||||
font-size: 20rpx;
|
||||
text-align: center;
|
||||
left: 0;
|
||||
top: -5rpx;
|
||||
width: 27rpx;
|
||||
height: 27rpx;
|
||||
line-height: 28rpx;
|
||||
background: #666666;
|
||||
border-radius: 50%;
|
||||
.item-text
|
||||
width: 23rpx;
|
||||
@@ -151,14 +422,14 @@ const state = reactive({});
|
||||
z-index: 1;
|
||||
.nearby-list
|
||||
margin-top: 40rpx;
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
// background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
.list-head
|
||||
height: 77rpx;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 17rpx 17rpx 0rpx 0rpx;
|
||||
position: relative;
|
||||
top: -17rpx;
|
||||
z-index: 9999;
|
||||
z-index: 2;
|
||||
.tab-options
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -189,7 +460,8 @@ const state = reactive({});
|
||||
align-items: center;
|
||||
.tab-recommend
|
||||
white-space: nowrap;
|
||||
width: 92rpx;
|
||||
width: fit-content;
|
||||
padding: 0 10rpx;
|
||||
height: 42rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 17rpx 17rpx 0rpx 17rpx;
|
||||
@@ -231,6 +503,9 @@ const state = reactive({});
|
||||
color: #606060;
|
||||
.textblue
|
||||
color: #4778EC;
|
||||
.row-right
|
||||
min-width: 120rpx
|
||||
text-align: right
|
||||
.row-left
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,72 +1,237 @@
|
||||
<template>
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll">
|
||||
<scroll-view :scroll-y="true" class="nearby-scroll" @scrolltolower="scrollBottom">
|
||||
<view class="two-head">
|
||||
<view class="head-item active">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view class="head-item">市北区</view>
|
||||
<view
|
||||
class="head-item"
|
||||
:class="{ active: item.value === fromValue.area }"
|
||||
v-for="(item, index) in oneDictData('area')"
|
||||
:key="item.value"
|
||||
@click="changeArea(item.value, item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
<view
|
||||
class="head-item"
|
||||
:class="{ active: state.tabBxText === fromValue.area }"
|
||||
@click="changeArea(state.tabBxText, item)"
|
||||
>
|
||||
不限区域
|
||||
</view>
|
||||
</view>
|
||||
<view class="nearby-list">
|
||||
<view class="list-head" @touchmove.stop.prevent>
|
||||
<view class="tab-options">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll">
|
||||
<scroll-view :scroll-x="true" :show-scrollbar="false" class="tab-scroll" @touchmove.stop>
|
||||
<view class="tab-op-left">
|
||||
<view class="tab-list" v-for="(item, index) in 4" :key="index">中国万岁</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === 'all' }"
|
||||
@click="choosePosition('all')"
|
||||
>
|
||||
全部
|
||||
</view>
|
||||
<view
|
||||
class="tab-list"
|
||||
:class="{ tabchecked: state.tabIndex === index }"
|
||||
@click="choosePosition(index)"
|
||||
v-for="(item, index) in userInfo.jobTitle"
|
||||
:key="index"
|
||||
>
|
||||
{{ item }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-op-right">
|
||||
<view class="tab-recommend">推荐</view>
|
||||
<view class="tab-filter">
|
||||
<view class="tab-number">1000+</view>
|
||||
<uni-icons type="plusempty" style="margin-right: 10rpx" size="20"></uni-icons>
|
||||
<view class="tab-recommend">
|
||||
<latestHotestStatus @confirm="handelHostestSearch"></latestHotestStatus>
|
||||
</view>
|
||||
<view class="tab-filter" @click="emit('onFilter', 1)">
|
||||
<view class="tab-number" v-show="pageState.total">{{ formatTotal(pageState.total) }}</view>
|
||||
<image class="image" src="/static/icon/filter.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="one-cards">
|
||||
<view class="card-box" v-for="(item, index) in 20" :key="index">
|
||||
<view class="card-box" v-for="(item, index) in list" :key="item.jobId" @click="navToPost(item.jobId)">
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-left">销售工程师-高级销售经理</view>
|
||||
<view class="row-right">1万-2万</view>
|
||||
<view class="row-left">{{ item.jobTitle }}</view>
|
||||
<view class="row-right">
|
||||
<Salary-Expectation
|
||||
:max-salary="item.maxSalary"
|
||||
:min-salary="item.minSalary"
|
||||
></Salary-Expectation>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left">
|
||||
<view class="row-tag">本科</view>
|
||||
<view class="row-tag">1-5年</view>
|
||||
<view class="row-tag" v-if="item.education">
|
||||
<dict-Label dictType="education" :value="item.education"></dict-Label>
|
||||
</view>
|
||||
<view class="row-tag" v-if="item.experience">
|
||||
<dict-Label dictType="experience" :value="item.experience"></dict-Label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row mar_top0">
|
||||
<view class="row-item mineText">2024.1.8</view>
|
||||
<view class="row-item mineText">8人</view>
|
||||
<view class="row-item mineText textblue">匹配度93%</view>
|
||||
<view class="row-item mineText">{{ item.postingDate || '发布日期' }}</view>
|
||||
<view class="row-item mineText">{{ vacanciesTo(item.vacancies) }}</view>
|
||||
<view class="row-item mineText textblue"><matchingDegree :job="item"></matchingDegree></view>
|
||||
<view class="row-item">
|
||||
<uni-icons type="star" size="28"></uni-icons>
|
||||
<!-- <uni-icons type="star-filled" color="#FFCB47" size="30"></uni-icons> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-row">
|
||||
<view class="row-left mineText">湖南沃森电气科技有限公司</view>
|
||||
<view class="row-right mineText">青岛 青岛经济技术开发区 550m</view>
|
||||
<view class="row-left mineText">{{ item.companyName }}</view>
|
||||
<view class="row-right mineText">
|
||||
青岛
|
||||
<dict-Label dictType="area" :value="item.jobLocationAreaCode"></dict-Label>
|
||||
<convert-distance
|
||||
:alat="item.latitude"
|
||||
:along="item.longitude"
|
||||
:blat="latitude()"
|
||||
:blong="longitude()"
|
||||
></convert-distance>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<loadmore ref="loadmoreRef"></loadmore>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import dictLabel from '@/components/dict-Label/dict-Label.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
const state = reactive({});
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import useLocationStore from '@/stores/useLocationStore';
|
||||
const { getLocation, longitude, latitude } = useLocationStore();
|
||||
const { getDictSelectOption, oneDictData } = useDictStore();
|
||||
const { $api, navTo, vacanciesTo, formatTotal } = inject('globalFunction');
|
||||
const emit = defineEmits(['onFilter']);
|
||||
const state = reactive({
|
||||
tabIndex: 'all',
|
||||
tabBxText: 'buxianquyu',
|
||||
});
|
||||
const isLoaded = ref(false);
|
||||
const fromValue = reactive({
|
||||
area: 0,
|
||||
});
|
||||
const loadmoreRef = ref(null);
|
||||
const userInfo = ref({});
|
||||
const pageState = reactive({
|
||||
page: 0,
|
||||
total: 0,
|
||||
maxPage: 2,
|
||||
pageSize: 10,
|
||||
search: {
|
||||
order: 0,
|
||||
},
|
||||
});
|
||||
const list = ref([]);
|
||||
|
||||
onShow(() => {
|
||||
userInfo.value = useUserStore().userInfo;
|
||||
});
|
||||
|
||||
function navToPost(jobId) {
|
||||
navTo(`/packageA/pages/post/post?jobId=${btoa(jobId)}`);
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
if (isLoaded.value) return;
|
||||
const area = oneDictData('area')[0];
|
||||
fromValue.area = area.value;
|
||||
getJobList('refresh');
|
||||
isLoaded.value = true;
|
||||
} catch (err) {
|
||||
isLoaded.value = false; // 重置状态允许重试
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function scrollBottom() {
|
||||
getJobList();
|
||||
loadmoreRef.value.change('loading');
|
||||
}
|
||||
|
||||
function choosePosition(index) {
|
||||
state.tabIndex = index;
|
||||
if (index === 'all') {
|
||||
pageState.search.jobTitle = '';
|
||||
} else {
|
||||
pageState.search.jobTitle = useUserStore().userInfo.jobTitle[index];
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
function changeArea(area, item) {
|
||||
fromValue.area = area;
|
||||
getJobList('refresh');
|
||||
}
|
||||
function getJobList(type = 'add') {
|
||||
if (type === 'add' && pageState.page < pageState.maxPage) {
|
||||
pageState.page += 1;
|
||||
}
|
||||
if (type === 'refresh') {
|
||||
pageState.page = 1;
|
||||
pageState.maxPage = 2;
|
||||
}
|
||||
let params = {
|
||||
current: pageState.page,
|
||||
pageSize: pageState.pageSize,
|
||||
countyIds: [fromValue.area],
|
||||
...pageState.search,
|
||||
};
|
||||
if (fromValue.area === state.tabBxText) {
|
||||
params.countyIds = [];
|
||||
}
|
||||
$api.createRequest('/app/job/countyJob', params, 'POST').then((resData) => {
|
||||
const { rows, total } = resData;
|
||||
if (type === 'add') {
|
||||
const str = pageState.pageSize * (pageState.page - 1);
|
||||
const end = list.value.length;
|
||||
const reslist = rows;
|
||||
list.value.splice(str, end, ...reslist);
|
||||
} else {
|
||||
list.value = rows;
|
||||
}
|
||||
pageState.total = resData.total;
|
||||
pageState.maxPage = Math.ceil(pageState.total / pageState.pageSize);
|
||||
if (rows.length < pageState.pageSize) {
|
||||
loadmoreRef.value.change('noMore');
|
||||
} else {
|
||||
loadmoreRef.value.change('more');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handelHostestSearch(val) {
|
||||
pageState.search.order = val.value;
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
function handleFilterConfirm(val) {
|
||||
pageState.search = {
|
||||
order: pageState.search.order,
|
||||
};
|
||||
for (const [key, value] of Object.entries(val)) {
|
||||
pageState.search[key] = value.join(',');
|
||||
}
|
||||
getJobList('refresh');
|
||||
}
|
||||
|
||||
defineExpose({ loadData, handleFilterConfirm });
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tabchecked
|
||||
color: #4778EC !important
|
||||
.nearby-scroll
|
||||
overflow: hidden;
|
||||
.two-head
|
||||
@@ -93,7 +258,7 @@ const state = reactive({});
|
||||
color: #FFFFFF;
|
||||
.nearby-list
|
||||
margin-top: 40rpx;
|
||||
background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
// background: linear-gradient( 180deg, #4778EC 0%, #002979 100%);
|
||||
.list-head
|
||||
height: 77rpx;
|
||||
background-color: #FFFFFF;
|
||||
@@ -131,7 +296,8 @@ const state = reactive({});
|
||||
align-items: center;
|
||||
.tab-recommend
|
||||
white-space: nowrap;
|
||||
width: 92rpx;
|
||||
width: fit-content;
|
||||
padding: 0 10rpx;
|
||||
height: 42rpx;
|
||||
background: #4778EC;
|
||||
border-radius: 17rpx 17rpx 0rpx 17rpx;
|
||||
@@ -173,6 +339,9 @@ const state = reactive({});
|
||||
color: #606060;
|
||||
.textblue
|
||||
color: #4778EC;
|
||||
.row-right
|
||||
min-width: 120rpx
|
||||
text-align: right
|
||||
.row-left
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -8,44 +8,112 @@
|
||||
</view>
|
||||
<view class="nearby-content">
|
||||
<swiper class="swiper" :current="state.current" @change="changeSwiperType">
|
||||
<swiper-item class="swiper-item" disable-touch>
|
||||
<oneComponent></oneComponent>
|
||||
</swiper-item>
|
||||
<swiper-item class="swiper-item">
|
||||
<twoComponent></twoComponent>
|
||||
</swiper-item>
|
||||
<swiper-item class="swiper-item">
|
||||
<threeComponent></threeComponent>
|
||||
</swiper-item>
|
||||
<swiper-item class="swiper-item">
|
||||
<fourComponent></fourComponent>
|
||||
<!-- 动态绑定ref -->
|
||||
<swiper-item class="swiper-item" v-for="(_, index) in 4" :key="index">
|
||||
<component
|
||||
:is="components[index]"
|
||||
@onFilter="addfileter"
|
||||
:ref="(el) => handelComponentsRef(el, index)"
|
||||
/>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
<!-- 弹窗 -->
|
||||
<screeningJobRequirementsVue
|
||||
:area="false"
|
||||
v-model:show="showFilter"
|
||||
@confirm="handleFilterConfirm"
|
||||
></screeningJobRequirementsVue>
|
||||
<screeningJobRequirementsVue
|
||||
:area="false"
|
||||
v-model:show="showFilter1"
|
||||
@confirm="handleFilterConfirm"
|
||||
></screeningJobRequirementsVue>
|
||||
<screeningJobRequirementsVue
|
||||
:area="false"
|
||||
v-model:show="showFilter2"
|
||||
@confirm="handleFilterConfirm"
|
||||
></screeningJobRequirementsVue>
|
||||
<screeningJobRequirementsVue
|
||||
:area="false"
|
||||
v-model:show="showFilter3"
|
||||
@confirm="handleFilterConfirm"
|
||||
></screeningJobRequirementsVue>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import screeningJobRequirementsVue from '@/components/screening-job-requirements/screening-job-requirements.vue';
|
||||
import oneComponent from './components/one.vue';
|
||||
import twoComponent from './components/two.vue';
|
||||
import threeComponent from './components/three.vue';
|
||||
import fourComponent from './components/four.vue';
|
||||
import { reactive, inject, watch, ref, onMounted } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
const { $api, debounce, throttle } = inject('globalFunction');
|
||||
const loadedMap = reactive([false, false, false, false]);
|
||||
const swiperRefs = [ref(null), ref(null), ref(null), ref(null)];
|
||||
const components = [oneComponent, twoComponent, threeComponent, fourComponent];
|
||||
|
||||
const filterId = ref(0);
|
||||
const showFilter = ref(false);
|
||||
const showFilter1 = ref(false);
|
||||
const showFilter2 = ref(false);
|
||||
const showFilter3 = ref(false);
|
||||
|
||||
const state = reactive({
|
||||
current: 2,
|
||||
current: 0,
|
||||
all: [{}],
|
||||
});
|
||||
|
||||
onLoad(() => {});
|
||||
// filter education aera scale 。。。。
|
||||
function handleFilterConfirm(e) {
|
||||
swiperRefs[filterId.value].value?.handleFilterConfirm(e);
|
||||
}
|
||||
|
||||
function addfileter(val) {
|
||||
filterId.value = val;
|
||||
switch (val) {
|
||||
case 0:
|
||||
showFilter.value = true;
|
||||
break;
|
||||
case 1:
|
||||
showFilter1.value = true;
|
||||
break;
|
||||
case 2:
|
||||
showFilter2.value = true;
|
||||
break;
|
||||
case 3:
|
||||
showFilter3.value = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleTabChange(state.current);
|
||||
});
|
||||
|
||||
const handelComponentsRef = (el, index) => {
|
||||
if (el) {
|
||||
swiperRefs[index].value = el;
|
||||
}
|
||||
};
|
||||
// 查看消息类型
|
||||
function changeSwiperType(e) {
|
||||
const currented = e.detail.current;
|
||||
state.current = currented;
|
||||
const index = e.detail.current;
|
||||
state.current = index;
|
||||
handleTabChange(index);
|
||||
}
|
||||
function changeType(index) {
|
||||
state.current = index;
|
||||
handleTabChange(index);
|
||||
}
|
||||
|
||||
function handleTabChange(index) {
|
||||
if (!loadedMap[index]) {
|
||||
swiperRefs[index].value?.loadData();
|
||||
loadedMap[index] = true;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -68,7 +136,7 @@ function changeType(index) {
|
||||
width: calc(100% / 4);
|
||||
z-index: 9
|
||||
.actived
|
||||
width: 169rpx;
|
||||
// width: 169rpx;
|
||||
height: 63rpx;
|
||||
background: #13C57C;
|
||||
box-shadow: 0rpx 7rpx 7rpx 0rpx rgba(0,0,0,0.25);
|
||||
|
||||
Reference in New Issue
Block a user